blob: 78e1544b4d32d01bd4f641088316bedb7eee9523 [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',
Peter Kotwicz3c339f32020-10-19 19:59:181378 'testing/scripts/run_isolated_script_test.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041379 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421380 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1381 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131382 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Caleb Raitto28864fc2020-01-07 00:18:191383 ('third_party/blink/renderer/bindings/scripts/'
1384 'generate_high_entropy_list.pydeps'),
John Budorickbc3571aa2019-04-25 02:20:061385 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221386 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401387]
1388
wnwenbdc444e2016-05-25 13:44:151389
agrievef32bcc72016-04-04 14:57:401390_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1391
1392
Eric Boren6fd2b932018-01-25 15:05:081393# Bypass the AUTHORS check for these accounts.
1394_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591395 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451396 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591397 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521398 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Rakib M. Hasan015291ed2020-10-14 17:13:071399 'wpt-autoroller', 'chrome-weblayer-builder')
Eric Boren835d71f2018-09-07 21:09:041400 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271401 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041402 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:301403 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:081404
1405
Daniel Bratell65b033262019-04-23 08:17:061406def _IsCPlusPlusFile(input_api, file_path):
1407 """Returns True if this file contains C++-like code (and not Python,
1408 Go, Java, MarkDown, ...)"""
1409
1410 ext = input_api.os_path.splitext(file_path)[1]
1411 # This list is compatible with CppChecker.IsCppFile but we should
1412 # consider adding ".c" to it. If we do that we can use this function
1413 # at more places in the code.
1414 return ext in (
1415 '.h',
1416 '.cc',
1417 '.cpp',
1418 '.m',
1419 '.mm',
1420 )
1421
1422def _IsCPlusPlusHeaderFile(input_api, file_path):
1423 return input_api.os_path.splitext(file_path)[1] == ".h"
1424
1425
1426def _IsJavaFile(input_api, file_path):
1427 return input_api.os_path.splitext(file_path)[1] == ".java"
1428
1429
1430def _IsProtoFile(input_api, file_path):
1431 return input_api.os_path.splitext(file_path)[1] == ".proto"
1432
Saagar Sanghavifceeaae2020-08-12 16:40:361433def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
[email protected]55459852011-08-10 15:17:191434 """Attempts to prevent use of functions intended only for testing in
1435 non-testing code. For now this is just a best-effort implementation
1436 that ignores header files and may have some false positives. A
1437 better implementation would probably need a proper C++ parser.
1438 """
1439 # We only scan .cc files and the like, as the declaration of
1440 # for-testing functions in header files are hard to distinguish from
1441 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491442 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191443
jochenc0d4808c2015-07-27 09:25:421444 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191445 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091446 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
danakjf26536bf2020-09-10 00:46:131447 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
[email protected]55459852011-08-10 15:17:191448 exclusion_pattern = input_api.re.compile(
1449 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1450 base_function_pattern, base_function_pattern))
danakjf26536bf2020-09-10 00:46:131451 # Avoid a false positive in this case, where the method name, the ::, and
1452 # the closing { are all on different lines due to line wrapping.
1453 # HelperClassForTesting::
1454 # HelperClassForTesting(
1455 # args)
1456 # : member(0) {}
1457 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191458
1459 def FilterFile(affected_file):
James Cook24a504192020-07-23 00:08:441460 files_to_skip = (_EXCLUDED_PATHS +
1461 _TEST_CODE_EXCLUDED_PATHS +
1462 input_api.DEFAULT_FILES_TO_SKIP)
[email protected]55459852011-08-10 15:17:191463 return input_api.FilterSourceFile(
1464 affected_file,
James Cook24a504192020-07-23 00:08:441465 files_to_check=file_inclusion_pattern,
1466 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191467
1468 problems = []
1469 for f in input_api.AffectedSourceFiles(FilterFile):
1470 local_path = f.LocalPath()
danakjf26536bf2020-09-10 00:46:131471 in_method_defn = False
[email protected]825d27182014-01-02 21:24:241472 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031473 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461474 not comment_pattern.search(line) and
danakjf26536bf2020-09-10 00:46:131475 not exclusion_pattern.search(line) and
1476 not allowlist_pattern.search(line) and
1477 not in_method_defn):
[email protected]55459852011-08-10 15:17:191478 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031479 '%s:%d\n %s' % (local_path, line_number, line.strip()))
danakjf26536bf2020-09-10 00:46:131480 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191481
1482 if problems:
[email protected]f7051d52013-04-02 18:31:421483 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031484 else:
1485 return []
[email protected]55459852011-08-10 15:17:191486
1487
Saagar Sanghavifceeaae2020-08-12 16:40:361488def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Vaclav Brozek7dbc28c2018-03-27 08:35:231489 """This is a simplified version of
Saagar Sanghavi0bc3e692020-08-13 19:46:591490 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
Vaclav Brozek7dbc28c2018-03-27 08:35:231491 """
1492 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1493 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1494 name_pattern = r'ForTest(s|ing)?'
1495 # Describes an occurrence of "ForTest*" inside a // comment.
1496 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
Peter Wen6367b882020-08-05 16:55:501497 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
Sky Malice9e6d6032020-10-15 22:49:551498 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
Vaclav Brozek7dbc28c2018-03-27 08:35:231499 # Catch calls.
1500 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1501 # Ignore definitions. (Comments are ignored separately.)
1502 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1503
1504 problems = []
1505 sources = lambda x: input_api.FilterSourceFile(
1506 x,
James Cook24a504192020-07-23 00:08:441507 files_to_skip=(('(?i).*test', r'.*\/junit\/')
1508 + input_api.DEFAULT_FILES_TO_SKIP),
1509 files_to_check=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231510 )
1511 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1512 local_path = f.LocalPath()
1513 is_inside_javadoc = False
1514 for line_number, line in f.ChangedContents():
1515 if is_inside_javadoc and javadoc_end_re.search(line):
1516 is_inside_javadoc = False
1517 if not is_inside_javadoc and javadoc_start_re.search(line):
1518 is_inside_javadoc = True
1519 if is_inside_javadoc:
1520 continue
1521 if (inclusion_re.search(line) and
1522 not comment_re.search(line) and
Peter Wen6367b882020-08-05 16:55:501523 not annotation_re.search(line) and
Vaclav Brozek7dbc28c2018-03-27 08:35:231524 not exclusion_re.search(line)):
1525 problems.append(
1526 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1527
1528 if problems:
1529 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1530 else:
1531 return []
1532
1533
Saagar Sanghavifceeaae2020-08-12 16:40:361534def CheckNoIOStreamInHeaders(input_api, output_api):
[email protected]10689ca2011-09-02 02:31:541535 """Checks to make sure no .h files include <iostream>."""
1536 files = []
1537 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1538 input_api.re.MULTILINE)
1539 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1540 if not f.LocalPath().endswith('.h'):
1541 continue
1542 contents = input_api.ReadFile(f)
1543 if pattern.search(contents):
1544 files.append(f)
1545
1546 if len(files):
yolandyandaabc6d2016-04-18 18:29:391547 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061548 'Do not #include <iostream> in header files, since it inserts static '
1549 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541550 '#include <ostream>. See http://crbug.com/94794',
1551 files) ]
1552 return []
1553
Danil Chapovalov3518f362018-08-11 16:13:431554def _CheckNoStrCatRedefines(input_api, output_api):
1555 """Checks no windows headers with StrCat redefined are included directly."""
1556 files = []
1557 pattern_deny = input_api.re.compile(
1558 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1559 input_api.re.MULTILINE)
1560 pattern_allow = input_api.re.compile(
1561 r'^#include\s"base/win/windows_defines.inc"',
1562 input_api.re.MULTILINE)
1563 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1564 contents = input_api.ReadFile(f)
1565 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1566 files.append(f.LocalPath())
1567
1568 if len(files):
1569 return [output_api.PresubmitError(
1570 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1571 'directly since they pollute code with StrCat macro. Instead, '
1572 'include matching header from base/win. See http://crbug.com/856536',
1573 files) ]
1574 return []
1575
[email protected]10689ca2011-09-02 02:31:541576
Saagar Sanghavifceeaae2020-08-12 16:40:361577def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521578 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181579 problems = []
1580 for f in input_api.AffectedFiles():
1581 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1582 continue
1583
1584 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041585 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181586 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1587
1588 if not problems:
1589 return []
1590 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1591 '\n'.join(problems))]
1592
Saagar Sanghavifceeaae2020-08-12 16:40:361593def CheckNoDISABLETypoInTests(input_api, output_api):
Dominic Battre033531052018-09-24 15:45:341594 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1595
1596 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1597 instead of DISABLED_. To filter false positives, reports are only generated
1598 if a corresponding MAYBE_ line exists.
1599 """
1600 problems = []
1601
1602 # The following two patterns are looked for in tandem - is a test labeled
1603 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1604 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1605 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1606
1607 # This is for the case that a test is disabled on all platforms.
1608 full_disable_pattern = input_api.re.compile(
1609 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1610 input_api.re.MULTILINE)
1611
Katie Df13948e2018-09-25 07:33:441612 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341613 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1614 continue
1615
1616 # Search for MABYE_, DISABLE_ pairs.
1617 disable_lines = {} # Maps of test name to line number.
1618 maybe_lines = {}
1619 for line_num, line in f.ChangedContents():
1620 disable_match = disable_pattern.search(line)
1621 if disable_match:
1622 disable_lines[disable_match.group(1)] = line_num
1623 maybe_match = maybe_pattern.search(line)
1624 if maybe_match:
1625 maybe_lines[maybe_match.group(1)] = line_num
1626
1627 # Search for DISABLE_ occurrences within a TEST() macro.
1628 disable_tests = set(disable_lines.keys())
1629 maybe_tests = set(maybe_lines.keys())
1630 for test in disable_tests.intersection(maybe_tests):
1631 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1632
1633 contents = input_api.ReadFile(f)
1634 full_disable_match = full_disable_pattern.search(contents)
1635 if full_disable_match:
1636 problems.append(' %s' % f.LocalPath())
1637
1638 if not problems:
1639 return []
1640 return [
1641 output_api.PresubmitPromptWarning(
1642 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1643 '\n'.join(problems))
1644 ]
1645
[email protected]72df4e782012-06-21 16:28:181646
Saagar Sanghavifceeaae2020-08-12 16:40:361647def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571648 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521649 errors = []
Hans Wennborg944479f2020-06-25 21:39:251650 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521651 input_api.re.MULTILINE)
1652 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1653 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1654 continue
1655 for lnum, line in f.ChangedContents():
1656 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171657 errors.append(output_api.PresubmitError(
1658 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571659 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171660 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521661 return errors
1662
1663
Makoto Shimazu3ad422cd2019-05-08 02:35:141664def _FindHistogramNameInChunk(histogram_name, chunk):
1665 """Tries to find a histogram name or prefix in a line.
1666
1667 Returns the existence of the histogram name, or None if it needs more chunk
1668 to determine."""
mcasasb7440c282015-02-04 14:52:191669 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
1670 # the histogram_name.
Makoto Shimazu3ad422cd2019-05-08 02:35:141671 if '<affected-histogram' in chunk:
1672 # If the tag is not completed, needs more chunk to get the name.
1673 if not '>' in chunk:
1674 return None
1675 if not 'name="' in chunk:
1676 return False
1677 # Retrieve the first portion of the chunk wrapped by double-quotations. We
1678 # expect the only attribute is the name.
1679 histogram_prefix = chunk.split('"')[1]
1680 return histogram_prefix in histogram_name
1681 # Typically the whole histogram name should in the line.
1682 return histogram_name in chunk
mcasasb7440c282015-02-04 14:52:191683
1684
Saagar Sanghavifceeaae2020-08-12 16:40:361685def CheckUmaHistogramChangesOnUpload(input_api, output_api):
mcasasb7440c282015-02-04 14:52:191686 """Check that UMA histogram names in touched lines can still be found in other
1687 lines of the patch or in histograms.xml. Note that this check would not catch
1688 the reverse: changes in histograms.xml not matched in the code itself."""
1689 touched_histograms = []
1690 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:471691 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
1692 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
1693 name_pattern = r'"(.*?)"'
1694 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
1695 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
1696 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
1697 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
1698 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:171699 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:191700 for f in input_api.AffectedFiles():
1701 # If histograms.xml itself is modified, keep the modified lines for later.
1702 if f.LocalPath().endswith(('histograms.xml')):
1703 histograms_xml_modifications = f.ChangedContents()
1704 continue
Vaclav Brozekbdac817c2018-03-24 06:30:471705 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
1706 single_line_re = single_line_c_re
1707 split_line_prefix_re = split_line_c_prefix_re
1708 elif f.LocalPath().endswith(('java')):
1709 single_line_re = single_line_java_re
1710 split_line_prefix_re = split_line_java_prefix_re
1711 else:
mcasasb7440c282015-02-04 14:52:191712 continue
1713 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:171714 if last_line_matched_prefix:
1715 suffix_found = split_line_suffix_re.search(line)
1716 if suffix_found :
1717 touched_histograms.append([suffix_found.group(1), f, line_num])
1718 last_line_matched_prefix = False
1719 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:061720 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:191721 if found:
1722 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:171723 continue
1724 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:191725
1726 # Search for the touched histogram names in the local modifications to
1727 # histograms.xml, and, if not found, on the base histograms.xml file.
1728 unmatched_histograms = []
1729 for histogram_info in touched_histograms:
1730 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141731 chunk = ''
mcasasb7440c282015-02-04 14:52:191732 for line_num, line in histograms_xml_modifications:
Makoto Shimazu3ad422cd2019-05-08 02:35:141733 chunk += line
1734 histogram_name_found = _FindHistogramNameInChunk(histogram_info[0], chunk)
1735 if histogram_name_found is None:
1736 continue
1737 chunk = ''
mcasasb7440c282015-02-04 14:52:191738 if histogram_name_found:
1739 break
1740 if not histogram_name_found:
1741 unmatched_histograms.append(histogram_info)
1742
eromanb90c82e7e32015-04-01 15:13:491743 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:191744 problems = []
1745 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:491746 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:191747 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:451748 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:191749 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141750 chunk = ''
mcasasb7440c282015-02-04 14:52:191751 for line in histograms_xml:
Makoto Shimazu3ad422cd2019-05-08 02:35:141752 chunk += line
1753 histogram_name_found = _FindHistogramNameInChunk(histogram_name,
1754 chunk)
1755 if histogram_name_found is None:
1756 continue
1757 chunk = ''
mcasasb7440c282015-02-04 14:52:191758 if histogram_name_found:
1759 break
1760 if not histogram_name_found:
1761 problems.append(' [%s:%d] %s' %
1762 (f.LocalPath(), line_num, histogram_name))
1763
1764 if not problems:
1765 return []
1766 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
1767 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:491768 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:191769
wnwenbdc444e2016-05-25 13:44:151770
Saagar Sanghavifceeaae2020-08-12 16:40:361771def CheckFlakyTestUsage(input_api, output_api):
yolandyandaabc6d2016-04-18 18:29:391772 """Check that FlakyTest annotation is our own instead of the android one"""
1773 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1774 files = []
1775 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1776 if f.LocalPath().endswith('Test.java'):
1777 if pattern.search(input_api.ReadFile(f)):
1778 files.append(f)
1779 if len(files):
1780 return [output_api.PresubmitError(
1781 'Use org.chromium.base.test.util.FlakyTest instead of '
1782 'android.test.FlakyTest',
1783 files)]
1784 return []
mcasasb7440c282015-02-04 14:52:191785
wnwenbdc444e2016-05-25 13:44:151786
Saagar Sanghavifceeaae2020-08-12 16:40:361787def CheckNoNewWStrings(input_api, output_api):
[email protected]8ea5d4b2011-09-13 21:49:221788 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271789 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221790 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201791 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571792 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341793 '/win/' in f.LocalPath() or
1794 'chrome_elf' in f.LocalPath() or
1795 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201796 continue
[email protected]8ea5d4b2011-09-13 21:49:221797
[email protected]a11dbe9b2012-08-07 01:32:581798 allowWString = False
[email protected]b5c24292011-11-28 14:38:201799 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581800 if 'presubmit: allow wstring' in line:
1801 allowWString = True
1802 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271803 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581804 allowWString = False
1805 else:
1806 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221807
[email protected]55463aa62011-10-12 00:48:271808 if not problems:
1809 return []
1810 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581811 ' If you are calling a cross-platform API that accepts a wstring, '
1812 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271813 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221814
1815
Saagar Sanghavifceeaae2020-08-12 16:40:361816def CheckNoDEPSGIT(input_api, output_api):
[email protected]2a8ac9c2011-10-19 17:20:441817 """Make sure .DEPS.git is never modified manually."""
1818 if any(f.LocalPath().endswith('.DEPS.git') for f in
1819 input_api.AffectedFiles()):
1820 return [output_api.PresubmitError(
1821 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1822 'automated system based on what\'s in DEPS and your changes will be\n'
1823 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501824 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1825 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441826 'for more information')]
1827 return []
1828
1829
Saagar Sanghavifceeaae2020-08-12 16:40:361830def CheckValidHostsInDEPSOnUpload(input_api, output_api):
tandriief664692014-09-23 14:51:471831 """Checks that DEPS file deps are from allowed_hosts."""
1832 # Run only if DEPS file has been modified to annoy fewer bystanders.
1833 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1834 return []
1835 # Outsource work to gclient verify
1836 try:
John Budorickf20c0042019-04-25 23:23:401837 gclient_path = input_api.os_path.join(
1838 input_api.PresubmitLocalPath(),
1839 'third_party', 'depot_tools', 'gclient.py')
1840 input_api.subprocess.check_output(
1841 [input_api.python_executable, gclient_path, 'verify'],
1842 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471843 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201844 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471845 return [output_api.PresubmitError(
1846 'DEPS file must have only git dependencies.',
1847 long_text=error.output)]
1848
1849
Mario Sanchez Prada2472cab2019-09-18 10:58:311850def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1851 type_name, message):
Saagar Sanghavi0bc3e692020-08-13 19:46:591852 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311853
1854 Returns an string composed of the name of the file, the line number where the
1855 match has been found and the additional text passed as |message| in case the
1856 target type name matches the text inside the line passed as parameter.
1857 """
Peng Huang9c5949a02020-06-11 19:20:541858 result = []
1859
1860 if line.endswith(" nocheck"):
1861 return result
1862
Mario Sanchez Prada2472cab2019-09-18 10:58:311863 matched = False
1864 if type_name[0:1] == '/':
1865 regex = type_name[1:]
1866 if input_api.re.search(regex, line):
1867 matched = True
1868 elif type_name in line:
1869 matched = True
1870
Mario Sanchez Prada2472cab2019-09-18 10:58:311871 if matched:
1872 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1873 for message_line in message:
1874 result.append(' %s' % message_line)
1875
1876 return result
1877
1878
Saagar Sanghavifceeaae2020-08-12 16:40:361879def CheckNoBannedFunctions(input_api, output_api):
[email protected]127f18ec2012-06-16 05:05:591880 """Make sure that banned functions are not used."""
1881 warnings = []
1882 errors = []
1883
James Cook24a504192020-07-23 00:08:441884 def IsExcludedFile(affected_file, excluded_paths):
wnwenbdc444e2016-05-25 13:44:151885 local_path = affected_file.LocalPath()
James Cook24a504192020-07-23 00:08:441886 for item in excluded_paths:
wnwenbdc444e2016-05-25 13:44:151887 if input_api.re.match(item, local_path):
1888 return True
1889 return False
1890
Peter K. Lee6c03ccff2019-07-15 14:40:051891 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541892 local_path = affected_file.LocalPath()
1893 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1894 return False
1895 basename = input_api.os_path.basename(local_path)
1896 if 'ios' in basename.split('_'):
1897 return True
1898 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1899 if sep and 'ios' in local_path.split(sep):
1900 return True
1901 return False
1902
wnwenbdc444e2016-05-25 13:44:151903 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311904 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1905 func_name, message)
1906 if problems:
wnwenbdc444e2016-05-25 13:44:151907 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311908 errors.extend(problems)
1909 else:
1910 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151911
Eric Stevensona9a980972017-09-23 00:04:411912 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1913 for f in input_api.AffectedFiles(file_filter=file_filter):
1914 for line_num, line in f.ChangedContents():
1915 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1916 CheckForMatch(f, line_num, line, func_name, message, error)
1917
[email protected]127f18ec2012-06-16 05:05:591918 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1919 for f in input_api.AffectedFiles(file_filter=file_filter):
1920 for line_num, line in f.ChangedContents():
1921 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151922 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591923
Peter K. Lee6c03ccff2019-07-15 14:40:051924 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541925 for line_num, line in f.ChangedContents():
1926 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1927 CheckForMatch(f, line_num, line, func_name, message, error)
1928
Peter K. Lee6c03ccff2019-07-15 14:40:051929 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1930 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1931 for line_num, line in f.ChangedContents():
1932 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1933 CheckForMatch(f, line_num, line, func_name, message, error)
1934
[email protected]127f18ec2012-06-16 05:05:591935 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1936 for f in input_api.AffectedFiles(file_filter=file_filter):
1937 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491938 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
James Cook24a504192020-07-23 00:08:441939 if IsExcludedFile(f, excluded_paths):
[email protected]7345da02012-11-27 14:31:491940 continue
wnwenbdc444e2016-05-25 13:44:151941 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591942
1943 result = []
1944 if (warnings):
1945 result.append(output_api.PresubmitPromptWarning(
1946 'Banned functions were used.\n' + '\n'.join(warnings)))
1947 if (errors):
1948 result.append(output_api.PresubmitError(
1949 'Banned functions were used.\n' + '\n'.join(errors)))
1950 return result
1951
1952
Michael Thiessen44457642020-02-06 00:24:151953def _CheckAndroidNoBannedImports(input_api, output_api):
1954 """Make sure that banned java imports are not used."""
1955 errors = []
1956
1957 def IsException(path, exceptions):
1958 for exception in exceptions:
1959 if (path.startswith(exception)):
1960 return True
1961 return False
1962
1963 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1964 for f in input_api.AffectedFiles(file_filter=file_filter):
1965 for line_num, line in f.ChangedContents():
1966 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1967 if IsException(f.LocalPath(), exceptions):
1968 continue;
1969 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1970 'import ' + import_name, message)
1971 if problems:
1972 errors.extend(problems)
1973 result = []
1974 if (errors):
1975 result.append(output_api.PresubmitError(
1976 'Banned imports were used.\n' + '\n'.join(errors)))
1977 return result
1978
1979
Saagar Sanghavifceeaae2020-08-12 16:40:361980def CheckNoDeprecatedMojoTypes(input_api, output_api):
Mario Sanchez Prada2472cab2019-09-18 10:58:311981 """Make sure that old Mojo types are not used."""
1982 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571983 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311984
Mario Sanchez Pradaaab91382019-12-19 08:57:091985 # For any path that is not an "ok" or an "error" path, a warning will be
1986 # raised if deprecated mojo types are found.
1987 ok_paths = ['components/arc']
1988 error_paths = ['third_party/blink', 'content']
1989
Mario Sanchez Prada2472cab2019-09-18 10:58:311990 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1991 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571992 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091993 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311994 continue
1995
1996 for line_num, line in f.ChangedContents():
1997 for func_name, message in _DEPRECATED_MOJO_TYPES:
1998 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1999 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:572000
Mario Sanchez Prada2472cab2019-09-18 10:58:312001 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:092002 # Raise errors inside |error_paths| and warnings everywhere else.
2003 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:572004 errors.extend(problems)
2005 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:312006 warnings.extend(problems)
2007
2008 result = []
2009 if (warnings):
2010 result.append(output_api.PresubmitPromptWarning(
2011 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:572012 if (errors):
2013 result.append(output_api.PresubmitError(
2014 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:312015 return result
2016
2017
Saagar Sanghavifceeaae2020-08-12 16:40:362018def CheckNoPragmaOnce(input_api, output_api):
[email protected]6c063c62012-07-11 19:11:062019 """Make sure that banned functions are not used."""
2020 files = []
2021 pattern = input_api.re.compile(r'^#pragma\s+once',
2022 input_api.re.MULTILINE)
2023 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2024 if not f.LocalPath().endswith('.h'):
2025 continue
2026 contents = input_api.ReadFile(f)
2027 if pattern.search(contents):
2028 files.append(f)
2029
2030 if files:
2031 return [output_api.PresubmitError(
2032 'Do not use #pragma once in header files.\n'
2033 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
2034 files)]
2035 return []
2036
[email protected]127f18ec2012-06-16 05:05:592037
Saagar Sanghavifceeaae2020-08-12 16:40:362038def CheckNoTrinaryTrueFalse(input_api, output_api):
[email protected]e7479052012-09-19 00:26:122039 """Checks to make sure we don't introduce use of foo ? true : false."""
2040 problems = []
2041 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
2042 for f in input_api.AffectedFiles():
2043 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2044 continue
2045
2046 for line_num, line in f.ChangedContents():
2047 if pattern.match(line):
2048 problems.append(' %s:%d' % (f.LocalPath(), line_num))
2049
2050 if not problems:
2051 return []
2052 return [output_api.PresubmitPromptWarning(
2053 'Please consider avoiding the "? true : false" pattern if possible.\n' +
2054 '\n'.join(problems))]
2055
2056
Saagar Sanghavifceeaae2020-08-12 16:40:362057def CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:282058 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:182059 change. Breaking - rules is an error, breaking ! rules is a
2060 warning.
2061 """
mohan.reddyf21db962014-10-16 12:26:472062 import sys
[email protected]55f9f382012-07-31 11:02:182063 # We need to wait until we have an input_api object and use this
2064 # roundabout construct to import checkdeps because this file is
2065 # eval-ed and thus doesn't have __file__.
2066 original_sys_path = sys.path
2067 try:
2068 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:472069 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:182070 import checkdeps
[email protected]55f9f382012-07-31 11:02:182071 from rules import Rule
2072 finally:
2073 # Restore sys.path to what it was before.
2074 sys.path = original_sys_path
2075
2076 added_includes = []
rhalavati08acd232017-04-03 07:23:282077 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:242078 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:182079 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:062080 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502081 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082082 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062083 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502084 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082085 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062086 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502087 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082088 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:182089
[email protected]26385172013-05-09 23:11:352090 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182091
2092 error_descriptions = []
2093 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:282094 error_subjects = set()
2095 warning_subjects = set()
Saagar Sanghavifceeaae2020-08-12 16:40:362096
[email protected]55f9f382012-07-31 11:02:182097 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2098 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:082099 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182100 description_with_path = '%s\n %s' % (path, rule_description)
2101 if rule_type == Rule.DISALLOW:
2102 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282103 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:182104 else:
2105 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282106 warning_subjects.add("#includes")
2107
2108 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2109 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:082110 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:282111 description_with_path = '%s\n %s' % (path, rule_description)
2112 if rule_type == Rule.DISALLOW:
2113 error_descriptions.append(description_with_path)
2114 error_subjects.add("imports")
2115 else:
2116 warning_descriptions.append(description_with_path)
2117 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:182118
Jinsuk Kim5a092672017-10-24 22:42:242119 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:022120 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:082121 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:242122 description_with_path = '%s\n %s' % (path, rule_description)
2123 if rule_type == Rule.DISALLOW:
2124 error_descriptions.append(description_with_path)
2125 error_subjects.add("imports")
2126 else:
2127 warning_descriptions.append(description_with_path)
2128 warning_subjects.add("imports")
2129
[email protected]55f9f382012-07-31 11:02:182130 results = []
2131 if error_descriptions:
2132 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:282133 'You added one or more %s that violate checkdeps rules.'
2134 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:182135 error_descriptions))
2136 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:422137 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:282138 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:182139 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:282140 '%s? See relevant DEPS file(s) for details and contacts.' %
2141 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:182142 warning_descriptions))
2143 return results
2144
2145
Saagar Sanghavifceeaae2020-08-12 16:40:362146def CheckFilePermissions(input_api, output_api):
[email protected]fbcafe5a2012-08-08 15:31:222147 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:152148 if input_api.platform == 'win32':
2149 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:292150 checkperms_tool = input_api.os_path.join(
2151 input_api.PresubmitLocalPath(),
2152 'tools', 'checkperms', 'checkperms.py')
2153 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:472154 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:392155 with input_api.CreateTemporaryFile() as file_list:
2156 for f in input_api.AffectedFiles():
2157 # checkperms.py file/directory arguments must be relative to the
2158 # repository.
2159 file_list.write(f.LocalPath() + '\n')
2160 file_list.close()
2161 args += ['--file-list', file_list.name]
2162 try:
2163 input_api.subprocess.check_output(args)
2164 return []
2165 except input_api.subprocess.CalledProcessError as error:
2166 return [output_api.PresubmitError(
2167 'checkperms.py failed:',
2168 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:222169
2170
Saagar Sanghavifceeaae2020-08-12 16:40:362171def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
[email protected]c8278b32012-10-30 20:35:492172 """Makes sure we don't include ui/aura/window_property.h
2173 in header files.
2174 """
2175 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2176 errors = []
2177 for f in input_api.AffectedFiles():
2178 if not f.LocalPath().endswith('.h'):
2179 continue
2180 for line_num, line in f.ChangedContents():
2181 if pattern.match(line):
2182 errors.append(' %s:%d' % (f.LocalPath(), line_num))
2183
2184 results = []
2185 if errors:
2186 results.append(output_api.PresubmitError(
2187 'Header files should not include ui/aura/window_property.h', errors))
2188 return results
2189
2190
[email protected]70ca77752012-11-20 03:45:032191def _CheckForVersionControlConflictsInFile(input_api, f):
2192 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2193 errors = []
2194 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:162195 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:232196 # First-level headers in markdown look a lot like version control
2197 # conflict markers. http://daringfireball.net/projects/markdown/basics
2198 continue
[email protected]70ca77752012-11-20 03:45:032199 if pattern.match(line):
2200 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2201 return errors
2202
2203
Saagar Sanghavifceeaae2020-08-12 16:40:362204def CheckForVersionControlConflicts(input_api, output_api):
[email protected]70ca77752012-11-20 03:45:032205 """Usually this is not intentional and will cause a compile failure."""
2206 errors = []
2207 for f in input_api.AffectedFiles():
2208 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
2209
2210 results = []
2211 if errors:
2212 results.append(output_api.PresubmitError(
2213 'Version control conflict markers found, please resolve.', errors))
2214 return results
2215
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202216
Saagar Sanghavifceeaae2020-08-12 16:40:362217def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
estadee17314a02017-01-12 16:22:162218 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2219 errors = []
2220 for f in input_api.AffectedFiles():
2221 for line_num, line in f.ChangedContents():
2222 if pattern.search(line):
2223 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2224
2225 results = []
2226 if errors:
2227 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502228 'Found Google support URL addressed by answer number. Please replace '
2229 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162230 return results
2231
[email protected]70ca77752012-11-20 03:45:032232
Saagar Sanghavifceeaae2020-08-12 16:40:362233def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
[email protected]06e6d0ff2012-12-11 01:36:442234 def FilterFile(affected_file):
2235 """Filter function for use with input_api.AffectedSourceFiles,
2236 below. This filters out everything except non-test files from
2237 top-level directories that generally speaking should not hard-code
2238 service URLs (e.g. src/android_webview/, src/content/ and others).
2239 """
2240 return input_api.FilterSourceFile(
2241 affected_file,
James Cook24a504192020-07-23 00:08:442242 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2243 files_to_skip=(_EXCLUDED_PATHS +
2244 _TEST_CODE_EXCLUDED_PATHS +
2245 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442246
reillyi38965732015-11-16 18:27:332247 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2248 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462249 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2250 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442251 problems = [] # items are (filename, line_number, line)
2252 for f in input_api.AffectedSourceFiles(FilterFile):
2253 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462254 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442255 problems.append((f.LocalPath(), line_num, line))
2256
2257 if problems:
[email protected]f7051d52013-04-02 18:31:422258 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442259 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582260 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442261 [' %s:%d: %s' % (
2262 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032263 else:
2264 return []
[email protected]06e6d0ff2012-12-11 01:36:442265
2266
Saagar Sanghavifceeaae2020-08-12 16:40:362267def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
James Cook6b6597c2019-11-06 22:05:292268 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2269 def FileFilter(affected_file):
2270 """Includes directories known to be Chrome OS only."""
2271 return input_api.FilterSourceFile(
2272 affected_file,
James Cook24a504192020-07-23 00:08:442273 files_to_check=('^ash/',
2274 '^chromeos/', # Top-level src/chromeos.
2275 '/chromeos/', # Any path component.
2276 '^components/arc',
2277 '^components/exo'),
2278 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292279
2280 prefs = []
2281 priority_prefs = []
2282 for f in input_api.AffectedFiles(file_filter=FileFilter):
2283 for line_num, line in f.ChangedContents():
2284 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2285 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2286 prefs.append(' %s' % line)
2287 if input_api.re.search(
2288 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2289 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2290 priority_prefs.append(' %s' % line)
2291
2292 results = []
2293 if (prefs):
2294 results.append(output_api.PresubmitPromptWarning(
2295 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2296 'by browser sync settings. If these prefs should be controlled by OS '
2297 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2298 if (priority_prefs):
2299 results.append(output_api.PresubmitPromptWarning(
2300 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2301 'controlled by browser sync settings. If these prefs should be '
2302 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2303 'instead.\n' + '\n'.join(prefs)))
2304 return results
2305
2306
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492307# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362308def CheckNoAbbreviationInPngFileName(input_api, output_api):
[email protected]d2530012013-01-25 16:39:272309 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312310 The native_client_sdk directory is excluded because it has auto-generated PNG
2311 files for documentation.
[email protected]d2530012013-01-25 16:39:272312 """
[email protected]d2530012013-01-25 16:39:272313 errors = []
James Cook24a504192020-07-23 00:08:442314 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
2315 files_to_skip = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312316 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442317 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
binji0dcdf342014-12-12 18:32:312318 for f in input_api.AffectedFiles(include_deletes=False,
2319 file_filter=file_filter):
2320 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272321
2322 results = []
2323 if errors:
2324 results.append(output_api.PresubmitError(
2325 'The name of PNG files should not have abbreviations. \n'
2326 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2327 'Contact [email protected] if you have questions.', errors))
2328 return results
2329
2330
Daniel Cheng4dcdb6b2017-04-13 08:30:172331def _ExtractAddRulesFromParsedDeps(parsed_deps):
2332 """Extract the rules that add dependencies from a parsed DEPS file.
2333
2334 Args:
2335 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2336 add_rules = set()
2337 add_rules.update([
2338 rule[1:] for rule in parsed_deps.get('include_rules', [])
2339 if rule.startswith('+') or rule.startswith('!')
2340 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502341 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172342 {}).iteritems():
2343 add_rules.update([
2344 rule[1:] for rule in rules
2345 if rule.startswith('+') or rule.startswith('!')
2346 ])
2347 return add_rules
2348
2349
2350def _ParseDeps(contents):
2351 """Simple helper for parsing DEPS files."""
2352 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172353 class _VarImpl:
2354
2355 def __init__(self, local_scope):
2356 self._local_scope = local_scope
2357
2358 def Lookup(self, var_name):
2359 """Implements the Var syntax."""
2360 try:
2361 return self._local_scope['vars'][var_name]
2362 except KeyError:
2363 raise Exception('Var is not defined: %s' % var_name)
2364
2365 local_scope = {}
2366 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172367 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592368 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172369 }
2370 exec contents in global_scope, local_scope
2371 return local_scope
2372
2373
2374def _CalculateAddedDeps(os_path, old_contents, new_contents):
Saagar Sanghavi0bc3e692020-08-13 19:46:592375 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412376 a set of DEPS entries that we should look up.
2377
2378 For a directory (rather than a specific filename) we fake a path to
2379 a specific filename by adding /DEPS. This is chosen as a file that
2380 will seldom or never be subject to per-file include_rules.
2381 """
[email protected]2b438d62013-11-14 17:54:142382 # We ignore deps entries on auto-generated directories.
2383 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082384
Daniel Cheng4dcdb6b2017-04-13 08:30:172385 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2386 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2387
2388 added_deps = new_deps.difference(old_deps)
2389
[email protected]2b438d62013-11-14 17:54:142390 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172391 for added_dep in added_deps:
2392 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2393 continue
2394 # Assume that a rule that ends in .h is a rule for a specific file.
2395 if added_dep.endswith('.h'):
2396 results.add(added_dep)
2397 else:
2398 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082399 return results
2400
2401
Saagar Sanghavifceeaae2020-08-12 16:40:362402def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
[email protected]e871964c2013-05-13 14:14:552403 """When a dependency prefixed with + is added to a DEPS file, we
2404 want to make sure that the change is reviewed by an OWNER of the
2405 target file or directory, to avoid layering violations from being
2406 introduced. This check verifies that this happens.
2407 """
Daniel Cheng4dcdb6b2017-04-13 08:30:172408 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242409
2410 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492411 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242412 for f in input_api.AffectedFiles(include_deletes=False,
2413 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552414 filename = input_api.os_path.basename(f.LocalPath())
2415 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172416 virtual_depended_on_files.update(_CalculateAddedDeps(
2417 input_api.os_path,
2418 '\n'.join(f.OldContents()),
2419 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552420
[email protected]e871964c2013-05-13 14:14:552421 if not virtual_depended_on_files:
2422 return []
2423
2424 if input_api.is_committing:
2425 if input_api.tbr:
2426 return [output_api.PresubmitNotifyResult(
2427 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272428 if input_api.dry_run:
2429 return [output_api.PresubmitNotifyResult(
2430 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552431 if not input_api.change.issue:
2432 return [output_api.PresubmitError(
2433 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402434 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552435 output = output_api.PresubmitError
2436 else:
2437 output = output_api.PresubmitNotifyResult
2438
2439 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:502440 owner_email, reviewers = (
2441 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2442 input_api,
2443 owners_db.email_regexp,
2444 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552445
2446 owner_email = owner_email or input_api.change.author_email
2447
[email protected]de4f7d22013-05-23 14:27:462448 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:512449 if owner_email:
[email protected]de4f7d22013-05-23 14:27:462450 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:552451 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
2452 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:412453
2454 # We strip the /DEPS part that was added by
2455 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2456 # directory.
2457 def StripDeps(path):
2458 start_deps = path.rfind('/DEPS')
2459 if start_deps != -1:
2460 return path[:start_deps]
2461 else:
2462 return path
2463 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552464 for path in missing_files]
2465
2466 if unapproved_dependencies:
2467 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152468 output('You need LGTM from owners of depends-on paths in DEPS that were '
2469 'modified in this CL:\n %s' %
2470 '\n '.join(sorted(unapproved_dependencies)))]
2471 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
2472 output_list.append(output(
2473 'Suggested missing target path OWNERS:\n %s' %
2474 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552475 return output_list
2476
2477 return []
2478
2479
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492480# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362481def CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492482 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
James Cook24a504192020-07-23 00:08:442483 files_to_skip = (_EXCLUDED_PATHS +
2484 _TEST_CODE_EXCLUDED_PATHS +
2485 input_api.DEFAULT_FILES_TO_SKIP +
2486 (r"^base[\\/]logging\.h$",
2487 r"^base[\\/]logging\.cc$",
2488 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2489 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2490 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2491 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2492 r"startup_browser_creator\.cc$",
2493 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2494 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2495 r"diagnostics_writer\.cc$",
2496 r"^chrome[\\/]chrome_cleaner[\\/].*",
2497 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2498 r"dll_hash_main\.cc$",
2499 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2500 r"^chromecast[\\/]",
2501 r"^cloud_print[\\/]",
2502 r"^components[\\/]browser_watcher[\\/]"
2503 r"dump_stability_report_main_win.cc$",
2504 r"^components[\\/]media_control[\\/]renderer[\\/]"
2505 r"media_playback_options\.cc$",
2506 r"^components[\\/]zucchini[\\/].*",
2507 # TODO(peter): Remove exception. https://crbug.com/534537
2508 r"^content[\\/]browser[\\/]notifications[\\/]"
2509 r"notification_event_dispatcher_impl\.cc$",
2510 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2511 r"gl_helper_benchmark\.cc$",
2512 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2513 r"^courgette[\\/]courgette_tool\.cc$",
2514 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
2515 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
2516 r"^fuchsia[\\/]engine[\\/]context_provider_main.cc$",
2517 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2518 r"^ipc[\\/]ipc_logging\.cc$",
2519 r"^native_client_sdk[\\/]",
2520 r"^remoting[\\/]base[\\/]logging\.h$",
2521 r"^remoting[\\/]host[\\/].*",
2522 r"^sandbox[\\/]linux[\\/].*",
2523 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2524 r"dump_file_system.cc$",
2525 r"^tools[\\/]",
2526 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2527 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2528 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2529 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2530 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402531 source_file_filter = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442532 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402533
thomasanderson625d3932017-03-29 07:16:582534 log_info = set([])
2535 printf = set([])
[email protected]85218562013-11-22 07:41:402536
2537 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582538 for _, line in f.ChangedContents():
2539 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2540 log_info.add(f.LocalPath())
2541 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2542 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372543
thomasanderson625d3932017-03-29 07:16:582544 if input_api.re.search(r"\bprintf\(", line):
2545 printf.add(f.LocalPath())
2546 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2547 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402548
2549 if log_info:
2550 return [output_api.PresubmitError(
2551 'These files spam the console log with LOG(INFO):',
2552 items=log_info)]
2553 if printf:
2554 return [output_api.PresubmitError(
2555 'These files spam the console log with printf/fprintf:',
2556 items=printf)]
2557 return []
2558
2559
Saagar Sanghavifceeaae2020-08-12 16:40:362560def CheckForAnonymousVariables(input_api, output_api):
[email protected]49aa76a2013-12-04 06:59:162561 """These types are all expected to hold locks while in scope and
2562 so should never be anonymous (which causes them to be immediately
2563 destroyed)."""
2564 they_who_must_be_named = [
2565 'base::AutoLock',
2566 'base::AutoReset',
2567 'base::AutoUnlock',
2568 'SkAutoAlphaRestore',
2569 'SkAutoBitmapShaderInstall',
2570 'SkAutoBlitterChoose',
2571 'SkAutoBounderCommit',
2572 'SkAutoCallProc',
2573 'SkAutoCanvasRestore',
2574 'SkAutoCommentBlock',
2575 'SkAutoDescriptor',
2576 'SkAutoDisableDirectionCheck',
2577 'SkAutoDisableOvalCheck',
2578 'SkAutoFree',
2579 'SkAutoGlyphCache',
2580 'SkAutoHDC',
2581 'SkAutoLockColors',
2582 'SkAutoLockPixels',
2583 'SkAutoMalloc',
2584 'SkAutoMaskFreeImage',
2585 'SkAutoMutexAcquire',
2586 'SkAutoPathBoundsUpdate',
2587 'SkAutoPDFRelease',
2588 'SkAutoRasterClipValidate',
2589 'SkAutoRef',
2590 'SkAutoTime',
2591 'SkAutoTrace',
2592 'SkAutoUnref',
2593 ]
2594 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2595 # bad: base::AutoLock(lock.get());
2596 # not bad: base::AutoLock lock(lock.get());
2597 bad_pattern = input_api.re.compile(anonymous)
2598 # good: new base::AutoLock(lock.get())
2599 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2600 errors = []
2601
2602 for f in input_api.AffectedFiles():
2603 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2604 continue
2605 for linenum, line in f.ChangedContents():
2606 if bad_pattern.search(line) and not good_pattern.search(line):
2607 errors.append('%s:%d' % (f.LocalPath(), linenum))
2608
2609 if errors:
2610 return [output_api.PresubmitError(
2611 'These lines create anonymous variables that need to be named:',
2612 items=errors)]
2613 return []
2614
2615
Saagar Sanghavifceeaae2020-08-12 16:40:362616def CheckUniquePtrOnUpload(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532617 # Returns whether |template_str| is of the form <T, U...> for some types T
2618 # and U. Assumes that |template_str| is already in the form <...>.
2619 def HasMoreThanOneArg(template_str):
2620 # Level of <...> nesting.
2621 nesting = 0
2622 for c in template_str:
2623 if c == '<':
2624 nesting += 1
2625 elif c == '>':
2626 nesting -= 1
2627 elif c == ',' and nesting == 1:
2628 return True
2629 return False
2630
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492631 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102632 sources = lambda affected_file: input_api.FilterSourceFile(
2633 affected_file,
James Cook24a504192020-07-23 00:08:442634 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2635 input_api.DEFAULT_FILES_TO_SKIP),
2636 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552637
2638 # Pattern to capture a single "<...>" block of template arguments. It can
2639 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2640 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2641 # latter would likely require counting that < and > match, which is not
2642 # expressible in regular languages. Should the need arise, one can introduce
2643 # limited counting (matching up to a total number of nesting depth), which
2644 # should cover all practical cases for already a low nesting limit.
2645 template_arg_pattern = (
2646 r'<[^>]*' # Opening block of <.
2647 r'>([^<]*>)?') # Closing block of >.
2648 # Prefix expressing that whatever follows is not already inside a <...>
2649 # block.
2650 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102651 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552652 not_inside_template_arg_pattern
2653 + r'\bstd::unique_ptr'
2654 + template_arg_pattern
2655 + r'\(\)')
2656
2657 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2658 template_arg_no_array_pattern = (
2659 r'<[^>]*[^]]' # Opening block of <.
2660 r'>([^(<]*[^]]>)?') # Closing block of >.
2661 # Prefix saying that what follows is the start of an expression.
2662 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2663 # Suffix saying that what follows are call parentheses with a non-empty list
2664 # of arguments.
2665 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532666 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552667 return_construct_pattern = input_api.re.compile(
2668 start_of_expr_pattern
2669 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532670 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552671 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532672 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552673 + nonempty_arg_list_pattern)
2674
Vaclav Brozek851d9602018-04-04 16:13:052675 problems_constructor = []
2676 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102677 for f in input_api.AffectedSourceFiles(sources):
2678 for line_number, line in f.ChangedContents():
2679 # Disallow:
2680 # return std::unique_ptr<T>(foo);
2681 # bar = std::unique_ptr<T>(foo);
2682 # But allow:
2683 # return std::unique_ptr<T[]>(foo);
2684 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532685 # And also allow cases when the second template argument is present. Those
2686 # cases cannot be handled by std::make_unique:
2687 # return std::unique_ptr<T, U>(foo);
2688 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052689 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532690 return_construct_result = return_construct_pattern.search(line)
2691 if return_construct_result and not HasMoreThanOneArg(
2692 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052693 problems_constructor.append(
2694 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102695 # Disallow:
2696 # std::unique_ptr<T>()
2697 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052698 problems_nullptr.append(
2699 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2700
2701 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162702 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052703 errors.append(output_api.PresubmitError(
2704 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162705 problems_nullptr))
2706 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052707 errors.append(output_api.PresubmitError(
2708 'The following files use explicit std::unique_ptr constructor.'
2709 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162710 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102711 return errors
2712
2713
Saagar Sanghavifceeaae2020-08-12 16:40:362714def CheckUserActionUpdate(input_api, output_api):
[email protected]999261d2014-03-03 20:08:082715 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522716 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082717 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522718 # If actions.xml is already included in the changelist, the PRESUBMIT
2719 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082720 return []
2721
[email protected]999261d2014-03-03 20:08:082722 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
2723 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522724 current_actions = None
[email protected]999261d2014-03-03 20:08:082725 for f in input_api.AffectedFiles(file_filter=file_filter):
2726 for line_num, line in f.ChangedContents():
2727 match = input_api.re.search(action_re, line)
2728 if match:
[email protected]2f92dec2014-03-07 19:21:522729 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2730 # loaded only once.
2731 if not current_actions:
2732 with open('tools/metrics/actions/actions.xml') as actions_f:
2733 current_actions = actions_f.read()
2734 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082735 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522736 action = 'name="{0}"'.format(action_name)
2737 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082738 return [output_api.PresubmitPromptWarning(
2739 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522740 'tools/metrics/actions/actions.xml. Please run '
2741 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082742 % (f.LocalPath(), line_num, action_name))]
2743 return []
2744
2745
Daniel Cheng13ca61a882017-08-25 15:11:252746def _ImportJSONCommentEater(input_api):
2747 import sys
2748 sys.path = sys.path + [input_api.os_path.join(
2749 input_api.PresubmitLocalPath(),
2750 'tools', 'json_comment_eater')]
2751 import json_comment_eater
2752 return json_comment_eater
2753
2754
[email protected]99171a92014-06-03 08:44:472755def _GetJSONParseError(input_api, filename, eat_comments=True):
2756 try:
2757 contents = input_api.ReadFile(filename)
2758 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252759 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132760 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472761
2762 input_api.json.loads(contents)
2763 except ValueError as e:
2764 return e
2765 return None
2766
2767
2768def _GetIDLParseError(input_api, filename):
2769 try:
2770 contents = input_api.ReadFile(filename)
2771 idl_schema = input_api.os_path.join(
2772 input_api.PresubmitLocalPath(),
2773 'tools', 'json_schema_compiler', 'idl_schema.py')
2774 process = input_api.subprocess.Popen(
2775 [input_api.python_executable, idl_schema],
2776 stdin=input_api.subprocess.PIPE,
2777 stdout=input_api.subprocess.PIPE,
2778 stderr=input_api.subprocess.PIPE,
2779 universal_newlines=True)
2780 (_, error) = process.communicate(input=contents)
2781 return error or None
2782 except ValueError as e:
2783 return e
2784
2785
Saagar Sanghavifceeaae2020-08-12 16:40:362786def CheckParseErrors(input_api, output_api):
[email protected]99171a92014-06-03 08:44:472787 """Check that IDL and JSON files do not contain syntax errors."""
2788 actions = {
2789 '.idl': _GetIDLParseError,
2790 '.json': _GetJSONParseError,
2791 }
[email protected]99171a92014-06-03 08:44:472792 # Most JSON files are preprocessed and support comments, but these do not.
2793 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042794 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472795 ]
2796 # Only run IDL checker on files in these directories.
2797 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042798 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2799 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472800 ]
2801
2802 def get_action(affected_file):
2803 filename = affected_file.LocalPath()
2804 return actions.get(input_api.os_path.splitext(filename)[1])
2805
[email protected]99171a92014-06-03 08:44:472806 def FilterFile(affected_file):
2807 action = get_action(affected_file)
2808 if not action:
2809 return False
2810 path = affected_file.LocalPath()
2811
Erik Staab2dd72b12020-04-16 15:03:402812 if _MatchesFile(input_api,
2813 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2814 path):
[email protected]99171a92014-06-03 08:44:472815 return False
2816
2817 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162818 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472819 return False
2820 return True
2821
2822 results = []
2823 for affected_file in input_api.AffectedFiles(
2824 file_filter=FilterFile, include_deletes=False):
2825 action = get_action(affected_file)
2826 kwargs = {}
2827 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162828 _MatchesFile(input_api, json_no_comments_patterns,
2829 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472830 kwargs['eat_comments'] = False
2831 parse_error = action(input_api,
2832 affected_file.AbsoluteLocalPath(),
2833 **kwargs)
2834 if parse_error:
2835 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2836 (affected_file.LocalPath(), parse_error)))
2837 return results
2838
2839
Saagar Sanghavifceeaae2020-08-12 16:40:362840def CheckJavaStyle(input_api, output_api):
[email protected]760deea2013-12-10 19:33:492841 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472842 import sys
[email protected]760deea2013-12-10 19:33:492843 original_sys_path = sys.path
2844 try:
2845 sys.path = sys.path + [input_api.os_path.join(
2846 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2847 import checkstyle
2848 finally:
2849 # Restore sys.path to what it was before.
2850 sys.path = original_sys_path
2851
2852 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092853 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
James Cook24a504192020-07-23 00:08:442854 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
[email protected]760deea2013-12-10 19:33:492855
2856
Saagar Sanghavifceeaae2020-08-12 16:40:362857def CheckPythonDevilInit(input_api, output_api):
Nate Fischerdfd9812e2019-07-18 22:03:002858 """Checks to make sure devil is initialized correctly in python scripts."""
2859 script_common_initialize_pattern = input_api.re.compile(
2860 r'script_common\.InitializeEnvironment\(')
2861 devil_env_config_initialize = input_api.re.compile(
2862 r'devil_env\.config\.Initialize\(')
2863
2864 errors = []
2865
2866 sources = lambda affected_file: input_api.FilterSourceFile(
2867 affected_file,
James Cook24a504192020-07-23 00:08:442868 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
2869 (r'^build[\\/]android[\\/]devil_chromium\.py',
2870 r'^third_party[\\/].*',)),
2871 files_to_check=[r'.*\.py$'])
Nate Fischerdfd9812e2019-07-18 22:03:002872
2873 for f in input_api.AffectedSourceFiles(sources):
2874 for line_num, line in f.ChangedContents():
2875 if (script_common_initialize_pattern.search(line) or
2876 devil_env_config_initialize.search(line)):
2877 errors.append("%s:%d" % (f.LocalPath(), line_num))
2878
2879 results = []
2880
2881 if errors:
2882 results.append(output_api.PresubmitError(
2883 'Devil initialization should always be done using '
2884 'devil_chromium.Initialize() in the chromium project, to use better '
2885 'defaults for dependencies (ex. up-to-date version of adb).',
2886 errors))
2887
2888 return results
2889
2890
Sean Kau46e29bc2017-08-28 16:31:162891def _MatchesFile(input_api, patterns, path):
2892 for pattern in patterns:
2893 if input_api.re.search(pattern, path):
2894 return True
2895 return False
2896
2897
Daniel Cheng7052cdf2017-11-21 19:23:292898def _GetOwnersFilesToCheckForIpcOwners(input_api):
2899 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172900
Daniel Cheng7052cdf2017-11-21 19:23:292901 Returns:
2902 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2903 contain to cover IPC-related files with noparent reviewer rules.
2904 """
2905 # Whether or not a file affects IPC is (mostly) determined by a simple list
2906 # of filename patterns.
dchenge07de812016-06-20 19:27:172907 file_patterns = [
palmerb19a0932017-01-24 04:00:312908 # Legacy IPC:
dchenge07de812016-06-20 19:27:172909 '*_messages.cc',
2910 '*_messages*.h',
2911 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312912 # Mojo IPC:
dchenge07de812016-06-20 19:27:172913 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472914 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172915 '*_struct_traits*.*',
2916 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312917 '*.typemap',
2918 # Android native IPC:
2919 '*.aidl',
2920 # Blink uses a different file naming convention:
2921 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472922 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172923 '*StructTraits*.*',
2924 '*TypeConverter*.*',
2925 ]
2926
scottmg7a6ed5ba2016-11-04 18:22:042927 # These third_party directories do not contain IPCs, but contain files
2928 # matching the above patterns, which trigger false positives.
2929 exclude_paths = [
2930 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162931 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232932 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292933 'third_party/win_build_output/*',
Dan Harringtonb60e1aa2019-11-20 08:48:542934 'third_party/feed_library/*',
Scott Violet9f82d362019-11-06 21:42:162935 # These files are just used to communicate between class loaders running
2936 # in the same process.
2937 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572938 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2939
scottmg7a6ed5ba2016-11-04 18:22:042940 ]
2941
dchenge07de812016-06-20 19:27:172942 # Dictionary mapping an OWNERS file path to Patterns.
2943 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2944 # rules ) to a PatternEntry.
2945 # PatternEntry is a dictionary with two keys:
2946 # - 'files': the files that are matched by this pattern
2947 # - 'rules': the per-file rules needed for this pattern
2948 # For example, if we expect OWNERS file to contain rules for *.mojom and
2949 # *_struct_traits*.*, Patterns might look like this:
2950 # {
2951 # '*.mojom': {
2952 # 'files': ...,
2953 # 'rules': [
2954 # 'per-file *.mojom=set noparent',
2955 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2956 # ],
2957 # },
2958 # '*_struct_traits*.*': {
2959 # 'files': ...,
2960 # 'rules': [
2961 # 'per-file *_struct_traits*.*=set noparent',
2962 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2963 # ],
2964 # },
2965 # }
2966 to_check = {}
2967
Daniel Cheng13ca61a882017-08-25 15:11:252968 def AddPatternToCheck(input_file, pattern):
2969 owners_file = input_api.os_path.join(
2970 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2971 if owners_file not in to_check:
2972 to_check[owners_file] = {}
2973 if pattern not in to_check[owners_file]:
2974 to_check[owners_file][pattern] = {
2975 'files': [],
2976 'rules': [
2977 'per-file %s=set noparent' % pattern,
2978 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2979 ]
2980 }
Vaclav Brozekd5de76a2018-03-17 07:57:502981 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252982
dchenge07de812016-06-20 19:27:172983 # Iterate through the affected files to see what we actually need to check
2984 # for. We should only nag patch authors about per-file rules if a file in that
2985 # directory would match that pattern. If a directory only contains *.mojom
2986 # files and no *_messages*.h files, we should only nag about rules for
2987 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252988 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262989 # Manifest files don't have a strong naming convention. Instead, try to find
2990 # affected .cc and .h files which look like they contain a manifest
2991 # definition.
2992 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2993 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2994 if (manifest_pattern.search(f.LocalPath()) and not
2995 test_manifest_pattern.search(f.LocalPath())):
2996 # We expect all actual service manifest files to contain at least one
2997 # qualified reference to service_manager::Manifest.
2998 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:252999 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:173000 for pattern in file_patterns:
3001 if input_api.fnmatch.fnmatch(
3002 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:043003 skip = False
3004 for exclude in exclude_paths:
3005 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
3006 skip = True
3007 break
3008 if skip:
3009 continue
Daniel Cheng13ca61a882017-08-25 15:11:253010 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:173011 break
3012
Daniel Cheng7052cdf2017-11-21 19:23:293013 return to_check
3014
3015
Wez17c66962020-04-29 15:26:033016def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
3017 """Adds OWNERS files to check for correct Fuchsia security owners."""
3018
3019 file_patterns = [
3020 # Component specifications.
3021 '*.cml', # Component Framework v2.
3022 '*.cmx', # Component Framework v1.
3023
3024 # Fuchsia IDL protocol specifications.
3025 '*.fidl',
3026 ]
3027
3028 def AddPatternToCheck(input_file, pattern):
3029 owners_file = input_api.os_path.join(
3030 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
3031 if owners_file not in to_check:
3032 to_check[owners_file] = {}
3033 if pattern not in to_check[owners_file]:
3034 to_check[owners_file][pattern] = {
3035 'files': [],
3036 'rules': [
3037 'per-file %s=set noparent' % pattern,
3038 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
3039 ]
3040 }
3041 to_check[owners_file][pattern]['files'].append(input_file)
3042
3043 # Iterate through the affected files to see what we actually need to check
3044 # for. We should only nag patch authors about per-file rules if a file in that
3045 # directory would match that pattern.
3046 for f in input_api.AffectedFiles(include_deletes=False):
3047 for pattern in file_patterns:
3048 if input_api.fnmatch.fnmatch(
3049 input_api.os_path.basename(f.LocalPath()), pattern):
3050 AddPatternToCheck(f, pattern)
3051 break
3052
3053 return to_check
3054
3055
Saagar Sanghavifceeaae2020-08-12 16:40:363056def CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:293057 """Checks that affected files involving IPC have an IPC OWNERS rule."""
3058 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:033059 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:293060
3061 if to_check:
3062 # If there are any OWNERS files to check, there are IPC-related changes in
3063 # this CL. Auto-CC the review list.
3064 output_api.AppendCC('[email protected]')
3065
3066 # Go through the OWNERS files to check, filtering out rules that are already
3067 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:173068 for owners_file, patterns in to_check.iteritems():
3069 try:
3070 with file(owners_file) as f:
3071 lines = set(f.read().splitlines())
3072 for entry in patterns.itervalues():
3073 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
3074 ]
3075 except IOError:
3076 # No OWNERS file, so all the rules are definitely missing.
3077 continue
3078
3079 # All the remaining lines weren't found in OWNERS files, so emit an error.
3080 errors = []
3081 for owners_file, patterns in to_check.iteritems():
3082 missing_lines = []
3083 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:503084 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:173085 missing_lines.extend(entry['rules'])
3086 files.extend([' %s' % f.LocalPath() for f in entry['files']])
3087 if missing_lines:
3088 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:053089 'Because of the presence of files:\n%s\n\n'
3090 '%s needs the following %d lines added:\n\n%s' %
3091 ('\n'.join(files), owners_file, len(missing_lines),
3092 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:173093
3094 results = []
3095 if errors:
vabrf5ce3bf92016-07-11 14:52:413096 if input_api.is_committing:
3097 output = output_api.PresubmitError
3098 else:
3099 output = output_api.PresubmitPromptWarning
3100 results.append(output(
Daniel Cheng52111692017-06-14 08:00:593101 'Found OWNERS files that need to be updated for IPC security ' +
3102 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:173103 long_text='\n\n'.join(errors)))
3104
3105 return results
3106
3107
Robert Sesek2c905332020-05-06 23:17:133108def _GetFilesUsingSecurityCriticalFunctions(input_api):
3109 """Checks affected files for changes to security-critical calls. This
3110 function checks the full change diff, to catch both additions/changes
3111 and removals.
3112
3113 Returns a dict keyed by file name, and the value is a set of detected
3114 functions.
3115 """
3116 # Map of function pretty name (displayed in an error) to the pattern to
3117 # match it with.
3118 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:373119 'content::GetServiceSandboxType<>()':
3120 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:133121 }
3122 _PATTERNS_TO_CHECK = {
3123 k: input_api.re.compile(v)
3124 for k, v in _PATTERNS_TO_CHECK.items()
3125 }
3126
3127 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3128 files_to_functions = {}
3129 for f in input_api.AffectedFiles():
3130 diff = f.GenerateScmDiff()
3131 for line in diff.split('\n'):
3132 # Not using just RightHandSideLines() because removing a
3133 # call to a security-critical function can be just as important
3134 # as adding or changing the arguments.
3135 if line.startswith('-') or (line.startswith('+') and
3136 not line.startswith('++')):
3137 for name, pattern in _PATTERNS_TO_CHECK.items():
3138 if pattern.search(line):
3139 path = f.LocalPath()
3140 if not path in files_to_functions:
3141 files_to_functions[path] = set()
3142 files_to_functions[path].add(name)
3143 return files_to_functions
3144
3145
Saagar Sanghavifceeaae2020-08-12 16:40:363146def CheckSecurityChanges(input_api, output_api):
Robert Sesek2c905332020-05-06 23:17:133147 """Checks that changes involving security-critical functions are reviewed
3148 by the security team.
3149 """
3150 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3151 if len(files_to_functions):
3152 owners_db = input_api.owners_db
3153 owner_email, reviewers = (
3154 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3155 input_api,
3156 owners_db.email_regexp,
3157 approval_needed=input_api.is_committing))
3158
3159 # Load the OWNERS file for security changes.
3160 owners_file = 'ipc/SECURITY_OWNERS'
3161 security_owners = owners_db.owners_rooted_at_file(owners_file)
3162
3163 has_security_owner = any([owner in reviewers for owner in security_owners])
3164 if not has_security_owner:
3165 msg = 'The following files change calls to security-sensive functions\n' \
3166 'that need to be reviewed by {}.\n'.format(owners_file)
3167 for path, names in files_to_functions.items():
3168 msg += ' {}\n'.format(path)
3169 for name in names:
3170 msg += ' {}\n'.format(name)
3171 msg += '\n'
3172
3173 if input_api.is_committing:
3174 output = output_api.PresubmitError
3175 else:
3176 output = output_api.PresubmitNotifyResult
3177 return [output(msg)]
3178
3179 return []
3180
3181
Saagar Sanghavifceeaae2020-08-12 16:40:363182def CheckSetNoParent(input_api, output_api):
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263183 """Checks that set noparent is only used together with an OWNERS file in
3184 //build/OWNERS.setnoparent (see also
3185 //docs/code_reviews.md#owners-files-details)
3186 """
3187 errors = []
3188
3189 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3190 allowed_owners_files = set()
3191 with open(allowed_owners_files_file, 'r') as f:
3192 for line in f:
3193 line = line.strip()
3194 if not line or line.startswith('#'):
3195 continue
3196 allowed_owners_files.add(line)
3197
3198 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3199
3200 for f in input_api.AffectedFiles(include_deletes=False):
3201 if not f.LocalPath().endswith('OWNERS'):
3202 continue
3203
3204 found_owners_files = set()
3205 found_set_noparent_lines = dict()
3206
3207 # Parse the OWNERS file.
3208 for lineno, line in enumerate(f.NewContents(), 1):
3209 line = line.strip()
3210 if line.startswith('set noparent'):
3211 found_set_noparent_lines[''] = lineno
3212 if line.startswith('file://'):
3213 if line in allowed_owners_files:
3214 found_owners_files.add('')
3215 if line.startswith('per-file'):
3216 match = per_file_pattern.match(line)
3217 if match:
3218 glob = match.group(1).strip()
3219 directive = match.group(2).strip()
3220 if directive == 'set noparent':
3221 found_set_noparent_lines[glob] = lineno
3222 if directive.startswith('file://'):
3223 if directive in allowed_owners_files:
3224 found_owners_files.add(glob)
3225
3226 # Check that every set noparent line has a corresponding file:// line
3227 # listed in build/OWNERS.setnoparent.
3228 for set_noparent_line in found_set_noparent_lines:
3229 if set_noparent_line in found_owners_files:
3230 continue
3231 errors.append(' %s:%d' % (f.LocalPath(),
3232 found_set_noparent_lines[set_noparent_line]))
3233
3234 results = []
3235 if errors:
3236 if input_api.is_committing:
3237 output = output_api.PresubmitError
3238 else:
3239 output = output_api.PresubmitPromptWarning
3240 results.append(output(
3241 'Found the following "set noparent" restrictions in OWNERS files that '
3242 'do not include owners from build/OWNERS.setnoparent:',
3243 long_text='\n\n'.join(errors)))
3244 return results
3245
3246
Saagar Sanghavifceeaae2020-08-12 16:40:363247def CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313248 """Checks that added or removed lines in non third party affected
3249 header files do not lead to new useless class or struct forward
3250 declaration.
jbriance9e12f162016-11-25 07:57:503251 """
3252 results = []
3253 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3254 input_api.re.MULTILINE)
3255 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3256 input_api.re.MULTILINE)
3257 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313258 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193259 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493260 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313261 continue
3262
jbriance9e12f162016-11-25 07:57:503263 if not f.LocalPath().endswith('.h'):
3264 continue
3265
3266 contents = input_api.ReadFile(f)
3267 fwd_decls = input_api.re.findall(class_pattern, contents)
3268 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3269
3270 useless_fwd_decls = []
3271 for decl in fwd_decls:
3272 count = sum(1 for _ in input_api.re.finditer(
3273 r'\b%s\b' % input_api.re.escape(decl), contents))
3274 if count == 1:
3275 useless_fwd_decls.append(decl)
3276
3277 if not useless_fwd_decls:
3278 continue
3279
3280 for line in f.GenerateScmDiff().splitlines():
3281 if (line.startswith('-') and not line.startswith('--') or
3282 line.startswith('+') and not line.startswith('++')):
3283 for decl in useless_fwd_decls:
3284 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3285 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243286 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503287 (f.LocalPath(), decl)))
3288 useless_fwd_decls.remove(decl)
3289
3290 return results
3291
Jinsong Fan91ebbbd2019-04-16 14:57:173292def _CheckAndroidDebuggableBuild(input_api, output_api):
3293 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3294 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3295 this is a debuggable build of Android.
3296 """
3297 build_type_check_pattern = input_api.re.compile(
3298 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3299
3300 errors = []
3301
3302 sources = lambda affected_file: input_api.FilterSourceFile(
3303 affected_file,
James Cook24a504192020-07-23 00:08:443304 files_to_skip=(_EXCLUDED_PATHS +
3305 _TEST_CODE_EXCLUDED_PATHS +
3306 input_api.DEFAULT_FILES_TO_SKIP +
3307 (r"^android_webview[\\/]support_library[\\/]"
3308 "boundary_interfaces[\\/]",
3309 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3310 r'^third_party[\\/].*',
3311 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3312 r"webview[\\/]chromium[\\/]License.*",)),
3313 files_to_check=[r'.*\.java$'])
Jinsong Fan91ebbbd2019-04-16 14:57:173314
3315 for f in input_api.AffectedSourceFiles(sources):
3316 for line_num, line in f.ChangedContents():
3317 if build_type_check_pattern.search(line):
3318 errors.append("%s:%d" % (f.LocalPath(), line_num))
3319
3320 results = []
3321
3322 if errors:
3323 results.append(output_api.PresubmitPromptWarning(
3324 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3325 ' Please use BuildInfo.isDebugAndroid() instead.',
3326 errors))
3327
3328 return results
jbriance9e12f162016-11-25 07:57:503329
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493330# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293331def _CheckAndroidToastUsage(input_api, output_api):
3332 """Checks that code uses org.chromium.ui.widget.Toast instead of
3333 android.widget.Toast (Chromium Toast doesn't force hardware
3334 acceleration on low-end devices, saving memory).
3335 """
3336 toast_import_pattern = input_api.re.compile(
3337 r'^import android\.widget\.Toast;$')
3338
3339 errors = []
3340
3341 sources = lambda affected_file: input_api.FilterSourceFile(
3342 affected_file,
James Cook24a504192020-07-23 00:08:443343 files_to_skip=(_EXCLUDED_PATHS +
3344 _TEST_CODE_EXCLUDED_PATHS +
3345 input_api.DEFAULT_FILES_TO_SKIP +
3346 (r'^chromecast[\\/].*',
3347 r'^remoting[\\/].*')),
3348 files_to_check=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293349
3350 for f in input_api.AffectedSourceFiles(sources):
3351 for line_num, line in f.ChangedContents():
3352 if toast_import_pattern.search(line):
3353 errors.append("%s:%d" % (f.LocalPath(), line_num))
3354
3355 results = []
3356
3357 if errors:
3358 results.append(output_api.PresubmitError(
3359 'android.widget.Toast usage is detected. Android toasts use hardware'
3360 ' acceleration, and can be\ncostly on low-end devices. Please use'
3361 ' org.chromium.ui.widget.Toast instead.\n'
3362 'Contact [email protected] if you have any questions.',
3363 errors))
3364
3365 return results
3366
3367
dgnaa68d5e2015-06-10 10:08:223368def _CheckAndroidCrLogUsage(input_api, output_api):
3369 """Checks that new logs using org.chromium.base.Log:
3370 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513371 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223372 """
pkotwicza1dd0b002016-05-16 14:41:043373
torne89540622017-03-24 19:41:303374 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043375 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303376 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043377 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303378 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043379 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3380 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093381 # The customtabs_benchmark is a small app that does not depend on Chromium
3382 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043383 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043384 ]
3385
dgnaa68d5e2015-06-10 10:08:223386 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123387 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3388 class_in_base_pattern = input_api.re.compile(
3389 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3390 has_some_log_import_pattern = input_api.re.compile(
3391 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223392 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553393 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223394 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463395 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553396 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223397
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463398 REF_MSG = ('See docs/android_logging.md for more info.')
James Cook24a504192020-07-23 00:08:443399 sources = lambda x: input_api.FilterSourceFile(x,
3400 files_to_check=[r'.*\.java$'],
3401 files_to_skip=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123402
dgnaa68d5e2015-06-10 10:08:223403 tag_decl_errors = []
3404 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123405 tag_errors = []
dgn38736db2015-09-18 19:20:513406 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123407 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223408
3409 for f in input_api.AffectedSourceFiles(sources):
3410 file_content = input_api.ReadFile(f)
3411 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223412 # Per line checks
dgn87d9fb62015-06-12 09:15:123413 if (cr_log_import_pattern.search(file_content) or
3414 (class_in_base_pattern.search(file_content) and
3415 not has_some_log_import_pattern.search(file_content))):
3416 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223417 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553418 if rough_log_decl_pattern.search(line):
3419 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223420
3421 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123422 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223423 if match:
3424 has_modified_logs = True
3425
3426 # Make sure it uses "TAG"
3427 if not match.group('tag') == 'TAG':
3428 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123429 else:
3430 # Report non cr Log function calls in changed lines
3431 for line_num, line in f.ChangedContents():
3432 if log_call_pattern.search(line):
3433 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223434
3435 # Per file checks
3436 if has_modified_logs:
3437 # Make sure the tag is using the "cr" prefix and is not too long
3438 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513439 tag_name = match.group('name') if match else None
3440 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223441 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513442 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223443 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513444 elif '.' in tag_name:
3445 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223446
3447 results = []
3448 if tag_decl_errors:
3449 results.append(output_api.PresubmitPromptWarning(
3450 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513451 '"private static final String TAG = "<package tag>".\n'
3452 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223453 tag_decl_errors))
3454
3455 if tag_length_errors:
3456 results.append(output_api.PresubmitError(
3457 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513458 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223459 tag_length_errors))
3460
3461 if tag_errors:
3462 results.append(output_api.PresubmitPromptWarning(
3463 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3464 tag_errors))
3465
dgn87d9fb62015-06-12 09:15:123466 if util_log_errors:
dgn4401aa52015-04-29 16:26:173467 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123468 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3469 util_log_errors))
3470
dgn38736db2015-09-18 19:20:513471 if tag_with_dot_errors:
3472 results.append(output_api.PresubmitPromptWarning(
3473 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3474 tag_with_dot_errors))
3475
dgn4401aa52015-04-29 16:26:173476 return results
3477
3478
Yoland Yanb92fa522017-08-28 17:37:063479def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3480 """Checks that junit.framework.* is no longer used."""
3481 deprecated_junit_framework_pattern = input_api.re.compile(
3482 r'^import junit\.framework\..*;',
3483 input_api.re.MULTILINE)
3484 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443485 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063486 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133487 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063488 for line_num, line in f.ChangedContents():
3489 if deprecated_junit_framework_pattern.search(line):
3490 errors.append("%s:%d" % (f.LocalPath(), line_num))
3491
3492 results = []
3493 if errors:
3494 results.append(output_api.PresubmitError(
3495 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3496 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3497 ' if you have any question.', errors))
3498 return results
3499
3500
3501def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3502 """Checks that if new Java test classes have inheritance.
3503 Either the new test class is JUnit3 test or it is a JUnit4 test class
3504 with a base class, either case is undesirable.
3505 """
3506 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3507
3508 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443509 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063510 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133511 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063512 if not f.OldContents():
3513 class_declaration_start_flag = False
3514 for line_num, line in f.ChangedContents():
3515 if class_declaration_pattern.search(line):
3516 class_declaration_start_flag = True
3517 if class_declaration_start_flag and ' extends ' in line:
3518 errors.append('%s:%d' % (f.LocalPath(), line_num))
3519 if '{' in line:
3520 class_declaration_start_flag = False
3521
3522 results = []
3523 if errors:
3524 results.append(output_api.PresubmitPromptWarning(
3525 'The newly created files include Test classes that inherits from base'
3526 ' class. Please do not use inheritance in JUnit4 tests or add new'
3527 ' JUnit3 tests. Contact [email protected] if you have any'
3528 ' questions.', errors))
3529 return results
3530
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203531
yolandyan45001472016-12-21 21:12:423532def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3533 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3534 deprecated_annotation_import_pattern = input_api.re.compile(
3535 r'^import android\.test\.suitebuilder\.annotation\..*;',
3536 input_api.re.MULTILINE)
3537 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443538 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
yolandyan45001472016-12-21 21:12:423539 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133540 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423541 for line_num, line in f.ChangedContents():
3542 if deprecated_annotation_import_pattern.search(line):
3543 errors.append("%s:%d" % (f.LocalPath(), line_num))
3544
3545 results = []
3546 if errors:
3547 results.append(output_api.PresubmitError(
3548 'Annotations in android.test.suitebuilder.annotation have been'
3549 ' deprecated since API level 24. Please use android.support.test.filters'
3550 ' from //third_party/android_support_test_runner:runner_java instead.'
3551 ' Contact [email protected] if you have any questions.', errors))
3552 return results
3553
3554
agrieve7b6479d82015-10-07 14:24:223555def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3556 """Checks if MDPI assets are placed in a correct directory."""
3557 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3558 ('/res/drawable/' in f.LocalPath() or
3559 '/res/drawable-ldrtl/' in f.LocalPath()))
3560 errors = []
3561 for f in input_api.AffectedFiles(include_deletes=False,
3562 file_filter=file_filter):
3563 errors.append(' %s' % f.LocalPath())
3564
3565 results = []
3566 if errors:
3567 results.append(output_api.PresubmitError(
3568 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3569 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3570 '/res/drawable-ldrtl/.\n'
3571 'Contact [email protected] if you have questions.', errors))
3572 return results
3573
3574
Nate Fischer535972b2017-09-16 01:06:183575def _CheckAndroidWebkitImports(input_api, output_api):
3576 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353577 android.webview.ValueCallback except in the WebView glue layer
3578 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183579 """
3580 valuecallback_import_pattern = input_api.re.compile(
3581 r'^import android\.webkit\.ValueCallback;$')
3582
3583 errors = []
3584
3585 sources = lambda affected_file: input_api.FilterSourceFile(
3586 affected_file,
James Cook24a504192020-07-23 00:08:443587 files_to_skip=(_EXCLUDED_PATHS +
3588 _TEST_CODE_EXCLUDED_PATHS +
3589 input_api.DEFAULT_FILES_TO_SKIP +
3590 (r'^android_webview[\\/]glue[\\/].*',
3591 r'^weblayer[\\/].*',)),
3592 files_to_check=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183593
3594 for f in input_api.AffectedSourceFiles(sources):
3595 for line_num, line in f.ChangedContents():
3596 if valuecallback_import_pattern.search(line):
3597 errors.append("%s:%d" % (f.LocalPath(), line_num))
3598
3599 results = []
3600
3601 if errors:
3602 results.append(output_api.PresubmitError(
3603 'android.webkit.ValueCallback usage is detected outside of the glue'
3604 ' layer. To stay compatible with the support library, android.webkit.*'
3605 ' classes should only be used inside the glue layer and'
3606 ' org.chromium.base.Callback should be used instead.',
3607 errors))
3608
3609 return results
3610
3611
Becky Zhou7c69b50992018-12-10 19:37:573612def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3613 """Checks Android XML styles """
3614 import sys
3615 original_sys_path = sys.path
3616 try:
3617 sys.path = sys.path + [input_api.os_path.join(
3618 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3619 import checkxmlstyle
3620 finally:
3621 # Restore sys.path to what it was before.
3622 sys.path = original_sys_path
3623
3624 if is_check_on_upload:
3625 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3626 else:
3627 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3628
3629
agrievef32bcc72016-04-04 14:57:403630class PydepsChecker(object):
3631 def __init__(self, input_api, pydeps_files):
3632 self._file_cache = {}
3633 self._input_api = input_api
3634 self._pydeps_files = pydeps_files
3635
3636 def _LoadFile(self, path):
3637 """Returns the list of paths within a .pydeps file relative to //."""
3638 if path not in self._file_cache:
3639 with open(path) as f:
3640 self._file_cache[path] = f.read()
3641 return self._file_cache[path]
3642
3643 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3644 """Returns an interable of paths within the .pydep, relativized to //."""
3645 os_path = self._input_api.os_path
3646 pydeps_dir = os_path.dirname(pydeps_path)
3647 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
3648 if not l.startswith('*'))
3649 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
3650
3651 def _CreateFilesToPydepsMap(self):
3652 """Returns a map of local_path -> list_of_pydeps."""
3653 ret = {}
3654 for pydep_local_path in self._pydeps_files:
3655 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3656 ret.setdefault(path, []).append(pydep_local_path)
3657 return ret
3658
3659 def ComputeAffectedPydeps(self):
3660 """Returns an iterable of .pydeps files that might need regenerating."""
3661 affected_pydeps = set()
3662 file_to_pydeps_map = None
3663 for f in self._input_api.AffectedFiles(include_deletes=True):
3664 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463665 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3666 # subrepositories. We can't figure out which files change, so re-check
3667 # all files.
3668 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383669 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3670 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403671 return self._pydeps_files
3672 elif local_path.endswith('.pydeps'):
3673 if local_path in self._pydeps_files:
3674 affected_pydeps.add(local_path)
3675 elif local_path.endswith('.py'):
3676 if file_to_pydeps_map is None:
3677 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3678 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3679 return affected_pydeps
3680
3681 def DetermineIfStale(self, pydeps_path):
3682 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413683 import difflib
John Budorick47ca3fe2018-02-10 00:53:103684 import os
3685
agrievef32bcc72016-04-04 14:57:403686 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033687 if old_pydeps_data:
3688 cmd = old_pydeps_data[1][1:].strip()
3689 old_contents = old_pydeps_data[2:]
3690 else:
3691 # A default cmd that should work in most cases (as long as pydeps filename
3692 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3693 # file is empty/new.
3694 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3695 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3696 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103697 env = dict(os.environ)
3698 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403699 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103700 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413701 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033702 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413703 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403704
3705
Tibor Goldschwendt360793f72019-06-25 18:23:493706def _ParseGclientArgs():
3707 args = {}
3708 with open('build/config/gclient_args.gni', 'r') as f:
3709 for line in f:
3710 line = line.strip()
3711 if not line or line.startswith('#'):
3712 continue
3713 attribute, value = line.split('=')
3714 args[attribute.strip()] = value.strip()
3715 return args
3716
3717
Saagar Sanghavifceeaae2020-08-12 16:40:363718def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
agrievef32bcc72016-04-04 14:57:403719 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403720 # This check is for Python dependency lists (.pydeps files), and involves
3721 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3722 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283723 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003724 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493725 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403726 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403727 results = []
3728 # First, check for new / deleted .pydeps.
3729 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033730 # Check whether we are running the presubmit check for a file in src.
3731 # f.LocalPath is relative to repo (src, or internal repo).
3732 # os_path.exists is relative to src repo.
3733 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3734 # to src and we can conclude that the pydeps is in src.
3735 if input_api.os_path.exists(f.LocalPath()):
3736 if f.LocalPath().endswith('.pydeps'):
3737 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3738 results.append(output_api.PresubmitError(
3739 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3740 'remove %s' % f.LocalPath()))
3741 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3742 results.append(output_api.PresubmitError(
3743 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3744 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403745
3746 if results:
3747 return results
3748
Mohamed Heikal7cd4d8312020-06-16 16:49:403749 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3750 affected_pydeps = set(checker.ComputeAffectedPydeps())
3751 affected_android_pydeps = affected_pydeps.intersection(
3752 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3753 if affected_android_pydeps and not is_android:
3754 results.append(output_api.PresubmitPromptOrNotify(
3755 'You have changed python files that may affect pydeps for android\n'
3756 'specific scripts. However, the relevant presumbit check cannot be\n'
3757 'run because you are not using an Android checkout. To validate that\n'
3758 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3759 'use the android-internal-presubmit optional trybot.\n'
3760 'Possibly stale pydeps files:\n{}'.format(
3761 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403762
Mohamed Heikal7cd4d8312020-06-16 16:49:403763 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3764 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403765 try:
phajdan.jr0d9878552016-11-04 10:49:413766 result = checker.DetermineIfStale(pydep_path)
3767 if result:
3768 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403769 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413770 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3771 'To regenerate, run:\n\n %s' %
3772 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403773 except input_api.subprocess.CalledProcessError as error:
3774 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3775 long_text=error.output)]
3776
3777 return results
3778
3779
Saagar Sanghavifceeaae2020-08-12 16:40:363780def CheckSingletonInHeaders(input_api, output_api):
glidere61efad2015-02-18 17:39:433781 """Checks to make sure no header files have |Singleton<|."""
3782 def FileFilter(affected_file):
3783 # It's ok for base/memory/singleton.h to have |Singleton<|.
James Cook24a504192020-07-23 00:08:443784 files_to_skip = (_EXCLUDED_PATHS +
3785 input_api.DEFAULT_FILES_TO_SKIP +
3786 (r"^base[\\/]memory[\\/]singleton\.h$",
3787 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
3788 r"quic_singleton_impl\.h$"))
3789 return input_api.FilterSourceFile(affected_file,
3790 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433791
sergeyu34d21222015-09-16 00:11:443792 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433793 files = []
3794 for f in input_api.AffectedSourceFiles(FileFilter):
3795 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3796 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3797 contents = input_api.ReadFile(f)
3798 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243799 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433800 pattern.search(line)):
3801 files.append(f)
3802 break
3803
3804 if files:
yolandyandaabc6d2016-04-18 18:29:393805 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443806 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433807 'Please move them to an appropriate source file so that the ' +
3808 'template gets instantiated in a single compilation unit.',
3809 files) ]
3810 return []
3811
3812
[email protected]fd20b902014-05-09 02:14:533813_DEPRECATED_CSS = [
3814 # Values
3815 ( "-webkit-box", "flex" ),
3816 ( "-webkit-inline-box", "inline-flex" ),
3817 ( "-webkit-flex", "flex" ),
3818 ( "-webkit-inline-flex", "inline-flex" ),
3819 ( "-webkit-min-content", "min-content" ),
3820 ( "-webkit-max-content", "max-content" ),
3821
3822 # Properties
3823 ( "-webkit-background-clip", "background-clip" ),
3824 ( "-webkit-background-origin", "background-origin" ),
3825 ( "-webkit-background-size", "background-size" ),
3826 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443827 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533828
3829 # Functions
3830 ( "-webkit-gradient", "gradient" ),
3831 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3832 ( "-webkit-linear-gradient", "linear-gradient" ),
3833 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3834 ( "-webkit-radial-gradient", "radial-gradient" ),
3835 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3836]
3837
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203838
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493839# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363840def CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533841 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253842 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343843 documentation and iOS CSS for dom distiller
3844 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253845 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533846 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493847 file_inclusion_pattern = [r".+\.css$"]
James Cook24a504192020-07-23 00:08:443848 files_to_skip = (_EXCLUDED_PATHS +
3849 _TEST_CODE_EXCLUDED_PATHS +
3850 input_api.DEFAULT_FILES_TO_SKIP +
3851 (r"^chrome/common/extensions/docs",
3852 r"^chrome/docs",
3853 r"^components/dom_distiller/core/css/distilledpage_ios.css",
3854 r"^components/neterror/resources/neterror.css",
3855 r"^native_client_sdk"))
[email protected]9a48e3f82014-05-22 00:06:253856 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443857 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]fd20b902014-05-09 02:14:533858 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3859 for line_num, line in fpath.ChangedContents():
3860 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023861 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533862 results.append(output_api.PresubmitError(
3863 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3864 (fpath.LocalPath(), line_num, deprecated_value, value)))
3865 return results
3866
mohan.reddyf21db962014-10-16 12:26:473867
Saagar Sanghavifceeaae2020-08-12 16:40:363868def CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363869 bad_files = {}
3870 for f in input_api.AffectedFiles(include_deletes=False):
3871 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493872 not f.LocalPath().startswith('third_party/blink') and
3873 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363874 continue
3875
Daniel Bratell65b033262019-04-23 08:17:063876 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363877 continue
3878
Vaclav Brozekd5de76a2018-03-17 07:57:503879 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363880 if "#include" in line and "../" in line]
3881 if not relative_includes:
3882 continue
3883 bad_files[f.LocalPath()] = relative_includes
3884
3885 if not bad_files:
3886 return []
3887
3888 error_descriptions = []
3889 for file_path, bad_lines in bad_files.iteritems():
3890 error_description = file_path
3891 for line in bad_lines:
3892 error_description += '\n ' + line
3893 error_descriptions.append(error_description)
3894
3895 results = []
3896 results.append(output_api.PresubmitError(
3897 'You added one or more relative #include paths (including "../").\n'
3898 'These shouldn\'t be used because they can be used to include headers\n'
3899 'from code that\'s not correctly specified as a dependency in the\n'
3900 'relevant BUILD.gn file(s).',
3901 error_descriptions))
3902
3903 return results
3904
Takeshi Yoshinoe387aa32017-08-02 13:16:133905
Saagar Sanghavifceeaae2020-08-12 16:40:363906def CheckForCcIncludes(input_api, output_api):
Daniel Bratell65b033262019-04-23 08:17:063907 """Check that nobody tries to include a cc file. It's a relatively
3908 common error which results in duplicate symbols in object
3909 files. This may not always break the build until someone later gets
3910 very confusing linking errors."""
3911 results = []
3912 for f in input_api.AffectedFiles(include_deletes=False):
3913 # We let third_party code do whatever it wants
3914 if (f.LocalPath().startswith('third_party') and
3915 not f.LocalPath().startswith('third_party/blink') and
3916 not f.LocalPath().startswith('third_party\\blink')):
3917 continue
3918
3919 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3920 continue
3921
3922 for _, line in f.ChangedContents():
3923 if line.startswith('#include "'):
3924 included_file = line.split('"')[1]
3925 if _IsCPlusPlusFile(input_api, included_file):
3926 # The most common naming for external files with C++ code,
3927 # apart from standard headers, is to call them foo.inc, but
3928 # Chromium sometimes uses foo-inc.cc so allow that as well.
3929 if not included_file.endswith(('.h', '-inc.cc')):
3930 results.append(output_api.PresubmitError(
3931 'Only header files or .inc files should be included in other\n'
3932 'C++ files. Compiling the contents of a cc file more than once\n'
3933 'will cause duplicate information in the build which may later\n'
3934 'result in strange link_errors.\n' +
3935 f.LocalPath() + ':\n ' +
3936 line))
3937
3938 return results
3939
3940
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203941def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3942 if not isinstance(key, ast.Str):
3943 return 'Key at line %d must be a string literal' % key.lineno
3944 if not isinstance(value, ast.Dict):
3945 return 'Value at line %d must be a dict' % value.lineno
3946 if len(value.keys) != 1:
3947 return 'Dict at line %d must have single entry' % value.lineno
3948 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3949 return (
3950 'Entry at line %d must have a string literal \'filepath\' as key' %
3951 value.lineno)
3952 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133953
Takeshi Yoshinoe387aa32017-08-02 13:16:133954
Sergey Ulanov4af16052018-11-08 02:41:463955def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203956 if not isinstance(key, ast.Str):
3957 return 'Key at line %d must be a string literal' % key.lineno
3958 if not isinstance(value, ast.List):
3959 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463960 for element in value.elts:
3961 if not isinstance(element, ast.Str):
3962 return 'Watchlist elements on line %d is not a string' % key.lineno
3963 if not email_regex.match(element.s):
3964 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3965 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203966 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133967
Takeshi Yoshinoe387aa32017-08-02 13:16:133968
Sergey Ulanov4af16052018-11-08 02:41:463969def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203970 mismatch_template = (
3971 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3972 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133973
Sergey Ulanov4af16052018-11-08 02:41:463974 email_regex = input_api.re.compile(
3975 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3976
3977 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203978 i = 0
3979 last_key = ''
3980 while True:
3981 if i >= len(wd_dict.keys):
3982 if i >= len(w_dict.keys):
3983 return None
3984 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3985 elif i >= len(w_dict.keys):
3986 return (
3987 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133988
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203989 wd_key = wd_dict.keys[i]
3990 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133991
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203992 result = _CheckWatchlistDefinitionsEntrySyntax(
3993 wd_key, wd_dict.values[i], ast)
3994 if result is not None:
3995 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133996
Sergey Ulanov4af16052018-11-08 02:41:463997 result = _CheckWatchlistsEntrySyntax(
3998 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203999 if result is not None:
4000 return 'Bad entry in WATCHLISTS dict: %s' % result
4001
4002 if wd_key.s != w_key.s:
4003 return mismatch_template % (
4004 '%s at line %d' % (wd_key.s, wd_key.lineno),
4005 '%s at line %d' % (w_key.s, w_key.lineno))
4006
4007 if wd_key.s < last_key:
4008 return (
4009 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
4010 (wd_key.lineno, w_key.lineno))
4011 last_key = wd_key.s
4012
4013 i = i + 1
4014
4015
Sergey Ulanov4af16052018-11-08 02:41:464016def _CheckWATCHLISTSSyntax(expression, input_api):
4017 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204018 if not isinstance(expression, ast.Expression):
4019 return 'WATCHLISTS file must contain a valid expression'
4020 dictionary = expression.body
4021 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
4022 return 'WATCHLISTS file must have single dict with exactly two entries'
4023
4024 first_key = dictionary.keys[0]
4025 first_value = dictionary.values[0]
4026 second_key = dictionary.keys[1]
4027 second_value = dictionary.values[1]
4028
4029 if (not isinstance(first_key, ast.Str) or
4030 first_key.s != 'WATCHLIST_DEFINITIONS' or
4031 not isinstance(first_value, ast.Dict)):
4032 return (
4033 'The first entry of the dict in WATCHLISTS file must be '
4034 'WATCHLIST_DEFINITIONS dict')
4035
4036 if (not isinstance(second_key, ast.Str) or
4037 second_key.s != 'WATCHLISTS' or
4038 not isinstance(second_value, ast.Dict)):
4039 return (
4040 'The second entry of the dict in WATCHLISTS file must be '
4041 'WATCHLISTS dict')
4042
Sergey Ulanov4af16052018-11-08 02:41:464043 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:134044
4045
Saagar Sanghavifceeaae2020-08-12 16:40:364046def CheckWATCHLISTS(input_api, output_api):
Takeshi Yoshinoe387aa32017-08-02 13:16:134047 for f in input_api.AffectedFiles(include_deletes=False):
4048 if f.LocalPath() == 'WATCHLISTS':
4049 contents = input_api.ReadFile(f, 'r')
4050
4051 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204052 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:134053 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204054 # Get an AST tree for it and scan the tree for detailed style checking.
4055 expression = input_api.ast.parse(
4056 contents, filename='WATCHLISTS', mode='eval')
4057 except ValueError as e:
4058 return [output_api.PresubmitError(
4059 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4060 except SyntaxError as e:
4061 return [output_api.PresubmitError(
4062 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4063 except TypeError as e:
4064 return [output_api.PresubmitError(
4065 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:134066
Sergey Ulanov4af16052018-11-08 02:41:464067 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204068 if result is not None:
4069 return [output_api.PresubmitError(result)]
4070 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134071
4072 return []
4073
4074
Saagar Sanghavifceeaae2020-08-12 16:40:364075def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194076 """Checks that newly added header files have corresponding GN changes.
4077 Note that this is only a heuristic. To be precise, run script:
4078 build/check_gn_headers.py.
4079 """
4080
4081 def headers(f):
4082 return input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444083 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194084
4085 new_headers = []
4086 for f in input_api.AffectedSourceFiles(headers):
4087 if f.Action() != 'A':
4088 continue
4089 new_headers.append(f.LocalPath())
4090
4091 def gn_files(f):
James Cook24a504192020-07-23 00:08:444092 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194093
4094 all_gn_changed_contents = ''
4095 for f in input_api.AffectedSourceFiles(gn_files):
4096 for _, line in f.ChangedContents():
4097 all_gn_changed_contents += line
4098
4099 problems = []
4100 for header in new_headers:
4101 basename = input_api.os_path.basename(header)
4102 if basename not in all_gn_changed_contents:
4103 problems.append(header)
4104
4105 if problems:
4106 return [output_api.PresubmitPromptWarning(
4107 'Missing GN changes for new header files', items=sorted(problems),
4108 long_text='Please double check whether newly added header files need '
4109 'corresponding changes in gn or gni files.\nThis checking is only a '
4110 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4111 'Read https://crbug.com/661774 for more info.')]
4112 return []
4113
4114
Saagar Sanghavifceeaae2020-08-12 16:40:364115def CheckCorrectProductNameInMessages(input_api, output_api):
Michael Giuffridad3bc8672018-10-25 22:48:024116 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
4117
4118 This assumes we won't intentionally reference one product from the other
4119 product.
4120 """
4121 all_problems = []
4122 test_cases = [{
4123 "filename_postfix": "google_chrome_strings.grd",
4124 "correct_name": "Chrome",
4125 "incorrect_name": "Chromium",
4126 }, {
4127 "filename_postfix": "chromium_strings.grd",
4128 "correct_name": "Chromium",
4129 "incorrect_name": "Chrome",
4130 }]
4131
4132 for test_case in test_cases:
4133 problems = []
4134 filename_filter = lambda x: x.LocalPath().endswith(
4135 test_case["filename_postfix"])
4136
4137 # Check each new line. Can yield false positives in multiline comments, but
4138 # easier than trying to parse the XML because messages can have nested
4139 # children, and associating message elements with affected lines is hard.
4140 for f in input_api.AffectedSourceFiles(filename_filter):
4141 for line_num, line in f.ChangedContents():
4142 if "<message" in line or "<!--" in line or "-->" in line:
4143 continue
4144 if test_case["incorrect_name"] in line:
4145 problems.append(
4146 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4147
4148 if problems:
4149 message = (
4150 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4151 % (test_case["correct_name"], test_case["correct_name"],
4152 test_case["incorrect_name"]))
4153 all_problems.append(
4154 output_api.PresubmitPromptWarning(message, items=problems))
4155
4156 return all_problems
4157
4158
Saagar Sanghavifceeaae2020-08-12 16:40:364159def CheckBuildtoolsRevisionsAreInSync(input_api, output_api):
Dirk Pranke3c18a382019-03-15 01:07:514160 # TODO(crbug.com/941824): We need to make sure the entries in
4161 # //buildtools/DEPS are kept in sync with the entries in //DEPS
4162 # so that users of //buildtools in other projects get the same tooling
4163 # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
4164 # support to gclient, we can eliminate the duplication and delete
4165 # this presubmit check.
4166
4167 # Update this regexp if new revisions are added to the files.
4168 rev_regexp = input_api.re.compile(
Xiaohui Chen3fdc6742020-02-29 02:13:264169 "'((clang_format|libcxx|libcxxabi|libunwind)_revision|gn_version)':")
Dirk Pranke3c18a382019-03-15 01:07:514170
4171 # If a user is changing one revision, they need to change the same
4172 # line in both files. This means that any given change should contain
4173 # exactly the same list of changed lines that match the regexps. The
4174 # replace(' ', '') call allows us to ignore whitespace changes to the
4175 # lines. The 'long_text' parameter to the error will contain the
4176 # list of changed lines in both files, which should make it easy enough
4177 # to spot the error without going overboard in this implementation.
4178 revs_changes = {
4179 'DEPS': {},
4180 'buildtools/DEPS': {},
4181 }
4182 long_text = ''
4183
4184 for f in input_api.AffectedFiles(
4185 file_filter=lambda f: f.LocalPath() in ('DEPS', 'buildtools/DEPS')):
4186 for line_num, line in f.ChangedContents():
4187 if rev_regexp.search(line):
4188 revs_changes[f.LocalPath()][line.replace(' ', '')] = line
4189 long_text += '%s:%d: %s\n' % (f.LocalPath(), line_num, line)
4190
4191 if set(revs_changes['DEPS']) != set(revs_changes['buildtools/DEPS']):
4192 return [output_api.PresubmitError(
4193 'Change buildtools revisions in sync in both //DEPS and '
4194 '//buildtools/DEPS.', long_text=long_text + '\n')]
4195 else:
4196 return []
4197
4198
Saagar Sanghavifceeaae2020-08-12 16:40:364199def CheckForTooLargeFiles(input_api, output_api):
Daniel Bratell93eb6c62019-04-29 20:13:364200 """Avoid large files, especially binary files, in the repository since
4201 git doesn't scale well for those. They will be in everyone's repo
4202 clones forever, forever making Chromium slower to clone and work
4203 with."""
4204
4205 # Uploading files to cloud storage is not trivial so we don't want
4206 # to set the limit too low, but the upper limit for "normal" large
4207 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4208 # anything over 20 MB is exceptional.
4209 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4210
4211 too_large_files = []
4212 for f in input_api.AffectedFiles():
4213 # Check both added and modified files (but not deleted files).
4214 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384215 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364216 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4217 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4218
4219 if too_large_files:
4220 message = (
4221 'Do not commit large files to git since git scales badly for those.\n' +
4222 'Instead put the large files in cloud storage and use DEPS to\n' +
4223 'fetch them.\n' + '\n'.join(too_large_files)
4224 )
4225 return [output_api.PresubmitError(
4226 'Too large files found in commit', long_text=message + '\n')]
4227 else:
4228 return []
4229
Max Morozb47503b2019-08-08 21:03:274230
Saagar Sanghavifceeaae2020-08-12 16:40:364231def CheckFuzzTargetsOnUpload(input_api, output_api):
Max Morozb47503b2019-08-08 21:03:274232 """Checks specific for fuzz target sources."""
4233 EXPORTED_SYMBOLS = [
4234 'LLVMFuzzerInitialize',
4235 'LLVMFuzzerCustomMutator',
4236 'LLVMFuzzerCustomCrossOver',
4237 'LLVMFuzzerMutate',
4238 ]
4239
4240 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4241
4242 def FilterFile(affected_file):
4243 """Ignore libFuzzer source code."""
James Cook24a504192020-07-23 00:08:444244 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4245 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274246
4247 return input_api.FilterSourceFile(
4248 affected_file,
James Cook24a504192020-07-23 00:08:444249 files_to_check=[files_to_check],
4250 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274251
4252 files_with_missing_header = []
4253 for f in input_api.AffectedSourceFiles(FilterFile):
4254 contents = input_api.ReadFile(f, 'r')
4255 if REQUIRED_HEADER in contents:
4256 continue
4257
4258 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4259 files_with_missing_header.append(f.LocalPath())
4260
4261 if not files_with_missing_header:
4262 return []
4263
4264 long_text = (
4265 'If you define any of the libFuzzer optional functions (%s), it is '
4266 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4267 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4268 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4269 'to access command line arguments passed to the fuzzer. Instead, prefer '
4270 'static initialization and shared resources as documented in '
4271 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
4272 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4273 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4274 )
4275
4276 return [output_api.PresubmitPromptWarning(
4277 message="Missing '%s' in:" % REQUIRED_HEADER,
4278 items=files_with_missing_header,
4279 long_text=long_text)]
4280
4281
Mohamed Heikald048240a2019-11-12 16:57:374282def _CheckNewImagesWarning(input_api, output_api):
4283 """
4284 Warns authors who add images into the repo to make sure their images are
4285 optimized before committing.
4286 """
4287 images_added = False
4288 image_paths = []
4289 errors = []
4290 filter_lambda = lambda x: input_api.FilterSourceFile(
4291 x,
James Cook24a504192020-07-23 00:08:444292 files_to_skip=(('(?i).*test', r'.*\/junit\/')
4293 + input_api.DEFAULT_FILES_TO_SKIP),
4294 files_to_check=[r'.*\/(drawable|mipmap)' ]
Mohamed Heikald048240a2019-11-12 16:57:374295 )
4296 for f in input_api.AffectedFiles(
4297 include_deletes=False, file_filter=filter_lambda):
4298 local_path = f.LocalPath().lower()
4299 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4300 images_added = True
4301 image_paths.append(f)
4302 if images_added:
4303 errors.append(output_api.PresubmitPromptWarning(
4304 'It looks like you are trying to commit some images. If these are '
4305 'non-test-only images, please make sure to read and apply the tips in '
4306 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4307 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4308 'FYI only and will not block your CL on the CQ.', image_paths))
4309 return errors
4310
4311
Saagar Sanghavifceeaae2020-08-12 16:40:364312def ChecksAndroidSpecificOnUpload(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574313 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224314 results = []
dgnaa68d5e2015-06-10 10:08:224315 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174316 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224317 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294318 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064319 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4320 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424321 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184322 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574323 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374324 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154325 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574326 return results
4327
Saagar Sanghavifceeaae2020-08-12 16:40:364328def ChecksAndroidSpecificOnCommit(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574329 """Groups commit checks that target android code."""
4330 results = []
4331 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224332 return results
4333
Chris Hall59f8d0c72020-05-01 07:31:194334# TODO(chrishall): could we additionally match on any path owned by
4335# ui/accessibility/OWNERS ?
4336_ACCESSIBILITY_PATHS = (
4337 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4338 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4339 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4340 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4341 r"^content[\\/]browser[\\/]accessibility[\\/]",
4342 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4343 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4344 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4345 r"^ui[\\/]accessibility[\\/]",
4346 r"^ui[\\/]views[\\/]accessibility[\\/]",
4347)
4348
Saagar Sanghavifceeaae2020-08-12 16:40:364349def CheckAccessibilityRelnotesField(input_api, output_api):
Chris Hall59f8d0c72020-05-01 07:31:194350 """Checks that commits to accessibility code contain an AX-Relnotes field in
4351 their commit message."""
4352 def FileFilter(affected_file):
4353 paths = _ACCESSIBILITY_PATHS
James Cook24a504192020-07-23 00:08:444354 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194355
4356 # Only consider changes affecting accessibility paths.
4357 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4358 return []
4359
Akihiro Ota08108e542020-05-20 15:30:534360 # AX-Relnotes can appear in either the description or the footer.
4361 # When searching the description, require 'AX-Relnotes:' to appear at the
4362 # beginning of a line.
4363 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4364 description_has_relnotes = any(ax_regex.match(line)
4365 for line in input_api.change.DescriptionText().lower().splitlines())
4366
4367 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4368 'AX-Relnotes', [])
4369 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194370 return []
4371
4372 # TODO(chrishall): link to Relnotes documentation in message.
4373 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4374 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4375 "user-facing changes"
4376 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4377 "user-facing effects"
4378 "\n if this is confusing or annoying then please contact members "
4379 "of ui/accessibility/OWNERS.")
4380
4381 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224382
Saagar Sanghavifceeaae2020-08-12 16:40:364383def ChecksCommon(input_api, output_api):
[email protected]22c9bd72011-03-27 16:47:394384 """Checks common to both upload and commit."""
4385 results = []
4386 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384387 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544388 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084389
4390 author = input_api.change.author_email
4391 if author and author not in _KNOWN_ROBOTS:
4392 results.extend(
4393 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4394
[email protected]9f919cc2013-07-31 03:04:044395 results.extend(
4396 input_api.canned_checks.CheckChangeHasNoTabs(
4397 input_api,
4398 output_api,
4399 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
Sergiy Byelozyorov366b6482017-11-06 18:20:434400 results.extend(input_api.RunTests(
4401 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
[email protected]2299dcf2012-11-15 19:56:244402
Edward Lesmesce51df52020-08-04 22:10:174403 dirmd_bin = input_api.os_path.join(
4404 input_api.PresubmitLocalPath(), 'third_party', 'depot_tools', 'dirmd')
4405 results.extend(input_api.RunTests(
4406 input_api.canned_checks.CheckDirMetadataFormat(
4407 input_api, output_api, dirmd_bin)))
4408 results.extend(
4409 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4410 input_api, output_api))
4411
Vaclav Brozekcdc7defb2018-03-20 09:54:354412 for f in input_api.AffectedFiles():
4413 path, name = input_api.os_path.split(f.LocalPath())
4414 if name == 'PRESUBMIT.py':
4415 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004416 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4417 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074418 # The PRESUBMIT.py file (and the directory containing it) might
4419 # have been affected by being moved or removed, so only try to
4420 # run the tests if they still exist.
4421 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4422 input_api, output_api, full_path,
James Cook24a504192020-07-23 00:08:444423 files_to_check=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:394424 return results
[email protected]1f7b4172010-01-28 01:17:344425
[email protected]b337cb5b2011-01-23 21:24:054426
Saagar Sanghavifceeaae2020-08-12 16:40:364427def CheckPatchFiles(input_api, output_api):
[email protected]b8079ae4a2012-12-05 19:56:494428 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4429 if f.LocalPath().endswith(('.orig', '.rej'))]
4430 if problems:
4431 return [output_api.PresubmitError(
4432 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034433 else:
4434 return []
[email protected]b8079ae4a2012-12-05 19:56:494435
4436
Saagar Sanghavifceeaae2020-08-12 16:40:364437def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214438 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4439 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4440 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074441 include_re = input_api.re.compile(
4442 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4443 extension_re = input_api.re.compile(r'\.[a-z]+$')
4444 errors = []
4445 for f in input_api.AffectedFiles():
4446 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4447 continue
4448 found_line_number = None
4449 found_macro = None
4450 for line_num, line in f.ChangedContents():
4451 match = macro_re.search(line)
4452 if match:
4453 found_line_number = line_num
4454 found_macro = match.group(2)
4455 break
4456 if not found_line_number:
4457 continue
4458
4459 found_include = False
4460 for line in f.NewContents():
4461 if include_re.search(line):
4462 found_include = True
4463 break
4464 if found_include:
4465 continue
4466
4467 if not f.LocalPath().endswith('.h'):
4468 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4469 try:
4470 content = input_api.ReadFile(primary_header_path, 'r')
4471 if include_re.search(content):
4472 continue
4473 except IOError:
4474 pass
4475 errors.append('%s:%d %s macro is used without including build/'
4476 'build_config.h.'
4477 % (f.LocalPath(), found_line_number, found_macro))
4478 if errors:
4479 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4480 return []
4481
4482
[email protected]b00342e7f2013-03-26 16:21:544483def _DidYouMeanOSMacro(bad_macro):
4484 try:
4485 return {'A': 'OS_ANDROID',
4486 'B': 'OS_BSD',
4487 'C': 'OS_CHROMEOS',
4488 'F': 'OS_FREEBSD',
Avi Drissman34594e902020-07-25 05:35:444489 'I': 'OS_IOS',
[email protected]b00342e7f2013-03-26 16:21:544490 'L': 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:444491 'M': 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:544492 'N': 'OS_NACL',
4493 'O': 'OS_OPENBSD',
4494 'P': 'OS_POSIX',
4495 'S': 'OS_SOLARIS',
4496 'W': 'OS_WIN'}[bad_macro[3].upper()]
4497 except KeyError:
4498 return ''
4499
4500
4501def _CheckForInvalidOSMacrosInFile(input_api, f):
4502 """Check for sensible looking, totally invalid OS macros."""
4503 preprocessor_statement = input_api.re.compile(r'^\s*#')
4504 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4505 results = []
4506 for lnum, line in f.ChangedContents():
4507 if preprocessor_statement.search(line):
4508 for match in os_macro.finditer(line):
4509 if not match.group(1) in _VALID_OS_MACROS:
4510 good = _DidYouMeanOSMacro(match.group(1))
4511 did_you_mean = ' (did you mean %s?)' % good if good else ''
4512 results.append(' %s:%d %s%s' % (f.LocalPath(),
4513 lnum,
4514 match.group(1),
4515 did_you_mean))
4516 return results
4517
4518
Saagar Sanghavifceeaae2020-08-12 16:40:364519def CheckForInvalidOSMacros(input_api, output_api):
[email protected]b00342e7f2013-03-26 16:21:544520 """Check all affected files for invalid OS macros."""
4521 bad_macros = []
tzik3f295992018-12-04 20:32:234522 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474523 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544524 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4525
4526 if not bad_macros:
4527 return []
4528
4529 return [output_api.PresubmitError(
4530 'Possibly invalid OS macro[s] found. Please fix your code\n'
4531 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4532
lliabraa35bab3932014-10-01 12:16:444533
4534def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4535 """Check all affected files for invalid "if defined" macros."""
4536 ALWAYS_DEFINED_MACROS = (
4537 "TARGET_CPU_PPC",
4538 "TARGET_CPU_PPC64",
4539 "TARGET_CPU_68K",
4540 "TARGET_CPU_X86",
4541 "TARGET_CPU_ARM",
4542 "TARGET_CPU_MIPS",
4543 "TARGET_CPU_SPARC",
4544 "TARGET_CPU_ALPHA",
4545 "TARGET_IPHONE_SIMULATOR",
4546 "TARGET_OS_EMBEDDED",
4547 "TARGET_OS_IPHONE",
4548 "TARGET_OS_MAC",
4549 "TARGET_OS_UNIX",
4550 "TARGET_OS_WIN32",
4551 )
4552 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4553 results = []
4554 for lnum, line in f.ChangedContents():
4555 for match in ifdef_macro.finditer(line):
4556 if match.group(1) in ALWAYS_DEFINED_MACROS:
4557 always_defined = ' %s is always defined. ' % match.group(1)
4558 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4559 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4560 lnum,
4561 always_defined,
4562 did_you_mean))
4563 return results
4564
4565
Saagar Sanghavifceeaae2020-08-12 16:40:364566def CheckForInvalidIfDefinedMacros(input_api, output_api):
lliabraa35bab3932014-10-01 12:16:444567 """Check all affected files for invalid "if defined" macros."""
4568 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054569 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444570 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054571 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214572 continue
lliabraa35bab3932014-10-01 12:16:444573 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4574 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4575
4576 if not bad_macros:
4577 return []
4578
4579 return [output_api.PresubmitError(
4580 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4581 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4582 bad_macros)]
4583
4584
Saagar Sanghavifceeaae2020-08-12 16:40:364585def CheckForIPCRules(input_api, output_api):
mlamouria82272622014-09-16 18:45:044586 """Check for same IPC rules described in
4587 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4588 """
4589 base_pattern = r'IPC_ENUM_TRAITS\('
4590 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4591 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4592
4593 problems = []
4594 for f in input_api.AffectedSourceFiles(None):
4595 local_path = f.LocalPath()
4596 if not local_path.endswith('.h'):
4597 continue
4598 for line_number, line in f.ChangedContents():
4599 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4600 problems.append(
4601 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4602
4603 if problems:
4604 return [output_api.PresubmitPromptWarning(
4605 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4606 else:
4607 return []
4608
[email protected]b00342e7f2013-03-26 16:21:544609
Saagar Sanghavifceeaae2020-08-12 16:40:364610def CheckForLongPathnames(input_api, output_api):
Stephen Martinis97a394142018-06-07 23:06:054611 """Check to make sure no files being submitted have long paths.
4612 This causes issues on Windows.
4613 """
4614 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194615 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054616 local_path = f.LocalPath()
4617 # Windows has a path limit of 260 characters. Limit path length to 200 so
4618 # that we have some extra for the prefix on dev machines and the bots.
4619 if len(local_path) > 200:
4620 problems.append(local_path)
4621
4622 if problems:
4623 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4624 else:
4625 return []
4626
4627
Saagar Sanghavifceeaae2020-08-12 16:40:364628def CheckForIncludeGuards(input_api, output_api):
Daniel Bratell8ba52722018-03-02 16:06:144629 """Check that header files have proper guards against multiple inclusion.
4630 If a file should not have such guards (and it probably should) then it
4631 should include the string "no-include-guard-because-multiply-included".
4632 """
Daniel Bratell6a75baef62018-06-04 10:04:454633 def is_chromium_header_file(f):
4634 # We only check header files under the control of the Chromium
4635 # project. That is, those outside third_party apart from
4636 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324637 # We also exclude *_message_generator.h headers as they use
4638 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454639 file_with_path = input_api.os_path.normpath(f.LocalPath())
4640 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324641 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454642 (not file_with_path.startswith('third_party') or
4643 file_with_path.startswith(
4644 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144645
4646 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344647 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144648
4649 errors = []
4650
Daniel Bratell6a75baef62018-06-04 10:04:454651 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144652 guard_name = None
4653 guard_line_number = None
4654 seen_guard_end = False
4655
4656 file_with_path = input_api.os_path.normpath(f.LocalPath())
4657 base_file_name = input_api.os_path.splitext(
4658 input_api.os_path.basename(file_with_path))[0]
4659 upper_base_file_name = base_file_name.upper()
4660
4661 expected_guard = replace_special_with_underscore(
4662 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144663
4664 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574665 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4666 # are too many (1000+) files with slight deviations from the
4667 # coding style. The most important part is that the include guard
4668 # is there, and that it's unique, not the name so this check is
4669 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144670 #
4671 # As code becomes more uniform, this could be made stricter.
4672
4673 guard_name_pattern_list = [
4674 # Anything with the right suffix (maybe with an extra _).
4675 r'\w+_H__?',
4676
Daniel Bratell39b5b062018-05-16 18:09:574677 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144678 r'\w+_h',
4679
4680 # Anything including the uppercase name of the file.
4681 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4682 upper_base_file_name)) + r'\w*',
4683 ]
4684 guard_name_pattern = '|'.join(guard_name_pattern_list)
4685 guard_pattern = input_api.re.compile(
4686 r'#ifndef\s+(' + guard_name_pattern + ')')
4687
4688 for line_number, line in enumerate(f.NewContents()):
4689 if 'no-include-guard-because-multiply-included' in line:
4690 guard_name = 'DUMMY' # To not trigger check outside the loop.
4691 break
4692
4693 if guard_name is None:
4694 match = guard_pattern.match(line)
4695 if match:
4696 guard_name = match.group(1)
4697 guard_line_number = line_number
4698
Daniel Bratell39b5b062018-05-16 18:09:574699 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454700 # don't match the chromium style guide, but new files should
4701 # get it right.
4702 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574703 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144704 errors.append(output_api.PresubmitPromptWarning(
4705 'Header using the wrong include guard name %s' % guard_name,
4706 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574707 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144708 else:
4709 # The line after #ifndef should have a #define of the same name.
4710 if line_number == guard_line_number + 1:
4711 expected_line = '#define %s' % guard_name
4712 if line != expected_line:
4713 errors.append(output_api.PresubmitPromptWarning(
4714 'Missing "%s" for include guard' % expected_line,
4715 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4716 'Expected: %r\nGot: %r' % (expected_line, line)))
4717
4718 if not seen_guard_end and line == '#endif // %s' % guard_name:
4719 seen_guard_end = True
4720 elif seen_guard_end:
4721 if line.strip() != '':
4722 errors.append(output_api.PresubmitPromptWarning(
4723 'Include guard %s not covering the whole file' % (
4724 guard_name), [f.LocalPath()]))
4725 break # Nothing else to check and enough to warn once.
4726
4727 if guard_name is None:
4728 errors.append(output_api.PresubmitPromptWarning(
4729 'Missing include guard %s' % expected_guard,
4730 [f.LocalPath()],
4731 'Missing include guard in %s\n'
4732 'Recommended name: %s\n'
4733 'This check can be disabled by having the string\n'
4734 'no-include-guard-because-multiply-included in the header.' %
4735 (f.LocalPath(), expected_guard)))
4736
4737 return errors
4738
4739
Saagar Sanghavifceeaae2020-08-12 16:40:364740def CheckForWindowsLineEndings(input_api, output_api):
mostynbb639aca52015-01-07 20:31:234741 """Check source code and known ascii text files for Windows style line
4742 endings.
4743 """
earthdok1b5e0ee2015-03-10 15:19:104744 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234745
4746 file_inclusion_pattern = (
4747 known_text_files,
4748 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4749 )
4750
mostynbb639aca52015-01-07 20:31:234751 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534752 source_file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444753 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
Andrew Grieve933d12e2017-10-30 20:22:534754 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504755 include_file = False
4756 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234757 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504758 include_file = True
4759 if include_file:
4760 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234761
4762 if problems:
4763 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4764 'these files to contain Windows style line endings?\n' +
4765 '\n'.join(problems))]
4766
4767 return []
4768
4769
Saagar Sanghavifceeaae2020-08-12 16:40:364770def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134771 """Checks that all source files use SYSLOG properly."""
4772 syslog_files = []
Saagar Sanghavifceeaae2020-08-12 16:40:364773 for f in input_api.AffectedSourceFiles(src_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564774 for line_number, line in f.ChangedContents():
4775 if 'SYSLOG' in line:
4776 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4777
pastarmovj89f7ee12016-09-20 14:58:134778 if syslog_files:
4779 return [output_api.PresubmitPromptWarning(
4780 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4781 ' calls.\nFiles to check:\n', items=syslog_files)]
4782 return []
4783
4784
[email protected]1f7b4172010-01-28 01:17:344785def CheckChangeOnUpload(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364786 if input_api.version < [2, 0, 0]:
4787 return [output_api.PresubmitError("Your depot_tools is out of date. "
4788 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4789 "but your version is %d.%d.%d" % tuple(input_api.version))]
[email protected]1f7b4172010-01-28 01:17:344790 results = []
scottmg39b29952014-12-08 18:31:284791 results.extend(
jam93a6ee792017-02-08 23:59:224792 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544793 return results
[email protected]ca8d1982009-02-19 16:33:124794
4795
[email protected]1bfb8322014-04-23 01:02:414796def GetTryServerMasterForBot(bot):
4797 """Returns the Try Server master for the given bot.
4798
[email protected]0bb112362014-07-26 04:38:324799 It tries to guess the master from the bot name, but may still fail
4800 and return None. There is no longer a default master.
4801 """
4802 # Potentially ambiguous bot names are listed explicitly.
4803 master_map = {
tandriie5587792016-07-14 00:34:504804 'chromium_presubmit': 'master.tryserver.chromium.linux',
4805 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414806 }
[email protected]0bb112362014-07-26 04:38:324807 master = master_map.get(bot)
4808 if not master:
wnwen4fbaab82016-05-25 12:54:364809 if 'android' in bot:
tandriie5587792016-07-14 00:34:504810 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364811 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504812 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324813 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504814 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324815 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504816 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324817 return master
[email protected]1bfb8322014-04-23 01:02:414818
4819
[email protected]ca8d1982009-02-19 16:33:124820def CheckChangeOnCommit(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364821 if input_api.version < [2, 0, 0]:
4822 return [output_api.PresubmitError("Your depot_tools is out of date. "
4823 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4824 "but your version is %d.%d.%d" % tuple(input_api.version))]
4825
[email protected]fe5f57c52009-06-05 14:25:544826 results = []
[email protected]fe5f57c52009-06-05 14:25:544827 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274828 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344829 input_api,
4830 output_api,
[email protected]2fdd1f362013-01-16 03:56:034831 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274832
jam93a6ee792017-02-08 23:59:224833 results.extend(
4834 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544835 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4836 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384837 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4838 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414839 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4840 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544841 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144842
4843
Saagar Sanghavifceeaae2020-08-12 16:40:364844def CheckStrings(input_api, output_api):
Rainhard Findlingfc31844c52020-05-15 09:58:264845 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024846 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4847 # footer is set to true.
4848 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264849 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024850 footer.lower()
4851 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264852 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024853
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144854 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264855 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144856 import sys
4857 from io import StringIO
4858
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144859 new_or_added_paths = set(f.LocalPath()
4860 for f in input_api.AffectedFiles()
4861 if (f.Action() == 'A' or f.Action() == 'M'))
4862 removed_paths = set(f.LocalPath()
4863 for f in input_api.AffectedFiles(include_deletes=True)
4864 if f.Action() == 'D')
4865
Andrew Grieve0e8790c2020-09-03 17:27:324866 affected_grds = [
4867 f for f in input_api.AffectedFiles()
4868 if f.LocalPath().endswith(('.grd', '.grdp'))
4869 ]
4870 affected_grds = [f for f in affected_grds if not 'testdata' in f.LocalPath()]
meacer8c0d3832019-12-26 21:46:164871 if not affected_grds:
4872 return []
4873
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144874 affected_png_paths = [f.AbsoluteLocalPath()
4875 for f in input_api.AffectedFiles()
4876 if (f.LocalPath().endswith('.png'))]
4877
4878 # Check for screenshots. Developers can upload screenshots using
4879 # tools/translation/upload_screenshots.py which finds and uploads
4880 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4881 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4882 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4883 #
4884 # The logic here is as follows:
4885 #
4886 # - If the CL has a .png file under the screenshots directory for a grd
4887 # file, warn the developer. Actual images should never be checked into the
4888 # Chrome repo.
4889 #
4890 # - If the CL contains modified or new messages in grd files and doesn't
4891 # contain the corresponding .sha1 files, warn the developer to add images
4892 # and upload them via tools/translation/upload_screenshots.py.
4893 #
4894 # - If the CL contains modified or new messages in grd files and the
4895 # corresponding .sha1 files, everything looks good.
4896 #
4897 # - If the CL contains removed messages in grd files but the corresponding
4898 # .sha1 files aren't removed, warn the developer to remove them.
4899 unnecessary_screenshots = []
4900 missing_sha1 = []
4901 unnecessary_sha1_files = []
4902
Rainhard Findlingfc31844c52020-05-15 09:58:264903 # This checks verifies that the ICU syntax of messages this CL touched is
4904 # valid, and reports any found syntax errors.
4905 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4906 # without developers being aware of them. Later on, such ICU syntax errors
4907 # break message extraction for translation, hence would block Chromium
4908 # translations until they are fixed.
4909 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144910
4911 def _CheckScreenshotAdded(screenshots_dir, message_id):
4912 sha1_path = input_api.os_path.join(
4913 screenshots_dir, message_id + '.png.sha1')
4914 if sha1_path not in new_or_added_paths:
4915 missing_sha1.append(sha1_path)
4916
4917
4918 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4919 sha1_path = input_api.os_path.join(
4920 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034921 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144922 unnecessary_sha1_files.append(sha1_path)
4923
Rainhard Findlingfc31844c52020-05-15 09:58:264924
4925 def _ValidateIcuSyntax(text, level, signatures):
4926 """Validates ICU syntax of a text string.
4927
4928 Check if text looks similar to ICU and checks for ICU syntax correctness
4929 in this case. Reports various issues with ICU syntax and values of
4930 variants. Supports checking of nested messages. Accumulate information of
4931 each ICU messages found in the text for further checking.
4932
4933 Args:
4934 text: a string to check.
4935 level: a number of current nesting level.
4936 signatures: an accumulator, a list of tuple of (level, variable,
4937 kind, variants).
4938
4939 Returns:
4940 None if a string is not ICU or no issue detected.
4941 A tuple of (message, start index, end index) if an issue detected.
4942 """
4943 valid_types = {
4944 'plural': (frozenset(
4945 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4946 frozenset(['=1', 'other'])),
4947 'selectordinal': (frozenset(
4948 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4949 frozenset(['one', 'other'])),
4950 'select': (frozenset(), frozenset(['other'])),
4951 }
4952
4953 # Check if the message looks like an attempt to use ICU
4954 # plural. If yes - check if its syntax strictly matches ICU format.
4955 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
4956 if not like:
4957 signatures.append((level, None, None, None))
4958 return
4959
4960 # Check for valid prefix and suffix
4961 m = re.match(
4962 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
4963 r'(plural|selectordinal|select),\s*'
4964 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
4965 if not m:
4966 return (('This message looks like an ICU plural, '
4967 'but does not follow ICU syntax.'), like.start(), like.end())
4968 starting, variable, kind, variant_pairs = m.groups()
4969 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
4970 if depth:
4971 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
4972 len(text))
4973 first = text[0]
4974 ending = text[last_pos:]
4975 if not starting:
4976 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
4977 last_pos)
4978 if not ending or '}' not in ending:
4979 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
4980 last_pos)
4981 elif first != '{':
4982 return (
4983 ('Invalid ICU format. Extra characters at the start of a complex '
4984 'message (go/icu-message-migration): "%s"') %
4985 starting, 0, len(starting))
4986 elif ending != '}':
4987 return (('Invalid ICU format. Extra characters at the end of a complex '
4988 'message (go/icu-message-migration): "%s"')
4989 % ending, last_pos - 1, len(text) - 1)
4990 if kind not in valid_types:
4991 return (('Unknown ICU message type %s. '
4992 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
4993 known, required = valid_types[kind]
4994 defined_variants = set()
4995 for variant, variant_range, value, value_range in variants:
4996 start, end = variant_range
4997 if variant in defined_variants:
4998 return ('Variant "%s" is defined more than once' % variant,
4999 start, end)
5000 elif known and variant not in known:
5001 return ('Variant "%s" is not valid for %s message' % (variant, kind),
5002 start, end)
5003 defined_variants.add(variant)
5004 # Check for nested structure
5005 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5006 if res:
5007 return (res[0], res[1] + value_range[0] + 1,
5008 res[2] + value_range[0] + 1)
5009 missing = required - defined_variants
5010 if missing:
5011 return ('Required variants missing: %s' % ', '.join(missing), 0,
5012 len(text))
5013 signatures.append((level, variable, kind, defined_variants))
5014
5015
5016 def _ParseIcuVariants(text, offset=0):
5017 """Parse variants part of ICU complex message.
5018
5019 Builds a tuple of variant names and values, as well as
5020 their offsets in the input string.
5021
5022 Args:
5023 text: a string to parse
5024 offset: additional offset to add to positions in the text to get correct
5025 position in the complete ICU string.
5026
5027 Returns:
5028 List of tuples, each tuple consist of four fields: variant name,
5029 variant name span (tuple of two integers), variant value, value
5030 span (tuple of two integers).
5031 """
5032 depth, start, end = 0, -1, -1
5033 variants = []
5034 key = None
5035 for idx, char in enumerate(text):
5036 if char == '{':
5037 if not depth:
5038 start = idx
5039 chunk = text[end + 1:start]
5040 key = chunk.strip()
5041 pos = offset + end + 1 + chunk.find(key)
5042 span = (pos, pos + len(key))
5043 depth += 1
5044 elif char == '}':
5045 if not depth:
5046 return variants, depth, offset + idx
5047 depth -= 1
5048 if not depth:
5049 end = idx
5050 variants.append((key, span, text[start:end + 1], (offset + start,
5051 offset + end + 1)))
5052 return variants, depth, offset + end + 1
5053
meacer8c0d3832019-12-26 21:46:165054 try:
5055 old_sys_path = sys.path
5056 sys.path = sys.path + [input_api.os_path.join(
5057 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5058 from helper import grd_helper
5059 finally:
5060 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145061
5062 for f in affected_grds:
5063 file_path = f.LocalPath()
5064 old_id_to_msg_map = {}
5065 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385066 # Note that this code doesn't check if the file has been deleted. This is
5067 # OK because it only uses the old and new file contents and doesn't load
5068 # the file via its path.
5069 # It's also possible that a file's content refers to a renamed or deleted
5070 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5071 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5072 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145073 if file_path.endswith('.grdp'):
5074 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585075 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395076 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145077 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585078 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395079 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145080 else:
meacerff8a9b62019-12-10 19:43:585081 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145082 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585083 old_id_to_msg_map = grd_helper.GetGrdMessages(
5084 StringIO(unicode('\n'.join(f.OldContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145085 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585086 new_id_to_msg_map = grd_helper.GetGrdMessages(
5087 StringIO(unicode('\n'.join(f.NewContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145088
Rainhard Findlingd8d04372020-08-13 13:30:095089 grd_name, ext = input_api.os_path.splitext(
5090 input_api.os_path.basename(file_path))
5091 screenshots_dir = input_api.os_path.join(
5092 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5093
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145094 # Compute added, removed and modified message IDs.
5095 old_ids = set(old_id_to_msg_map)
5096 new_ids = set(new_id_to_msg_map)
5097 added_ids = new_ids - old_ids
5098 removed_ids = old_ids - new_ids
5099 modified_ids = set([])
5100 for key in old_ids.intersection(new_ids):
Rainhard Findling1a3e71e2020-09-21 07:33:355101 if (old_id_to_msg_map[key].ContentsAsXml('', True)
Rainhard Findlingd8d04372020-08-13 13:30:095102 != new_id_to_msg_map[key].ContentsAsXml('', True)):
5103 # The message content itself changed. Require an updated screenshot.
5104 modified_ids.add(key)
Rainhard Findling1a3e71e2020-09-21 07:33:355105 elif old_id_to_msg_map[key].attrs['meaning'] != \
5106 new_id_to_msg_map[key].attrs['meaning']:
5107 # The message meaning changed. Ensure there is a screenshot for it.
5108 sha1_path = input_api.os_path.join(screenshots_dir, key + '.png.sha1')
5109 if sha1_path not in new_or_added_paths and not \
5110 input_api.os_path.exists(sha1_path):
5111 # There is neither a previous screenshot nor is a new one added now.
5112 # Require a screenshot.
5113 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145114
Rainhard Findlingfc31844c52020-05-15 09:58:265115 if run_screenshot_check:
5116 # Check the screenshot directory for .png files. Warn if there is any.
5117 for png_path in affected_png_paths:
5118 if png_path.startswith(screenshots_dir):
5119 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145120
Rainhard Findlingfc31844c52020-05-15 09:58:265121 for added_id in added_ids:
5122 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145123
Rainhard Findlingfc31844c52020-05-15 09:58:265124 for modified_id in modified_ids:
5125 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145126
Rainhard Findlingfc31844c52020-05-15 09:58:265127 for removed_id in removed_ids:
5128 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5129
5130 # Check new and changed strings for ICU syntax errors.
5131 for key in added_ids.union(modified_ids):
5132 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5133 err = _ValidateIcuSyntax(msg, 0, [])
5134 if err is not None:
5135 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145136
5137 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265138 if run_screenshot_check:
5139 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005140 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265141 'Do not include actual screenshots in the changelist. Run '
5142 'tools/translate/upload_screenshots.py to upload them instead:',
5143 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145144
Rainhard Findlingfc31844c52020-05-15 09:58:265145 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005146 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265147 'You are adding or modifying UI strings.\n'
5148 'To ensure the best translations, take screenshots of the relevant UI '
5149 '(https://g.co/chrome/translation) and add these files to your '
5150 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145151
Rainhard Findlingfc31844c52020-05-15 09:58:265152 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005153 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265154 'You removed strings associated with these files. Remove:',
5155 sorted(unnecessary_sha1_files)))
5156 else:
5157 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5158 'screenshots check.'))
5159
5160 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075161 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265162 'ICU syntax errors were found in the following strings (problems or '
5163 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145164
5165 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125166
5167
Saagar Sanghavifceeaae2020-08-12 16:40:365168def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125169 repo_root=None,
5170 translation_expectations_path=None,
5171 grd_files=None):
5172 import sys
5173 affected_grds = [f for f in input_api.AffectedFiles()
5174 if (f.LocalPath().endswith('.grd') or
5175 f.LocalPath().endswith('.grdp'))]
5176 if not affected_grds:
5177 return []
5178
5179 try:
5180 old_sys_path = sys.path
5181 sys.path = sys.path + [
5182 input_api.os_path.join(
5183 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5184 from helper import git_helper
5185 from helper import translation_helper
5186 finally:
5187 sys.path = old_sys_path
5188
5189 # Check that translation expectations can be parsed and we can get a list of
5190 # translatable grd files. |repo_root| and |translation_expectations_path| are
5191 # only passed by tests.
5192 if not repo_root:
5193 repo_root = input_api.PresubmitLocalPath()
5194 if not translation_expectations_path:
5195 translation_expectations_path = input_api.os_path.join(
5196 repo_root, 'tools', 'gritsettings',
5197 'translation_expectations.pyl')
5198 if not grd_files:
5199 grd_files = git_helper.list_grds_in_repository(repo_root)
5200
5201 try:
5202 translation_helper.get_translatable_grds(repo_root, grd_files,
5203 translation_expectations_path)
5204 except Exception as e:
5205 return [output_api.PresubmitNotifyResult(
5206 'Failed to get a list of translatable grd files. This happens when:\n'
5207 ' - One of the modified grd or grdp files cannot be parsed or\n'
5208 ' - %s is not updated.\n'
5209 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5210 return []
Ken Rockotc31f4832020-05-29 18:58:515211
5212
Saagar Sanghavifceeaae2020-08-12 16:40:365213def CheckStableMojomChanges(input_api, output_api):
Ken Rockotc31f4832020-05-29 18:58:515214 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095215 changed_mojoms = input_api.AffectedFiles(
5216 include_deletes=True,
5217 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Ken Rockotc31f4832020-05-29 18:58:515218 delta = []
5219 for mojom in changed_mojoms:
5220 old_contents = ''.join(mojom.OldContents()) or None
5221 new_contents = ''.join(mojom.NewContents()) or None
5222 delta.append({
5223 'filename': mojom.LocalPath(),
5224 'old': '\n'.join(mojom.OldContents()) or None,
5225 'new': '\n'.join(mojom.NewContents()) or None,
5226 })
5227
5228 process = input_api.subprocess.Popen(
5229 [input_api.python_executable,
5230 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5231 'public', 'tools', 'mojom',
5232 'check_stable_mojom_compatibility.py'),
5233 '--src-root', input_api.PresubmitLocalPath()],
5234 stdin=input_api.subprocess.PIPE,
5235 stdout=input_api.subprocess.PIPE,
5236 stderr=input_api.subprocess.PIPE,
5237 universal_newlines=True)
5238 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5239 if process.returncode:
5240 return [output_api.PresubmitError(
5241 'One or more [Stable] mojom definitions appears to have been changed '
5242 'in a way that is not backward-compatible.',
5243 long_text=error)]
5244 return []