blob: 301b5aa9698fff4d2b5db32f926ec27cb49325b8 [file] [log] [blame]
Avi Drissman24976592022-09-12 15:24:311# Copyright 2012 The Chromium Authors
[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
Daniel Chengd88244472022-05-16 09:08:477See https://www.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"""
Daniel Chenga44a1bcd2022-03-15 20:00:1510
Daniel Chenga37c03db2022-05-12 17:20:3411from typing import Callable
Daniel Chenga44a1bcd2022-03-15 20:00:1512from typing import Optional
13from typing import Sequence
14from dataclasses import dataclass
15
Saagar Sanghavifceeaae2020-08-12 16:40:3616PRESUBMIT_VERSION = '2.0.0'
[email protected]eea609a2011-11-18 13:10:1217
Dirk Prankee3c9c62d2021-05-18 18:35:5918
[email protected]379e7dd2010-01-28 17:39:2119_EXCLUDED_PATHS = (
Bruce Dawson7f8566b2022-05-06 16:22:1820 # Generated file
Bruce Dawson40fece62022-09-16 19:58:3121 (r"chrome/android/webapk/shell_apk/src/org/chromium"
22 r"/webapk/lib/runtime_library/IWebApkApi.java"),
Mila Greene3aa7222021-09-07 16:34:0823 # File needs to write to stdout to emulate a tool it's replacing.
Bruce Dawson40fece62022-09-16 19:58:3124 r"chrome/updater/mac/keystone/ksadmin.mm",
Ilya Shermane8a7d2d2020-07-25 04:33:4725 # Generated file.
Bruce Dawson40fece62022-09-16 19:58:3126 (r"^components/variations/proto/devtools/"
Ilya Shermanc167a962020-08-18 18:40:2627 r"client_variations.js"),
Bruce Dawson3bd976c2022-05-06 22:47:5228 # These are video files, not typescript.
Bruce Dawson40fece62022-09-16 19:58:3129 r"^media/test/data/.*.ts",
30 r"^native_client_sdksrc/build_tools/make_rules.py",
31 r"^native_client_sdk/src/build_tools/make_simple.py",
32 r"^native_client_sdk/src/tools/.*.mk",
33 r"^net/tools/spdyshark/.*",
34 r"^skia/.*",
35 r"^third_party/blink/.*",
36 r"^third_party/breakpad/.*",
Darwin Huangd74a9d32019-07-17 17:58:4637 # sqlite is an imported third party dependency.
Bruce Dawson40fece62022-09-16 19:58:3138 r"^third_party/sqlite/.*",
39 r"^v8/.*",
[email protected]3e4eb112011-01-18 03:29:5440 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5341 r".+_autogen\.h$",
Yue Shecf1380552022-08-23 20:59:2042 r".+_pb2(_grpc)?\.py$",
Bruce Dawson40fece62022-09-16 19:58:3143 r".+/pnacl_shim\.c$",
44 r"^gpu/config/.*_list_json\.cc$",
45 r"tools/md_browser/.*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1446 # Test pages for Maps telemetry tests.
Bruce Dawson40fece62022-09-16 19:58:3147 r"tools/perf/page_sets/maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5448 # Test pages for WebRTC telemetry tests.
Bruce Dawson40fece62022-09-16 19:58:3149 r"tools/perf/page_sets/webrtc_cases.*",
dpapad2efd4452023-04-06 01:43:4550 # Test file compared with generated output.
51 r"tools/polymer/tests/html_to_wrapper/.*.html.ts$",
[email protected]4306417642009-06-11 00:33:4052)
[email protected]ca8d1982009-02-19 16:33:1253
John Abd-El-Malek759fea62021-03-13 03:41:1454_EXCLUDED_SET_NO_PARENT_PATHS = (
55 # It's for historical reasons that blink isn't a top level directory, where
56 # it would be allowed to have "set noparent" to avoid top level owners
57 # accidentally +1ing changes.
58 'third_party/blink/OWNERS',
59)
60
wnwenbdc444e2016-05-25 13:44:1561
[email protected]06e6d0ff2012-12-11 01:36:4462# Fragment of a regular expression that matches C++ and Objective-C++
63# implementation files.
64_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
65
wnwenbdc444e2016-05-25 13:44:1566
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1967# Fragment of a regular expression that matches C++ and Objective-C++
68# header files.
69_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
70
71
Aleksey Khoroshilov9b28c032022-06-03 16:35:3272# Paths with sources that don't use //base.
73_NON_BASE_DEPENDENT_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:3174 r"^chrome/browser/browser_switcher/bho/",
75 r"^tools/win/",
Aleksey Khoroshilov9b28c032022-06-03 16:35:3276)
77
78
[email protected]06e6d0ff2012-12-11 01:36:4479# Regular expression that matches code only used for test binaries
80# (best effort).
81_TEST_CODE_EXCLUDED_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:3182 r'.*/(fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4483 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
James Cook1b4dc132021-03-09 22:45:1384 # Test suite files, like:
85 # foo_browsertest.cc
86 # bar_unittest_mac.cc (suffix)
87 # baz_unittests.cc (plural)
88 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(s)?(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1289 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1890 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
Victor Hugo Vianna Silvac22e0202021-06-09 19:46:2191 r'.+sync_service_impl_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Bruce Dawson40fece62022-09-16 19:58:3192 r'.*/(test|tool(s)?)/.*',
danakj89f47082020-09-02 17:53:4393 # content_shell is used for running content_browsertests.
Bruce Dawson40fece62022-09-16 19:58:3194 r'content/shell/.*',
danakj89f47082020-09-02 17:53:4395 # Web test harness.
Bruce Dawson40fece62022-09-16 19:58:3196 r'content/web_test/.*',
[email protected]7b054982013-11-27 00:44:4797 # Non-production example code.
Bruce Dawson40fece62022-09-16 19:58:3198 r'mojo/examples/.*',
[email protected]8176de12014-06-20 19:07:0899 # Launcher for running iOS tests on the simulator.
Bruce Dawson40fece62022-09-16 19:58:31100 r'testing/iossim/iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:41101 # EarlGrey app side code for tests.
Bruce Dawson40fece62022-09-16 19:58:31102 r'ios/.*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:17103 # Views Examples code
Bruce Dawson40fece62022-09-16 19:58:31104 r'ui/views/examples/.*',
Austin Sullivan33da70a2020-10-07 15:39:41105 # Chromium Codelab
Bruce Dawson40fece62022-09-16 19:58:31106 r'codelabs/*'
[email protected]06e6d0ff2012-12-11 01:36:44107)
[email protected]ca8d1982009-02-19 16:33:12108
Daniel Bratell609102be2019-03-27 20:53:21109_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:15110
[email protected]eea609a2011-11-18 13:10:12111_TEST_ONLY_WARNING = (
112 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:55113 'production code. If you are doing this from inside another method\n'
114 'named as *ForTesting(), then consider exposing things to have tests\n'
115 'make that same call directly.\n'
116 'If that is not possible, you may put a comment on the same line with\n'
117 ' // IN-TEST \n'
118 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
119 'method and can be ignored. Do not do this inside production code.\n'
120 'The android-binary-size trybot will block if the method exists in the\n'
121 'release apk.')
[email protected]eea609a2011-11-18 13:10:12122
123
Daniel Chenga44a1bcd2022-03-15 20:00:15124@dataclass
125class BanRule:
Daniel Chenga37c03db2022-05-12 17:20:34126 # String pattern. If the pattern begins with a slash, the pattern will be
127 # treated as a regular expression instead.
128 pattern: str
129 # Explanation as a sequence of strings. Each string in the sequence will be
130 # printed on its own line.
131 explanation: Sequence[str]
132 # Whether or not to treat this ban as a fatal error. If unspecified,
133 # defaults to true.
134 treat_as_error: Optional[bool] = None
135 # Paths that should be excluded from the ban check. Each string is a regular
136 # expression that will be matched against the path of the file being checked
137 # relative to the root of the source tree.
138 excluded_paths: Optional[Sequence[str]] = None
[email protected]cf9b78f2012-11-14 11:40:28139
Daniel Chenga44a1bcd2022-03-15 20:00:15140
Daniel Cheng917ce542022-03-15 20:46:57141_BANNED_JAVA_IMPORTS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15142 BanRule(
143 'import java.net.URI;',
144 (
145 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
146 ),
147 excluded_paths=(
148 (r'net/android/javatests/src/org/chromium/net/'
149 'AndroidProxySelectorTest\.java'),
150 r'components/cronet/',
151 r'third_party/robolectric/local/',
152 ),
Michael Thiessen44457642020-02-06 00:24:15153 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15154 BanRule(
155 'import android.annotation.TargetApi;',
156 (
157 'Do not use TargetApi, use @androidx.annotation.RequiresApi instead. '
158 'RequiresApi ensures that any calls are guarded by the appropriate '
159 'SDK_INT check. See https://crbug.com/1116486.',
160 ),
161 ),
162 BanRule(
Mohamed Heikal3d7a94c2023-03-28 16:55:24163 'import androidx.test.rule.UiThreadTestRule;',
Daniel Chenga44a1bcd2022-03-15 20:00:15164 (
165 'Do not use UiThreadTestRule, just use '
166 '@org.chromium.base.test.UiThreadTest on test methods that should run '
167 'on the UI thread. See https://crbug.com/1111893.',
168 ),
169 ),
170 BanRule(
Mohamed Heikal3d7a94c2023-03-28 16:55:24171 'import androidx.test.annotation.UiThreadTest;',
172 ('Do not use androidx.test.annotation.UiThreadTest, use '
Daniel Chenga44a1bcd2022-03-15 20:00:15173 'org.chromium.base.test.UiThreadTest instead. See '
174 'https://crbug.com/1111893.',
175 ),
176 ),
177 BanRule(
Mohamed Heikal3d7a94c2023-03-28 16:55:24178 'import androidx.test.rule.ActivityTestRule;',
Daniel Chenga44a1bcd2022-03-15 20:00:15179 (
180 'Do not use ActivityTestRule, use '
181 'org.chromium.base.test.BaseActivityTestRule instead.',
182 ),
183 excluded_paths=(
184 'components/cronet/',
185 ),
186 ),
Min Qinbc44383c2023-02-22 17:25:26187 BanRule(
188 'import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;',
189 (
190 'Do not use VectorDrawableCompat, use getResources().getDrawable() to '
191 'avoid extra indirections. Please also add trace event as the call '
192 'might take more than 20 ms to complete.',
193 ),
194 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15195)
wnwenbdc444e2016-05-25 13:44:15196
Daniel Cheng917ce542022-03-15 20:46:57197_BANNED_JAVA_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15198 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41199 'StrictMode.allowThreadDiskReads()',
200 (
201 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
202 'directly.',
203 ),
204 False,
205 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15206 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41207 'StrictMode.allowThreadDiskWrites()',
208 (
209 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
210 'directly.',
211 ),
212 False,
213 ),
Daniel Cheng917ce542022-03-15 20:46:57214 BanRule(
Michael Thiessen0f2547e2020-07-27 21:55:36215 '.waitForIdleSync()',
216 (
217 'Do not use waitForIdleSync as it masks underlying issues. There is '
218 'almost always something else you should wait on instead.',
219 ),
220 False,
221 ),
Ashley Newson09cbd602022-10-26 11:40:14222 BanRule(
Ashley Newsoneb6f5ce2022-10-26 14:45:42223 r'/(?<!\bsuper\.)(?<!\bIntent )\bregisterReceiver\(',
Ashley Newson09cbd602022-10-26 11:40:14224 (
225 'Do not call android.content.Context.registerReceiver (or an override) '
226 'directly. Use one of the wrapper methods defined in '
227 'org.chromium.base.ContextUtils, such as '
228 'registerProtectedBroadcastReceiver, '
229 'registerExportedBroadcastReceiver, or '
230 'registerNonExportedBroadcastReceiver. See their documentation for '
231 'which one to use.',
232 ),
233 True,
234 excluded_paths=(
Ashley Newson22bc26d2022-11-01 20:30:57235 r'.*Test[^a-z]',
236 r'third_party/',
Ashley Newson09cbd602022-10-26 11:40:14237 'base/android/java/src/org/chromium/base/ContextUtils.java',
Brandon Mousseau7e76a9c2022-12-08 22:08:38238 'chromecast/browser/android/apk/src/org/chromium/chromecast/shell/BroadcastReceiverScope.java',
Ashley Newson09cbd602022-10-26 11:40:14239 ),
240 ),
Ted Chocd5b327b12022-11-05 02:13:22241 BanRule(
242 r'/(?:extends|new)\s*(?:android.util.)?Property<[A-Za-z.]+,\s*(?:Integer|Float)>',
243 (
244 'Do not use Property<..., Integer|Float>, but use FloatProperty or '
245 'IntProperty because it will avoid unnecessary autoboxing of '
246 'primitives.',
247 ),
248 ),
Peilin Wangbba4a8652022-11-10 16:33:57249 BanRule(
250 'requestLayout()',
251 (
252 'Layouts can be expensive. Prefer using ViewUtils.requestLayout(), '
253 'which emits a trace event with additional information to help with '
254 'scroll jank investigations. See http://crbug.com/1354176.',
255 ),
256 False,
257 excluded_paths=(
258 'ui/android/java/src/org/chromium/ui/base/ViewUtils.java',
259 ),
260 ),
Ted Chocf40ea9152023-02-14 19:02:39261 BanRule(
262 'Profile.getLastUsedRegularProfile()',
263 (
264 'Prefer passing in the Profile reference instead of relying on the '
265 'static getLastUsedRegularProfile() call. Only top level entry points '
266 '(e.g. Activities) should call this method. Otherwise, the Profile '
267 'should either be passed in explicitly or retreived from an existing '
268 'entity with a reference to the Profile (e.g. WebContents).',
269 ),
270 False,
271 excluded_paths=(
272 r'.*Test[A-Z]?.*\.java',
273 ),
274 ),
Min Qinbc44383c2023-02-22 17:25:26275 BanRule(
276 r'/(ResourcesCompat|getResources\(\))\.getDrawable\(\)',
277 (
278 'getDrawable() can be expensive. If you have a lot of calls to '
279 'GetDrawable() or your code may introduce janks, please put your calls '
280 'inside a trace().',
281 ),
282 False,
283 excluded_paths=(
284 r'.*Test[A-Z]?.*\.java',
285 ),
286 ),
Henrique Nakashimabbf2b262023-03-10 17:21:39287 BanRule(
288 r'/RecordHistogram\.getHistogram(ValueCount|TotalCount|Samples)ForTesting\(',
289 (
290 'Raw histogram counts are easy to misuse; for example they don\'t reset '
Thiago Perrotta099034f2023-06-05 18:10:20291 'between batched tests. Use HistogramWatcher to check histogram records '
292 'instead.',
Henrique Nakashimabbf2b262023-03-10 17:21:39293 ),
294 False,
295 excluded_paths=(
296 'base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java',
297 'base/test/android/javatests/src/org/chromium/base/test/util/HistogramWatcher.java',
298 ),
299 ),
Eric Stevensona9a980972017-09-23 00:04:41300)
301
Clement Yan9b330cb2022-11-17 05:25:29302_BANNED_JAVASCRIPT_FUNCTIONS : Sequence [BanRule] = (
303 BanRule(
304 r'/\bchrome\.send\b',
305 (
306 'The use of chrome.send is disallowed in Chrome (context: https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/security/handling-messages-from-web-content.md).',
307 'Please use mojo instead for new webuis. https://docs.google.com/document/d/1RF-GSUoveYa37eoyZ9EhwMtaIwoW7Z88pIgNZ9YzQi4/edit#heading=h.gkk22wgk6wff',
308 ),
309 True,
310 (
311 r'^(?!ash\/webui).+',
312 # TODO(crbug.com/1385601): pre-existing violations still need to be
313 # cleaned up.
Rebekah Potter57aa94df2022-12-13 20:30:58314 'ash/webui/common/resources/cr.m.js',
Clement Yan9b330cb2022-11-17 05:25:29315 'ash/webui/common/resources/multidevice_setup/multidevice_setup_browser_proxy.js',
Martin Bidlingmaiera921fee72023-06-03 07:52:22316 'ash/webui/common/resources/quick_unlock/lock_screen_constants.ts',
Clement Yan9b330cb2022-11-17 05:25:29317 'ash/webui/common/resources/smb_shares/smb_browser_proxy.js',
318 'ash/webui/connectivity_diagnostics/resources/connectivity_diagnostics.js',
319 'ash/webui/diagnostics_ui/resources/diagnostics_browser_proxy.ts',
320 'ash/webui/multidevice_debug/resources/logs.js',
321 'ash/webui/multidevice_debug/resources/webui.js',
322 'ash/webui/projector_app/resources/annotator/trusted/annotator_browser_proxy.js',
323 'ash/webui/projector_app/resources/app/trusted/projector_browser_proxy.js',
Ashley Prasad71f9024e2023-09-25 22:33:55324 # TODO(b/301634378): Remove violation exception once Scanning App
325 # migrated off usage of `chrome.send`.
326 'ash/webui/scanning/resources/scanning_browser_proxy.ts',
Clement Yan9b330cb2022-11-17 05:25:29327 ),
328 ),
329)
330
Daniel Cheng917ce542022-03-15 20:46:57331_BANNED_OBJC_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15332 BanRule(
[email protected]127f18ec2012-06-16 05:05:59333 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20334 (
335 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59336 'prohibited. Please use CrTrackingArea instead.',
337 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
338 ),
339 False,
340 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15341 BanRule(
[email protected]eaae1972014-04-16 04:17:26342 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20343 (
344 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59345 'instead.',
346 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
347 ),
348 False,
349 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15350 BanRule(
[email protected]127f18ec2012-06-16 05:05:59351 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20352 (
353 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59354 'Please use |convertPoint:(point) fromView:nil| instead.',
355 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
356 ),
357 True,
358 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15359 BanRule(
[email protected]127f18ec2012-06-16 05:05:59360 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20361 (
362 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59363 'Please use |convertPoint:(point) toView:nil| instead.',
364 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
365 ),
366 True,
367 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15368 BanRule(
[email protected]127f18ec2012-06-16 05:05:59369 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20370 (
371 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59372 'Please use |convertRect:(point) fromView:nil| instead.',
373 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
374 ),
375 True,
376 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15377 BanRule(
[email protected]127f18ec2012-06-16 05:05:59378 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20379 (
380 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59381 'Please use |convertRect:(point) toView:nil| instead.',
382 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
383 ),
384 True,
385 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15386 BanRule(
[email protected]127f18ec2012-06-16 05:05:59387 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20388 (
389 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59390 'Please use |convertSize:(point) fromView:nil| instead.',
391 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
392 ),
393 True,
394 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15395 BanRule(
[email protected]127f18ec2012-06-16 05:05:59396 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20397 (
398 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59399 'Please use |convertSize:(point) toView:nil| instead.',
400 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
401 ),
402 True,
403 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15404 BanRule(
jif65398702016-10-27 10:19:48405 r"/\s+UTF8String\s*]",
406 (
407 'The use of -[NSString UTF8String] is dangerous as it can return null',
408 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
409 'Please use |SysNSStringToUTF8| instead.',
410 ),
411 True,
Marijn Kruisselbrink1b7c48952023-08-31 16:58:34412 excluded_paths = (
413 '^third_party/ocmock/OCMock/',
414 ),
jif65398702016-10-27 10:19:48415 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15416 BanRule(
Sylvain Defresne4cf1d182017-09-18 14:16:34417 r'__unsafe_unretained',
418 (
419 'The use of __unsafe_unretained is almost certainly wrong, unless',
420 'when interacting with NSFastEnumeration or NSInvocation.',
421 'Please use __weak in files build with ARC, nothing otherwise.',
422 ),
423 False,
424 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15425 BanRule(
Avi Drissman7382afa02019-04-29 23:27:13426 'freeWhenDone:NO',
427 (
428 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
429 'Foundation types is prohibited.',
430 ),
431 True,
432 ),
Avi Drissman3d243a42023-08-01 16:53:59433 BanRule(
434 'This file requires ARC support.',
435 (
436 'ARC compilation is default in Chromium; do not add boilerplate to ',
437 'files that require ARC.',
438 ),
439 True,
440 ),
[email protected]127f18ec2012-06-16 05:05:59441)
442
Sylvain Defresnea8b73d252018-02-28 15:45:54443_BANNED_IOS_OBJC_FUNCTIONS = (
Daniel Chenga44a1bcd2022-03-15 20:00:15444 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54445 r'/\bTEST[(]',
446 (
447 'TEST() macro should not be used in Objective-C++ code as it does not ',
448 'drain the autorelease pool at the end of the test. Use TEST_F() ',
449 'macro instead with a fixture inheriting from PlatformTest (or a ',
450 'typedef).'
451 ),
452 True,
453 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15454 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54455 r'/\btesting::Test\b',
456 (
457 'testing::Test should not be used in Objective-C++ code as it does ',
458 'not drain the autorelease pool at the end of the test. Use ',
459 'PlatformTest instead.'
460 ),
461 True,
462 ),
Ewann2ecc8d72022-07-18 07:41:23463 BanRule(
464 ' systemImageNamed:',
465 (
466 '+[UIImage systemImageNamed:] should not be used to create symbols.',
467 'Instead use a wrapper defined in:',
Victor Vianna77a40f62023-01-31 19:04:53468 'ios/chrome/browser/ui/icons/symbol_helpers.h'
Ewann2ecc8d72022-07-18 07:41:23469 ),
470 True,
Ewann450a2ef2022-07-19 14:38:23471 excluded_paths=(
Gauthier Ambard4d8756b2023-04-07 17:26:41472 'ios/chrome/browser/shared/ui/symbols/symbol_helpers.mm',
Gauthier Ambardd36c10b12023-03-16 08:45:03473 'ios/chrome/search_widget_extension/',
Ewann450a2ef2022-07-19 14:38:23474 ),
Ewann2ecc8d72022-07-18 07:41:23475 ),
Sylvain Defresnea8b73d252018-02-28 15:45:54476)
477
Daniel Cheng917ce542022-03-15 20:46:57478_BANNED_IOS_EGTEST_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15479 BanRule(
Peter K. Lee6c03ccff2019-07-15 14:40:05480 r'/\bEXPECT_OCMOCK_VERIFY\b',
481 (
482 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
483 'it is meant for GTests. Use [mock verify] instead.'
484 ),
485 True,
486 ),
487)
488
Daniel Cheng917ce542022-03-15 20:46:57489_BANNED_CPP_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15490 BanRule(
Peter Kasting94a56c42019-10-25 21:54:04491 r'/\busing namespace ',
492 (
493 'Using directives ("using namespace x") are banned by the Google Style',
494 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
495 'Explicitly qualify symbols or use using declarations ("using x::foo").',
496 ),
497 True,
498 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
499 ),
Antonio Gomes07300d02019-03-13 20:59:57500 # Make sure that gtest's FRIEND_TEST() macro is not used; the
501 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
502 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
Daniel Chenga44a1bcd2022-03-15 20:00:15503 BanRule(
[email protected]23e6cbc2012-06-16 18:51:20504 'FRIEND_TEST(',
505 (
[email protected]e3c945502012-06-26 20:01:49506 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20507 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
508 ),
509 False,
Arthur Sonzogni19aa4922023-08-28 17:28:59510 excluded_paths = (
511 "base/gtest_prod_util.h",
Arthur Sonzogni0bcc0232023-10-03 08:48:32512 "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/gtest_prod_util.h",
Arthur Sonzogni19aa4922023-08-28 17:28:59513 ),
[email protected]23e6cbc2012-06-16 18:51:20514 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15515 BanRule(
tomhudsone2c14d552016-05-26 17:07:46516 'setMatrixClip',
517 (
518 'Overriding setMatrixClip() is prohibited; ',
519 'the base function is deprecated. ',
520 ),
521 True,
522 (),
523 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15524 BanRule(
[email protected]52657f62013-05-20 05:30:31525 'SkRefPtr',
526 (
527 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22528 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31529 ),
530 True,
531 (),
532 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15533 BanRule(
[email protected]52657f62013-05-20 05:30:31534 'SkAutoRef',
535 (
536 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22537 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31538 ),
539 True,
540 (),
541 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15542 BanRule(
[email protected]52657f62013-05-20 05:30:31543 'SkAutoTUnref',
544 (
545 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22546 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31547 ),
548 True,
549 (),
550 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15551 BanRule(
[email protected]52657f62013-05-20 05:30:31552 'SkAutoUnref',
553 (
554 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
555 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22556 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31557 ),
558 True,
559 (),
560 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15561 BanRule(
[email protected]d89eec82013-12-03 14:10:59562 r'/HANDLE_EINTR\(.*close',
563 (
564 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
565 'descriptor will be closed, and it is incorrect to retry the close.',
566 'Either call close directly and ignore its return value, or wrap close',
567 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
568 ),
569 True,
570 (),
571 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15572 BanRule(
[email protected]d89eec82013-12-03 14:10:59573 r'/IGNORE_EINTR\((?!.*close)',
574 (
575 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
576 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
577 ),
578 True,
579 (
580 # Files that #define IGNORE_EINTR.
Bruce Dawson40fece62022-09-16 19:58:31581 r'^base/posix/eintr_wrapper\.h$',
582 r'^ppapi/tests/test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59583 ),
584 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15585 BanRule(
[email protected]ec5b3f02014-04-04 18:43:43586 r'/v8::Extension\(',
587 (
588 'Do not introduce new v8::Extensions into the code base, use',
589 'gin::Wrappable instead. See http://crbug.com/334679',
590 ),
591 True,
[email protected]f55c90ee62014-04-12 00:50:03592 (
Bruce Dawson40fece62022-09-16 19:58:31593 r'extensions/renderer/safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03594 ),
[email protected]ec5b3f02014-04-04 18:43:43595 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15596 BanRule(
jame2d1a952016-04-02 00:27:10597 '#pragma comment(lib,',
598 (
599 'Specify libraries to link with in build files and not in the source.',
600 ),
601 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41602 (
Bruce Dawson40fece62022-09-16 19:58:31603 r'^base/third_party/symbolize/.*',
604 r'^third_party/abseil-cpp/.*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41605 ),
jame2d1a952016-04-02 00:27:10606 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15607 BanRule(
Gabriel Charette7cc6c432018-04-25 20:52:02608 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59609 (
610 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
611 ),
612 False,
613 (),
614 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15615 BanRule(
Gabriel Charette7cc6c432018-04-25 20:52:02616 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59617 (
618 'Consider using THREAD_CHECKER macros instead of the class directly.',
619 ),
620 False,
621 (),
622 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15623 BanRule(
Sean Maher03efef12022-09-23 22:43:13624 r'/\b(?!(Sequenced|SingleThread))\w*TaskRunner::(GetCurrentDefault|CurrentDefaultHandle)',
625 (
626 'It is not allowed to call these methods from the subclasses ',
627 'of Sequenced or SingleThread task runners.',
628 ),
629 True,
630 (),
631 ),
632 BanRule(
Yuri Wiitala2f8de5c2017-07-21 00:11:06633 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
634 (
635 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
636 'deprecated (http://crbug.com/634507). Please avoid converting away',
637 'from the Time types in Chromium code, especially if any math is',
638 'being done on time values. For interfacing with platform/library',
Peter Kasting8a2605652023-09-14 03:57:15639 'APIs, use base::Time::(From,To)DeltaSinceWindowsEpoch() or',
640 'base::{TimeDelta::In}Microseconds(), or one of the other type',
641 'converter methods instead. For faking TimeXXX values (for unit',
Peter Kasting53fd6ee2021-10-05 20:40:48642 'testing only), use TimeXXX() + Microseconds(N). For',
Yuri Wiitala2f8de5c2017-07-21 00:11:06643 'other use cases, please contact base/time/OWNERS.',
644 ),
645 False,
Arthur Sonzogni19aa4922023-08-28 17:28:59646 excluded_paths = (
647 "base/time/time.h",
Arthur Sonzogni0bcc0232023-10-03 08:48:32648 "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/time/time.h",
Arthur Sonzogni19aa4922023-08-28 17:28:59649 ),
Yuri Wiitala2f8de5c2017-07-21 00:11:06650 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15651 BanRule(
dbeamb6f4fde2017-06-15 04:03:06652 'CallJavascriptFunctionUnsafe',
653 (
654 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
655 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
656 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
657 ),
658 False,
659 (
Bruce Dawson40fece62022-09-16 19:58:31660 r'^content/browser/webui/web_ui_impl\.(cc|h)$',
661 r'^content/public/browser/web_ui\.h$',
662 r'^content/public/test/test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06663 ),
664 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15665 BanRule(
dskiba1474c2bfd62017-07-20 02:19:24666 'leveldb::DB::Open',
667 (
668 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
669 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
670 "Chrome's tracing, making their memory usage visible.",
671 ),
672 True,
673 (
674 r'^third_party/leveldatabase/.*\.(cc|h)$',
675 ),
Gabriel Charette0592c3a2017-07-26 12:02:04676 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15677 BanRule(
Chris Mumfordc38afb62017-10-09 17:55:08678 'leveldb::NewMemEnv',
679 (
680 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58681 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
682 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08683 ),
684 True,
685 (
686 r'^third_party/leveldatabase/.*\.(cc|h)$',
687 ),
688 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15689 BanRule(
Gabriel Charetted9839bc2017-07-29 14:17:47690 'RunLoop::QuitCurrent',
691 (
Robert Liao64b7ab22017-08-04 23:03:43692 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
693 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47694 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41695 False,
Gabriel Charetted9839bc2017-07-29 14:17:47696 (),
Gabriel Charettea44975052017-08-21 23:14:04697 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15698 BanRule(
Gabriel Charettea44975052017-08-21 23:14:04699 'base::ScopedMockTimeMessageLoopTaskRunner',
700 (
Gabriel Charette87cc1af2018-04-25 20:52:51701 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11702 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51703 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
704 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
705 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04706 ),
Gabriel Charette87cc1af2018-04-25 20:52:51707 False,
Gabriel Charettea44975052017-08-21 23:14:04708 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57709 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15710 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44711 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57712 (
713 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02714 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57715 ),
716 True,
Robert Ogden4c43a712023-06-28 22:03:19717 [
718 # Abseil's benchmarks never linked into chrome.
719 'third_party/abseil-cpp/.*_benchmark.cc',
Robert Ogden4c43a712023-06-28 22:03:19720 ],
Francois Doray43670e32017-09-27 12:40:38721 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15722 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:08723 r'/\bstd::sto(i|l|ul|ll|ull)\b',
Peter Kasting991618a62019-06-17 22:00:09724 (
Peter Kastinge2c5ee82023-02-15 17:23:08725 'std::sto{i,l,ul,ll,ull}() use exceptions to communicate results. ',
726 'Use base::StringTo[U]Int[64]() instead.',
Peter Kasting991618a62019-06-17 22:00:09727 ),
728 True,
729 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
730 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15731 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:08732 r'/\bstd::sto(f|d|ld)\b',
Peter Kasting991618a62019-06-17 22:00:09733 (
Peter Kastinge2c5ee82023-02-15 17:23:08734 'std::sto{f,d,ld}() use exceptions to communicate results. ',
Peter Kasting991618a62019-06-17 22:00:09735 'For locale-independent values, e.g. reading numbers from disk',
736 'profiles, use base::StringToDouble().',
737 'For user-visible values, parse using ICU.',
738 ),
739 True,
740 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
741 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15742 BanRule(
Daniel Bratell69334cc2019-03-26 11:07:45743 r'/\bstd::to_string\b',
744 (
Peter Kastinge2c5ee82023-02-15 17:23:08745 'std::to_string() is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09746 'For locale-independent strings, e.g. writing numbers to disk',
747 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45748 'For user-visible strings, use base::FormatNumber() and',
749 'the related functions in base/i18n/number_formatting.h.',
750 ),
Peter Kasting991618a62019-06-17 22:00:09751 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21752 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45753 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15754 BanRule(
Peter Kasting6f79b202023-08-09 21:25:41755 r'/#include <(cctype|ctype\.h|cwctype|wctype.h)>',
756 (
757 '<cctype>/<ctype.h>/<cwctype>/<wctype.h> are banned. Use',
758 '"third_party/abseil-cpp/absl/strings/ascii.h" instead.',
759 ),
760 True,
761 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
762 ),
763 BanRule(
Daniel Bratell69334cc2019-03-26 11:07:45764 r'/\bstd::shared_ptr\b',
765 (
Peter Kastinge2c5ee82023-02-15 17:23:08766 'std::shared_ptr is banned. Use scoped_refptr instead.',
Daniel Bratell69334cc2019-03-26 11:07:45767 ),
768 True,
Ulan Degenbaev947043882021-02-10 14:02:31769 [
770 # Needed for interop with third-party library.
771 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
Alex Chau9eb03cdd52020-07-13 21:04:57772 'array_buffer_contents\.(cc|h)',
Ben Kelly39bf6bef2021-10-04 22:54:58773 '^third_party/blink/renderer/bindings/core/v8/' +
774 'v8_wasm_response_extensions.cc',
Wez5f56be52021-05-04 09:30:58775 '^gin/array_buffer\.(cc|h)',
Jiahe Zhange97ba772023-07-27 02:46:41776 '^gin/per_isolate_data\.(cc|h)',
Wez5f56be52021-05-04 09:30:58777 '^chrome/services/sharing/nearby/',
Stephen Nuskoe09c8ef22022-09-29 00:47:28778 # Needed for interop with third-party library libunwindstack.
Stephen Nuskoe51c1382022-09-26 15:49:03779 '^base/profiler/libunwindstack_unwinder_android\.(cc|h)',
Thiabaud Engelbrecht42e09812023-08-29 21:19:30780 '^base/profiler/native_unwinder_android_memory_regions_map_impl.(cc|h)',
Bob Beck03509d282022-12-07 21:49:05781 # Needed for interop with third-party boringssl cert verifier
782 '^third_party/boringssl/',
783 '^net/cert/',
784 '^net/tools/cert_verify_tool/',
785 '^services/cert_verifier/',
786 '^components/certificate_transparency/',
787 '^components/media_router/common/providers/cast/certificate/',
Meilin Wang00efc7c2021-05-13 01:12:42788 # gRPC provides some C++ libraries that use std::shared_ptr<>.
Yeunjoo Choi1b644402022-08-25 02:36:10789 '^chromeos/ash/services/libassistant/grpc/',
Vigen Issahhanjanfdf9de52021-12-22 21:13:59790 '^chromecast/cast_core/grpc',
791 '^chromecast/cast_core/runtime/browser',
Yue Shef83d95202022-09-26 20:23:45792 '^ios/chrome/test/earl_grey/chrome_egtest_plugin_client\.(mm|h)',
Wez5f56be52021-05-04 09:30:58793 # Fuchsia provides C++ libraries that use std::shared_ptr<>.
Wez6da2e412022-11-23 11:28:48794 '^base/fuchsia/.*\.(cc|h)',
Wez5f56be52021-05-04 09:30:58795 '.*fuchsia.*test\.(cc|h)',
miktb599ed12023-05-26 07:03:56796 # Clang plugins have different build config.
797 '^tools/clang/plugins/',
Alex Chau9eb03cdd52020-07-13 21:04:57798 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21799 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15800 BanRule(
Peter Kasting991618a62019-06-17 22:00:09801 r'/\bstd::weak_ptr\b',
802 (
Peter Kastinge2c5ee82023-02-15 17:23:08803 'std::weak_ptr is banned. Use base::WeakPtr instead.',
Peter Kasting991618a62019-06-17 22:00:09804 ),
805 True,
806 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
807 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15808 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21809 r'/\blong long\b',
810 (
Peter Kastinge2c5ee82023-02-15 17:23:08811 'long long is banned. Use [u]int64_t instead.',
Daniel Bratell609102be2019-03-27 20:53:21812 ),
813 False, # Only a warning since it is already used.
814 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
815 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15816 BanRule(
Daniel Cheng192683f2022-11-01 20:52:44817 r'/\b(absl|std)::any\b',
Daniel Chengc05fcc62022-01-12 16:54:29818 (
Peter Kastinge2c5ee82023-02-15 17:23:08819 '{absl,std}::any are banned due to incompatibility with the component ',
820 'build.',
Daniel Chengc05fcc62022-01-12 16:54:29821 ),
822 True,
823 # Not an error in third party folders, though it probably should be :)
824 [_THIRD_PARTY_EXCEPT_BLINK],
825 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15826 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21827 r'/\bstd::bind\b',
828 (
Peter Kastinge2c5ee82023-02-15 17:23:08829 'std::bind() is banned because of lifetime risks. Use ',
830 'base::Bind{Once,Repeating}() instead.',
Daniel Bratell609102be2019-03-27 20:53:21831 ),
832 True,
833 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
834 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15835 BanRule(
Daniel Cheng192683f2022-11-01 20:52:44836 (
Peter Kastingc7460d982023-03-14 21:01:42837 r'/\bstd::(?:'
838 r'linear_congruential_engine|mersenne_twister_engine|'
839 r'subtract_with_carry_engine|discard_block_engine|'
840 r'independent_bits_engine|shuffle_order_engine|'
841 r'minstd_rand0?|mt19937(_64)?|ranlux(24|48)(_base)?|knuth_b|'
842 r'default_random_engine|'
843 r'random_device|'
844 r'seed_seq'
Daniel Cheng192683f2022-11-01 20:52:44845 r')\b'
846 ),
847 (
848 'STL random number engines and generators are banned. Use the ',
849 'helpers in base/rand_util.h instead, e.g. base::RandBytes() or ',
850 'base::RandomBitGenerator.'
851 ),
852 True,
853 [
854 # Not an error in third_party folders.
855 _THIRD_PARTY_EXCEPT_BLINK,
856 # Various tools which build outside of Chrome.
857 r'testing/libfuzzer',
858 r'tools/android/io_benchmark/',
859 # Fuzzers are allowed to use standard library random number generators
860 # since fuzzing speed + reproducibility is important.
861 r'tools/ipc_fuzzer/',
862 r'.+_fuzzer\.cc$',
863 r'.+_fuzzertest\.cc$',
864 # TODO(https://crbug.com/1380528): These are all unsanctioned uses of
865 # the standard library's random number generators, and should be
866 # migrated to the //base equivalent.
867 r'ash/ambient/model/ambient_topic_queue\.cc',
Arthur Sonzogni0bcc0232023-10-03 08:48:32868 r'base/allocator/partition_allocator/src/partition_alloc/partition_alloc_unittest\.cc',
Daniel Cheng192683f2022-11-01 20:52:44869 r'base/ranges/algorithm_unittest\.cc',
870 r'base/test/launcher/test_launcher\.cc',
871 r'cc/metrics/video_playback_roughness_reporter_unittest\.cc',
872 r'chrome/browser/apps/app_service/metrics/website_metrics\.cc',
873 r'chrome/browser/ash/power/auto_screen_brightness/monotone_cubic_spline_unittest\.cc',
874 r'chrome/browser/ash/printing/zeroconf_printer_detector_unittest\.cc',
875 r'chrome/browser/nearby_sharing/contacts/nearby_share_contact_manager_impl_unittest\.cc',
876 r'chrome/browser/nearby_sharing/contacts/nearby_share_contacts_sorter_unittest\.cc',
877 r'chrome/browser/privacy_budget/mesa_distribution_unittest\.cc',
878 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
879 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
880 r'chrome/browser/win/conflicts/module_blocklist_cache_util_unittest\.cc',
881 r'chrome/chrome_cleaner/logging/detailed_info_sampler\.cc',
882 r'chromeos/ash/components/memory/userspace_swap/swap_storage_unittest\.cc',
883 r'chromeos/ash/components/memory/userspace_swap/userspace_swap\.cc',
884 r'components/metrics/metrics_state_manager\.cc',
885 r'components/omnibox/browser/history_quick_provider_performance_unittest\.cc',
886 r'components/zucchini/disassembler_elf_unittest\.cc',
887 r'content/browser/webid/federated_auth_request_impl\.cc',
888 r'content/browser/webid/federated_auth_request_impl\.cc',
889 r'media/cast/test/utility/udp_proxy\.h',
890 r'sql/recover_module/module_unittest\.cc',
891 ],
892 ),
893 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:08894 r'/\b(absl,std)::bind_front\b',
Peter Kasting4f35bfc2022-10-18 18:39:12895 (
Peter Kastinge2c5ee82023-02-15 17:23:08896 '{absl,std}::bind_front() are banned. Use base::Bind{Once,Repeating}() '
897 'instead.',
Peter Kasting4f35bfc2022-10-18 18:39:12898 ),
899 True,
900 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
901 ),
902 BanRule(
903 r'/\bABSL_FLAG\b',
904 (
905 'ABSL_FLAG is banned. Use base::CommandLine instead.',
906 ),
907 True,
908 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
909 ),
910 BanRule(
911 r'/\babsl::c_',
912 (
Peter Kastinge2c5ee82023-02-15 17:23:08913 'Abseil container utilities are banned. Use base/ranges/algorithm.h ',
Peter Kasting4f35bfc2022-10-18 18:39:12914 'instead.',
915 ),
916 True,
917 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
918 ),
919 BanRule(
Peter Kasting431239a2023-09-29 03:11:44920 r'/\babsl::FixedArray\b',
921 (
922 'absl::FixedArray is banned. Use base::FixedArray instead.',
923 ),
924 True,
925 [
926 # base::FixedArray provides canonical access.
927 r'^base/types/fixed_array.h',
928 # Not an error in third_party folders.
929 _THIRD_PARTY_EXCEPT_BLINK,
930 ],
931 ),
932 BanRule(
Peter Kasting4f35bfc2022-10-18 18:39:12933 r'/\babsl::FunctionRef\b',
934 (
935 'absl::FunctionRef is banned. Use base::FunctionRef instead.',
936 ),
937 True,
938 [
939 # base::Bind{Once,Repeating} references absl::FunctionRef to disallow
940 # interoperability.
941 r'^base/functional/bind_internal\.h',
942 # base::FunctionRef is implemented on top of absl::FunctionRef.
943 r'^base/functional/function_ref.*\..+',
944 # Not an error in third_party folders.
945 _THIRD_PARTY_EXCEPT_BLINK,
946 ],
947 ),
948 BanRule(
949 r'/\babsl::(Insecure)?BitGen\b',
950 (
Daniel Cheng192683f2022-11-01 20:52:44951 'absl random number generators are banned. Use the helpers in '
952 'base/rand_util.h instead, e.g. base::RandBytes() or ',
953 'base::RandomBitGenerator.'
Peter Kasting4f35bfc2022-10-18 18:39:12954 ),
955 True,
956 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
957 ),
958 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:08959 r'/(\babsl::Span\b|#include <span>)',
Peter Kasting4f35bfc2022-10-18 18:39:12960 (
Peter Kastinge2c5ee82023-02-15 17:23:08961 'absl::Span is banned and <span> is not allowed yet ',
962 '(https://crbug.com/1414652). Use base::span instead.',
Peter Kasting4f35bfc2022-10-18 18:39:12963 ),
964 True,
Victor Vasiliev23b9ea6a2023-01-05 19:42:29965 [
966 # Needed to use QUICHE API.
967 r'services/network/web_transport\.cc',
Brianna Goldstein846d8002023-05-16 19:24:30968 r'chrome/browser/ip_protection/.*',
Victor Vasiliev23b9ea6a2023-01-05 19:42:29969 # Not an error in third_party folders.
970 _THIRD_PARTY_EXCEPT_BLINK
971 ],
Peter Kasting4f35bfc2022-10-18 18:39:12972 ),
973 BanRule(
974 r'/\babsl::StatusOr\b',
975 (
976 'absl::StatusOr is banned. Use base::expected instead.',
977 ),
978 True,
Adithya Srinivasanb2041882022-10-21 19:34:20979 [
980 # Needed to use liburlpattern API.
981 r'third_party/blink/renderer/core/url_pattern/.*',
Louise Brettc6d23872023-04-11 02:48:32982 r'third_party/blink/renderer/modules/manifest/manifest_parser\.cc',
Brianna Goldstein846d8002023-05-16 19:24:30983 # Needed to use QUICHE API.
984 r'chrome/browser/ip_protection/.*',
Adithya Srinivasanb2041882022-10-21 19:34:20985 # Not an error in third_party folders.
986 _THIRD_PARTY_EXCEPT_BLINK
987 ],
Peter Kasting4f35bfc2022-10-18 18:39:12988 ),
989 BanRule(
990 r'/\babsl::StrFormat\b',
991 (
Peter Kastinge2c5ee82023-02-15 17:23:08992 'absl::StrFormat() is not allowed yet (https://crbug.com/1371963). ',
993 'Use base::StringPrintf() instead.',
Peter Kasting4f35bfc2022-10-18 18:39:12994 ),
995 True,
996 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
997 ),
998 BanRule(
Peter Kasting4f35bfc2022-10-18 18:39:12999 r'/\babsl::(StrSplit|StrJoin|StrCat|StrAppend|Substitute|StrContains)\b',
1000 (
1001 'Abseil string utilities are banned. Use base/strings instead.',
1002 ),
1003 True,
1004 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1005 ),
1006 BanRule(
1007 r'/\babsl::(Mutex|CondVar|Notification|Barrier|BlockingCounter)\b',
1008 (
1009 'Abseil synchronization primitives are banned. Use',
1010 'base/synchronization instead.',
1011 ),
1012 True,
1013 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1014 ),
1015 BanRule(
1016 r'/\babsl::(Duration|Time|TimeZone|CivilDay)\b',
1017 (
1018 'Abseil\'s time library is banned. Use base/time instead.',
1019 ),
1020 True,
Dustin J. Mitchell626a6d322023-06-26 15:02:481021 [
1022 # Needed to use QUICHE API.
1023 r'chrome/browser/ip_protection/.*',
Victor Vasilieva8638882023-09-25 16:41:041024 r'services/network/web_transport.*',
Dustin J. Mitchell626a6d322023-06-26 15:02:481025 _THIRD_PARTY_EXCEPT_BLINK # Not an error in third_party folders.
1026 ],
Peter Kasting4f35bfc2022-10-18 18:39:121027 ),
1028 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081029 r'/#include <chrono>',
Daniel Bratell609102be2019-03-27 20:53:211030 (
Peter Kastinge2c5ee82023-02-15 17:23:081031 '<chrono> is banned. Use base/time instead.',
Daniel Bratell609102be2019-03-27 20:53:211032 ),
1033 True,
Arthur Sonzogni2ee5e382023-09-11 09:13:031034 [
1035 # Not an error in third_party folders:
1036 _THIRD_PARTY_EXCEPT_BLINK,
1037 # PartitionAlloc's starscan, doesn't depend on base/. It can't use
1038 # base::ConditionalVariable::TimedWait(..).
Arthur Sonzogni0bcc0232023-10-03 08:48:321039 "base/allocator/partition_allocator/src/partition_alloc/starscan/pcscan_internal.cc",
Arthur Sonzogni2ee5e382023-09-11 09:13:031040 ]
Daniel Bratell609102be2019-03-27 20:53:211041 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151042 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081043 r'/#include <exception>',
Daniel Bratell609102be2019-03-27 20:53:211044 (
1045 'Exceptions are banned and disabled in Chromium.',
1046 ),
1047 True,
1048 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1049 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151050 BanRule(
Daniel Bratell609102be2019-03-27 20:53:211051 r'/\bstd::function\b',
1052 (
Peter Kastinge2c5ee82023-02-15 17:23:081053 'std::function is banned. Use base::{Once,Repeating}Callback instead.',
Daniel Bratell609102be2019-03-27 20:53:211054 ),
Daniel Chenge5583e3c2022-09-22 00:19:411055 True,
Daniel Chengcd23b8b2022-09-16 17:16:241056 [
1057 # Has tests that template trait helpers don't unintentionally match
1058 # std::function.
Daniel Chenge5583e3c2022-09-22 00:19:411059 r'base/functional/callback_helpers_unittest\.cc',
1060 # Required to implement interfaces from the third-party perfetto
1061 # library.
1062 r'base/tracing/perfetto_task_runner\.cc',
1063 r'base/tracing/perfetto_task_runner\.h',
1064 # Needed for interop with the third-party nearby library type
1065 # location::nearby::connections::ResultCallback.
1066 'chrome/services/sharing/nearby/nearby_connections_conversions\.cc'
1067 # Needed for interop with the internal libassistant library.
1068 'chromeos/ash/services/libassistant/callback_utils\.h',
1069 # Needed for interop with Fuchsia fidl APIs.
1070 'fuchsia_web/webengine/browser/context_impl_browsertest\.cc',
1071 'fuchsia_web/webengine/browser/cookie_manager_impl_unittest\.cc',
1072 'fuchsia_web/webengine/browser/media_player_impl_unittest\.cc',
1073 # Required to interop with interfaces from the third-party perfetto
1074 # library.
1075 'services/tracing/public/cpp/perfetto/custom_event_recorder\.cc',
1076 'services/tracing/public/cpp/perfetto/perfetto_traced_process\.cc',
1077 'services/tracing/public/cpp/perfetto/perfetto_traced_process\.h',
1078 'services/tracing/public/cpp/perfetto/perfetto_tracing_backend\.cc',
1079 'services/tracing/public/cpp/perfetto/producer_client\.cc',
1080 'services/tracing/public/cpp/perfetto/producer_client\.h',
1081 'services/tracing/public/cpp/perfetto/producer_test_utils\.cc',
1082 'services/tracing/public/cpp/perfetto/producer_test_utils\.h',
1083 # Required for interop with the third-party webrtc library.
1084 'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.cc',
1085 'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.h',
Bob Beck5fc0be82022-12-12 23:32:521086 # This code is in the process of being extracted into a third-party library.
1087 # See https://crbug.com/1322914
1088 '^net/cert/pki/path_builder_unittest\.cc',
Daniel Chenge5583e3c2022-09-22 00:19:411089 # TODO(https://crbug.com/1364577): Various uses that should be
1090 # migrated to something else.
1091 # Should use base::OnceCallback or base::RepeatingCallback.
1092 'base/allocator/dispatcher/initializer_unittest\.cc',
1093 'chrome/browser/ash/accessibility/speech_monitor\.cc',
1094 'chrome/browser/ash/accessibility/speech_monitor\.h',
1095 'chrome/browser/ash/login/ash_hud_login_browsertest\.cc',
1096 'chromecast/base/observer_unittest\.cc',
1097 'chromecast/browser/cast_web_view\.h',
1098 'chromecast/public/cast_media_shlib\.h',
1099 'device/bluetooth/floss/exported_callback_manager\.h',
1100 'device/bluetooth/floss/floss_dbus_client\.h',
1101 'device/fido/cable/v2_handshake_unittest\.cc',
1102 'device/fido/pin\.cc',
1103 'services/tracing/perfetto/test_utils\.h',
1104 # Should use base::FunctionRef.
1105 'chrome/browser/media/webrtc/test_stats_dictionary\.cc',
1106 'chrome/browser/media/webrtc/test_stats_dictionary\.h',
1107 'chromeos/ash/services/libassistant/device_settings_controller\.cc',
1108 'components/browser_ui/client_certificate/android/ssl_client_certificate_request\.cc',
1109 'components/gwp_asan/client/sampling_malloc_shims_unittest\.cc',
1110 'content/browser/font_unique_name_lookup/font_unique_name_lookup_unittest\.cc',
1111 # Does not need std::function at all.
1112 'components/omnibox/browser/autocomplete_result\.cc',
1113 'device/fido/win/webauthn_api\.cc',
1114 'media/audio/alsa/alsa_util\.cc',
1115 'media/remoting/stream_provider\.h',
1116 'sql/vfs_wrapper\.cc',
1117 # TODO(https://crbug.com/1364585): Remove usage and exception list
1118 # entries.
1119 'extensions/renderer/api/automation/automation_internal_custom_bindings\.cc',
1120 'extensions/renderer/api/automation/automation_internal_custom_bindings\.h',
1121 # TODO(https://crbug.com/1364579): Remove usage and exception list
1122 # entry.
1123 'ui/views/controls/focus_ring\.h',
1124
1125 # Various pre-existing uses in //tools that is low-priority to fix.
1126 'tools/binary_size/libsupersize/viewer/caspian/diff\.cc',
1127 'tools/binary_size/libsupersize/viewer/caspian/model\.cc',
1128 'tools/binary_size/libsupersize/viewer/caspian/model\.h',
1129 'tools/binary_size/libsupersize/viewer/caspian/tree_builder\.h',
1130 'tools/clang/base_bind_rewriters/BaseBindRewriters\.cpp',
1131
Daniel Chengcd23b8b2022-09-16 17:16:241132 # Not an error in third_party folders.
1133 _THIRD_PARTY_EXCEPT_BLINK
1134 ],
Daniel Bratell609102be2019-03-27 20:53:211135 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151136 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081137 r'/#include <X11/',
Tom Andersona95e12042020-09-09 23:08:001138 (
1139 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
1140 ),
1141 True,
1142 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1143 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151144 BanRule(
Daniel Bratell609102be2019-03-27 20:53:211145 r'/\bstd::ratio\b',
1146 (
1147 'std::ratio is banned by the Google Style Guide.',
1148 ),
1149 True,
1150 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:451151 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151152 BanRule(
Peter Kasting6d77e9d2023-02-09 21:58:181153 r'/\bstd::aligned_alloc\b',
1154 (
Peter Kastinge2c5ee82023-02-15 17:23:081155 'std::aligned_alloc() is not yet allowed (crbug.com/1412818). Use ',
1156 'base::AlignedAlloc() instead.',
Peter Kasting6d77e9d2023-02-09 21:58:181157 ),
1158 True,
1159 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1160 ),
1161 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081162 r'/#include <(barrier|latch|semaphore|stop_token)>',
Peter Kasting6d77e9d2023-02-09 21:58:181163 (
Peter Kastinge2c5ee82023-02-15 17:23:081164 'The thread support library is banned. Use base/synchronization '
1165 'instead.',
Peter Kasting6d77e9d2023-02-09 21:58:181166 ),
1167 True,
1168 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1169 ),
1170 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081171 r'/\bstd::(c8rtomb|mbrtoc8)\b',
Peter Kasting6d77e9d2023-02-09 21:58:181172 (
Peter Kastinge2c5ee82023-02-15 17:23:081173 'std::c8rtomb() and std::mbrtoc8() are banned.',
Peter Kasting6d77e9d2023-02-09 21:58:181174 ),
1175 True,
1176 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1177 ),
1178 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081179 r'/\bchar8_t|std::u8string\b',
Peter Kasting6d77e9d2023-02-09 21:58:181180 (
Peter Kastinge2c5ee82023-02-15 17:23:081181 'char8_t and std::u8string are not yet allowed. Can you use [unsigned]',
1182 ' char and std::string instead?',
1183 ),
1184 True,
Daniel Cheng893c563f2023-04-21 09:54:521185 [
1186 # The demangler does not use this type but needs to know about it.
1187 'base/third_party/symbolize/demangle\.cc',
1188 # Don't warn in third_party folders.
1189 _THIRD_PARTY_EXCEPT_BLINK
1190 ],
Peter Kastinge2c5ee82023-02-15 17:23:081191 ),
1192 BanRule(
1193 r'/(\b(co_await|co_return|co_yield)\b|#include <coroutine>)',
1194 (
1195 'Coroutines are not yet allowed (https://crbug.com/1403840).',
1196 ),
1197 True,
1198 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1199 ),
1200 BanRule(
Peter Kastingcc152522023-03-22 20:17:371201 r'/^\s*(export\s|import\s+["<:\w]|module(;|\s+[:\w]))',
Peter Kasting69357dc2023-03-14 01:34:291202 (
1203 'Modules are disallowed for now due to lack of toolchain support.',
1204 ),
1205 True,
1206 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1207 ),
1208 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081209 r'/\[\[(un)?likely\]\]',
1210 (
1211 '[[likely]] and [[unlikely]] are not yet allowed ',
1212 '(https://crbug.com/1414620). Use [UN]LIKELY instead.',
1213 ),
1214 True,
1215 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1216 ),
1217 BanRule(
1218 r'/#include <format>',
1219 (
1220 '<format> is not yet allowed. Use base::StringPrintf() instead.',
1221 ),
1222 True,
1223 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1224 ),
1225 BanRule(
1226 r'/#include <ranges>',
1227 (
1228 '<ranges> is not yet allowed. Use base/ranges/algorithm.h instead.',
1229 ),
1230 True,
1231 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1232 ),
1233 BanRule(
1234 r'/#include <source_location>',
1235 (
1236 '<source_location> is not yet allowed. Use base/location.h instead.',
1237 ),
1238 True,
1239 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1240 ),
1241 BanRule(
1242 r'/#include <syncstream>',
1243 (
1244 '<syncstream> is banned.',
Peter Kasting6d77e9d2023-02-09 21:58:181245 ),
1246 True,
1247 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1248 ),
1249 BanRule(
Michael Giuffrida7f93d6922019-04-19 14:39:581250 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:191251 (
1252 'RunMessageLoop is deprecated, use RunLoop instead.',
1253 ),
1254 False,
1255 (),
1256 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151257 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441258 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:191259 (
1260 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
1261 "if you're convinced you need this.",
1262 ),
1263 False,
1264 (),
1265 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151266 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441267 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:191268 (
1269 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:041270 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:191271 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
1272 'async events instead of flushing threads.',
1273 ),
1274 False,
1275 (),
1276 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151277 BanRule(
Gabriel Charette147335ea2018-03-22 15:59:191278 r'MessageLoopRunner',
1279 (
1280 'MessageLoopRunner is deprecated, use RunLoop instead.',
1281 ),
1282 False,
1283 (),
1284 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151285 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441286 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:191287 (
1288 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
1289 "gab@ if you found a use case where this is the only solution.",
1290 ),
1291 False,
1292 (),
1293 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151294 BanRule(
Victor Costane48a2e82019-03-15 22:02:341295 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:161296 (
Victor Costane48a2e82019-03-15 22:02:341297 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:161298 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
1299 ),
1300 True,
1301 (
1302 r'^sql/initialization\.(cc|h)$',
1303 r'^third_party/sqlite/.*\.(c|cc|h)$',
1304 ),
1305 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151306 BanRule(
Austin Sullivand661ab52022-11-16 08:55:151307 'CREATE VIEW',
1308 (
1309 'SQL views are disabled in Chromium feature code',
1310 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-views',
1311 ),
1312 True,
1313 (
1314 _THIRD_PARTY_EXCEPT_BLINK,
1315 # sql/ itself uses views when using memory-mapped IO.
1316 r'^sql/.*',
1317 # Various performance tools that do not build as part of Chrome.
1318 r'^infra/.*',
1319 r'^tools/perf.*',
1320 r'.*perfetto.*',
1321 ),
1322 ),
1323 BanRule(
1324 'CREATE VIRTUAL TABLE',
1325 (
1326 'SQL virtual tables are disabled in Chromium feature code',
1327 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-virtual-tables',
1328 ),
1329 True,
1330 (
1331 _THIRD_PARTY_EXCEPT_BLINK,
1332 # sql/ itself uses virtual tables in the recovery module and tests.
1333 r'^sql/.*',
1334 # TODO(https://crbug.com/695592): Remove once WebSQL is deprecated.
1335 r'third_party/blink/web_tests/storage/websql/.*'
1336 # Various performance tools that do not build as part of Chrome.
1337 r'^tools/perf.*',
1338 r'.*perfetto.*',
1339 ),
1340 ),
1341 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441342 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:471343 (
1344 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
1345 'base::RandomShuffle instead.'
1346 ),
1347 True,
1348 (),
1349 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151350 BanRule(
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:241351 'ios/web/public/test/http_server',
1352 (
1353 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
1354 ),
1355 False,
1356 (),
1357 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151358 BanRule(
Robert Liao764c9492019-01-24 18:46:281359 'GetAddressOf',
1360 (
1361 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:531362 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:111363 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:531364 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:281365 ),
1366 True,
1367 (),
1368 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151369 BanRule(
Ben Lewisa9514602019-04-29 17:53:051370 'SHFileOperation',
1371 (
1372 'SHFileOperation was deprecated in Windows Vista, and there are less ',
1373 'complex functions to achieve the same goals. Use IFileOperation for ',
1374 'any esoteric actions instead.'
1375 ),
1376 True,
1377 (),
1378 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151379 BanRule(
Cliff Smolinsky81951642019-04-30 21:39:511380 'StringFromGUID2',
1381 (
1382 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241383 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511384 ),
1385 True,
1386 (
Daniel Chenga44a1bcd2022-03-15 20:00:151387 r'/base/win/win_util_unittest.cc',
Cliff Smolinsky81951642019-04-30 21:39:511388 ),
1389 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151390 BanRule(
Cliff Smolinsky81951642019-04-30 21:39:511391 'StringFromCLSID',
1392 (
1393 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241394 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511395 ),
1396 True,
1397 (
Daniel Chenga44a1bcd2022-03-15 20:00:151398 r'/base/win/win_util_unittest.cc',
Cliff Smolinsky81951642019-04-30 21:39:511399 ),
1400 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151401 BanRule(
Avi Drissman7382afa02019-04-29 23:27:131402 'kCFAllocatorNull',
1403 (
1404 'The use of kCFAllocatorNull with the NoCopy creation of ',
1405 'CoreFoundation types is prohibited.',
1406 ),
1407 True,
1408 (),
1409 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151410 BanRule(
Oksana Zhuravlovafd247772019-05-16 16:57:291411 'mojo::ConvertTo',
1412 (
1413 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1414 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1415 'StringTraits if you would like to convert between custom types and',
1416 'the wire format of mojom types.'
1417 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221418 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291419 (
David Dorwin13dc48b2022-06-03 21:18:421420 r'^fuchsia_web/webengine/browser/url_request_rewrite_rules_manager\.cc$',
1421 r'^fuchsia_web/webengine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291422 r'^third_party/blink/.*\.(cc|h)$',
1423 r'^content/renderer/.*\.(cc|h)$',
1424 ),
1425 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151426 BanRule(
Oksana Zhuravlovac8222d22019-12-19 19:21:161427 'GetInterfaceProvider',
1428 (
1429 'InterfaceProvider is deprecated.',
1430 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1431 'or Platform::GetBrowserInterfaceBroker.'
1432 ),
1433 False,
1434 (),
1435 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151436 BanRule(
Robert Liao1d78df52019-11-11 20:02:011437 'CComPtr',
1438 (
1439 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1440 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1441 'details.'
1442 ),
1443 False,
1444 (),
1445 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151446 BanRule(
Xiaohan Wang72bd2ba2020-02-18 21:38:201447 r'/\b(IFACE|STD)METHOD_?\(',
1448 (
1449 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1450 'Instead, always use IFACEMETHODIMP in the declaration.'
1451 ),
1452 False,
1453 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1454 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151455 BanRule(
Allen Bauer53b43fb12020-03-12 17:21:471456 'set_owned_by_client',
1457 (
1458 'set_owned_by_client is deprecated.',
1459 'views::View already owns the child views by default. This introduces ',
1460 'a competing ownership model which makes the code difficult to reason ',
1461 'about. See http://crbug.com/1044687 for more details.'
1462 ),
1463 False,
1464 (),
1465 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151466 BanRule(
Peter Boström7ff41522021-07-29 03:43:271467 'RemoveAllChildViewsWithoutDeleting',
1468 (
1469 'RemoveAllChildViewsWithoutDeleting is deprecated.',
1470 'This method is deemed dangerous as, unless raw pointers are re-added,',
1471 'calls to this method introduce memory leaks.'
1472 ),
1473 False,
1474 (),
1475 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151476 BanRule(
Eric Secklerbe6f48d2020-05-06 18:09:121477 r'/\bTRACE_EVENT_ASYNC_',
1478 (
1479 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1480 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1481 ),
1482 False,
1483 (
1484 r'^base/trace_event/.*',
1485 r'^base/tracing/.*',
1486 ),
1487 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151488 BanRule(
Aditya Kushwah5a286b72022-02-10 04:54:431489 r'/\bbase::debug::DumpWithoutCrashingUnthrottled[(][)]',
1490 (
1491 'base::debug::DumpWithoutCrashingUnthrottled() does not throttle',
1492 'dumps and may spam crash reports. Consider if the throttled',
1493 'variants suffice instead.',
1494 ),
1495 False,
1496 (),
1497 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151498 BanRule(
Robert Liao22f66a52021-04-10 00:57:521499 'RoInitialize',
1500 (
Robert Liao48018922021-04-16 23:03:021501 'Improper use of [base::win]::RoInitialize() has been implicated in a ',
Robert Liao22f66a52021-04-10 00:57:521502 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
1503 'instead. See http://crbug.com/1197722 for more information.'
1504 ),
1505 True,
Robert Liao48018922021-04-16 23:03:021506 (
Bruce Dawson40fece62022-09-16 19:58:311507 r'^base/win/scoped_winrt_initializer\.cc$',
Danil Chapovalov07694382023-05-24 17:55:211508 r'^third_party/abseil-cpp/absl/.*',
Robert Liao48018922021-04-16 23:03:021509 ),
Robert Liao22f66a52021-04-10 00:57:521510 ),
Patrick Monettec343bb982022-06-01 17:18:451511 BanRule(
1512 r'base::Watchdog',
1513 (
1514 'base::Watchdog is deprecated because it creates its own thread.',
1515 'Instead, manually start a timer on a SequencedTaskRunner.',
1516 ),
1517 False,
1518 (),
1519 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091520 BanRule(
1521 'base::Passed',
1522 (
1523 'Do not use base::Passed. It is a legacy helper for capturing ',
1524 'move-only types with base::BindRepeating, but invoking the ',
1525 'resulting RepeatingCallback moves the captured value out of ',
1526 'the callback storage, and subsequent invocations may pass the ',
1527 'value in a valid but undefined state. Prefer base::BindOnce().',
1528 'See http://crbug.com/1326449 for context.'
1529 ),
1530 False,
Daniel Cheng91f6fbaf2022-09-16 12:07:481531 (
1532 # False positive, but it is also fine to let bind internals reference
1533 # base::Passed.
Daniel Chengcd23b8b2022-09-16 17:16:241534 r'^base[\\/]functional[\\/]bind\.h',
Daniel Cheng91f6fbaf2022-09-16 12:07:481535 r'^base[\\/]functional[\\/]bind_internal\.h',
1536 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091537 ),
Daniel Cheng2248b332022-07-27 06:16:591538 BanRule(
Daniel Chengba3bc2e2022-10-03 02:45:431539 r'base::Feature k',
1540 (
1541 'Please use BASE_DECLARE_FEATURE() or BASE_FEATURE() instead of ',
1542 'directly declaring/defining features.'
1543 ),
1544 True,
1545 [
1546 _THIRD_PARTY_EXCEPT_BLINK,
1547 ],
1548 ),
Robert Ogden92101dcb2022-10-19 23:49:361549 BanRule(
Arthur Sonzogni1da65fa2023-03-27 16:01:521550 r'/\bchartorune\b',
Robert Ogden92101dcb2022-10-19 23:49:361551 (
1552 'chartorune is not memory-safe, unless you can guarantee the input ',
1553 'string is always null-terminated. Otherwise, please use charntorune ',
1554 'from libphonenumber instead.'
1555 ),
1556 True,
1557 [
1558 _THIRD_PARTY_EXCEPT_BLINK,
1559 # Exceptions to this rule should have a fuzzer.
1560 ],
1561 ),
Arthur Sonzogni1da65fa2023-03-27 16:01:521562 BanRule(
1563 r'/\b#include "base/atomicops\.h"\b',
1564 (
1565 'Do not use base::subtle atomics, but std::atomic, which are simpler '
1566 'to use, have better understood, clearer and richer semantics, and are '
1567 'harder to mis-use. See details in base/atomicops.h.',
1568 ),
1569 False,
1570 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Benoit Lize79cf0592023-01-27 10:01:571571 ),
Arthur Sonzogni60348572e2023-04-07 10:22:521572 BanRule(
1573 r'CrossThreadPersistent<',
1574 (
1575 'Do not use blink::CrossThreadPersistent, but '
1576 'blink::CrossThreadHandle. It is harder to mis-use.',
1577 'More info: '
1578 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1579 'Please contact platform-architecture-dev@ before adding new instances.'
1580 ),
1581 False,
1582 []
1583 ),
1584 BanRule(
1585 r'CrossThreadWeakPersistent<',
1586 (
1587 'Do not use blink::CrossThreadWeakPersistent, but '
1588 'blink::CrossThreadWeakHandle. It is harder to mis-use.',
1589 'More info: '
1590 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1591 'Please contact platform-architecture-dev@ before adding new instances.'
1592 ),
1593 False,
1594 []
1595 ),
Avi Drissman491617c2023-04-13 17:33:151596 BanRule(
1597 r'objc/objc.h',
1598 (
1599 'Do not include <objc/objc.h>. It defines away ARC lifetime '
1600 'annotations, and is thus dangerous.',
1601 'Please use the pimpl pattern; search for `ObjCStorage` for examples.',
1602 'For further reading on how to safely mix C++ and Obj-C, see',
1603 'https://chromium.googlesource.com/chromium/src/+/main/docs/mac/mixing_cpp_and_objc.md'
1604 ),
1605 True,
1606 []
1607 ),
Grace Park8d59b54b2023-04-26 17:53:351608 BanRule(
1609 r'/#include <filesystem>',
1610 (
1611 'libc++ <filesystem> is banned per the Google C++ styleguide.',
1612 ),
1613 True,
1614 # This fuzzing framework is a standalone open source project and
1615 # cannot rely on Chromium base.
1616 (r'third_party/centipede'),
1617 ),
Daniel Cheng72153e02023-05-18 21:18:141618 BanRule(
1619 r'TopDocument()',
1620 (
1621 'TopDocument() does not work correctly with out-of-process iframes. '
1622 'Please do not introduce new uses.',
1623 ),
1624 True,
1625 (
1626 # TODO(crbug.com/617677): Remove all remaining uses.
1627 r'^third_party/blink/renderer/core/dom/document\.cc',
1628 r'^third_party/blink/renderer/core/dom/document\.h',
1629 r'^third_party/blink/renderer/core/dom/element\.cc',
1630 r'^third_party/blink/renderer/core/exported/web_disallow_transition_scope_test\.cc',
1631 r'^third_party/blink/renderer/core/exported/web_document_test\.cc',
Daniel Cheng72153e02023-05-18 21:18:141632 r'^third_party/blink/renderer/core/html/html_anchor_element\.cc',
1633 r'^third_party/blink/renderer/core/html/html_dialog_element\.cc',
1634 r'^third_party/blink/renderer/core/html/html_element\.cc',
1635 r'^third_party/blink/renderer/core/html/html_frame_owner_element\.cc',
1636 r'^third_party/blink/renderer/core/html/media/video_wake_lock\.cc',
1637 r'^third_party/blink/renderer/core/loader/anchor_element_interaction_tracker\.cc',
1638 r'^third_party/blink/renderer/core/page/scrolling/root_scroller_controller\.cc',
1639 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.cc',
1640 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.h',
1641 r'^third_party/blink/renderer/core/script/classic_pending_script\.cc',
1642 r'^third_party/blink/renderer/core/script/script_loader\.cc',
1643 ),
1644 ),
Arthur Sonzognif0eea302023-08-18 19:20:311645 BanRule(
1646 pattern = r'base::raw_ptr<',
1647 explanation = (
1648 'Do not use base::raw_ptr, use raw_ptr.',
1649 ),
1650 treat_as_error = True,
1651 excluded_paths = (
1652 '^base/',
1653 '^tools/',
1654 ),
1655 ),
1656 BanRule(
1657 pattern = r'base:raw_ref<',
1658 explanation = (
1659 'Do not use base::raw_ref, use raw_ref.',
1660 ),
1661 treat_as_error = True,
1662 excluded_paths = (
1663 '^base/',
1664 '^tools/',
1665 ),
1666 ),
Anton Maliev66751812023-08-24 16:28:131667 BanRule(
Tom Sepez41eb158d2023-09-12 16:16:221668 pattern = r'/raw_ptr<[^;}]*\w{};',
1669 explanation = (
1670 'Do not use {} for raw_ptr initialization, use = nullptr instead.',
1671 ),
1672 treat_as_error = True,
1673 excluded_paths = (
1674 '^base/',
1675 '^tools/',
1676 ),
1677 ),
1678 BanRule(
Arthur Sonzogni48c6aea22023-09-04 22:25:201679 pattern = r'/#include "base/allocator/.*/raw_'
1680 r'(ptr|ptr_cast|ptr_exclusion|ref).h"',
1681 explanation = (
1682 'Please include the corresponding facade headers:',
1683 '- #include "base/memory/raw_ptr.h"',
1684 '- #include "base/memory/raw_ptr_cast.h"',
1685 '- #include "base/memory/raw_ptr_exclusion.h"',
1686 '- #include "base/memory/raw_ref.h"',
1687 ),
1688 treat_as_error = True,
1689 excluded_paths = (
1690 '^base/',
1691 '^tools/',
1692 ),
1693 ),
1694 BanRule(
Anton Maliev66751812023-08-24 16:28:131695 pattern = r'ContentSettingsType::COOKIES',
1696 explanation = (
1697 'Do not use ContentSettingsType::COOKIES to check whether cookies are '
1698 'supported in the provided context. Instead rely on the '
1699 'content_settings::CookieSettings API. If you are using '
1700 'ContentSettingsType::COOKIES to check the user preference setting '
1701 'specifically, disregard this warning.',
1702 ),
1703 treat_as_error = False,
1704 excluded_paths = (
1705 '^chrome/browser/ui/content_settings/',
1706 '^components/content_settings/',
1707 '^services/network/cookie_settings/',
1708 'test.cc',
1709 ),
1710 ),
Tom Andersoncd522072023-10-03 00:52:351711 BanRule(
1712 pattern = r'\bg_signal_connect',
1713 explanation = (
1714 'Use ScopedGSignal instead of g_signal_connect*()',
1715 ),
1716 treat_as_error = True,
1717 excluded_paths = (
1718 '^ui/base/glib/scoped_gsignal.h',
1719 ),
1720 ),
[email protected]127f18ec2012-06-16 05:05:591721)
1722
Daniel Cheng92c15e32022-03-16 17:48:221723_BANNED_MOJOM_PATTERNS : Sequence[BanRule] = (
1724 BanRule(
1725 'handle<shared_buffer>',
1726 (
1727 'Please use one of the more specific shared memory types instead:',
1728 ' mojo_base.mojom.ReadOnlySharedMemoryRegion',
1729 ' mojo_base.mojom.WritableSharedMemoryRegion',
1730 ' mojo_base.mojom.UnsafeSharedMemoryRegion',
1731 ),
1732 True,
1733 ),
1734)
1735
mlamouria82272622014-09-16 18:45:041736_IPC_ENUM_TRAITS_DEPRECATED = (
1737 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501738 'See http://www.chromium.org/Home/chromium-security/education/'
1739 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041740
Stephen Martinis97a394142018-06-07 23:06:051741_LONG_PATH_ERROR = (
1742 'Some files included in this CL have file names that are too long (> 200'
1743 ' characters). If committed, these files will cause issues on Windows. See'
1744 ' https://crbug.com/612667 for more details.'
1745)
1746
Shenghua Zhangbfaa38b82017-11-16 21:58:021747_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Bruce Dawson40fece62022-09-16 19:58:311748 r".*/AppHooksImpl\.java",
1749 r".*/BuildHooksAndroidImpl\.java",
1750 r".*/LicenseContentProvider\.java",
1751 r".*/PlatformServiceBridgeImpl.java",
1752 r".*chrome/android/feed/dummy/.*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021753]
[email protected]127f18ec2012-06-16 05:05:591754
Mohamed Heikald048240a2019-11-12 16:57:371755# List of image extensions that are used as resources in chromium.
1756_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1757
Sean Kau46e29bc2017-08-28 16:31:161758# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401759_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Bruce Dawson40fece62022-09-16 19:58:311760 r'test/data/',
1761 r'testing/buildbot/',
1762 r'^components/policy/resources/policy_templates\.json$',
1763 r'^third_party/protobuf/',
Camillo Bruni1411a352023-05-24 12:39:031764 r'^third_party/blink/perf_tests/speedometer.*/resources/todomvc/learn\.json',
Bruce Dawson40fece62022-09-16 19:58:311765 r'^third_party/blink/renderer/devtools/protocol\.json$',
1766 r'^third_party/blink/web_tests/external/wpt/',
1767 r'^tools/perf/',
1768 r'^tools/traceline/svgui/startup-release.json',
Daniel Cheng2d4c2d192022-07-01 01:38:311769 # vscode configuration files allow comments
Bruce Dawson40fece62022-09-16 19:58:311770 r'^tools/vscode/',
Sean Kau46e29bc2017-08-28 16:31:161771]
1772
Andrew Grieveb773bad2020-06-05 18:00:381773# These are not checked on the public chromium-presubmit trybot.
1774# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041775# checkouts.
agrievef32bcc72016-04-04 14:57:401776_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381777 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381778]
1779
1780
1781_GENERIC_PYDEPS_FILES = [
Bruce Dawson853b739e62022-05-03 23:03:101782 'android_webview/test/components/run_webview_component_smoketest.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041783 'android_webview/tools/run_cts.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361784 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041785 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361786 'build/android/gyp/aar.pydeps',
1787 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271788 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361789 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381790 'build/android/gyp/assert_static_initializers.pydeps',
Mohamed Heikal133e1f22023-04-18 20:04:371791 'build/android/gyp/binary_baseline_profile.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361792 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021793 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:221794 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111795 'build/android/gyp/compile_java.pydeps',
Peter Weneaa963f2023-01-20 19:40:301796 'build/android/gyp/compile_kt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361797 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361798 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361799 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111800 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041801 'build/android/gyp/create_app_bundle_apks.pydeps',
1802 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361803 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121804 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091805 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221806 'build/android/gyp/create_size_info_files.pydeps',
Peter Wene6e017e2022-07-27 21:40:401807 'build/android/gyp/create_test_apk_wrapper_script.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001808 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361809 'build/android/gyp/dex.pydeps',
1810 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361811 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:211812 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361813 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361814 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361815 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581816 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361817 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141818 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261819 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:471820 'build/android/gyp/java_google_api_keys.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041821 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361822 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361823 'build/android/gyp/merge_manifest.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:101824 'build/android/gyp/optimize_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361825 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221826 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361827 'build/android/gyp/proguard.pydeps',
Andrew Grievee3a775ab2022-05-16 15:59:221828 'build/android/gyp/system_image_apks.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:101829 'build/android/gyp/trace_event_bytecode_rewriter.pydeps',
Peter Wen578730b2020-03-19 19:55:461830 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:301831 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241832 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361833 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461834 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561835 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361836 'build/android/incremental_install/generate_android_manifest.pydeps',
1837 'build/android/incremental_install/write_installer_json.pydeps',
Stephanie Kim392913b452022-06-15 17:25:321838 'build/android/pylib/results/presentation/test_results_presentation.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041839 'build/android/resource_sizes.pydeps',
1840 'build/android/test_runner.pydeps',
1841 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361842 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361843 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321844 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271845 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1846 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:041847 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001848 'components/cronet/tools/generate_javadoc.pydeps',
1849 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381850 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001851 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381852 'net/tools/testserver/testserver.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181853 'testing/scripts/run_isolated_script_test.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411854 'testing/merge_scripts/standard_isolated_script_merge.pydeps',
1855 'testing/merge_scripts/standard_gtest_merge.pydeps',
1856 'testing/merge_scripts/code_coverage/merge_results.pydeps',
1857 'testing/merge_scripts/code_coverage/merge_steps.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041858 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421859 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
Yuki Shiino38eeaad12022-08-11 06:40:251860 'third_party/blink/renderer/bindings/scripts/check_generated_file_list.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421861 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131862 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Yuki Shiinoea477d32023-08-21 06:24:341863 'third_party/blink/renderer/bindings/scripts/generate_event_interface_names.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:501864 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411865 'third_party/blink/tools/blinkpy/web_tests/merge_results.pydeps',
1866 'third_party/blink/tools/merge_web_test_results.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061867 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221868 'tools/binary_size/supersize.pydeps',
Ben Pastene028104a2022-08-10 19:17:451869 'tools/perf/process_perf_results.pydeps',
agrievef32bcc72016-04-04 14:57:401870]
1871
wnwenbdc444e2016-05-25 13:44:151872
agrievef32bcc72016-04-04 14:57:401873_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1874
1875
Eric Boren6fd2b932018-01-25 15:05:081876# Bypass the AUTHORS check for these accounts.
1877_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591878 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451879 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591880 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521881 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:231882 'wpt-autoroller', 'chrome-weblayer-builder',
Garrett Beaty4d4fcf62021-11-24 17:57:471883 'lacros-version-skew-roller', 'skylab-test-cros-roller',
Sven Zheng722960ba2022-07-18 16:40:461884 'infra-try-recipes-tester', 'lacros-tracking-roller',
Brian Sheedy1c951e62022-10-27 01:16:181885 'lacros-sdk-version-roller', 'chrome-automated-expectation',
Stephanie Kimb49bdd242023-04-28 16:46:041886 'chromium-automated-expectation', 'chrome-branch-day',
1887 'chromium-autosharder')
Eric Boren835d71f2018-09-07 21:09:041888 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271889 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041890 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:161891 for s in ('chromium-internal-autoroll',)
1892 ) | set('%[email protected]' % s
Chong Gub277e342022-10-15 03:30:551893 for s in ('swarming-tasks',)
1894 ) | set('%[email protected]' % s
1895 for s in ('global-integration-try-builder',
Joey Scarr1103c5d2023-09-14 01:17:551896 'global-integration-ci-builder')
Suma Kasa3b9cf7a2023-09-21 22:05:541897 ) | set('%[email protected]' % s
1898 for s in ('chops-security-borg',
1899 'chops-security-cronjobs-cpesuggest'))
Eric Boren6fd2b932018-01-25 15:05:081900
Matt Stark6ef08872021-07-29 01:21:461901_INVALID_GRD_FILE_LINE = [
1902 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
1903]
Eric Boren6fd2b932018-01-25 15:05:081904
Daniel Bratell65b033262019-04-23 08:17:061905def _IsCPlusPlusFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501906 """Returns True if this file contains C++-like code (and not Python,
1907 Go, Java, MarkDown, ...)"""
Daniel Bratell65b033262019-04-23 08:17:061908
Sam Maiera6e76d72022-02-11 21:43:501909 ext = input_api.os_path.splitext(file_path)[1]
1910 # This list is compatible with CppChecker.IsCppFile but we should
1911 # consider adding ".c" to it. If we do that we can use this function
1912 # at more places in the code.
1913 return ext in (
1914 '.h',
1915 '.cc',
1916 '.cpp',
1917 '.m',
1918 '.mm',
1919 )
1920
Daniel Bratell65b033262019-04-23 08:17:061921
1922def _IsCPlusPlusHeaderFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501923 return input_api.os_path.splitext(file_path)[1] == ".h"
Daniel Bratell65b033262019-04-23 08:17:061924
1925
1926def _IsJavaFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501927 return input_api.os_path.splitext(file_path)[1] == ".java"
Daniel Bratell65b033262019-04-23 08:17:061928
1929
1930def _IsProtoFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501931 return input_api.os_path.splitext(file_path)[1] == ".proto"
Daniel Bratell65b033262019-04-23 08:17:061932
Mohamed Heikal5e5b7922020-10-29 18:57:591933
Erik Staabc734cd7a2021-11-23 03:11:521934def _IsXmlOrGrdFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501935 ext = input_api.os_path.splitext(file_path)[1]
1936 return ext in ('.grd', '.xml')
Erik Staabc734cd7a2021-11-23 03:11:521937
1938
Sven Zheng76a79ea2022-12-21 21:25:241939def _IsMojomFile(input_api, file_path):
1940 return input_api.os_path.splitext(file_path)[1] == ".mojom"
1941
1942
Mohamed Heikal5e5b7922020-10-29 18:57:591943def CheckNoUpstreamDepsOnClank(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501944 """Prevent additions of dependencies from the upstream repo on //clank."""
1945 # clank can depend on clank
1946 if input_api.change.RepositoryRoot().endswith('clank'):
1947 return []
1948 build_file_patterns = [
1949 r'(.+/)?BUILD\.gn',
1950 r'.+\.gni',
1951 ]
1952 excluded_files = [r'build[/\\]config[/\\]android[/\\]config\.gni']
1953 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
Mohamed Heikal5e5b7922020-10-29 18:57:591954
Sam Maiera6e76d72022-02-11 21:43:501955 error_message = 'Disallowed import on //clank in an upstream build file:'
Mohamed Heikal5e5b7922020-10-29 18:57:591956
Sam Maiera6e76d72022-02-11 21:43:501957 def FilterFile(affected_file):
1958 return input_api.FilterSourceFile(affected_file,
1959 files_to_check=build_file_patterns,
1960 files_to_skip=excluded_files)
Mohamed Heikal5e5b7922020-10-29 18:57:591961
Sam Maiera6e76d72022-02-11 21:43:501962 problems = []
1963 for f in input_api.AffectedSourceFiles(FilterFile):
1964 local_path = f.LocalPath()
1965 for line_number, line in f.ChangedContents():
1966 if (bad_pattern.search(line)):
1967 problems.append('%s:%d\n %s' %
1968 (local_path, line_number, line.strip()))
1969 if problems:
1970 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1971 else:
1972 return []
Mohamed Heikal5e5b7922020-10-29 18:57:591973
1974
Saagar Sanghavifceeaae2020-08-12 16:40:361975def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501976 """Attempts to prevent use of functions intended only for testing in
1977 non-testing code. For now this is just a best-effort implementation
1978 that ignores header files and may have some false positives. A
1979 better implementation would probably need a proper C++ parser.
1980 """
1981 # We only scan .cc files and the like, as the declaration of
1982 # for-testing functions in header files are hard to distinguish from
1983 # calls to such functions without a proper C++ parser.
1984 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191985
Sam Maiera6e76d72022-02-11 21:43:501986 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
1987 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' %
1988 base_function_pattern)
1989 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
1990 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
1991 exclusion_pattern = input_api.re.compile(
1992 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' %
1993 (base_function_pattern, base_function_pattern))
1994 # Avoid a false positive in this case, where the method name, the ::, and
1995 # the closing { are all on different lines due to line wrapping.
1996 # HelperClassForTesting::
1997 # HelperClassForTesting(
1998 # args)
1999 # : member(0) {}
2000 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:192001
Sam Maiera6e76d72022-02-11 21:43:502002 def FilterFile(affected_file):
2003 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2004 input_api.DEFAULT_FILES_TO_SKIP)
2005 return input_api.FilterSourceFile(
2006 affected_file,
2007 files_to_check=file_inclusion_pattern,
2008 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:192009
Sam Maiera6e76d72022-02-11 21:43:502010 problems = []
2011 for f in input_api.AffectedSourceFiles(FilterFile):
2012 local_path = f.LocalPath()
2013 in_method_defn = False
2014 for line_number, line in f.ChangedContents():
2015 if (inclusion_pattern.search(line)
2016 and not comment_pattern.search(line)
2017 and not exclusion_pattern.search(line)
2018 and not allowlist_pattern.search(line)
2019 and not in_method_defn):
2020 problems.append('%s:%d\n %s' %
2021 (local_path, line_number, line.strip()))
2022 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:192023
Sam Maiera6e76d72022-02-11 21:43:502024 if problems:
2025 return [
2026 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
2027 ]
2028 else:
2029 return []
[email protected]55459852011-08-10 15:17:192030
2031
Saagar Sanghavifceeaae2020-08-12 16:40:362032def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502033 """This is a simplified version of
2034 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
2035 """
2036 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
2037 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
2038 name_pattern = r'ForTest(s|ing)?'
2039 # Describes an occurrence of "ForTest*" inside a // comment.
2040 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
2041 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
2042 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
2043 # Catch calls.
2044 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
2045 # Ignore definitions. (Comments are ignored separately.)
2046 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
Andrew Grieve40f451d2023-07-06 19:46:512047 allowlist_re = input_api.re.compile(r'// IN-TEST$')
Vaclav Brozek7dbc28c2018-03-27 08:35:232048
Sam Maiera6e76d72022-02-11 21:43:502049 problems = []
2050 sources = lambda x: input_api.FilterSourceFile(
2051 x,
2052 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
2053 DEFAULT_FILES_TO_SKIP),
2054 files_to_check=[r'.*\.java$'])
2055 for f in input_api.AffectedFiles(include_deletes=False,
2056 file_filter=sources):
2057 local_path = f.LocalPath()
Vaclav Brozek7dbc28c2018-03-27 08:35:232058 is_inside_javadoc = False
Sam Maiera6e76d72022-02-11 21:43:502059 for line_number, line in f.ChangedContents():
2060 if is_inside_javadoc and javadoc_end_re.search(line):
2061 is_inside_javadoc = False
2062 if not is_inside_javadoc and javadoc_start_re.search(line):
2063 is_inside_javadoc = True
2064 if is_inside_javadoc:
2065 continue
2066 if (inclusion_re.search(line) and not comment_re.search(line)
2067 and not annotation_re.search(line)
Andrew Grieve40f451d2023-07-06 19:46:512068 and not allowlist_re.search(line)
Sam Maiera6e76d72022-02-11 21:43:502069 and not exclusion_re.search(line)):
2070 problems.append('%s:%d\n %s' %
2071 (local_path, line_number, line.strip()))
Vaclav Brozek7dbc28c2018-03-27 08:35:232072
Sam Maiera6e76d72022-02-11 21:43:502073 if problems:
2074 return [
2075 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
2076 ]
2077 else:
2078 return []
Vaclav Brozek7dbc28c2018-03-27 08:35:232079
2080
Saagar Sanghavifceeaae2020-08-12 16:40:362081def CheckNoIOStreamInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502082 """Checks to make sure no .h files include <iostream>."""
2083 files = []
2084 pattern = input_api.re.compile(r'^#include\s*<iostream>',
2085 input_api.re.MULTILINE)
2086 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2087 if not f.LocalPath().endswith('.h'):
2088 continue
2089 contents = input_api.ReadFile(f)
2090 if pattern.search(contents):
2091 files.append(f)
[email protected]10689ca2011-09-02 02:31:542092
Sam Maiera6e76d72022-02-11 21:43:502093 if len(files):
2094 return [
2095 output_api.PresubmitError(
2096 'Do not #include <iostream> in header files, since it inserts static '
2097 'initialization into every file including the header. Instead, '
2098 '#include <ostream>. See http://crbug.com/94794', files)
2099 ]
2100 return []
2101
[email protected]10689ca2011-09-02 02:31:542102
Aleksey Khoroshilov9b28c032022-06-03 16:35:322103def CheckNoStrCatRedefines(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502104 """Checks no windows headers with StrCat redefined are included directly."""
2105 files = []
Aleksey Khoroshilov9b28c032022-06-03 16:35:322106 files_to_check = (r'.+%s' % _HEADER_EXTENSIONS,
2107 r'.+%s' % _IMPLEMENTATION_EXTENSIONS)
2108 files_to_skip = (input_api.DEFAULT_FILES_TO_SKIP +
2109 _NON_BASE_DEPENDENT_PATHS)
2110 sources_filter = lambda f: input_api.FilterSourceFile(
2111 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
2112
Sam Maiera6e76d72022-02-11 21:43:502113 pattern_deny = input_api.re.compile(
2114 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
2115 input_api.re.MULTILINE)
2116 pattern_allow = input_api.re.compile(
2117 r'^#include\s"base/win/windows_defines.inc"', input_api.re.MULTILINE)
Aleksey Khoroshilov9b28c032022-06-03 16:35:322118 for f in input_api.AffectedSourceFiles(sources_filter):
Sam Maiera6e76d72022-02-11 21:43:502119 contents = input_api.ReadFile(f)
2120 if pattern_deny.search(
2121 contents) and not pattern_allow.search(contents):
2122 files.append(f.LocalPath())
Danil Chapovalov3518f362018-08-11 16:13:432123
Sam Maiera6e76d72022-02-11 21:43:502124 if len(files):
2125 return [
2126 output_api.PresubmitError(
2127 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
2128 'directly since they pollute code with StrCat macro. Instead, '
2129 'include matching header from base/win. See http://crbug.com/856536',
2130 files)
2131 ]
2132 return []
Danil Chapovalov3518f362018-08-11 16:13:432133
[email protected]10689ca2011-09-02 02:31:542134
Andrew Williamsc9f69b482023-07-10 16:07:362135def _CheckNoUNIT_TESTInSourceFiles(input_api, f):
2136 problems = []
2137
2138 unit_test_macro = input_api.re.compile(
2139 '^\s*#.*(?:ifn?def\s+UNIT_TEST|defined\s*\(?\s*UNIT_TEST\s*\)?)(?:$|\s+)')
2140 for line_num, line in f.ChangedContents():
2141 if unit_test_macro.match(line):
2142 problems.append(' %s:%d' % (f.LocalPath(), line_num))
2143
2144 return problems
2145
2146
Saagar Sanghavifceeaae2020-08-12 16:40:362147def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502148 """Checks to make sure no source files use UNIT_TEST."""
2149 problems = []
2150 for f in input_api.AffectedFiles():
2151 if (not f.LocalPath().endswith(('.cc', '.mm'))):
2152 continue
Andrew Williamsc9f69b482023-07-10 16:07:362153 problems.extend(
2154 _CheckNoUNIT_TESTInSourceFiles(input_api, f))
[email protected]72df4e782012-06-21 16:28:182155
Sam Maiera6e76d72022-02-11 21:43:502156 if not problems:
2157 return []
2158 return [
2159 output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
2160 '\n'.join(problems))
2161 ]
2162
[email protected]72df4e782012-06-21 16:28:182163
Saagar Sanghavifceeaae2020-08-12 16:40:362164def CheckNoDISABLETypoInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502165 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
Dominic Battre033531052018-09-24 15:45:342166
Sam Maiera6e76d72022-02-11 21:43:502167 This test warns if somebody tries to disable a test with the DISABLE_ prefix
2168 instead of DISABLED_. To filter false positives, reports are only generated
2169 if a corresponding MAYBE_ line exists.
2170 """
2171 problems = []
Dominic Battre033531052018-09-24 15:45:342172
Sam Maiera6e76d72022-02-11 21:43:502173 # The following two patterns are looked for in tandem - is a test labeled
2174 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
2175 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
2176 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
Dominic Battre033531052018-09-24 15:45:342177
Sam Maiera6e76d72022-02-11 21:43:502178 # This is for the case that a test is disabled on all platforms.
2179 full_disable_pattern = input_api.re.compile(
2180 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
2181 input_api.re.MULTILINE)
Dominic Battre033531052018-09-24 15:45:342182
Sam Maiera6e76d72022-02-11 21:43:502183 for f in input_api.AffectedFiles(False):
2184 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2185 continue
Dominic Battre033531052018-09-24 15:45:342186
Sam Maiera6e76d72022-02-11 21:43:502187 # Search for MABYE_, DISABLE_ pairs.
2188 disable_lines = {} # Maps of test name to line number.
2189 maybe_lines = {}
2190 for line_num, line in f.ChangedContents():
2191 disable_match = disable_pattern.search(line)
2192 if disable_match:
2193 disable_lines[disable_match.group(1)] = line_num
2194 maybe_match = maybe_pattern.search(line)
2195 if maybe_match:
2196 maybe_lines[maybe_match.group(1)] = line_num
Dominic Battre033531052018-09-24 15:45:342197
Sam Maiera6e76d72022-02-11 21:43:502198 # Search for DISABLE_ occurrences within a TEST() macro.
2199 disable_tests = set(disable_lines.keys())
2200 maybe_tests = set(maybe_lines.keys())
2201 for test in disable_tests.intersection(maybe_tests):
2202 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
Dominic Battre033531052018-09-24 15:45:342203
Sam Maiera6e76d72022-02-11 21:43:502204 contents = input_api.ReadFile(f)
2205 full_disable_match = full_disable_pattern.search(contents)
2206 if full_disable_match:
2207 problems.append(' %s' % f.LocalPath())
Dominic Battre033531052018-09-24 15:45:342208
Sam Maiera6e76d72022-02-11 21:43:502209 if not problems:
2210 return []
2211 return [
2212 output_api.PresubmitPromptWarning(
2213 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
2214 '\n'.join(problems))
2215 ]
2216
Dominic Battre033531052018-09-24 15:45:342217
Nina Satragnof7660532021-09-20 18:03:352218def CheckForgettingMAYBEInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502219 """Checks to make sure tests disabled conditionally are not missing a
2220 corresponding MAYBE_ prefix.
2221 """
2222 # Expect at least a lowercase character in the test name. This helps rule out
2223 # false positives with macros wrapping the actual tests name.
2224 define_maybe_pattern = input_api.re.compile(
2225 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
Bruce Dawsonffc55292022-04-20 04:18:192226 # The test_maybe_pattern needs to handle all of these forms. The standard:
2227 # IN_PROC_TEST_F(SyncTest, MAYBE_Start) {
2228 # With a wrapper macro around the test name:
2229 # IN_PROC_TEST_F(SyncTest, E2E_ENABLED(MAYBE_Start)) {
2230 # And the odd-ball NACL_BROWSER_TEST_f format:
2231 # NACL_BROWSER_TEST_F(NaClBrowserTest, SimpleLoad, {
2232 # The optional E2E_ENABLED-style is handled with (\w*\()?
2233 # The NACL_BROWSER_TEST_F pattern is handled by allowing a trailing comma or
2234 # trailing ')'.
2235 test_maybe_pattern = (
2236 r'^\s*\w*TEST[^(]*\(\s*\w+,\s*(\w*\()?MAYBE_{test_name}[\),]')
Sam Maiera6e76d72022-02-11 21:43:502237 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
2238 warnings = []
Nina Satragnof7660532021-09-20 18:03:352239
Sam Maiera6e76d72022-02-11 21:43:502240 # Read the entire files. We can't just read the affected lines, forgetting to
2241 # add MAYBE_ on a change would not show up otherwise.
2242 for f in input_api.AffectedFiles(False):
2243 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2244 continue
2245 contents = input_api.ReadFile(f)
2246 lines = contents.splitlines(True)
2247 current_position = 0
2248 warning_test_names = set()
2249 for line_num, line in enumerate(lines, start=1):
2250 current_position += len(line)
2251 maybe_match = define_maybe_pattern.search(line)
2252 if maybe_match:
2253 test_name = maybe_match.group('test_name')
2254 # Do not warn twice for the same test.
2255 if (test_name in warning_test_names):
2256 continue
2257 warning_test_names.add(test_name)
Nina Satragnof7660532021-09-20 18:03:352258
Sam Maiera6e76d72022-02-11 21:43:502259 # Attempt to find the corresponding MAYBE_ test or suite, starting from
2260 # the current position.
2261 test_match = input_api.re.compile(
2262 test_maybe_pattern.format(test_name=test_name),
2263 input_api.re.MULTILINE).search(contents, current_position)
2264 suite_match = input_api.re.compile(
2265 suite_maybe_pattern.format(test_name=test_name),
2266 input_api.re.MULTILINE).search(contents, current_position)
2267 if not test_match and not suite_match:
2268 warnings.append(
2269 output_api.PresubmitPromptWarning(
2270 '%s:%d found MAYBE_ defined without corresponding test %s'
2271 % (f.LocalPath(), line_num, test_name)))
2272 return warnings
2273
[email protected]72df4e782012-06-21 16:28:182274
Saagar Sanghavifceeaae2020-08-12 16:40:362275def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502276 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
2277 errors = []
Kalvin Lee4a3b79de2022-05-26 16:00:162278 pattern = input_api.re.compile(r'\bDCHECK_IS_ON\b(?!\(\))',
Sam Maiera6e76d72022-02-11 21:43:502279 input_api.re.MULTILINE)
2280 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2281 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
2282 continue
2283 for lnum, line in f.ChangedContents():
2284 if input_api.re.search(pattern, line):
2285 errors.append(
2286 output_api.PresubmitError((
2287 '%s:%d: Use of DCHECK_IS_ON() must be written as "#if '
2288 + 'DCHECK_IS_ON()", not forgetting the parentheses.') %
2289 (f.LocalPath(), lnum)))
2290 return errors
danakj61c1aa22015-10-26 19:55:522291
2292
Weilun Shia487fad2020-10-28 00:10:342293# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
2294# more reliable way. See
2295# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:192296
wnwenbdc444e2016-05-25 13:44:152297
Saagar Sanghavifceeaae2020-08-12 16:40:362298def CheckFlakyTestUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502299 """Check that FlakyTest annotation is our own instead of the android one"""
2300 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
2301 files = []
2302 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2303 if f.LocalPath().endswith('Test.java'):
2304 if pattern.search(input_api.ReadFile(f)):
2305 files.append(f)
2306 if len(files):
2307 return [
2308 output_api.PresubmitError(
2309 'Use org.chromium.base.test.util.FlakyTest instead of '
2310 'android.test.FlakyTest', files)
2311 ]
2312 return []
mcasasb7440c282015-02-04 14:52:192313
wnwenbdc444e2016-05-25 13:44:152314
Saagar Sanghavifceeaae2020-08-12 16:40:362315def CheckNoDEPSGIT(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502316 """Make sure .DEPS.git is never modified manually."""
2317 if any(f.LocalPath().endswith('.DEPS.git')
2318 for f in input_api.AffectedFiles()):
2319 return [
2320 output_api.PresubmitError(
2321 'Never commit changes to .DEPS.git. This file is maintained by an\n'
2322 'automated system based on what\'s in DEPS and your changes will be\n'
2323 'overwritten.\n'
2324 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
2325 'get-the-code#Rolling_DEPS\n'
2326 'for more information')
2327 ]
2328 return []
[email protected]2a8ac9c2011-10-19 17:20:442329
2330
Sven Zheng76a79ea2022-12-21 21:25:242331def CheckCrosApiNeedBrowserTest(input_api, output_api):
2332 """Check new crosapi should add browser test."""
2333 has_new_crosapi = False
2334 has_browser_test = False
2335 for f in input_api.AffectedFiles():
2336 path = f.LocalPath()
2337 if (path.startswith('chromeos/crosapi/mojom') and
2338 _IsMojomFile(input_api, path) and f.Action() == 'A'):
2339 has_new_crosapi = True
2340 if path.endswith('browsertest.cc') or path.endswith('browser_test.cc'):
2341 has_browser_test = True
2342 if has_new_crosapi and not has_browser_test:
2343 return [
2344 output_api.PresubmitPromptWarning(
2345 'You are adding a new crosapi, but there is no file ends with '
2346 'browsertest.cc file being added or modified. It is important '
2347 'to add crosapi browser test coverage to avoid version '
2348 ' skew issues.\n'
2349 'Check //docs/lacros/test_instructions.md for more information.'
2350 )
2351 ]
2352 return []
2353
2354
Saagar Sanghavifceeaae2020-08-12 16:40:362355def CheckValidHostsInDEPSOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502356 """Checks that DEPS file deps are from allowed_hosts."""
2357 # Run only if DEPS file has been modified to annoy fewer bystanders.
2358 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
2359 return []
2360 # Outsource work to gclient verify
2361 try:
2362 gclient_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
2363 'third_party', 'depot_tools',
2364 'gclient.py')
2365 input_api.subprocess.check_output(
Bruce Dawson8a43cf72022-05-13 17:10:322366 [input_api.python3_executable, gclient_path, 'verify'],
Sam Maiera6e76d72022-02-11 21:43:502367 stderr=input_api.subprocess.STDOUT)
2368 return []
2369 except input_api.subprocess.CalledProcessError as error:
2370 return [
2371 output_api.PresubmitError(
2372 'DEPS file must have only git dependencies.',
2373 long_text=error.output)
2374 ]
tandriief664692014-09-23 14:51:472375
2376
Mario Sanchez Prada2472cab2019-09-18 10:58:312377def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152378 ban_rule):
Allen Bauer84778682022-09-22 16:28:562379 """Helper method for checking for banned constructs.
Mario Sanchez Prada2472cab2019-09-18 10:58:312380
Sam Maiera6e76d72022-02-11 21:43:502381 Returns an string composed of the name of the file, the line number where the
2382 match has been found and the additional text passed as |message| in case the
2383 target type name matches the text inside the line passed as parameter.
2384 """
2385 result = []
Peng Huang9c5949a02020-06-11 19:20:542386
Daniel Chenga44a1bcd2022-03-15 20:00:152387 # Ignore comments about banned types.
2388 if input_api.re.search(r"^ *//", line):
Sam Maiera6e76d72022-02-11 21:43:502389 return result
Daniel Chenga44a1bcd2022-03-15 20:00:152390 # A // nocheck comment will bypass this error.
2391 if line.endswith(" nocheck"):
Sam Maiera6e76d72022-02-11 21:43:502392 return result
2393
2394 matched = False
Daniel Chenga44a1bcd2022-03-15 20:00:152395 if ban_rule.pattern[0:1] == '/':
2396 regex = ban_rule.pattern[1:]
Sam Maiera6e76d72022-02-11 21:43:502397 if input_api.re.search(regex, line):
2398 matched = True
Daniel Chenga44a1bcd2022-03-15 20:00:152399 elif ban_rule.pattern in line:
Sam Maiera6e76d72022-02-11 21:43:502400 matched = True
2401
2402 if matched:
2403 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
Daniel Chenga44a1bcd2022-03-15 20:00:152404 for line in ban_rule.explanation:
2405 result.append(' %s' % line)
Sam Maiera6e76d72022-02-11 21:43:502406
danakjd18e8892020-12-17 17:42:012407 return result
Mario Sanchez Prada2472cab2019-09-18 10:58:312408
2409
Saagar Sanghavifceeaae2020-08-12 16:40:362410def CheckNoBannedFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502411 """Make sure that banned functions are not used."""
2412 warnings = []
2413 errors = []
[email protected]127f18ec2012-06-16 05:05:592414
Sam Maiera6e76d72022-02-11 21:43:502415 def IsExcludedFile(affected_file, excluded_paths):
Daniel Chenga44a1bcd2022-03-15 20:00:152416 if not excluded_paths:
2417 return False
2418
Sam Maiera6e76d72022-02-11 21:43:502419 local_path = affected_file.LocalPath()
Bruce Dawson40fece62022-09-16 19:58:312420 # Consistently use / as path separator to simplify the writing of regex
2421 # expressions.
2422 local_path = local_path.replace(input_api.os_path.sep, '/')
Sam Maiera6e76d72022-02-11 21:43:502423 for item in excluded_paths:
2424 if input_api.re.match(item, local_path):
2425 return True
2426 return False
wnwenbdc444e2016-05-25 13:44:152427
Sam Maiera6e76d72022-02-11 21:43:502428 def IsIosObjcFile(affected_file):
2429 local_path = affected_file.LocalPath()
2430 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m',
2431 '.h'):
2432 return False
2433 basename = input_api.os_path.basename(local_path)
2434 if 'ios' in basename.split('_'):
2435 return True
2436 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
2437 if sep and 'ios' in local_path.split(sep):
2438 return True
2439 return False
Sylvain Defresnea8b73d252018-02-28 15:45:542440
Daniel Chenga44a1bcd2022-03-15 20:00:152441 def CheckForMatch(affected_file, line_num: int, line: str,
2442 ban_rule: BanRule):
2443 if IsExcludedFile(affected_file, ban_rule.excluded_paths):
2444 return
2445
Sam Maiera6e76d72022-02-11 21:43:502446 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152447 ban_rule)
Sam Maiera6e76d72022-02-11 21:43:502448 if problems:
Daniel Chenga44a1bcd2022-03-15 20:00:152449 if ban_rule.treat_as_error is not None and ban_rule.treat_as_error:
Sam Maiera6e76d72022-02-11 21:43:502450 errors.extend(problems)
2451 else:
2452 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:152453
Sam Maiera6e76d72022-02-11 21:43:502454 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2455 for f in input_api.AffectedFiles(file_filter=file_filter):
2456 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152457 for ban_rule in _BANNED_JAVA_FUNCTIONS:
2458 CheckForMatch(f, line_num, line, ban_rule)
Eric Stevensona9a980972017-09-23 00:04:412459
Clement Yan9b330cb2022-11-17 05:25:292460 file_filter = lambda f: f.LocalPath().endswith(('.js', '.ts'))
2461 for f in input_api.AffectedFiles(file_filter=file_filter):
2462 for line_num, line in f.ChangedContents():
2463 for ban_rule in _BANNED_JAVASCRIPT_FUNCTIONS:
2464 CheckForMatch(f, line_num, line, ban_rule)
2465
Sam Maiera6e76d72022-02-11 21:43:502466 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
2467 for f in input_api.AffectedFiles(file_filter=file_filter):
2468 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152469 for ban_rule in _BANNED_OBJC_FUNCTIONS:
2470 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:592471
Sam Maiera6e76d72022-02-11 21:43:502472 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
2473 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152474 for ban_rule in _BANNED_IOS_OBJC_FUNCTIONS:
2475 CheckForMatch(f, line_num, line, ban_rule)
Sylvain Defresnea8b73d252018-02-28 15:45:542476
Sam Maiera6e76d72022-02-11 21:43:502477 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
2478 for f in input_api.AffectedFiles(file_filter=egtest_filter):
2479 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152480 for ban_rule in _BANNED_IOS_EGTEST_FUNCTIONS:
2481 CheckForMatch(f, line_num, line, ban_rule)
Peter K. Lee6c03ccff2019-07-15 14:40:052482
Sam Maiera6e76d72022-02-11 21:43:502483 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
2484 for f in input_api.AffectedFiles(file_filter=file_filter):
2485 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152486 for ban_rule in _BANNED_CPP_FUNCTIONS:
2487 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:592488
Daniel Cheng92c15e32022-03-16 17:48:222489 file_filter = lambda f: f.LocalPath().endswith(('.mojom'))
2490 for f in input_api.AffectedFiles(file_filter=file_filter):
2491 for line_num, line in f.ChangedContents():
2492 for ban_rule in _BANNED_MOJOM_PATTERNS:
2493 CheckForMatch(f, line_num, line, ban_rule)
2494
2495
Sam Maiera6e76d72022-02-11 21:43:502496 result = []
2497 if (warnings):
2498 result.append(
2499 output_api.PresubmitPromptWarning('Banned functions were used.\n' +
2500 '\n'.join(warnings)))
2501 if (errors):
2502 result.append(
2503 output_api.PresubmitError('Banned functions were used.\n' +
2504 '\n'.join(errors)))
2505 return result
[email protected]127f18ec2012-06-16 05:05:592506
Allen Bauer84778682022-09-22 16:28:562507def CheckNoLayoutCallsInTests(input_api, output_api):
2508 """Make sure there are no explicit calls to View::Layout() in tests"""
2509 warnings = []
2510 ban_rule = BanRule(
2511 r'/(\.|->)Layout\(\);',
2512 (
2513 'Direct calls to View::Layout() are not allowed in tests. '
2514 'If the view must be laid out here, use RunScheduledLayout(view). It '
2515 'is found in //ui/views/test/views_test_utils.h. '
2516 'See http://crbug.com/1350521 for more details.',
2517 ),
2518 False,
2519 )
2520 file_filter = lambda f: input_api.re.search(
2521 r'_(unittest|browsertest|ui_test).*\.(cc|mm)$', f.LocalPath())
2522 for f in input_api.AffectedFiles(file_filter = file_filter):
2523 for line_num, line in f.ChangedContents():
2524 problems = _GetMessageForMatchingType(input_api, f,
2525 line_num, line,
2526 ban_rule)
2527 if problems:
2528 warnings.extend(problems)
2529 result = []
2530 if (warnings):
2531 result.append(
2532 output_api.PresubmitPromptWarning(
2533 'Banned call to View::Layout() in tests.\n\n'.join(warnings)))
2534 return result
[email protected]127f18ec2012-06-16 05:05:592535
Michael Thiessen44457642020-02-06 00:24:152536def _CheckAndroidNoBannedImports(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502537 """Make sure that banned java imports are not used."""
2538 errors = []
Michael Thiessen44457642020-02-06 00:24:152539
Sam Maiera6e76d72022-02-11 21:43:502540 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2541 for f in input_api.AffectedFiles(file_filter=file_filter):
2542 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152543 for ban_rule in _BANNED_JAVA_IMPORTS:
2544 # Consider merging this into the above function. There is no
2545 # real difference anymore other than helping with a little
2546 # bit of boilerplate text. Doing so means things like
2547 # `treat_as_error` will also be uniformly handled.
Sam Maiera6e76d72022-02-11 21:43:502548 problems = _GetMessageForMatchingType(input_api, f, line_num,
Daniel Chenga44a1bcd2022-03-15 20:00:152549 line, ban_rule)
Sam Maiera6e76d72022-02-11 21:43:502550 if problems:
2551 errors.extend(problems)
2552 result = []
2553 if (errors):
2554 result.append(
2555 output_api.PresubmitError('Banned imports were used.\n' +
2556 '\n'.join(errors)))
2557 return result
Michael Thiessen44457642020-02-06 00:24:152558
2559
Saagar Sanghavifceeaae2020-08-12 16:40:362560def CheckNoPragmaOnce(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502561 """Make sure that banned functions are not used."""
2562 files = []
2563 pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
2564 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2565 if not f.LocalPath().endswith('.h'):
2566 continue
Bruce Dawson4c4c2922022-05-02 18:07:332567 if f.LocalPath().endswith('com_imported_mstscax.h'):
2568 continue
Sam Maiera6e76d72022-02-11 21:43:502569 contents = input_api.ReadFile(f)
2570 if pattern.search(contents):
2571 files.append(f)
[email protected]6c063c62012-07-11 19:11:062572
Sam Maiera6e76d72022-02-11 21:43:502573 if files:
2574 return [
2575 output_api.PresubmitError(
2576 'Do not use #pragma once in header files.\n'
2577 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
2578 files)
2579 ]
2580 return []
[email protected]6c063c62012-07-11 19:11:062581
[email protected]127f18ec2012-06-16 05:05:592582
Saagar Sanghavifceeaae2020-08-12 16:40:362583def CheckNoTrinaryTrueFalse(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502584 """Checks to make sure we don't introduce use of foo ? true : false."""
2585 problems = []
2586 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
2587 for f in input_api.AffectedFiles():
2588 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2589 continue
[email protected]e7479052012-09-19 00:26:122590
Sam Maiera6e76d72022-02-11 21:43:502591 for line_num, line in f.ChangedContents():
2592 if pattern.match(line):
2593 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]e7479052012-09-19 00:26:122594
Sam Maiera6e76d72022-02-11 21:43:502595 if not problems:
2596 return []
2597 return [
2598 output_api.PresubmitPromptWarning(
2599 'Please consider avoiding the "? true : false" pattern if possible.\n'
2600 + '\n'.join(problems))
2601 ]
[email protected]e7479052012-09-19 00:26:122602
2603
Saagar Sanghavifceeaae2020-08-12 16:40:362604def CheckUnwantedDependencies(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502605 """Runs checkdeps on #include and import statements added in this
2606 change. Breaking - rules is an error, breaking ! rules is a
2607 warning.
2608 """
2609 # Return early if no relevant file types were modified.
2610 for f in input_api.AffectedFiles():
2611 path = f.LocalPath()
2612 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path)
2613 or _IsJavaFile(input_api, path)):
2614 break
[email protected]55f9f382012-07-31 11:02:182615 else:
Sam Maiera6e76d72022-02-11 21:43:502616 return []
rhalavati08acd232017-04-03 07:23:282617
Sam Maiera6e76d72022-02-11 21:43:502618 import sys
2619 # We need to wait until we have an input_api object and use this
2620 # roundabout construct to import checkdeps because this file is
2621 # eval-ed and thus doesn't have __file__.
2622 original_sys_path = sys.path
2623 try:
2624 sys.path = sys.path + [
2625 input_api.os_path.join(input_api.PresubmitLocalPath(),
2626 'buildtools', 'checkdeps')
2627 ]
2628 import checkdeps
2629 from rules import Rule
2630 finally:
2631 # Restore sys.path to what it was before.
2632 sys.path = original_sys_path
[email protected]55f9f382012-07-31 11:02:182633
Sam Maiera6e76d72022-02-11 21:43:502634 added_includes = []
2635 added_imports = []
2636 added_java_imports = []
2637 for f in input_api.AffectedFiles():
2638 if _IsCPlusPlusFile(input_api, f.LocalPath()):
2639 changed_lines = [line for _, line in f.ChangedContents()]
2640 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
2641 elif _IsProtoFile(input_api, f.LocalPath()):
2642 changed_lines = [line for _, line in f.ChangedContents()]
2643 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
2644 elif _IsJavaFile(input_api, f.LocalPath()):
2645 changed_lines = [line for _, line in f.ChangedContents()]
2646 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:242647
Sam Maiera6e76d72022-02-11 21:43:502648 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
2649
2650 error_descriptions = []
2651 warning_descriptions = []
2652 error_subjects = set()
2653 warning_subjects = set()
2654
2655 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2656 added_includes):
2657 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2658 description_with_path = '%s\n %s' % (path, rule_description)
2659 if rule_type == Rule.DISALLOW:
2660 error_descriptions.append(description_with_path)
2661 error_subjects.add("#includes")
2662 else:
2663 warning_descriptions.append(description_with_path)
2664 warning_subjects.add("#includes")
2665
2666 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2667 added_imports):
2668 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2669 description_with_path = '%s\n %s' % (path, rule_description)
2670 if rule_type == Rule.DISALLOW:
2671 error_descriptions.append(description_with_path)
2672 error_subjects.add("imports")
2673 else:
2674 warning_descriptions.append(description_with_path)
2675 warning_subjects.add("imports")
2676
2677 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
2678 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
2679 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2680 description_with_path = '%s\n %s' % (path, rule_description)
2681 if rule_type == Rule.DISALLOW:
2682 error_descriptions.append(description_with_path)
2683 error_subjects.add("imports")
2684 else:
2685 warning_descriptions.append(description_with_path)
2686 warning_subjects.add("imports")
2687
2688 results = []
2689 if error_descriptions:
2690 results.append(
2691 output_api.PresubmitError(
2692 'You added one or more %s that violate checkdeps rules.' %
2693 " and ".join(error_subjects), error_descriptions))
2694 if warning_descriptions:
2695 results.append(
2696 output_api.PresubmitPromptOrNotify(
2697 'You added one or more %s of files that are temporarily\n'
2698 'allowed but being removed. Can you avoid introducing the\n'
2699 '%s? See relevant DEPS file(s) for details and contacts.' %
2700 (" and ".join(warning_subjects), "/".join(warning_subjects)),
2701 warning_descriptions))
2702 return results
[email protected]55f9f382012-07-31 11:02:182703
2704
Saagar Sanghavifceeaae2020-08-12 16:40:362705def CheckFilePermissions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502706 """Check that all files have their permissions properly set."""
2707 if input_api.platform == 'win32':
2708 return []
2709 checkperms_tool = input_api.os_path.join(input_api.PresubmitLocalPath(),
2710 'tools', 'checkperms',
2711 'checkperms.py')
2712 args = [
Bruce Dawson8a43cf72022-05-13 17:10:322713 input_api.python3_executable, checkperms_tool, '--root',
Sam Maiera6e76d72022-02-11 21:43:502714 input_api.change.RepositoryRoot()
2715 ]
2716 with input_api.CreateTemporaryFile() as file_list:
2717 for f in input_api.AffectedFiles():
2718 # checkperms.py file/directory arguments must be relative to the
2719 # repository.
2720 file_list.write((f.LocalPath() + '\n').encode('utf8'))
2721 file_list.close()
2722 args += ['--file-list', file_list.name]
2723 try:
2724 input_api.subprocess.check_output(args)
2725 return []
2726 except input_api.subprocess.CalledProcessError as error:
2727 return [
2728 output_api.PresubmitError('checkperms.py failed:',
2729 long_text=error.output.decode(
2730 'utf-8', 'ignore'))
2731 ]
[email protected]fbcafe5a2012-08-08 15:31:222732
2733
Saagar Sanghavifceeaae2020-08-12 16:40:362734def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502735 """Makes sure we don't include ui/aura/window_property.h
2736 in header files.
2737 """
2738 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2739 errors = []
2740 for f in input_api.AffectedFiles():
2741 if not f.LocalPath().endswith('.h'):
2742 continue
2743 for line_num, line in f.ChangedContents():
2744 if pattern.match(line):
2745 errors.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]c8278b32012-10-30 20:35:492746
Sam Maiera6e76d72022-02-11 21:43:502747 results = []
2748 if errors:
2749 results.append(
2750 output_api.PresubmitError(
2751 'Header files should not include ui/aura/window_property.h',
2752 errors))
2753 return results
[email protected]c8278b32012-10-30 20:35:492754
2755
Omer Katzcc77ea92021-04-26 10:23:282756def CheckNoInternalHeapIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502757 """Makes sure we don't include any headers from
2758 third_party/blink/renderer/platform/heap/impl or
2759 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
2760 third_party/blink/renderer/platform/heap
2761 """
2762 impl_pattern = input_api.re.compile(
2763 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
2764 v8_wrapper_pattern = input_api.re.compile(
2765 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"'
2766 )
Bruce Dawson40fece62022-09-16 19:58:312767 # Consistently use / as path separator to simplify the writing of regex
2768 # expressions.
Sam Maiera6e76d72022-02-11 21:43:502769 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:312770 r"^third_party/blink/renderer/platform/heap/.*",
2771 f.LocalPath().replace(input_api.os_path.sep, '/'))
Sam Maiera6e76d72022-02-11 21:43:502772 errors = []
Omer Katzcc77ea92021-04-26 10:23:282773
Sam Maiera6e76d72022-02-11 21:43:502774 for f in input_api.AffectedFiles(file_filter=file_filter):
2775 for line_num, line in f.ChangedContents():
2776 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
2777 errors.append(' %s:%d' % (f.LocalPath(), line_num))
Omer Katzcc77ea92021-04-26 10:23:282778
Sam Maiera6e76d72022-02-11 21:43:502779 results = []
2780 if errors:
2781 results.append(
2782 output_api.PresubmitError(
2783 'Do not include files from third_party/blink/renderer/platform/heap/impl'
2784 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
2785 'relevant counterparts from third_party/blink/renderer/platform/heap',
2786 errors))
2787 return results
Omer Katzcc77ea92021-04-26 10:23:282788
2789
[email protected]70ca77752012-11-20 03:45:032790def _CheckForVersionControlConflictsInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:502791 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2792 errors = []
2793 for line_num, line in f.ChangedContents():
2794 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
2795 # First-level headers in markdown look a lot like version control
2796 # conflict markers. http://daringfireball.net/projects/markdown/basics
2797 continue
2798 if pattern.match(line):
2799 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2800 return errors
[email protected]70ca77752012-11-20 03:45:032801
2802
Saagar Sanghavifceeaae2020-08-12 16:40:362803def CheckForVersionControlConflicts(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502804 """Usually this is not intentional and will cause a compile failure."""
2805 errors = []
2806 for f in input_api.AffectedFiles():
2807 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
[email protected]70ca77752012-11-20 03:45:032808
Sam Maiera6e76d72022-02-11 21:43:502809 results = []
2810 if errors:
2811 results.append(
2812 output_api.PresubmitError(
2813 'Version control conflict markers found, please resolve.',
2814 errors))
2815 return results
[email protected]70ca77752012-11-20 03:45:032816
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202817
Saagar Sanghavifceeaae2020-08-12 16:40:362818def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502819 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2820 errors = []
2821 for f in input_api.AffectedFiles():
2822 for line_num, line in f.ChangedContents():
2823 if pattern.search(line):
2824 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
estadee17314a02017-01-12 16:22:162825
Sam Maiera6e76d72022-02-11 21:43:502826 results = []
2827 if errors:
2828 results.append(
2829 output_api.PresubmitPromptWarning(
2830 'Found Google support URL addressed by answer number. Please replace '
2831 'with a p= identifier instead. See crbug.com/679462\n',
2832 errors))
2833 return results
estadee17314a02017-01-12 16:22:162834
[email protected]70ca77752012-11-20 03:45:032835
Saagar Sanghavifceeaae2020-08-12 16:40:362836def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502837 def FilterFile(affected_file):
2838 """Filter function for use with input_api.AffectedSourceFiles,
2839 below. This filters out everything except non-test files from
2840 top-level directories that generally speaking should not hard-code
2841 service URLs (e.g. src/android_webview/, src/content/ and others).
2842 """
2843 return input_api.FilterSourceFile(
2844 affected_file,
Bruce Dawson40fece62022-09-16 19:58:312845 files_to_check=[r'^(android_webview|base|content|net)/.*'],
Sam Maiera6e76d72022-02-11 21:43:502846 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2847 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442848
Sam Maiera6e76d72022-02-11 21:43:502849 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2850 '\.(com|net)[^"]*"')
2851 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2852 pattern = input_api.re.compile(base_pattern)
2853 problems = [] # items are (filename, line_number, line)
2854 for f in input_api.AffectedSourceFiles(FilterFile):
2855 for line_num, line in f.ChangedContents():
2856 if not comment_pattern.search(line) and pattern.search(line):
2857 problems.append((f.LocalPath(), line_num, line))
[email protected]06e6d0ff2012-12-11 01:36:442858
Sam Maiera6e76d72022-02-11 21:43:502859 if problems:
2860 return [
2861 output_api.PresubmitPromptOrNotify(
2862 'Most layers below src/chrome/ should not hardcode service URLs.\n'
2863 'Are you sure this is correct?', [
2864 ' %s:%d: %s' % (problem[0], problem[1], problem[2])
2865 for problem in problems
2866 ])
2867 ]
2868 else:
2869 return []
[email protected]06e6d0ff2012-12-11 01:36:442870
2871
Saagar Sanghavifceeaae2020-08-12 16:40:362872def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502873 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
James Cook6b6597c2019-11-06 22:05:292874
Sam Maiera6e76d72022-02-11 21:43:502875 def FileFilter(affected_file):
2876 """Includes directories known to be Chrome OS only."""
2877 return input_api.FilterSourceFile(
2878 affected_file,
2879 files_to_check=(
2880 '^ash/',
2881 '^chromeos/', # Top-level src/chromeos.
2882 '.*/chromeos/', # Any path component.
2883 '^components/arc',
2884 '^components/exo'),
2885 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292886
Sam Maiera6e76d72022-02-11 21:43:502887 prefs = []
2888 priority_prefs = []
2889 for f in input_api.AffectedFiles(file_filter=FileFilter):
2890 for line_num, line in f.ChangedContents():
2891 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF',
2892 line):
2893 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2894 prefs.append(' %s' % line)
2895 if input_api.re.search(
2896 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2897 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2898 priority_prefs.append(' %s' % line)
2899
2900 results = []
2901 if (prefs):
2902 results.append(
2903 output_api.PresubmitPromptWarning(
2904 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2905 'by browser sync settings. If these prefs should be controlled by OS '
2906 'sync settings use SYNCABLE_OS_PREF instead.\n' +
2907 '\n'.join(prefs)))
2908 if (priority_prefs):
2909 results.append(
2910 output_api.PresubmitPromptWarning(
2911 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2912 'controlled by browser sync settings. If these prefs should be '
2913 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2914 'instead.\n' + '\n'.join(prefs)))
2915 return results
James Cook6b6597c2019-11-06 22:05:292916
2917
Saagar Sanghavifceeaae2020-08-12 16:40:362918def CheckNoAbbreviationInPngFileName(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502919 """Makes sure there are no abbreviations in the name of PNG files.
2920 The native_client_sdk directory is excluded because it has auto-generated PNG
2921 files for documentation.
2922 """
2923 errors = []
Yuanqing Zhu9eef02832022-12-04 14:42:172924 files_to_check = [r'.*\.png$']
Bruce Dawson40fece62022-09-16 19:58:312925 files_to_skip = [r'^native_client_sdk/',
2926 r'^services/test/',
2927 r'^third_party/blink/web_tests/',
Bruce Dawson3db456212022-05-02 05:34:182928 ]
Sam Maiera6e76d72022-02-11 21:43:502929 file_filter = lambda f: input_api.FilterSourceFile(
2930 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Yuanqing Zhu9eef02832022-12-04 14:42:172931 abbreviation = input_api.re.compile('.+_[a-z]\.png|.+_[a-z]_.*\.png')
Sam Maiera6e76d72022-02-11 21:43:502932 for f in input_api.AffectedFiles(include_deletes=False,
2933 file_filter=file_filter):
Yuanqing Zhu9eef02832022-12-04 14:42:172934 file_name = input_api.os_path.split(f.LocalPath())[1]
2935 if abbreviation.search(file_name):
2936 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272937
Sam Maiera6e76d72022-02-11 21:43:502938 results = []
2939 if errors:
2940 results.append(
2941 output_api.PresubmitError(
2942 'The name of PNG files should not have abbreviations. \n'
2943 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2944 'Contact [email protected] if you have questions.', errors))
2945 return results
[email protected]d2530012013-01-25 16:39:272946
Evan Stade7cd4a2c2022-08-04 23:37:252947def CheckNoProductIconsAddedToPublicRepo(input_api, output_api):
2948 """Heuristically identifies product icons based on their file name and reminds
2949 contributors not to add them to the Chromium repository.
2950 """
2951 errors = []
2952 files_to_check = [r'.*google.*\.png$|.*google.*\.svg$|.*google.*\.icon$']
2953 file_filter = lambda f: input_api.FilterSourceFile(
2954 f, files_to_check=files_to_check)
2955 for f in input_api.AffectedFiles(include_deletes=False,
2956 file_filter=file_filter):
2957 errors.append(' %s' % f.LocalPath())
2958
2959 results = []
2960 if errors:
Bruce Dawson3bcf0c92022-08-12 00:03:082961 # Give warnings instead of errors on presubmit --all and presubmit
2962 # --files.
2963 message_type = (output_api.PresubmitNotifyResult if input_api.no_diffs
2964 else output_api.PresubmitError)
Evan Stade7cd4a2c2022-08-04 23:37:252965 results.append(
Bruce Dawson3bcf0c92022-08-12 00:03:082966 message_type(
Evan Stade7cd4a2c2022-08-04 23:37:252967 'Trademarked images should not be added to the public repo. '
2968 'See crbug.com/944754', errors))
2969 return results
2970
[email protected]d2530012013-01-25 16:39:272971
Daniel Cheng4dcdb6b2017-04-13 08:30:172972def _ExtractAddRulesFromParsedDeps(parsed_deps):
Sam Maiera6e76d72022-02-11 21:43:502973 """Extract the rules that add dependencies from a parsed DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172974
Sam Maiera6e76d72022-02-11 21:43:502975 Args:
2976 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2977 add_rules = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172978 add_rules.update([
Sam Maiera6e76d72022-02-11 21:43:502979 rule[1:] for rule in parsed_deps.get('include_rules', [])
Daniel Cheng4dcdb6b2017-04-13 08:30:172980 if rule.startswith('+') or rule.startswith('!')
2981 ])
Sam Maiera6e76d72022-02-11 21:43:502982 for _, rules in parsed_deps.get('specific_include_rules', {}).items():
2983 add_rules.update([
2984 rule[1:] for rule in rules
2985 if rule.startswith('+') or rule.startswith('!')
2986 ])
2987 return add_rules
Daniel Cheng4dcdb6b2017-04-13 08:30:172988
2989
2990def _ParseDeps(contents):
Sam Maiera6e76d72022-02-11 21:43:502991 """Simple helper for parsing DEPS files."""
Daniel Cheng4dcdb6b2017-04-13 08:30:172992
Sam Maiera6e76d72022-02-11 21:43:502993 # Stubs for handling special syntax in the root DEPS file.
2994 class _VarImpl:
2995 def __init__(self, local_scope):
2996 self._local_scope = local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172997
Sam Maiera6e76d72022-02-11 21:43:502998 def Lookup(self, var_name):
2999 """Implements the Var syntax."""
3000 try:
3001 return self._local_scope['vars'][var_name]
3002 except KeyError:
3003 raise Exception('Var is not defined: %s' % var_name)
Daniel Cheng4dcdb6b2017-04-13 08:30:173004
Sam Maiera6e76d72022-02-11 21:43:503005 local_scope = {}
3006 global_scope = {
3007 'Var': _VarImpl(local_scope).Lookup,
3008 'Str': str,
3009 }
Dirk Pranke1b9e06382021-05-14 01:16:223010
Sam Maiera6e76d72022-02-11 21:43:503011 exec(contents, global_scope, local_scope)
3012 return local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:173013
3014
3015def _CalculateAddedDeps(os_path, old_contents, new_contents):
Sam Maiera6e76d72022-02-11 21:43:503016 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
3017 a set of DEPS entries that we should look up.
[email protected]14a6131c2014-01-08 01:15:413018
Sam Maiera6e76d72022-02-11 21:43:503019 For a directory (rather than a specific filename) we fake a path to
3020 a specific filename by adding /DEPS. This is chosen as a file that
3021 will seldom or never be subject to per-file include_rules.
3022 """
3023 # We ignore deps entries on auto-generated directories.
3024 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:083025
Sam Maiera6e76d72022-02-11 21:43:503026 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
3027 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
Daniel Cheng4dcdb6b2017-04-13 08:30:173028
Sam Maiera6e76d72022-02-11 21:43:503029 added_deps = new_deps.difference(old_deps)
Daniel Cheng4dcdb6b2017-04-13 08:30:173030
Sam Maiera6e76d72022-02-11 21:43:503031 results = set()
3032 for added_dep in added_deps:
3033 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
3034 continue
3035 # Assume that a rule that ends in .h is a rule for a specific file.
3036 if added_dep.endswith('.h'):
3037 results.add(added_dep)
3038 else:
3039 results.add(os_path.join(added_dep, 'DEPS'))
3040 return results
[email protected]f32e2d1e2013-07-26 21:39:083041
3042
Saagar Sanghavifceeaae2020-08-12 16:40:363043def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503044 """When a dependency prefixed with + is added to a DEPS file, we
3045 want to make sure that the change is reviewed by an OWNER of the
3046 target file or directory, to avoid layering violations from being
3047 introduced. This check verifies that this happens.
3048 """
3049 # We rely on Gerrit's code-owners to check approvals.
3050 # input_api.gerrit is always set for Chromium, but other projects
3051 # might not use Gerrit.
Bruce Dawson344ab262022-06-04 11:35:103052 if not input_api.gerrit or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:503053 return []
Bruce Dawsonb357aeb2022-08-09 15:38:303054 if 'PRESUBMIT_SKIP_NETWORK' in input_api.environ:
Sam Maiera6e76d72022-02-11 21:43:503055 return []
Bruce Dawsonb357aeb2022-08-09 15:38:303056 try:
3057 if (input_api.change.issue and
3058 input_api.gerrit.IsOwnersOverrideApproved(
3059 input_api.change.issue)):
3060 # Skip OWNERS check when Owners-Override label is approved. This is
3061 # intended for global owners, trusted bots, and on-call sheriffs.
3062 # Review is still required for these changes.
3063 return []
3064 except Exception as e:
Sam Maier4cef9242022-10-03 14:21:243065 return [output_api.PresubmitPromptWarning(
3066 'Failed to retrieve owner override status - %s' % str(e))]
Edward Lesmes6fba51082021-01-20 04:20:233067
Sam Maiera6e76d72022-02-11 21:43:503068 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:243069
Bruce Dawson40fece62022-09-16 19:58:313070 # Consistently use / as path separator to simplify the writing of regex
3071 # expressions.
Sam Maiera6e76d72022-02-11 21:43:503072 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:313073 r"^third_party/blink/.*",
3074 f.LocalPath().replace(input_api.os_path.sep, '/'))
Sam Maiera6e76d72022-02-11 21:43:503075 for f in input_api.AffectedFiles(include_deletes=False,
3076 file_filter=file_filter):
3077 filename = input_api.os_path.basename(f.LocalPath())
3078 if filename == 'DEPS':
3079 virtual_depended_on_files.update(
3080 _CalculateAddedDeps(input_api.os_path,
3081 '\n'.join(f.OldContents()),
3082 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:553083
Sam Maiera6e76d72022-02-11 21:43:503084 if not virtual_depended_on_files:
3085 return []
[email protected]e871964c2013-05-13 14:14:553086
Sam Maiera6e76d72022-02-11 21:43:503087 if input_api.is_committing:
3088 if input_api.tbr:
3089 return [
3090 output_api.PresubmitNotifyResult(
3091 '--tbr was specified, skipping OWNERS check for DEPS additions'
3092 )
3093 ]
Daniel Cheng3008dc12022-05-13 04:02:113094 # TODO(dcheng): Make this generate an error on dry runs if the reviewer
3095 # is not added, to prevent review serialization.
Sam Maiera6e76d72022-02-11 21:43:503096 if input_api.dry_run:
3097 return [
3098 output_api.PresubmitNotifyResult(
3099 'This is a dry run, skipping OWNERS check for DEPS additions'
3100 )
3101 ]
3102 if not input_api.change.issue:
3103 return [
3104 output_api.PresubmitError(
3105 "DEPS approval by OWNERS check failed: this change has "
3106 "no change number, so we can't check it for approvals.")
3107 ]
3108 output = output_api.PresubmitError
[email protected]14a6131c2014-01-08 01:15:413109 else:
Sam Maiera6e76d72022-02-11 21:43:503110 output = output_api.PresubmitNotifyResult
[email protected]e871964c2013-05-13 14:14:553111
Sam Maiera6e76d72022-02-11 21:43:503112 owner_email, reviewers = (
3113 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3114 input_api, None, approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:553115
Sam Maiera6e76d72022-02-11 21:43:503116 owner_email = owner_email or input_api.change.author_email
3117
3118 approval_status = input_api.owners_client.GetFilesApprovalStatus(
3119 virtual_depended_on_files, reviewers.union([owner_email]), [])
3120 missing_files = [
3121 f for f in virtual_depended_on_files
3122 if approval_status[f] != input_api.owners_client.APPROVED
3123 ]
3124
3125 # We strip the /DEPS part that was added by
3126 # _FilesToCheckForIncomingDeps to fake a path to a file in a
3127 # directory.
3128 def StripDeps(path):
3129 start_deps = path.rfind('/DEPS')
3130 if start_deps != -1:
3131 return path[:start_deps]
3132 else:
3133 return path
3134
3135 unapproved_dependencies = [
3136 "'+%s'," % StripDeps(path) for path in missing_files
3137 ]
3138
3139 if unapproved_dependencies:
3140 output_list = [
3141 output(
3142 'You need LGTM from owners of depends-on paths in DEPS that were '
3143 'modified in this CL:\n %s' %
3144 '\n '.join(sorted(unapproved_dependencies)))
3145 ]
3146 suggested_owners = input_api.owners_client.SuggestOwners(
3147 missing_files, exclude=[owner_email])
3148 output_list.append(
3149 output('Suggested missing target path OWNERS:\n %s' %
3150 '\n '.join(suggested_owners or [])))
3151 return output_list
3152
3153 return []
[email protected]e871964c2013-05-13 14:14:553154
3155
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493156# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:363157def CheckSpamLogging(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503158 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3159 files_to_skip = (
3160 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3161 input_api.DEFAULT_FILES_TO_SKIP + (
Jaewon Jung2f323bb2022-12-07 23:55:013162 r"^base/fuchsia/scoped_fx_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313163 r"^base/logging\.h$",
3164 r"^base/logging\.cc$",
3165 r"^base/task/thread_pool/task_tracker\.cc$",
3166 r"^chrome/app/chrome_main_delegate\.cc$",
Yao Li359937b2023-02-15 23:43:033167 r"^chrome/browser/ash/arc/enterprise/cert_store/arc_cert_installer\.cc$",
3168 r"^chrome/browser/ash/policy/remote_commands/user_command_arc_job\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313169 r"^chrome/browser/chrome_browser_main\.cc$",
3170 r"^chrome/browser/ui/startup/startup_browser_creator\.cc$",
3171 r"^chrome/browser/browser_switcher/bho/.*",
3172 r"^chrome/browser/diagnostics/diagnostics_writer\.cc$",
3173 r"^chrome/chrome_cleaner/.*",
3174 r"^chrome/chrome_elf/dll_hash/dll_hash_main\.cc$",
3175 r"^chrome/installer/setup/.*",
3176 r"^chromecast/",
Vigen Issahhanjane2d93822023-06-30 15:57:203177 r"^components/cast",
Bruce Dawson40fece62022-09-16 19:58:313178 r"^components/media_control/renderer/media_playback_options\.cc$",
Salma Elmahallawy52976452023-01-27 17:04:493179 r"^components/policy/core/common/policy_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313180 r"^components/viz/service/display/"
Sam Maiera6e76d72022-02-11 21:43:503181 r"overlay_strategy_underlay_cast\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313182 r"^components/zucchini/.*",
Sam Maiera6e76d72022-02-11 21:43:503183 # TODO(peter): Remove exception. https://crbug.com/534537
Bruce Dawson40fece62022-09-16 19:58:313184 r"^content/browser/notifications/"
Sam Maiera6e76d72022-02-11 21:43:503185 r"notification_event_dispatcher_impl\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313186 r"^content/common/gpu/client/gl_helper_benchmark\.cc$",
3187 r"^courgette/courgette_minimal_tool\.cc$",
3188 r"^courgette/courgette_tool\.cc$",
3189 r"^extensions/renderer/logging_native_handler\.cc$",
3190 r"^fuchsia_web/common/init_logging\.cc$",
3191 r"^fuchsia_web/runners/common/web_component\.cc$",
Caroline Liua7050132023-02-13 22:23:153192 r"^fuchsia_web/shell/.*\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313193 r"^headless/app/headless_shell\.cc$",
3194 r"^ipc/ipc_logging\.cc$",
3195 r"^native_client_sdk/",
3196 r"^remoting/base/logging\.h$",
3197 r"^remoting/host/.*",
3198 r"^sandbox/linux/.*",
3199 r"^storage/browser/file_system/dump_file_system\.cc$",
3200 r"^tools/",
3201 r"^ui/base/resource/data_pack\.cc$",
3202 r"^ui/aura/bench/bench_main\.cc$",
3203 r"^ui/ozone/platform/cast/",
3204 r"^ui/base/x/xwmstartupcheck/"
Sam Maiera6e76d72022-02-11 21:43:503205 r"xwmstartupcheck\.cc$"))
3206 source_file_filter = lambda x: input_api.FilterSourceFile(
3207 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:403208
Sam Maiera6e76d72022-02-11 21:43:503209 log_info = set([])
3210 printf = set([])
[email protected]85218562013-11-22 07:41:403211
Sam Maiera6e76d72022-02-11 21:43:503212 for f in input_api.AffectedSourceFiles(source_file_filter):
3213 for _, line in f.ChangedContents():
3214 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
3215 log_info.add(f.LocalPath())
3216 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
3217 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:373218
Sam Maiera6e76d72022-02-11 21:43:503219 if input_api.re.search(r"\bprintf\(", line):
3220 printf.add(f.LocalPath())
3221 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
3222 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:403223
Sam Maiera6e76d72022-02-11 21:43:503224 if log_info:
3225 return [
3226 output_api.PresubmitError(
3227 'These files spam the console log with LOG(INFO):',
3228 items=log_info)
3229 ]
3230 if printf:
3231 return [
3232 output_api.PresubmitError(
3233 'These files spam the console log with printf/fprintf:',
3234 items=printf)
3235 ]
3236 return []
[email protected]85218562013-11-22 07:41:403237
3238
Saagar Sanghavifceeaae2020-08-12 16:40:363239def CheckForAnonymousVariables(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503240 """These types are all expected to hold locks while in scope and
3241 so should never be anonymous (which causes them to be immediately
3242 destroyed)."""
3243 they_who_must_be_named = [
3244 'base::AutoLock',
3245 'base::AutoReset',
3246 'base::AutoUnlock',
3247 'SkAutoAlphaRestore',
3248 'SkAutoBitmapShaderInstall',
3249 'SkAutoBlitterChoose',
3250 'SkAutoBounderCommit',
3251 'SkAutoCallProc',
3252 'SkAutoCanvasRestore',
3253 'SkAutoCommentBlock',
3254 'SkAutoDescriptor',
3255 'SkAutoDisableDirectionCheck',
3256 'SkAutoDisableOvalCheck',
3257 'SkAutoFree',
3258 'SkAutoGlyphCache',
3259 'SkAutoHDC',
3260 'SkAutoLockColors',
3261 'SkAutoLockPixels',
3262 'SkAutoMalloc',
3263 'SkAutoMaskFreeImage',
3264 'SkAutoMutexAcquire',
3265 'SkAutoPathBoundsUpdate',
3266 'SkAutoPDFRelease',
3267 'SkAutoRasterClipValidate',
3268 'SkAutoRef',
3269 'SkAutoTime',
3270 'SkAutoTrace',
3271 'SkAutoUnref',
3272 ]
3273 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
3274 # bad: base::AutoLock(lock.get());
3275 # not bad: base::AutoLock lock(lock.get());
3276 bad_pattern = input_api.re.compile(anonymous)
3277 # good: new base::AutoLock(lock.get())
3278 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
3279 errors = []
[email protected]49aa76a2013-12-04 06:59:163280
Sam Maiera6e76d72022-02-11 21:43:503281 for f in input_api.AffectedFiles():
3282 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
3283 continue
3284 for linenum, line in f.ChangedContents():
3285 if bad_pattern.search(line) and not good_pattern.search(line):
3286 errors.append('%s:%d' % (f.LocalPath(), linenum))
[email protected]49aa76a2013-12-04 06:59:163287
Sam Maiera6e76d72022-02-11 21:43:503288 if errors:
3289 return [
3290 output_api.PresubmitError(
3291 'These lines create anonymous variables that need to be named:',
3292 items=errors)
3293 ]
3294 return []
[email protected]49aa76a2013-12-04 06:59:163295
3296
Saagar Sanghavifceeaae2020-08-12 16:40:363297def CheckUniquePtrOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503298 # Returns whether |template_str| is of the form <T, U...> for some types T
3299 # and U. Assumes that |template_str| is already in the form <...>.
3300 def HasMoreThanOneArg(template_str):
3301 # Level of <...> nesting.
3302 nesting = 0
3303 for c in template_str:
3304 if c == '<':
3305 nesting += 1
3306 elif c == '>':
3307 nesting -= 1
3308 elif c == ',' and nesting == 1:
3309 return True
3310 return False
Vaclav Brozekb7fadb692018-08-30 06:39:533311
Sam Maiera6e76d72022-02-11 21:43:503312 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3313 sources = lambda affected_file: input_api.FilterSourceFile(
3314 affected_file,
3315 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3316 DEFAULT_FILES_TO_SKIP),
3317 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:553318
Sam Maiera6e76d72022-02-11 21:43:503319 # Pattern to capture a single "<...>" block of template arguments. It can
3320 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
3321 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
3322 # latter would likely require counting that < and > match, which is not
3323 # expressible in regular languages. Should the need arise, one can introduce
3324 # limited counting (matching up to a total number of nesting depth), which
3325 # should cover all practical cases for already a low nesting limit.
3326 template_arg_pattern = (
3327 r'<[^>]*' # Opening block of <.
3328 r'>([^<]*>)?') # Closing block of >.
3329 # Prefix expressing that whatever follows is not already inside a <...>
3330 # block.
3331 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
3332 null_construct_pattern = input_api.re.compile(
3333 not_inside_template_arg_pattern + r'\bstd::unique_ptr' +
3334 template_arg_pattern + r'\(\)')
Vaclav Brozeka54c528b2018-04-06 19:23:553335
Sam Maiera6e76d72022-02-11 21:43:503336 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
3337 template_arg_no_array_pattern = (
3338 r'<[^>]*[^]]' # Opening block of <.
3339 r'>([^(<]*[^]]>)?') # Closing block of >.
3340 # Prefix saying that what follows is the start of an expression.
3341 start_of_expr_pattern = r'(=|\breturn|^)\s*'
3342 # Suffix saying that what follows are call parentheses with a non-empty list
3343 # of arguments.
3344 nonempty_arg_list_pattern = r'\(([^)]|$)'
3345 # Put the template argument into a capture group for deeper examination later.
3346 return_construct_pattern = input_api.re.compile(
3347 start_of_expr_pattern + r'std::unique_ptr' + '(?P<template_arg>' +
3348 template_arg_no_array_pattern + ')' + nonempty_arg_list_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:553349
Sam Maiera6e76d72022-02-11 21:43:503350 problems_constructor = []
3351 problems_nullptr = []
3352 for f in input_api.AffectedSourceFiles(sources):
3353 for line_number, line in f.ChangedContents():
3354 # Disallow:
3355 # return std::unique_ptr<T>(foo);
3356 # bar = std::unique_ptr<T>(foo);
3357 # But allow:
3358 # return std::unique_ptr<T[]>(foo);
3359 # bar = std::unique_ptr<T[]>(foo);
3360 # And also allow cases when the second template argument is present. Those
3361 # cases cannot be handled by std::make_unique:
3362 # return std::unique_ptr<T, U>(foo);
3363 # bar = std::unique_ptr<T, U>(foo);
3364 local_path = f.LocalPath()
3365 return_construct_result = return_construct_pattern.search(line)
3366 if return_construct_result and not HasMoreThanOneArg(
3367 return_construct_result.group('template_arg')):
3368 problems_constructor.append(
3369 '%s:%d\n %s' % (local_path, line_number, line.strip()))
3370 # Disallow:
3371 # std::unique_ptr<T>()
3372 if null_construct_pattern.search(line):
3373 problems_nullptr.append(
3374 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Vaclav Brozek851d9602018-04-04 16:13:053375
Sam Maiera6e76d72022-02-11 21:43:503376 errors = []
3377 if problems_nullptr:
3378 errors.append(
3379 output_api.PresubmitPromptWarning(
3380 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
3381 problems_nullptr))
3382 if problems_constructor:
3383 errors.append(
3384 output_api.PresubmitError(
3385 'The following files use explicit std::unique_ptr constructor. '
3386 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
3387 'std::make_unique is not an option.', problems_constructor))
3388 return errors
Peter Kasting4844e46e2018-02-23 07:27:103389
3390
Saagar Sanghavifceeaae2020-08-12 16:40:363391def CheckUserActionUpdate(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503392 """Checks if any new user action has been added."""
3393 if any('actions.xml' == input_api.os_path.basename(f)
3394 for f in input_api.LocalPaths()):
3395 # If actions.xml is already included in the changelist, the PRESUBMIT
3396 # for actions.xml will do a more complete presubmit check.
3397 return []
3398
3399 file_inclusion_pattern = [r'.*\.(cc|mm)$']
3400 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3401 input_api.DEFAULT_FILES_TO_SKIP)
3402 file_filter = lambda f: input_api.FilterSourceFile(
3403 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
3404
3405 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
3406 current_actions = None
3407 for f in input_api.AffectedFiles(file_filter=file_filter):
3408 for line_num, line in f.ChangedContents():
3409 match = input_api.re.search(action_re, line)
3410 if match:
3411 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
3412 # loaded only once.
3413 if not current_actions:
Bruce Dawson6cb2d4d2023-03-01 21:35:093414 with open('tools/metrics/actions/actions.xml',
3415 encoding='utf-8') as actions_f:
Sam Maiera6e76d72022-02-11 21:43:503416 current_actions = actions_f.read()
3417 # Search for the matched user action name in |current_actions|.
3418 for action_name in match.groups():
3419 action = 'name="{0}"'.format(action_name)
3420 if action not in current_actions:
3421 return [
3422 output_api.PresubmitPromptWarning(
3423 'File %s line %d: %s is missing in '
3424 'tools/metrics/actions/actions.xml. Please run '
3425 'tools/metrics/actions/extract_actions.py to update.'
3426 % (f.LocalPath(), line_num, action_name))
3427 ]
[email protected]999261d2014-03-03 20:08:083428 return []
3429
[email protected]999261d2014-03-03 20:08:083430
Daniel Cheng13ca61a882017-08-25 15:11:253431def _ImportJSONCommentEater(input_api):
Sam Maiera6e76d72022-02-11 21:43:503432 import sys
3433 sys.path = sys.path + [
3434 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3435 'json_comment_eater')
3436 ]
3437 import json_comment_eater
3438 return json_comment_eater
Daniel Cheng13ca61a882017-08-25 15:11:253439
3440
[email protected]99171a92014-06-03 08:44:473441def _GetJSONParseError(input_api, filename, eat_comments=True):
dchenge07de812016-06-20 19:27:173442 try:
Sam Maiera6e76d72022-02-11 21:43:503443 contents = input_api.ReadFile(filename)
3444 if eat_comments:
3445 json_comment_eater = _ImportJSONCommentEater(input_api)
3446 contents = json_comment_eater.Nom(contents)
dchenge07de812016-06-20 19:27:173447
Sam Maiera6e76d72022-02-11 21:43:503448 input_api.json.loads(contents)
3449 except ValueError as e:
3450 return e
Andrew Grieve4deedb12022-02-03 21:34:503451 return None
3452
3453
Sam Maiera6e76d72022-02-11 21:43:503454def _GetIDLParseError(input_api, filename):
3455 try:
3456 contents = input_api.ReadFile(filename)
Devlin Croninf7582a12022-04-21 21:14:283457 for i, char in enumerate(contents):
Daniel Chenga37c03db2022-05-12 17:20:343458 if not char.isascii():
3459 return (
3460 'Non-ascii character "%s" (ord %d) found at offset %d.' %
3461 (char, ord(char), i))
Sam Maiera6e76d72022-02-11 21:43:503462 idl_schema = input_api.os_path.join(input_api.PresubmitLocalPath(),
3463 'tools', 'json_schema_compiler',
3464 'idl_schema.py')
3465 process = input_api.subprocess.Popen(
Bruce Dawson679fb082022-04-14 00:47:283466 [input_api.python3_executable, idl_schema],
Sam Maiera6e76d72022-02-11 21:43:503467 stdin=input_api.subprocess.PIPE,
3468 stdout=input_api.subprocess.PIPE,
3469 stderr=input_api.subprocess.PIPE,
3470 universal_newlines=True)
3471 (_, error) = process.communicate(input=contents)
3472 return error or None
3473 except ValueError as e:
3474 return e
agrievef32bcc72016-04-04 14:57:403475
agrievef32bcc72016-04-04 14:57:403476
Sam Maiera6e76d72022-02-11 21:43:503477def CheckParseErrors(input_api, output_api):
3478 """Check that IDL and JSON files do not contain syntax errors."""
3479 actions = {
3480 '.idl': _GetIDLParseError,
3481 '.json': _GetJSONParseError,
3482 }
3483 # Most JSON files are preprocessed and support comments, but these do not.
3484 json_no_comments_patterns = [
Bruce Dawson40fece62022-09-16 19:58:313485 r'^testing/',
Sam Maiera6e76d72022-02-11 21:43:503486 ]
3487 # Only run IDL checker on files in these directories.
3488 idl_included_patterns = [
Bruce Dawson40fece62022-09-16 19:58:313489 r'^chrome/common/extensions/api/',
3490 r'^extensions/common/api/',
Sam Maiera6e76d72022-02-11 21:43:503491 ]
agrievef32bcc72016-04-04 14:57:403492
Sam Maiera6e76d72022-02-11 21:43:503493 def get_action(affected_file):
3494 filename = affected_file.LocalPath()
3495 return actions.get(input_api.os_path.splitext(filename)[1])
agrievef32bcc72016-04-04 14:57:403496
Sam Maiera6e76d72022-02-11 21:43:503497 def FilterFile(affected_file):
3498 action = get_action(affected_file)
3499 if not action:
3500 return False
3501 path = affected_file.LocalPath()
agrievef32bcc72016-04-04 14:57:403502
Sam Maiera6e76d72022-02-11 21:43:503503 if _MatchesFile(input_api,
3504 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS, path):
3505 return False
3506
3507 if (action == _GetIDLParseError
3508 and not _MatchesFile(input_api, idl_included_patterns, path)):
3509 return False
3510 return True
3511
3512 results = []
3513 for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
3514 include_deletes=False):
3515 action = get_action(affected_file)
3516 kwargs = {}
3517 if (action == _GetJSONParseError
3518 and _MatchesFile(input_api, json_no_comments_patterns,
3519 affected_file.LocalPath())):
3520 kwargs['eat_comments'] = False
3521 parse_error = action(input_api, affected_file.AbsoluteLocalPath(),
3522 **kwargs)
3523 if parse_error:
3524 results.append(
3525 output_api.PresubmitError(
3526 '%s could not be parsed: %s' %
3527 (affected_file.LocalPath(), parse_error)))
3528 return results
3529
3530
3531def CheckJavaStyle(input_api, output_api):
3532 """Runs checkstyle on changed java files and returns errors if any exist."""
3533
3534 # Return early if no java files were modified.
3535 if not any(
3536 _IsJavaFile(input_api, f.LocalPath())
3537 for f in input_api.AffectedFiles()):
3538 return []
3539
3540 import sys
3541 original_sys_path = sys.path
3542 try:
3543 sys.path = sys.path + [
3544 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3545 'android', 'checkstyle')
3546 ]
3547 import checkstyle
3548 finally:
3549 # Restore sys.path to what it was before.
3550 sys.path = original_sys_path
3551
Andrew Grieve4f88e3ca2022-11-22 19:09:203552 return checkstyle.run_presubmit(
Sam Maiera6e76d72022-02-11 21:43:503553 input_api,
3554 output_api,
Sam Maiera6e76d72022-02-11 21:43:503555 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
3556
3557
3558def CheckPythonDevilInit(input_api, output_api):
3559 """Checks to make sure devil is initialized correctly in python scripts."""
3560 script_common_initialize_pattern = input_api.re.compile(
3561 r'script_common\.InitializeEnvironment\(')
3562 devil_env_config_initialize = input_api.re.compile(
3563 r'devil_env\.config\.Initialize\(')
3564
3565 errors = []
3566
3567 sources = lambda affected_file: input_api.FilterSourceFile(
3568 affected_file,
3569 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:313570 r'^build/android/devil_chromium\.py',
3571 r'^third_party/.*',
Sam Maiera6e76d72022-02-11 21:43:503572 )),
3573 files_to_check=[r'.*\.py$'])
3574
3575 for f in input_api.AffectedSourceFiles(sources):
3576 for line_num, line in f.ChangedContents():
3577 if (script_common_initialize_pattern.search(line)
3578 or devil_env_config_initialize.search(line)):
3579 errors.append("%s:%d" % (f.LocalPath(), line_num))
3580
3581 results = []
3582
3583 if errors:
3584 results.append(
3585 output_api.PresubmitError(
3586 'Devil initialization should always be done using '
3587 'devil_chromium.Initialize() in the chromium project, to use better '
3588 'defaults for dependencies (ex. up-to-date version of adb).',
3589 errors))
3590
3591 return results
3592
3593
3594def _MatchesFile(input_api, patterns, path):
Bruce Dawson40fece62022-09-16 19:58:313595 # Consistently use / as path separator to simplify the writing of regex
3596 # expressions.
3597 path = path.replace(input_api.os_path.sep, '/')
Sam Maiera6e76d72022-02-11 21:43:503598 for pattern in patterns:
3599 if input_api.re.search(pattern, path):
3600 return True
3601 return False
3602
3603
Daniel Chenga37c03db2022-05-12 17:20:343604def _ChangeHasSecurityReviewer(input_api, owners_file):
3605 """Returns True iff the CL has a reviewer from SECURITY_OWNERS.
Sam Maiera6e76d72022-02-11 21:43:503606
Daniel Chenga37c03db2022-05-12 17:20:343607 Args:
3608 input_api: The presubmit input API.
3609 owners_file: OWNERS file with required reviewers. Typically, this is
3610 something like ipc/SECURITY_OWNERS.
3611
3612 Note: if the presubmit is running for commit rather than for upload, this
3613 only returns True if a security reviewer has also approved the CL.
Sam Maiera6e76d72022-02-11 21:43:503614 """
Daniel Chengd88244472022-05-16 09:08:473615 # Owners-Override should bypass all additional OWNERS enforcement checks.
3616 # A CR+1 vote will still be required to land this change.
3617 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
3618 input_api.change.issue)):
3619 return True
3620
Daniel Chenga37c03db2022-05-12 17:20:343621 owner_email, reviewers = (
3622 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
Daniel Cheng3008dc12022-05-13 04:02:113623 input_api,
3624 None,
3625 approval_needed=input_api.is_committing and not input_api.dry_run))
Sam Maiera6e76d72022-02-11 21:43:503626
Daniel Chenga37c03db2022-05-12 17:20:343627 security_owners = input_api.owners_client.ListOwners(owners_file)
3628 return any(owner in reviewers for owner in security_owners)
Sam Maiera6e76d72022-02-11 21:43:503629
Daniel Chenga37c03db2022-05-12 17:20:343630
3631@dataclass
Daniel Cheng171dad8d2022-05-21 00:40:253632class _SecurityProblemWithItems:
3633 problem: str
3634 items: Sequence[str]
3635
3636
3637@dataclass
Daniel Chenga37c03db2022-05-12 17:20:343638class _MissingSecurityOwnersResult:
Daniel Cheng171dad8d2022-05-21 00:40:253639 owners_file_problems: Sequence[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:343640 has_security_sensitive_files: bool
Daniel Cheng171dad8d2022-05-21 00:40:253641 missing_reviewer_problem: Optional[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:343642
3643
3644def _FindMissingSecurityOwners(input_api,
3645 output_api,
3646 file_patterns: Sequence[str],
3647 excluded_patterns: Sequence[str],
3648 required_owners_file: str,
3649 custom_rule_function: Optional[Callable] = None
3650 ) -> _MissingSecurityOwnersResult:
3651 """Find OWNERS files missing per-file rules for security-sensitive files.
3652
3653 Args:
3654 input_api: the PRESUBMIT input API object.
3655 output_api: the PRESUBMIT output API object.
3656 file_patterns: basename patterns that require a corresponding per-file
3657 security restriction.
3658 excluded_patterns: path patterns that should be exempted from
3659 requiring a security restriction.
3660 required_owners_file: path to the required OWNERS file, e.g.
3661 ipc/SECURITY_OWNERS
3662 cc_alias: If not None, email that will be CCed automatically if the
3663 change contains security-sensitive files, as determined by
3664 `file_patterns` and `excluded_patterns`.
3665 custom_rule_function: If not None, will be called with `input_api` and
3666 the current file under consideration. Returning True will add an
3667 exact match per-file rule check for the current file.
3668 """
3669
3670 # `to_check` is a mapping of an OWNERS file path to Patterns.
3671 #
3672 # Patterns is a dictionary mapping glob patterns (suitable for use in
3673 # per-file rules) to a PatternEntry.
3674 #
Sam Maiera6e76d72022-02-11 21:43:503675 # PatternEntry is a dictionary with two keys:
3676 # - 'files': the files that are matched by this pattern
3677 # - 'rules': the per-file rules needed for this pattern
Daniel Chenga37c03db2022-05-12 17:20:343678 #
Sam Maiera6e76d72022-02-11 21:43:503679 # For example, if we expect OWNERS file to contain rules for *.mojom and
3680 # *_struct_traits*.*, Patterns might look like this:
3681 # {
3682 # '*.mojom': {
3683 # 'files': ...,
3684 # 'rules': [
3685 # 'per-file *.mojom=set noparent',
3686 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
3687 # ],
3688 # },
3689 # '*_struct_traits*.*': {
3690 # 'files': ...,
3691 # 'rules': [
3692 # 'per-file *_struct_traits*.*=set noparent',
3693 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
3694 # ],
3695 # },
3696 # }
3697 to_check = {}
Daniel Chenga37c03db2022-05-12 17:20:343698 files_to_review = []
Sam Maiera6e76d72022-02-11 21:43:503699
Daniel Chenga37c03db2022-05-12 17:20:343700 def AddPatternToCheck(file, pattern):
Sam Maiera6e76d72022-02-11 21:43:503701 owners_file = input_api.os_path.join(
Daniel Chengd88244472022-05-16 09:08:473702 input_api.os_path.dirname(file.LocalPath()), 'OWNERS')
Sam Maiera6e76d72022-02-11 21:43:503703 if owners_file not in to_check:
3704 to_check[owners_file] = {}
3705 if pattern not in to_check[owners_file]:
3706 to_check[owners_file][pattern] = {
3707 'files': [],
3708 'rules': [
Daniel Chenga37c03db2022-05-12 17:20:343709 f'per-file {pattern}=set noparent',
3710 f'per-file {pattern}=file://{required_owners_file}',
Sam Maiera6e76d72022-02-11 21:43:503711 ]
3712 }
Daniel Chenged57a162022-05-25 02:56:343713 to_check[owners_file][pattern]['files'].append(file.LocalPath())
Daniel Chenga37c03db2022-05-12 17:20:343714 files_to_review.append(file.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:503715
Daniel Chenga37c03db2022-05-12 17:20:343716 # Only enforce security OWNERS rules for a directory if that directory has a
3717 # file that matches `file_patterns`. For example, if a directory only
3718 # contains *.mojom files and no *_messages*.h files, the check should only
3719 # ensure that rules for *.mojom files are present.
3720 for file in input_api.AffectedFiles(include_deletes=False):
3721 file_basename = input_api.os_path.basename(file.LocalPath())
3722 if custom_rule_function is not None and custom_rule_function(
3723 input_api, file):
3724 AddPatternToCheck(file, file_basename)
3725 continue
Sam Maiera6e76d72022-02-11 21:43:503726
Daniel Chenga37c03db2022-05-12 17:20:343727 if any(
3728 input_api.fnmatch.fnmatch(file.LocalPath(), pattern)
3729 for pattern in excluded_patterns):
Sam Maiera6e76d72022-02-11 21:43:503730 continue
3731
3732 for pattern in file_patterns:
Daniel Chenga37c03db2022-05-12 17:20:343733 # Unlike `excluded_patterns`, `file_patterns` is checked only against the
3734 # file's basename.
3735 if input_api.fnmatch.fnmatch(file_basename, pattern):
3736 AddPatternToCheck(file, pattern)
Sam Maiera6e76d72022-02-11 21:43:503737 break
3738
Daniel Chenga37c03db2022-05-12 17:20:343739 has_security_sensitive_files = bool(to_check)
Daniel Cheng171dad8d2022-05-21 00:40:253740
3741 # Check if any newly added lines in OWNERS files intersect with required
3742 # per-file OWNERS lines. If so, ensure that a security reviewer is included.
3743 # This is a hack, but is needed because the OWNERS check (by design) ignores
3744 # new OWNERS entries; otherwise, a non-owner could add someone as a new
3745 # OWNER and have that newly-added OWNER self-approve their own addition.
3746 newly_covered_files = []
3747 for file in input_api.AffectedFiles(include_deletes=False):
3748 if not file.LocalPath() in to_check:
3749 continue
3750 for _, line in file.ChangedContents():
3751 for _, entry in to_check[file.LocalPath()].items():
3752 if line in entry['rules']:
3753 newly_covered_files.extend(entry['files'])
3754
3755 missing_reviewer_problems = None
3756 if newly_covered_files and not _ChangeHasSecurityReviewer(
Daniel Chenga37c03db2022-05-12 17:20:343757 input_api, required_owners_file):
Daniel Cheng171dad8d2022-05-21 00:40:253758 missing_reviewer_problems = _SecurityProblemWithItems(
3759 f'Review from an owner in {required_owners_file} is required for '
3760 'the following newly-added files:',
3761 [f'{file}' for file in sorted(set(newly_covered_files))])
Sam Maiera6e76d72022-02-11 21:43:503762
3763 # Go through the OWNERS files to check, filtering out rules that are already
3764 # present in that OWNERS file.
3765 for owners_file, patterns in to_check.items():
3766 try:
Daniel Cheng171dad8d2022-05-21 00:40:253767 lines = set(
3768 input_api.ReadFile(
3769 input_api.os_path.join(input_api.change.RepositoryRoot(),
3770 owners_file)).splitlines())
3771 for entry in patterns.values():
3772 entry['rules'] = [
3773 rule for rule in entry['rules'] if rule not in lines
3774 ]
Sam Maiera6e76d72022-02-11 21:43:503775 except IOError:
3776 # No OWNERS file, so all the rules are definitely missing.
3777 continue
3778
3779 # All the remaining lines weren't found in OWNERS files, so emit an error.
Daniel Cheng171dad8d2022-05-21 00:40:253780 owners_file_problems = []
Daniel Chenga37c03db2022-05-12 17:20:343781
Sam Maiera6e76d72022-02-11 21:43:503782 for owners_file, patterns in to_check.items():
3783 missing_lines = []
3784 files = []
3785 for _, entry in patterns.items():
Daniel Chenged57a162022-05-25 02:56:343786 files.extend(entry['files'])
Sam Maiera6e76d72022-02-11 21:43:503787 missing_lines.extend(entry['rules'])
Sam Maiera6e76d72022-02-11 21:43:503788 if missing_lines:
Daniel Cheng171dad8d2022-05-21 00:40:253789 joined_missing_lines = '\n'.join(line for line in missing_lines)
3790 owners_file_problems.append(
3791 _SecurityProblemWithItems(
3792 'Found missing OWNERS lines for security-sensitive files. '
3793 f'Please add the following lines to {owners_file}:\n'
3794 f'{joined_missing_lines}\n\nTo ensure security review for:',
3795 files))
Daniel Chenga37c03db2022-05-12 17:20:343796
Daniel Cheng171dad8d2022-05-21 00:40:253797 return _MissingSecurityOwnersResult(owners_file_problems,
Daniel Chenga37c03db2022-05-12 17:20:343798 has_security_sensitive_files,
Daniel Cheng171dad8d2022-05-21 00:40:253799 missing_reviewer_problems)
Daniel Chenga37c03db2022-05-12 17:20:343800
3801
3802def _CheckChangeForIpcSecurityOwners(input_api, output_api):
3803 # Whether or not a file affects IPC is (mostly) determined by a simple list
3804 # of filename patterns.
3805 file_patterns = [
3806 # Legacy IPC:
3807 '*_messages.cc',
3808 '*_messages*.h',
3809 '*_param_traits*.*',
3810 # Mojo IPC:
3811 '*.mojom',
3812 '*_mojom_traits*.*',
3813 '*_type_converter*.*',
3814 # Android native IPC:
3815 '*.aidl',
3816 ]
3817
Daniel Chenga37c03db2022-05-12 17:20:343818 excluded_patterns = [
Daniel Cheng518943f2022-05-12 22:15:463819 # These third_party directories do not contain IPCs, but contain files
3820 # matching the above patterns, which trigger false positives.
Daniel Chenga37c03db2022-05-12 17:20:343821 'third_party/crashpad/*',
3822 'third_party/blink/renderer/platform/bindings/*',
3823 'third_party/protobuf/benchmarks/python/*',
3824 'third_party/win_build_output/*',
Daniel Chengd88244472022-05-16 09:08:473825 # Enum-only mojoms used for web metrics, so no security review needed.
3826 'third_party/blink/public/mojom/use_counter/metrics/*',
Daniel Chenga37c03db2022-05-12 17:20:343827 # These files are just used to communicate between class loaders running
3828 # in the same process.
3829 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
3830 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
3831 ]
3832
3833 def IsMojoServiceManifestFile(input_api, file):
3834 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
3835 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
3836 if not manifest_pattern.search(file.LocalPath()):
3837 return False
3838
3839 if test_manifest_pattern.search(file.LocalPath()):
3840 return False
3841
3842 # All actual service manifest files should contain at least one
3843 # qualified reference to service_manager::Manifest.
3844 return any('service_manager::Manifest' in line
3845 for line in file.NewContents())
3846
3847 return _FindMissingSecurityOwners(
3848 input_api,
3849 output_api,
3850 file_patterns,
3851 excluded_patterns,
3852 'ipc/SECURITY_OWNERS',
3853 custom_rule_function=IsMojoServiceManifestFile)
3854
3855
3856def _CheckChangeForFuchsiaSecurityOwners(input_api, output_api):
3857 file_patterns = [
3858 # Component specifications.
3859 '*.cml', # Component Framework v2.
3860 '*.cmx', # Component Framework v1.
3861
3862 # Fuchsia IDL protocol specifications.
3863 '*.fidl',
3864 ]
3865
3866 # Don't check for owners files for changes in these directories.
3867 excluded_patterns = [
3868 'third_party/crashpad/*',
3869 ]
3870
3871 return _FindMissingSecurityOwners(input_api, output_api, file_patterns,
3872 excluded_patterns,
3873 'build/fuchsia/SECURITY_OWNERS')
3874
3875
3876def CheckSecurityOwners(input_api, output_api):
3877 """Checks that various security-sensitive files have an IPC OWNERS rule."""
3878 ipc_results = _CheckChangeForIpcSecurityOwners(input_api, output_api)
3879 fuchsia_results = _CheckChangeForFuchsiaSecurityOwners(
3880 input_api, output_api)
3881
3882 if ipc_results.has_security_sensitive_files:
3883 output_api.AppendCC('[email protected]')
Sam Maiera6e76d72022-02-11 21:43:503884
3885 results = []
Daniel Chenga37c03db2022-05-12 17:20:343886
Daniel Cheng171dad8d2022-05-21 00:40:253887 missing_reviewer_problems = []
3888 if ipc_results.missing_reviewer_problem:
3889 missing_reviewer_problems.append(ipc_results.missing_reviewer_problem)
3890 if fuchsia_results.missing_reviewer_problem:
3891 missing_reviewer_problems.append(
3892 fuchsia_results.missing_reviewer_problem)
Daniel Chenga37c03db2022-05-12 17:20:343893
Daniel Cheng171dad8d2022-05-21 00:40:253894 # Missing reviewers are an error unless there's no issue number
3895 # associated with this branch; in that case, the presubmit is being run
3896 # with --all or --files.
3897 #
3898 # Note that upload should never be an error; otherwise, it would be
3899 # impossible to upload changes at all.
3900 if input_api.is_committing and input_api.change.issue:
3901 make_presubmit_message = output_api.PresubmitError
3902 else:
3903 make_presubmit_message = output_api.PresubmitNotifyResult
3904 for problem in missing_reviewer_problems:
Sam Maiera6e76d72022-02-11 21:43:503905 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:253906 make_presubmit_message(problem.problem, items=problem.items))
Daniel Chenga37c03db2022-05-12 17:20:343907
Daniel Cheng171dad8d2022-05-21 00:40:253908 owners_file_problems = []
3909 owners_file_problems.extend(ipc_results.owners_file_problems)
3910 owners_file_problems.extend(fuchsia_results.owners_file_problems)
Daniel Chenga37c03db2022-05-12 17:20:343911
Daniel Cheng171dad8d2022-05-21 00:40:253912 for problem in owners_file_problems:
Daniel Cheng3008dc12022-05-13 04:02:113913 # Missing per-file rules are always an error. While swarming and caching
3914 # means that uploading a patchset with updated OWNERS files and sending
3915 # it to the CQ again should not have a large incremental cost, it is
3916 # still frustrating to discover the error only after the change has
3917 # already been uploaded.
Daniel Chenga37c03db2022-05-12 17:20:343918 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:253919 output_api.PresubmitError(problem.problem, items=problem.items))
Sam Maiera6e76d72022-02-11 21:43:503920
3921 return results
3922
3923
3924def _GetFilesUsingSecurityCriticalFunctions(input_api):
3925 """Checks affected files for changes to security-critical calls. This
3926 function checks the full change diff, to catch both additions/changes
3927 and removals.
3928
3929 Returns a dict keyed by file name, and the value is a set of detected
3930 functions.
3931 """
3932 # Map of function pretty name (displayed in an error) to the pattern to
3933 # match it with.
3934 _PATTERNS_TO_CHECK = {
3935 'content::GetServiceSandboxType<>()': 'GetServiceSandboxType\\<'
3936 }
3937 _PATTERNS_TO_CHECK = {
3938 k: input_api.re.compile(v)
3939 for k, v in _PATTERNS_TO_CHECK.items()
3940 }
3941
Sam Maiera6e76d72022-02-11 21:43:503942 # We don't want to trigger on strings within this file.
3943 def presubmit_file_filter(f):
Daniel Chenga37c03db2022-05-12 17:20:343944 return 'PRESUBMIT.py' != input_api.os_path.split(f.LocalPath())[1]
Sam Maiera6e76d72022-02-11 21:43:503945
3946 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3947 files_to_functions = {}
3948 for f in input_api.AffectedFiles(file_filter=presubmit_file_filter):
3949 diff = f.GenerateScmDiff()
3950 for line in diff.split('\n'):
3951 # Not using just RightHandSideLines() because removing a
3952 # call to a security-critical function can be just as important
3953 # as adding or changing the arguments.
3954 if line.startswith('-') or (line.startswith('+')
3955 and not line.startswith('++')):
3956 for name, pattern in _PATTERNS_TO_CHECK.items():
3957 if pattern.search(line):
3958 path = f.LocalPath()
3959 if not path in files_to_functions:
3960 files_to_functions[path] = set()
3961 files_to_functions[path].add(name)
3962 return files_to_functions
3963
3964
3965def CheckSecurityChanges(input_api, output_api):
3966 """Checks that changes involving security-critical functions are reviewed
3967 by the security team.
3968 """
3969 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3970 if not len(files_to_functions):
3971 return []
3972
Sam Maiera6e76d72022-02-11 21:43:503973 owners_file = 'ipc/SECURITY_OWNERS'
Daniel Chenga37c03db2022-05-12 17:20:343974 if _ChangeHasSecurityReviewer(input_api, owners_file):
Sam Maiera6e76d72022-02-11 21:43:503975 return []
3976
Daniel Chenga37c03db2022-05-12 17:20:343977 msg = 'The following files change calls to security-sensitive functions\n' \
Sam Maiera6e76d72022-02-11 21:43:503978 'that need to be reviewed by {}.\n'.format(owners_file)
3979 for path, names in files_to_functions.items():
3980 msg += ' {}\n'.format(path)
3981 for name in names:
3982 msg += ' {}\n'.format(name)
3983 msg += '\n'
3984
3985 if input_api.is_committing:
3986 output = output_api.PresubmitError
Mohamed Heikale217fc852020-07-06 19:44:033987 else:
Sam Maiera6e76d72022-02-11 21:43:503988 output = output_api.PresubmitNotifyResult
3989 return [output(msg)]
3990
3991
3992def CheckSetNoParent(input_api, output_api):
3993 """Checks that set noparent is only used together with an OWNERS file in
3994 //build/OWNERS.setnoparent (see also
3995 //docs/code_reviews.md#owners-files-details)
3996 """
3997 # Return early if no OWNERS files were modified.
3998 if not any(f.LocalPath().endswith('OWNERS')
3999 for f in input_api.AffectedFiles(include_deletes=False)):
4000 return []
4001
4002 errors = []
4003
4004 allowed_owners_files_file = 'build/OWNERS.setnoparent'
4005 allowed_owners_files = set()
Bruce Dawson58a45d22023-02-27 11:24:164006 with open(allowed_owners_files_file, 'r', encoding='utf-8') as f:
Sam Maiera6e76d72022-02-11 21:43:504007 for line in f:
4008 line = line.strip()
4009 if not line or line.startswith('#'):
4010 continue
4011 allowed_owners_files.add(line)
4012
4013 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
4014
4015 for f in input_api.AffectedFiles(include_deletes=False):
4016 if not f.LocalPath().endswith('OWNERS'):
4017 continue
4018
4019 found_owners_files = set()
4020 found_set_noparent_lines = dict()
4021
4022 # Parse the OWNERS file.
4023 for lineno, line in enumerate(f.NewContents(), 1):
4024 line = line.strip()
4025 if line.startswith('set noparent'):
4026 found_set_noparent_lines[''] = lineno
4027 if line.startswith('file://'):
4028 if line in allowed_owners_files:
4029 found_owners_files.add('')
4030 if line.startswith('per-file'):
4031 match = per_file_pattern.match(line)
4032 if match:
4033 glob = match.group(1).strip()
4034 directive = match.group(2).strip()
4035 if directive == 'set noparent':
4036 found_set_noparent_lines[glob] = lineno
4037 if directive.startswith('file://'):
4038 if directive in allowed_owners_files:
4039 found_owners_files.add(glob)
4040
4041 # Check that every set noparent line has a corresponding file:// line
4042 # listed in build/OWNERS.setnoparent. An exception is made for top level
4043 # directories since src/OWNERS shouldn't review them.
Bruce Dawson6bb0d672022-04-06 15:13:494044 linux_path = f.LocalPath().replace(input_api.os_path.sep, '/')
4045 if (linux_path.count('/') != 1
4046 and (not linux_path in _EXCLUDED_SET_NO_PARENT_PATHS)):
Sam Maiera6e76d72022-02-11 21:43:504047 for set_noparent_line in found_set_noparent_lines:
4048 if set_noparent_line in found_owners_files:
4049 continue
4050 errors.append(' %s:%d' %
Bruce Dawson6bb0d672022-04-06 15:13:494051 (linux_path,
Sam Maiera6e76d72022-02-11 21:43:504052 found_set_noparent_lines[set_noparent_line]))
4053
4054 results = []
4055 if errors:
4056 if input_api.is_committing:
4057 output = output_api.PresubmitError
4058 else:
4059 output = output_api.PresubmitPromptWarning
4060 results.append(
4061 output(
4062 'Found the following "set noparent" restrictions in OWNERS files that '
4063 'do not include owners from build/OWNERS.setnoparent:',
4064 long_text='\n\n'.join(errors)))
4065 return results
4066
4067
4068def CheckUselessForwardDeclarations(input_api, output_api):
4069 """Checks that added or removed lines in non third party affected
4070 header files do not lead to new useless class or struct forward
4071 declaration.
4072 """
4073 results = []
4074 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
4075 input_api.re.MULTILINE)
4076 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
4077 input_api.re.MULTILINE)
4078 for f in input_api.AffectedFiles(include_deletes=False):
4079 if (f.LocalPath().startswith('third_party')
4080 and not f.LocalPath().startswith('third_party/blink')
4081 and not f.LocalPath().startswith('third_party\\blink')):
4082 continue
4083
4084 if not f.LocalPath().endswith('.h'):
4085 continue
4086
4087 contents = input_api.ReadFile(f)
4088 fwd_decls = input_api.re.findall(class_pattern, contents)
4089 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
4090
4091 useless_fwd_decls = []
4092 for decl in fwd_decls:
4093 count = sum(1 for _ in input_api.re.finditer(
4094 r'\b%s\b' % input_api.re.escape(decl), contents))
4095 if count == 1:
4096 useless_fwd_decls.append(decl)
4097
4098 if not useless_fwd_decls:
4099 continue
4100
4101 for line in f.GenerateScmDiff().splitlines():
4102 if (line.startswith('-') and not line.startswith('--')
4103 or line.startswith('+') and not line.startswith('++')):
4104 for decl in useless_fwd_decls:
4105 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
4106 results.append(
4107 output_api.PresubmitPromptWarning(
4108 '%s: %s forward declaration is no longer needed'
4109 % (f.LocalPath(), decl)))
4110 useless_fwd_decls.remove(decl)
4111
4112 return results
4113
4114
4115def _CheckAndroidDebuggableBuild(input_api, output_api):
4116 """Checks that code uses BuildInfo.isDebugAndroid() instead of
4117 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
4118 this is a debuggable build of Android.
4119 """
4120 build_type_check_pattern = input_api.re.compile(
4121 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
4122
4123 errors = []
4124
4125 sources = lambda affected_file: input_api.FilterSourceFile(
4126 affected_file,
4127 files_to_skip=(
4128 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4129 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314130 r"^android_webview/support_library/boundary_interfaces/",
4131 r"^chrome/android/webapk/.*",
4132 r'^third_party/.*',
4133 r"tools/android/customtabs_benchmark/.*",
4134 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504135 )),
4136 files_to_check=[r'.*\.java$'])
4137
4138 for f in input_api.AffectedSourceFiles(sources):
4139 for line_num, line in f.ChangedContents():
4140 if build_type_check_pattern.search(line):
4141 errors.append("%s:%d" % (f.LocalPath(), line_num))
4142
4143 results = []
4144
4145 if errors:
4146 results.append(
4147 output_api.PresubmitPromptWarning(
4148 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
4149 ' Please use BuildInfo.isDebugAndroid() instead.', errors))
4150
4151 return results
4152
4153# TODO: add unit tests
4154def _CheckAndroidToastUsage(input_api, output_api):
4155 """Checks that code uses org.chromium.ui.widget.Toast instead of
4156 android.widget.Toast (Chromium Toast doesn't force hardware
4157 acceleration on low-end devices, saving memory).
4158 """
4159 toast_import_pattern = input_api.re.compile(
4160 r'^import android\.widget\.Toast;$')
4161
4162 errors = []
4163
4164 sources = lambda affected_file: input_api.FilterSourceFile(
4165 affected_file,
4166 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
Bruce Dawson40fece62022-09-16 19:58:314167 DEFAULT_FILES_TO_SKIP + (r'^chromecast/.*',
4168 r'^remoting/.*')),
Sam Maiera6e76d72022-02-11 21:43:504169 files_to_check=[r'.*\.java$'])
4170
4171 for f in input_api.AffectedSourceFiles(sources):
4172 for line_num, line in f.ChangedContents():
4173 if toast_import_pattern.search(line):
4174 errors.append("%s:%d" % (f.LocalPath(), line_num))
4175
4176 results = []
4177
4178 if errors:
4179 results.append(
4180 output_api.PresubmitError(
4181 'android.widget.Toast usage is detected. Android toasts use hardware'
4182 ' acceleration, and can be\ncostly on low-end devices. Please use'
4183 ' org.chromium.ui.widget.Toast instead.\n'
4184 'Contact [email protected] if you have any questions.',
4185 errors))
4186
4187 return results
4188
4189
4190def _CheckAndroidCrLogUsage(input_api, output_api):
4191 """Checks that new logs using org.chromium.base.Log:
4192 - Are using 'TAG' as variable name for the tags (warn)
4193 - Are using a tag that is shorter than 20 characters (error)
4194 """
4195
4196 # Do not check format of logs in the given files
4197 cr_log_check_excluded_paths = [
4198 # //chrome/android/webapk cannot depend on //base
Bruce Dawson40fece62022-09-16 19:58:314199 r"^chrome/android/webapk/.*",
Sam Maiera6e76d72022-02-11 21:43:504200 # WebView license viewer code cannot depend on //base; used in stub APK.
Bruce Dawson40fece62022-09-16 19:58:314201 r"^android_webview/glue/java/src/com/android/"
4202 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504203 # The customtabs_benchmark is a small app that does not depend on Chromium
4204 # java pieces.
Bruce Dawson40fece62022-09-16 19:58:314205 r"tools/android/customtabs_benchmark/.*",
Sam Maiera6e76d72022-02-11 21:43:504206 ]
4207
4208 cr_log_import_pattern = input_api.re.compile(
4209 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
4210 class_in_base_pattern = input_api.re.compile(
4211 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
4212 has_some_log_import_pattern = input_api.re.compile(r'^import .*\.Log;$',
4213 input_api.re.MULTILINE)
4214 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
4215 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
4216 log_decl_pattern = input_api.re.compile(
4217 r'static final String TAG = "(?P<name>(.*))"')
4218 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
4219
4220 REF_MSG = ('See docs/android_logging.md for more info.')
4221 sources = lambda x: input_api.FilterSourceFile(
4222 x,
4223 files_to_check=[r'.*\.java$'],
4224 files_to_skip=cr_log_check_excluded_paths)
4225
4226 tag_decl_errors = []
4227 tag_length_errors = []
4228 tag_errors = []
4229 tag_with_dot_errors = []
4230 util_log_errors = []
4231
4232 for f in input_api.AffectedSourceFiles(sources):
4233 file_content = input_api.ReadFile(f)
4234 has_modified_logs = False
4235 # Per line checks
4236 if (cr_log_import_pattern.search(file_content)
4237 or (class_in_base_pattern.search(file_content)
4238 and not has_some_log_import_pattern.search(file_content))):
4239 # Checks to run for files using cr log
4240 for line_num, line in f.ChangedContents():
4241 if rough_log_decl_pattern.search(line):
4242 has_modified_logs = True
4243
4244 # Check if the new line is doing some logging
4245 match = log_call_pattern.search(line)
4246 if match:
4247 has_modified_logs = True
4248
4249 # Make sure it uses "TAG"
4250 if not match.group('tag') == 'TAG':
4251 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
4252 else:
4253 # Report non cr Log function calls in changed lines
4254 for line_num, line in f.ChangedContents():
4255 if log_call_pattern.search(line):
4256 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
4257
4258 # Per file checks
4259 if has_modified_logs:
4260 # Make sure the tag is using the "cr" prefix and is not too long
4261 match = log_decl_pattern.search(file_content)
4262 tag_name = match.group('name') if match else None
4263 if not tag_name:
4264 tag_decl_errors.append(f.LocalPath())
4265 elif len(tag_name) > 20:
4266 tag_length_errors.append(f.LocalPath())
4267 elif '.' in tag_name:
4268 tag_with_dot_errors.append(f.LocalPath())
4269
4270 results = []
4271 if tag_decl_errors:
4272 results.append(
4273 output_api.PresubmitPromptWarning(
4274 'Please define your tags using the suggested format: .\n'
4275 '"private static final String TAG = "<package tag>".\n'
4276 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
4277 tag_decl_errors))
4278
4279 if tag_length_errors:
4280 results.append(
4281 output_api.PresubmitError(
4282 'The tag length is restricted by the system to be at most '
4283 '20 characters.\n' + REF_MSG, tag_length_errors))
4284
4285 if tag_errors:
4286 results.append(
4287 output_api.PresubmitPromptWarning(
4288 'Please use a variable named "TAG" for your log tags.\n' +
4289 REF_MSG, tag_errors))
4290
4291 if util_log_errors:
4292 results.append(
4293 output_api.PresubmitPromptWarning(
4294 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
4295 util_log_errors))
4296
4297 if tag_with_dot_errors:
4298 results.append(
4299 output_api.PresubmitPromptWarning(
4300 'Dot in log tags cause them to be elided in crash reports.\n' +
4301 REF_MSG, tag_with_dot_errors))
4302
4303 return results
4304
4305
4306def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
4307 """Checks that junit.framework.* is no longer used."""
4308 deprecated_junit_framework_pattern = input_api.re.compile(
4309 r'^import junit\.framework\..*;', input_api.re.MULTILINE)
4310 sources = lambda x: input_api.FilterSourceFile(
4311 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
4312 errors = []
4313 for f in input_api.AffectedFiles(file_filter=sources):
4314 for line_num, line in f.ChangedContents():
4315 if deprecated_junit_framework_pattern.search(line):
4316 errors.append("%s:%d" % (f.LocalPath(), line_num))
4317
4318 results = []
4319 if errors:
4320 results.append(
4321 output_api.PresubmitError(
4322 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
4323 '(org.junit.*) from //third_party/junit. Contact [email protected]'
4324 ' if you have any question.', errors))
4325 return results
4326
4327
4328def _CheckAndroidTestJUnitInheritance(input_api, output_api):
4329 """Checks that if new Java test classes have inheritance.
4330 Either the new test class is JUnit3 test or it is a JUnit4 test class
4331 with a base class, either case is undesirable.
4332 """
4333 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
4334
4335 sources = lambda x: input_api.FilterSourceFile(
4336 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
4337 errors = []
4338 for f in input_api.AffectedFiles(file_filter=sources):
4339 if not f.OldContents():
4340 class_declaration_start_flag = False
4341 for line_num, line in f.ChangedContents():
4342 if class_declaration_pattern.search(line):
4343 class_declaration_start_flag = True
4344 if class_declaration_start_flag and ' extends ' in line:
4345 errors.append('%s:%d' % (f.LocalPath(), line_num))
4346 if '{' in line:
4347 class_declaration_start_flag = False
4348
4349 results = []
4350 if errors:
4351 results.append(
4352 output_api.PresubmitPromptWarning(
4353 'The newly created files include Test classes that inherits from base'
4354 ' class. Please do not use inheritance in JUnit4 tests or add new'
4355 ' JUnit3 tests. Contact [email protected] if you have any'
4356 ' questions.', errors))
4357 return results
4358
4359
4360def _CheckAndroidTestAnnotationUsage(input_api, output_api):
4361 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
4362 deprecated_annotation_import_pattern = input_api.re.compile(
4363 r'^import android\.test\.suitebuilder\.annotation\..*;',
4364 input_api.re.MULTILINE)
4365 sources = lambda x: input_api.FilterSourceFile(
4366 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
4367 errors = []
4368 for f in input_api.AffectedFiles(file_filter=sources):
4369 for line_num, line in f.ChangedContents():
4370 if deprecated_annotation_import_pattern.search(line):
4371 errors.append("%s:%d" % (f.LocalPath(), line_num))
4372
4373 results = []
4374 if errors:
4375 results.append(
4376 output_api.PresubmitError(
4377 'Annotations in android.test.suitebuilder.annotation have been'
Mohamed Heikal3d7a94c2023-03-28 16:55:244378 ' deprecated since API level 24. Please use androidx.test.filters'
4379 ' from //third_party/androidx:androidx_test_runner_java instead.'
Sam Maiera6e76d72022-02-11 21:43:504380 ' Contact [email protected] if you have any questions.',
4381 errors))
4382 return results
4383
4384
4385def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
4386 """Checks if MDPI assets are placed in a correct directory."""
Bruce Dawson6c05e852022-07-21 15:48:514387 file_filter = lambda f: (f.LocalPath().endswith(
4388 '.png') and ('/res/drawable/'.replace('/', input_api.os_path.sep) in f.
4389 LocalPath() or '/res/drawable-ldrtl/'.replace(
4390 '/', input_api.os_path.sep) in f.LocalPath()))
Sam Maiera6e76d72022-02-11 21:43:504391 errors = []
4392 for f in input_api.AffectedFiles(include_deletes=False,
4393 file_filter=file_filter):
4394 errors.append(' %s' % f.LocalPath())
4395
4396 results = []
4397 if errors:
4398 results.append(
4399 output_api.PresubmitError(
4400 'MDPI assets should be placed in /res/drawable-mdpi/ or '
4401 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
4402 '/res/drawable-ldrtl/.\n'
4403 'Contact [email protected] if you have questions.', errors))
4404 return results
4405
4406
4407def _CheckAndroidWebkitImports(input_api, output_api):
4408 """Checks that code uses org.chromium.base.Callback instead of
4409 android.webview.ValueCallback except in the WebView glue layer
4410 and WebLayer.
4411 """
4412 valuecallback_import_pattern = input_api.re.compile(
4413 r'^import android\.webkit\.ValueCallback;$')
4414
4415 errors = []
4416
4417 sources = lambda affected_file: input_api.FilterSourceFile(
4418 affected_file,
4419 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4420 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314421 r'^android_webview/glue/.*',
4422 r'^weblayer/.*',
Sam Maiera6e76d72022-02-11 21:43:504423 )),
4424 files_to_check=[r'.*\.java$'])
4425
4426 for f in input_api.AffectedSourceFiles(sources):
4427 for line_num, line in f.ChangedContents():
4428 if valuecallback_import_pattern.search(line):
4429 errors.append("%s:%d" % (f.LocalPath(), line_num))
4430
4431 results = []
4432
4433 if errors:
4434 results.append(
4435 output_api.PresubmitError(
4436 'android.webkit.ValueCallback usage is detected outside of the glue'
4437 ' layer. To stay compatible with the support library, android.webkit.*'
4438 ' classes should only be used inside the glue layer and'
4439 ' org.chromium.base.Callback should be used instead.', errors))
4440
4441 return results
4442
4443
4444def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
4445 """Checks Android XML styles """
4446
4447 # Return early if no relevant files were modified.
4448 if not any(
4449 _IsXmlOrGrdFile(input_api, f.LocalPath())
4450 for f in input_api.AffectedFiles(include_deletes=False)):
4451 return []
4452
4453 import sys
4454 original_sys_path = sys.path
4455 try:
4456 sys.path = sys.path + [
4457 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4458 'android', 'checkxmlstyle')
4459 ]
4460 import checkxmlstyle
4461 finally:
4462 # Restore sys.path to what it was before.
4463 sys.path = original_sys_path
4464
4465 if is_check_on_upload:
4466 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
4467 else:
4468 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
4469
4470
4471def _CheckAndroidInfoBarDeprecation(input_api, output_api):
4472 """Checks Android Infobar Deprecation """
4473
4474 import sys
4475 original_sys_path = sys.path
4476 try:
4477 sys.path = sys.path + [
4478 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4479 'android', 'infobar_deprecation')
4480 ]
4481 import infobar_deprecation
4482 finally:
4483 # Restore sys.path to what it was before.
4484 sys.path = original_sys_path
4485
4486 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
4487
4488
4489class _PydepsCheckerResult:
4490 def __init__(self, cmd, pydeps_path, process, old_contents):
4491 self._cmd = cmd
4492 self._pydeps_path = pydeps_path
4493 self._process = process
4494 self._old_contents = old_contents
4495
4496 def GetError(self):
4497 """Returns an error message, or None."""
4498 import difflib
Andrew Grieved27620b62023-07-13 16:35:074499 new_contents = self._process.stdout.read().splitlines()[2:]
Sam Maiera6e76d72022-02-11 21:43:504500 if self._process.wait() != 0:
4501 # STDERR should already be printed.
4502 return 'Command failed: ' + self._cmd
Sam Maiera6e76d72022-02-11 21:43:504503 if self._old_contents != new_contents:
4504 diff = '\n'.join(
4505 difflib.context_diff(self._old_contents, new_contents))
4506 return ('File is stale: {}\n'
4507 'Diff (apply to fix):\n'
4508 '{}\n'
4509 'To regenerate, run:\n\n'
4510 ' {}').format(self._pydeps_path, diff, self._cmd)
4511 return None
4512
4513
4514class PydepsChecker:
4515 def __init__(self, input_api, pydeps_files):
4516 self._file_cache = {}
4517 self._input_api = input_api
4518 self._pydeps_files = pydeps_files
4519
4520 def _LoadFile(self, path):
4521 """Returns the list of paths within a .pydeps file relative to //."""
4522 if path not in self._file_cache:
4523 with open(path, encoding='utf-8') as f:
4524 self._file_cache[path] = f.read()
4525 return self._file_cache[path]
4526
4527 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
Gao Shenga79ebd42022-08-08 17:25:594528 """Returns an iterable of paths within the .pydep, relativized to //."""
Sam Maiera6e76d72022-02-11 21:43:504529 pydeps_data = self._LoadFile(pydeps_path)
4530 uses_gn_paths = '--gn-paths' in pydeps_data
4531 entries = (l for l in pydeps_data.splitlines()
4532 if not l.startswith('#'))
4533 if uses_gn_paths:
4534 # Paths look like: //foo/bar/baz
4535 return (e[2:] for e in entries)
4536 else:
4537 # Paths look like: path/relative/to/file.pydeps
4538 os_path = self._input_api.os_path
4539 pydeps_dir = os_path.dirname(pydeps_path)
4540 return (os_path.normpath(os_path.join(pydeps_dir, e))
4541 for e in entries)
4542
4543 def _CreateFilesToPydepsMap(self):
4544 """Returns a map of local_path -> list_of_pydeps."""
4545 ret = {}
4546 for pydep_local_path in self._pydeps_files:
4547 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
4548 ret.setdefault(path, []).append(pydep_local_path)
4549 return ret
4550
4551 def ComputeAffectedPydeps(self):
4552 """Returns an iterable of .pydeps files that might need regenerating."""
4553 affected_pydeps = set()
4554 file_to_pydeps_map = None
4555 for f in self._input_api.AffectedFiles(include_deletes=True):
4556 local_path = f.LocalPath()
4557 # Changes to DEPS can lead to .pydeps changes if any .py files are in
4558 # subrepositories. We can't figure out which files change, so re-check
4559 # all files.
4560 # Changes to print_python_deps.py affect all .pydeps.
4561 if local_path in ('DEPS', 'PRESUBMIT.py'
4562 ) or local_path.endswith('print_python_deps.py'):
4563 return self._pydeps_files
4564 elif local_path.endswith('.pydeps'):
4565 if local_path in self._pydeps_files:
4566 affected_pydeps.add(local_path)
4567 elif local_path.endswith('.py'):
4568 if file_to_pydeps_map is None:
4569 file_to_pydeps_map = self._CreateFilesToPydepsMap()
4570 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
4571 return affected_pydeps
4572
4573 def DetermineIfStaleAsync(self, pydeps_path):
4574 """Runs print_python_deps.py to see if the files is stale."""
4575 import os
4576
4577 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
4578 if old_pydeps_data:
4579 cmd = old_pydeps_data[1][1:].strip()
4580 if '--output' not in cmd:
4581 cmd += ' --output ' + pydeps_path
4582 old_contents = old_pydeps_data[2:]
4583 else:
4584 # A default cmd that should work in most cases (as long as pydeps filename
4585 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
4586 # file is empty/new.
4587 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
4588 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
4589 old_contents = []
4590 env = dict(os.environ)
4591 env['PYTHONDONTWRITEBYTECODE'] = '1'
4592 process = self._input_api.subprocess.Popen(
4593 cmd + ' --output ""',
4594 shell=True,
4595 env=env,
4596 stdout=self._input_api.subprocess.PIPE,
4597 encoding='utf-8')
4598 return _PydepsCheckerResult(cmd, pydeps_path, process, old_contents)
agrievef32bcc72016-04-04 14:57:404599
4600
Tibor Goldschwendt360793f72019-06-25 18:23:494601def _ParseGclientArgs():
Sam Maiera6e76d72022-02-11 21:43:504602 args = {}
4603 with open('build/config/gclient_args.gni', 'r') as f:
4604 for line in f:
4605 line = line.strip()
4606 if not line or line.startswith('#'):
4607 continue
4608 attribute, value = line.split('=')
4609 args[attribute.strip()] = value.strip()
4610 return args
Tibor Goldschwendt360793f72019-06-25 18:23:494611
4612
Saagar Sanghavifceeaae2020-08-12 16:40:364613def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
Sam Maiera6e76d72022-02-11 21:43:504614 """Checks if a .pydeps file needs to be regenerated."""
4615 # This check is for Python dependency lists (.pydeps files), and involves
4616 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
4617 # doesn't work on Windows and Mac, so skip it on other platforms.
4618 if not input_api.platform.startswith('linux'):
4619 return []
Erik Staabc734cd7a2021-11-23 03:11:524620
Sam Maiera6e76d72022-02-11 21:43:504621 results = []
4622 # First, check for new / deleted .pydeps.
4623 for f in input_api.AffectedFiles(include_deletes=True):
4624 # Check whether we are running the presubmit check for a file in src.
4625 # f.LocalPath is relative to repo (src, or internal repo).
4626 # os_path.exists is relative to src repo.
4627 # Therefore if os_path.exists is true, it means f.LocalPath is relative
4628 # to src and we can conclude that the pydeps is in src.
4629 if f.LocalPath().endswith('.pydeps'):
4630 if input_api.os_path.exists(f.LocalPath()):
4631 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
4632 results.append(
4633 output_api.PresubmitError(
4634 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
4635 'remove %s' % f.LocalPath()))
4636 elif f.Action() != 'D' and f.LocalPath(
4637 ) not in _ALL_PYDEPS_FILES:
4638 results.append(
4639 output_api.PresubmitError(
4640 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
4641 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:404642
Sam Maiera6e76d72022-02-11 21:43:504643 if results:
4644 return results
4645
4646 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
4647 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
4648 affected_pydeps = set(checker.ComputeAffectedPydeps())
4649 affected_android_pydeps = affected_pydeps.intersection(
4650 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
4651 if affected_android_pydeps and not is_android:
4652 results.append(
4653 output_api.PresubmitPromptOrNotify(
4654 'You have changed python files that may affect pydeps for android\n'
Gao Shenga79ebd42022-08-08 17:25:594655 'specific scripts. However, the relevant presubmit check cannot be\n'
Sam Maiera6e76d72022-02-11 21:43:504656 'run because you are not using an Android checkout. To validate that\n'
4657 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
4658 'use the android-internal-presubmit optional trybot.\n'
4659 'Possibly stale pydeps files:\n{}'.format(
4660 '\n'.join(affected_android_pydeps))))
4661
4662 all_pydeps = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
4663 pydeps_to_check = affected_pydeps.intersection(all_pydeps)
4664 # Process these concurrently, as each one takes 1-2 seconds.
4665 pydep_results = [checker.DetermineIfStaleAsync(p) for p in pydeps_to_check]
4666 for result in pydep_results:
4667 error_msg = result.GetError()
4668 if error_msg:
4669 results.append(output_api.PresubmitError(error_msg))
4670
agrievef32bcc72016-04-04 14:57:404671 return results
4672
agrievef32bcc72016-04-04 14:57:404673
Saagar Sanghavifceeaae2020-08-12 16:40:364674def CheckSingletonInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504675 """Checks to make sure no header files have |Singleton<|."""
4676
4677 def FileFilter(affected_file):
4678 # It's ok for base/memory/singleton.h to have |Singleton<|.
4679 files_to_skip = (_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
Bruce Dawson40fece62022-09-16 19:58:314680 (r"^base/memory/singleton\.h$",
4681 r"^net/quic/platform/impl/quic_singleton_impl\.h$"))
Sam Maiera6e76d72022-02-11 21:43:504682 return input_api.FilterSourceFile(affected_file,
4683 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:434684
Sam Maiera6e76d72022-02-11 21:43:504685 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
4686 files = []
4687 for f in input_api.AffectedSourceFiles(FileFilter):
4688 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx')
4689 or f.LocalPath().endswith('.hpp')
4690 or f.LocalPath().endswith('.inl')):
4691 contents = input_api.ReadFile(f)
4692 for line in contents.splitlines(False):
4693 if (not line.lstrip().startswith('//')
4694 and # Strip C++ comment.
4695 pattern.search(line)):
4696 files.append(f)
4697 break
glidere61efad2015-02-18 17:39:434698
Sam Maiera6e76d72022-02-11 21:43:504699 if files:
4700 return [
4701 output_api.PresubmitError(
4702 'Found base::Singleton<T> in the following header files.\n' +
4703 'Please move them to an appropriate source file so that the ' +
4704 'template gets instantiated in a single compilation unit.',
4705 files)
4706 ]
4707 return []
glidere61efad2015-02-18 17:39:434708
4709
[email protected]fd20b902014-05-09 02:14:534710_DEPRECATED_CSS = [
4711 # Values
4712 ( "-webkit-box", "flex" ),
4713 ( "-webkit-inline-box", "inline-flex" ),
4714 ( "-webkit-flex", "flex" ),
4715 ( "-webkit-inline-flex", "inline-flex" ),
4716 ( "-webkit-min-content", "min-content" ),
4717 ( "-webkit-max-content", "max-content" ),
4718
4719 # Properties
4720 ( "-webkit-background-clip", "background-clip" ),
4721 ( "-webkit-background-origin", "background-origin" ),
4722 ( "-webkit-background-size", "background-size" ),
4723 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:444724 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:534725
4726 # Functions
4727 ( "-webkit-gradient", "gradient" ),
4728 ( "-webkit-repeating-gradient", "repeating-gradient" ),
4729 ( "-webkit-linear-gradient", "linear-gradient" ),
4730 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
4731 ( "-webkit-radial-gradient", "radial-gradient" ),
4732 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
4733]
4734
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:204735
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:494736# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:364737def CheckNoDeprecatedCss(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504738 """ Make sure that we don't use deprecated CSS
4739 properties, functions or values. Our external
4740 documentation and iOS CSS for dom distiller
4741 (reader mode) are ignored by the hooks as it
4742 needs to be consumed by WebKit. """
4743 results = []
4744 file_inclusion_pattern = [r".+\.css$"]
4745 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
4746 input_api.DEFAULT_FILES_TO_SKIP +
4747 (r"^chrome/common/extensions/docs", r"^chrome/docs",
4748 r"^native_client_sdk"))
4749 file_filter = lambda f: input_api.FilterSourceFile(
4750 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
4751 for fpath in input_api.AffectedFiles(file_filter=file_filter):
4752 for line_num, line in fpath.ChangedContents():
4753 for (deprecated_value, value) in _DEPRECATED_CSS:
4754 if deprecated_value in line:
4755 results.append(
4756 output_api.PresubmitError(
4757 "%s:%d: Use of deprecated CSS %s, use %s instead" %
4758 (fpath.LocalPath(), line_num, deprecated_value,
4759 value)))
4760 return results
[email protected]fd20b902014-05-09 02:14:534761
mohan.reddyf21db962014-10-16 12:26:474762
Saagar Sanghavifceeaae2020-08-12 16:40:364763def CheckForRelativeIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504764 bad_files = {}
4765 for f in input_api.AffectedFiles(include_deletes=False):
4766 if (f.LocalPath().startswith('third_party')
4767 and not f.LocalPath().startswith('third_party/blink')
4768 and not f.LocalPath().startswith('third_party\\blink')):
4769 continue
rlanday6802cf632017-05-30 17:48:364770
Sam Maiera6e76d72022-02-11 21:43:504771 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
4772 continue
rlanday6802cf632017-05-30 17:48:364773
Sam Maiera6e76d72022-02-11 21:43:504774 relative_includes = [
4775 line for _, line in f.ChangedContents()
4776 if "#include" in line and "../" in line
4777 ]
4778 if not relative_includes:
4779 continue
4780 bad_files[f.LocalPath()] = relative_includes
rlanday6802cf632017-05-30 17:48:364781
Sam Maiera6e76d72022-02-11 21:43:504782 if not bad_files:
4783 return []
rlanday6802cf632017-05-30 17:48:364784
Sam Maiera6e76d72022-02-11 21:43:504785 error_descriptions = []
4786 for file_path, bad_lines in bad_files.items():
4787 error_description = file_path
4788 for line in bad_lines:
4789 error_description += '\n ' + line
4790 error_descriptions.append(error_description)
rlanday6802cf632017-05-30 17:48:364791
Sam Maiera6e76d72022-02-11 21:43:504792 results = []
4793 results.append(
4794 output_api.PresubmitError(
4795 'You added one or more relative #include paths (including "../").\n'
4796 'These shouldn\'t be used because they can be used to include headers\n'
4797 'from code that\'s not correctly specified as a dependency in the\n'
4798 'relevant BUILD.gn file(s).', error_descriptions))
rlanday6802cf632017-05-30 17:48:364799
Sam Maiera6e76d72022-02-11 21:43:504800 return results
rlanday6802cf632017-05-30 17:48:364801
Takeshi Yoshinoe387aa32017-08-02 13:16:134802
Saagar Sanghavifceeaae2020-08-12 16:40:364803def CheckForCcIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504804 """Check that nobody tries to include a cc file. It's a relatively
4805 common error which results in duplicate symbols in object
4806 files. This may not always break the build until someone later gets
4807 very confusing linking errors."""
4808 results = []
4809 for f in input_api.AffectedFiles(include_deletes=False):
4810 # We let third_party code do whatever it wants
4811 if (f.LocalPath().startswith('third_party')
4812 and not f.LocalPath().startswith('third_party/blink')
4813 and not f.LocalPath().startswith('third_party\\blink')):
4814 continue
Daniel Bratell65b033262019-04-23 08:17:064815
Sam Maiera6e76d72022-02-11 21:43:504816 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
4817 continue
Daniel Bratell65b033262019-04-23 08:17:064818
Sam Maiera6e76d72022-02-11 21:43:504819 for _, line in f.ChangedContents():
4820 if line.startswith('#include "'):
4821 included_file = line.split('"')[1]
4822 if _IsCPlusPlusFile(input_api, included_file):
4823 # The most common naming for external files with C++ code,
4824 # apart from standard headers, is to call them foo.inc, but
4825 # Chromium sometimes uses foo-inc.cc so allow that as well.
4826 if not included_file.endswith(('.h', '-inc.cc')):
4827 results.append(
4828 output_api.PresubmitError(
4829 'Only header files or .inc files should be included in other\n'
4830 'C++ files. Compiling the contents of a cc file more than once\n'
4831 'will cause duplicate information in the build which may later\n'
4832 'result in strange link_errors.\n' +
4833 f.LocalPath() + ':\n ' + line))
Daniel Bratell65b033262019-04-23 08:17:064834
Sam Maiera6e76d72022-02-11 21:43:504835 return results
Daniel Bratell65b033262019-04-23 08:17:064836
4837
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204838def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
Sam Maiera6e76d72022-02-11 21:43:504839 if not isinstance(key, ast.Str):
4840 return 'Key at line %d must be a string literal' % key.lineno
4841 if not isinstance(value, ast.Dict):
4842 return 'Value at line %d must be a dict' % value.lineno
4843 if len(value.keys) != 1:
4844 return 'Dict at line %d must have single entry' % value.lineno
4845 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
4846 return (
4847 'Entry at line %d must have a string literal \'filepath\' as key' %
4848 value.lineno)
4849 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:134850
Takeshi Yoshinoe387aa32017-08-02 13:16:134851
Sergey Ulanov4af16052018-11-08 02:41:464852def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Sam Maiera6e76d72022-02-11 21:43:504853 if not isinstance(key, ast.Str):
4854 return 'Key at line %d must be a string literal' % key.lineno
4855 if not isinstance(value, ast.List):
4856 return 'Value at line %d must be a list' % value.lineno
4857 for element in value.elts:
4858 if not isinstance(element, ast.Str):
4859 return 'Watchlist elements on line %d is not a string' % key.lineno
4860 if not email_regex.match(element.s):
4861 return ('Watchlist element on line %d doesn\'t look like a valid '
4862 + 'email: %s') % (key.lineno, element.s)
4863 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:134864
Takeshi Yoshinoe387aa32017-08-02 13:16:134865
Sergey Ulanov4af16052018-11-08 02:41:464866def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Sam Maiera6e76d72022-02-11 21:43:504867 mismatch_template = (
4868 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
4869 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:134870
Sam Maiera6e76d72022-02-11 21:43:504871 email_regex = input_api.re.compile(
4872 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
Sergey Ulanov4af16052018-11-08 02:41:464873
Sam Maiera6e76d72022-02-11 21:43:504874 ast = input_api.ast
4875 i = 0
4876 last_key = ''
4877 while True:
4878 if i >= len(wd_dict.keys):
4879 if i >= len(w_dict.keys):
4880 return None
4881 return mismatch_template % ('missing',
4882 'line %d' % w_dict.keys[i].lineno)
4883 elif i >= len(w_dict.keys):
4884 return (mismatch_template %
4885 ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:134886
Sam Maiera6e76d72022-02-11 21:43:504887 wd_key = wd_dict.keys[i]
4888 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:134889
Sam Maiera6e76d72022-02-11 21:43:504890 result = _CheckWatchlistDefinitionsEntrySyntax(wd_key,
4891 wd_dict.values[i], ast)
4892 if result is not None:
4893 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:134894
Sam Maiera6e76d72022-02-11 21:43:504895 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast,
4896 email_regex)
4897 if result is not None:
4898 return 'Bad entry in WATCHLISTS dict: %s' % result
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204899
Sam Maiera6e76d72022-02-11 21:43:504900 if wd_key.s != w_key.s:
4901 return mismatch_template % ('%s at line %d' %
4902 (wd_key.s, wd_key.lineno),
4903 '%s at line %d' %
4904 (w_key.s, w_key.lineno))
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204905
Sam Maiera6e76d72022-02-11 21:43:504906 if wd_key.s < last_key:
4907 return (
4908 'WATCHLISTS dict is not sorted lexicographically at line %d and %d'
4909 % (wd_key.lineno, w_key.lineno))
4910 last_key = wd_key.s
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204911
Sam Maiera6e76d72022-02-11 21:43:504912 i = i + 1
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204913
4914
Sergey Ulanov4af16052018-11-08 02:41:464915def _CheckWATCHLISTSSyntax(expression, input_api):
Sam Maiera6e76d72022-02-11 21:43:504916 ast = input_api.ast
4917 if not isinstance(expression, ast.Expression):
4918 return 'WATCHLISTS file must contain a valid expression'
4919 dictionary = expression.body
4920 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
4921 return 'WATCHLISTS file must have single dict with exactly two entries'
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204922
Sam Maiera6e76d72022-02-11 21:43:504923 first_key = dictionary.keys[0]
4924 first_value = dictionary.values[0]
4925 second_key = dictionary.keys[1]
4926 second_value = dictionary.values[1]
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204927
Sam Maiera6e76d72022-02-11 21:43:504928 if (not isinstance(first_key, ast.Str)
4929 or first_key.s != 'WATCHLIST_DEFINITIONS'
4930 or not isinstance(first_value, ast.Dict)):
4931 return ('The first entry of the dict in WATCHLISTS file must be '
4932 'WATCHLIST_DEFINITIONS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204933
Sam Maiera6e76d72022-02-11 21:43:504934 if (not isinstance(second_key, ast.Str) or second_key.s != 'WATCHLISTS'
4935 or not isinstance(second_value, ast.Dict)):
4936 return ('The second entry of the dict in WATCHLISTS file must be '
4937 'WATCHLISTS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204938
Sam Maiera6e76d72022-02-11 21:43:504939 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:134940
4941
Saagar Sanghavifceeaae2020-08-12 16:40:364942def CheckWATCHLISTS(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504943 for f in input_api.AffectedFiles(include_deletes=False):
4944 if f.LocalPath() == 'WATCHLISTS':
4945 contents = input_api.ReadFile(f, 'r')
Takeshi Yoshinoe387aa32017-08-02 13:16:134946
Sam Maiera6e76d72022-02-11 21:43:504947 try:
4948 # First, make sure that it can be evaluated.
4949 input_api.ast.literal_eval(contents)
4950 # Get an AST tree for it and scan the tree for detailed style checking.
4951 expression = input_api.ast.parse(contents,
4952 filename='WATCHLISTS',
4953 mode='eval')
4954 except ValueError as e:
4955 return [
4956 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4957 long_text=repr(e))
4958 ]
4959 except SyntaxError as e:
4960 return [
4961 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4962 long_text=repr(e))
4963 ]
4964 except TypeError as e:
4965 return [
4966 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4967 long_text=repr(e))
4968 ]
Takeshi Yoshinoe387aa32017-08-02 13:16:134969
Sam Maiera6e76d72022-02-11 21:43:504970 result = _CheckWATCHLISTSSyntax(expression, input_api)
4971 if result is not None:
4972 return [output_api.PresubmitError(result)]
4973 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134974
Sam Maiera6e76d72022-02-11 21:43:504975 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:134976
Sean Kaucb7c9b32022-10-25 21:25:524977def CheckGnRebasePath(input_api, output_api):
4978 """Checks that target_gen_dir is not used wtih "//" in rebase_path().
4979
4980 Developers should use root_build_dir instead of "//" when using target_gen_dir because
4981 Chromium is sometimes built outside of the source tree.
4982 """
4983
4984 def gn_files(f):
4985 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
4986
4987 rebase_path_regex = input_api.re.compile(r'rebase_path\(("\$target_gen_dir"|target_gen_dir), ("/"|"//")\)')
4988 problems = []
4989 for f in input_api.AffectedSourceFiles(gn_files):
4990 for line_num, line in f.ChangedContents():
4991 if rebase_path_regex.search(line):
4992 problems.append(
4993 'Absolute path in rebase_path() in %s:%d' %
4994 (f.LocalPath(), line_num))
4995
4996 if problems:
4997 return [
4998 output_api.PresubmitPromptWarning(
4999 'Using an absolute path in rebase_path()',
5000 items=sorted(problems),
5001 long_text=(
5002 'rebase_path() should use root_build_dir instead of "/" ',
5003 'since builds can be initiated from outside of the source ',
5004 'root.'))
5005 ]
5006 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:135007
Andrew Grieve1b290e4a22020-11-24 20:07:015008def CheckGnGlobForward(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505009 """Checks that forward_variables_from(invoker, "*") follows best practices.
Andrew Grieve1b290e4a22020-11-24 20:07:015010
Sam Maiera6e76d72022-02-11 21:43:505011 As documented at //build/docs/writing_gn_templates.md
5012 """
Andrew Grieve1b290e4a22020-11-24 20:07:015013
Sam Maiera6e76d72022-02-11 21:43:505014 def gn_files(f):
5015 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
Andrew Grieve1b290e4a22020-11-24 20:07:015016
Sam Maiera6e76d72022-02-11 21:43:505017 problems = []
5018 for f in input_api.AffectedSourceFiles(gn_files):
5019 for line_num, line in f.ChangedContents():
5020 if 'forward_variables_from(invoker, "*")' in line:
5021 problems.append(
5022 'Bare forward_variables_from(invoker, "*") in %s:%d' %
5023 (f.LocalPath(), line_num))
5024
5025 if problems:
5026 return [
5027 output_api.PresubmitPromptWarning(
5028 'forward_variables_from("*") without exclusions',
5029 items=sorted(problems),
5030 long_text=(
Gao Shenga79ebd42022-08-08 17:25:595031 'The variables "visibility" and "test_only" should be '
Sam Maiera6e76d72022-02-11 21:43:505032 'explicitly listed in forward_variables_from(). For more '
5033 'details, see:\n'
5034 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
5035 'build/docs/writing_gn_templates.md'
5036 '#Using-forward_variables_from'))
5037 ]
5038 return []
Andrew Grieve1b290e4a22020-11-24 20:07:015039
Saagar Sanghavifceeaae2020-08-12 16:40:365040def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505041 """Checks that newly added header files have corresponding GN changes.
5042 Note that this is only a heuristic. To be precise, run script:
5043 build/check_gn_headers.py.
5044 """
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195045
Sam Maiera6e76d72022-02-11 21:43:505046 def headers(f):
5047 return input_api.FilterSourceFile(
5048 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195049
Sam Maiera6e76d72022-02-11 21:43:505050 new_headers = []
5051 for f in input_api.AffectedSourceFiles(headers):
5052 if f.Action() != 'A':
5053 continue
5054 new_headers.append(f.LocalPath())
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195055
Sam Maiera6e76d72022-02-11 21:43:505056 def gn_files(f):
5057 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195058
Sam Maiera6e76d72022-02-11 21:43:505059 all_gn_changed_contents = ''
5060 for f in input_api.AffectedSourceFiles(gn_files):
5061 for _, line in f.ChangedContents():
5062 all_gn_changed_contents += line
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195063
Sam Maiera6e76d72022-02-11 21:43:505064 problems = []
5065 for header in new_headers:
5066 basename = input_api.os_path.basename(header)
5067 if basename not in all_gn_changed_contents:
5068 problems.append(header)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195069
Sam Maiera6e76d72022-02-11 21:43:505070 if problems:
5071 return [
5072 output_api.PresubmitPromptWarning(
5073 'Missing GN changes for new header files',
5074 items=sorted(problems),
5075 long_text=
5076 'Please double check whether newly added header files need '
5077 'corresponding changes in gn or gni files.\nThis checking is only a '
5078 'heuristic. Run build/check_gn_headers.py to be precise.\n'
5079 'Read https://crbug.com/661774 for more info.')
5080 ]
5081 return []
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195082
5083
Saagar Sanghavifceeaae2020-08-12 16:40:365084def CheckCorrectProductNameInMessages(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505085 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
Michael Giuffridad3bc8672018-10-25 22:48:025086
Sam Maiera6e76d72022-02-11 21:43:505087 This assumes we won't intentionally reference one product from the other
5088 product.
5089 """
5090 all_problems = []
5091 test_cases = [{
5092 "filename_postfix": "google_chrome_strings.grd",
5093 "correct_name": "Chrome",
5094 "incorrect_name": "Chromium",
5095 }, {
Thiago Perrotta099034f2023-06-05 18:10:205096 "filename_postfix": "google_chrome_strings.grd",
5097 "correct_name": "Chrome",
5098 "incorrect_name": "Chrome for Testing",
5099 }, {
Sam Maiera6e76d72022-02-11 21:43:505100 "filename_postfix": "chromium_strings.grd",
5101 "correct_name": "Chromium",
5102 "incorrect_name": "Chrome",
5103 }]
Michael Giuffridad3bc8672018-10-25 22:48:025104
Sam Maiera6e76d72022-02-11 21:43:505105 for test_case in test_cases:
5106 problems = []
5107 filename_filter = lambda x: x.LocalPath().endswith(test_case[
5108 "filename_postfix"])
Michael Giuffridad3bc8672018-10-25 22:48:025109
Sam Maiera6e76d72022-02-11 21:43:505110 # Check each new line. Can yield false positives in multiline comments, but
5111 # easier than trying to parse the XML because messages can have nested
5112 # children, and associating message elements with affected lines is hard.
5113 for f in input_api.AffectedSourceFiles(filename_filter):
5114 for line_num, line in f.ChangedContents():
5115 if "<message" in line or "<!--" in line or "-->" in line:
5116 continue
5117 if test_case["incorrect_name"] in line:
Thiago Perrotta099034f2023-06-05 18:10:205118 # Chrome for Testing is a special edge case: https://goo.gle/chrome-for-testing#bookmark=id.n1rat320av91
5119 if (test_case["correct_name"] == "Chromium" and line.count("Chrome") == line.count("Chrome for Testing")):
5120 continue
Sam Maiera6e76d72022-02-11 21:43:505121 problems.append("Incorrect product name in %s:%d" %
5122 (f.LocalPath(), line_num))
Michael Giuffridad3bc8672018-10-25 22:48:025123
Sam Maiera6e76d72022-02-11 21:43:505124 if problems:
5125 message = (
5126 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
5127 % (test_case["correct_name"], test_case["correct_name"],
5128 test_case["incorrect_name"]))
5129 all_problems.append(
5130 output_api.PresubmitPromptWarning(message, items=problems))
Michael Giuffridad3bc8672018-10-25 22:48:025131
Sam Maiera6e76d72022-02-11 21:43:505132 return all_problems
Michael Giuffridad3bc8672018-10-25 22:48:025133
5134
Saagar Sanghavifceeaae2020-08-12 16:40:365135def CheckForTooLargeFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505136 """Avoid large files, especially binary files, in the repository since
5137 git doesn't scale well for those. They will be in everyone's repo
5138 clones forever, forever making Chromium slower to clone and work
5139 with."""
Daniel Bratell93eb6c62019-04-29 20:13:365140
Sam Maiera6e76d72022-02-11 21:43:505141 # Uploading files to cloud storage is not trivial so we don't want
5142 # to set the limit too low, but the upper limit for "normal" large
5143 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
5144 # anything over 20 MB is exceptional.
Bruce Dawsonbb414db2022-12-27 20:21:255145 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024
Daniel Bratell93eb6c62019-04-29 20:13:365146
Sam Maiera6e76d72022-02-11 21:43:505147 too_large_files = []
5148 for f in input_api.AffectedFiles():
5149 # Check both added and modified files (but not deleted files).
5150 if f.Action() in ('A', 'M'):
5151 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Joe DeBlasio10a832f2023-04-21 20:20:185152 if size > TOO_LARGE_FILE_SIZE_LIMIT:
Sam Maiera6e76d72022-02-11 21:43:505153 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
Daniel Bratell93eb6c62019-04-29 20:13:365154
Sam Maiera6e76d72022-02-11 21:43:505155 if too_large_files:
5156 message = (
5157 'Do not commit large files to git since git scales badly for those.\n'
5158 +
5159 'Instead put the large files in cloud storage and use DEPS to\n' +
5160 'fetch them.\n' + '\n'.join(too_large_files))
5161 return [
5162 output_api.PresubmitError('Too large files found in commit',
5163 long_text=message + '\n')
5164 ]
5165 else:
5166 return []
Daniel Bratell93eb6c62019-04-29 20:13:365167
Max Morozb47503b2019-08-08 21:03:275168
Saagar Sanghavifceeaae2020-08-12 16:40:365169def CheckFuzzTargetsOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505170 """Checks specific for fuzz target sources."""
5171 EXPORTED_SYMBOLS = [
5172 'LLVMFuzzerInitialize',
5173 'LLVMFuzzerCustomMutator',
5174 'LLVMFuzzerCustomCrossOver',
5175 'LLVMFuzzerMutate',
5176 ]
Max Morozb47503b2019-08-08 21:03:275177
Sam Maiera6e76d72022-02-11 21:43:505178 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
Max Morozb47503b2019-08-08 21:03:275179
Sam Maiera6e76d72022-02-11 21:43:505180 def FilterFile(affected_file):
5181 """Ignore libFuzzer source code."""
5182 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
Bruce Dawson40fece62022-09-16 19:58:315183 files_to_skip = r"^third_party/libFuzzer"
Max Morozb47503b2019-08-08 21:03:275184
Sam Maiera6e76d72022-02-11 21:43:505185 return input_api.FilterSourceFile(affected_file,
5186 files_to_check=[files_to_check],
5187 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:275188
Sam Maiera6e76d72022-02-11 21:43:505189 files_with_missing_header = []
5190 for f in input_api.AffectedSourceFiles(FilterFile):
5191 contents = input_api.ReadFile(f, 'r')
5192 if REQUIRED_HEADER in contents:
5193 continue
Max Morozb47503b2019-08-08 21:03:275194
Sam Maiera6e76d72022-02-11 21:43:505195 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
5196 files_with_missing_header.append(f.LocalPath())
Max Morozb47503b2019-08-08 21:03:275197
Sam Maiera6e76d72022-02-11 21:43:505198 if not files_with_missing_header:
5199 return []
Max Morozb47503b2019-08-08 21:03:275200
Sam Maiera6e76d72022-02-11 21:43:505201 long_text = (
5202 'If you define any of the libFuzzer optional functions (%s), it is '
5203 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
5204 'work incorrectly on Mac (crbug.com/687076).\nNote that '
5205 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
5206 'to access command line arguments passed to the fuzzer. Instead, prefer '
5207 'static initialization and shared resources as documented in '
5208 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
5209 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n'
5210 % (', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER))
Max Morozb47503b2019-08-08 21:03:275211
Sam Maiera6e76d72022-02-11 21:43:505212 return [
5213 output_api.PresubmitPromptWarning(message="Missing '%s' in:" %
5214 REQUIRED_HEADER,
5215 items=files_with_missing_header,
5216 long_text=long_text)
5217 ]
Max Morozb47503b2019-08-08 21:03:275218
5219
Mohamed Heikald048240a2019-11-12 16:57:375220def _CheckNewImagesWarning(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505221 """
5222 Warns authors who add images into the repo to make sure their images are
5223 optimized before committing.
5224 """
5225 images_added = False
5226 image_paths = []
5227 errors = []
5228 filter_lambda = lambda x: input_api.FilterSourceFile(
5229 x,
5230 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
5231 DEFAULT_FILES_TO_SKIP),
5232 files_to_check=[r'.*\/(drawable|mipmap)'])
5233 for f in input_api.AffectedFiles(include_deletes=False,
5234 file_filter=filter_lambda):
5235 local_path = f.LocalPath().lower()
5236 if any(
5237 local_path.endswith(extension)
5238 for extension in _IMAGE_EXTENSIONS):
5239 images_added = True
5240 image_paths.append(f)
5241 if images_added:
5242 errors.append(
5243 output_api.PresubmitPromptWarning(
5244 'It looks like you are trying to commit some images. If these are '
5245 'non-test-only images, please make sure to read and apply the tips in '
5246 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
5247 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
5248 'FYI only and will not block your CL on the CQ.', image_paths))
5249 return errors
Mohamed Heikald048240a2019-11-12 16:57:375250
5251
Saagar Sanghavifceeaae2020-08-12 16:40:365252def ChecksAndroidSpecificOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505253 """Groups upload checks that target android code."""
5254 results = []
5255 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
5256 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
5257 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
5258 results.extend(_CheckAndroidToastUsage(input_api, output_api))
5259 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
5260 results.extend(_CheckAndroidTestJUnitFrameworkImport(
5261 input_api, output_api))
5262 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
5263 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
5264 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
5265 results.extend(_CheckNewImagesWarning(input_api, output_api))
5266 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
5267 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
5268 return results
5269
Becky Zhou7c69b50992018-12-10 19:37:575270
Saagar Sanghavifceeaae2020-08-12 16:40:365271def ChecksAndroidSpecificOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505272 """Groups commit checks that target android code."""
5273 results = []
5274 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
5275 return results
dgnaa68d5e2015-06-10 10:08:225276
Chris Hall59f8d0c72020-05-01 07:31:195277# TODO(chrishall): could we additionally match on any path owned by
5278# ui/accessibility/OWNERS ?
5279_ACCESSIBILITY_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:315280 r"^chrome/browser.*/accessibility/",
5281 r"^chrome/browser/extensions/api/automation.*/",
5282 r"^chrome/renderer/extensions/accessibility_.*",
5283 r"^chrome/tests/data/accessibility/",
Katie Dektar58ef07b2022-09-27 13:19:175284 r"^components/services/screen_ai/",
Bruce Dawson40fece62022-09-16 19:58:315285 r"^content/browser/accessibility/",
5286 r"^content/renderer/accessibility/",
5287 r"^content/tests/data/accessibility/",
5288 r"^extensions/renderer/api/automation/",
Katie Dektar58ef07b2022-09-27 13:19:175289 r"^services/accessibility/",
Bruce Dawson40fece62022-09-16 19:58:315290 r"^ui/accessibility/",
5291 r"^ui/views/accessibility/",
Chris Hall59f8d0c72020-05-01 07:31:195292)
5293
Saagar Sanghavifceeaae2020-08-12 16:40:365294def CheckAccessibilityRelnotesField(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505295 """Checks that commits to accessibility code contain an AX-Relnotes field in
5296 their commit message."""
Chris Hall59f8d0c72020-05-01 07:31:195297
Sam Maiera6e76d72022-02-11 21:43:505298 def FileFilter(affected_file):
5299 paths = _ACCESSIBILITY_PATHS
5300 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:195301
Sam Maiera6e76d72022-02-11 21:43:505302 # Only consider changes affecting accessibility paths.
5303 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
5304 return []
Akihiro Ota08108e542020-05-20 15:30:535305
Sam Maiera6e76d72022-02-11 21:43:505306 # AX-Relnotes can appear in either the description or the footer.
5307 # When searching the description, require 'AX-Relnotes:' to appear at the
5308 # beginning of a line.
5309 ax_regex = input_api.re.compile('ax-relnotes[:=]')
5310 description_has_relnotes = any(
5311 ax_regex.match(line)
5312 for line in input_api.change.DescriptionText().lower().splitlines())
Chris Hall59f8d0c72020-05-01 07:31:195313
Sam Maiera6e76d72022-02-11 21:43:505314 footer_relnotes = input_api.change.GitFootersFromDescription().get(
5315 'AX-Relnotes', [])
5316 if description_has_relnotes or footer_relnotes:
5317 return []
Chris Hall59f8d0c72020-05-01 07:31:195318
Sam Maiera6e76d72022-02-11 21:43:505319 # TODO(chrishall): link to Relnotes documentation in message.
5320 message = (
5321 "Missing 'AX-Relnotes:' field required for accessibility changes"
5322 "\n please add 'AX-Relnotes: [release notes].' to describe any "
5323 "user-facing changes"
5324 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
5325 "user-facing effects"
5326 "\n if this is confusing or annoying then please contact members "
5327 "of ui/accessibility/OWNERS.")
5328
5329 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:225330
Mark Schillacie5a0be22022-01-19 00:38:395331
5332_ACCESSIBILITY_EVENTS_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315333 r"^content/test/data/accessibility/event/.*\.html",
Mark Schillacie5a0be22022-01-19 00:38:395334)
5335
5336_ACCESSIBILITY_TREE_TEST_PATH = (
Aaron Leventhal267119f2023-08-18 22:45:345337 r"^content/test/data/accessibility/accname/"
5338 ".*-expected-(mac|win|uia-win|auralinux).txt",
5339 r"^content/test/data/accessibility/aria/"
5340 ".*-expected-(mac|win|uia-win|auralinux).txt",
5341 r"^content/test/data/accessibility/css/"
5342 ".*-expected-(mac|win|uia-win|auralinux).txt",
5343 r"^content/test/data/accessibility/event/"
5344 ".*-expected-(mac|win|uia-win|auralinux).txt",
5345 r"^content/test/data/accessibility/html/"
5346 ".*-expected-(mac|win|uia-win|auralinux).txt",
Mark Schillacie5a0be22022-01-19 00:38:395347)
5348
5349_ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315350 r"^.*/WebContentsAccessibilityEventsTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:395351)
5352
5353_ACCESSIBILITY_ANDROID_TREE_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315354 r"^.*/WebContentsAccessibilityTreeTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:395355)
5356
5357def CheckAccessibilityEventsTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505358 """Checks that commits that include a newly added, renamed/moved, or deleted
5359 test in the DumpAccessibilityEventsTest suite also includes a corresponding
5360 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:395361
Sam Maiera6e76d72022-02-11 21:43:505362 def FilePathFilter(affected_file):
5363 paths = _ACCESSIBILITY_EVENTS_TEST_PATH
5364 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395365
Sam Maiera6e76d72022-02-11 21:43:505366 def AndroidFilePathFilter(affected_file):
5367 paths = _ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH
5368 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395369
Sam Maiera6e76d72022-02-11 21:43:505370 # Only consider changes in the events test data path with html type.
5371 if not any(
5372 input_api.AffectedFiles(include_deletes=True,
5373 file_filter=FilePathFilter)):
5374 return []
Mark Schillacie5a0be22022-01-19 00:38:395375
Sam Maiera6e76d72022-02-11 21:43:505376 # If the commit contains any change to the Android test file, ignore.
5377 if any(
5378 input_api.AffectedFiles(include_deletes=True,
5379 file_filter=AndroidFilePathFilter)):
5380 return []
Mark Schillacie5a0be22022-01-19 00:38:395381
Sam Maiera6e76d72022-02-11 21:43:505382 # Only consider changes that are adding/renaming or deleting a file
5383 message = []
5384 for f in input_api.AffectedFiles(include_deletes=True,
5385 file_filter=FilePathFilter):
Aaron Leventhal267119f2023-08-18 22:45:345386 if f.Action() == 'A':
Sam Maiera6e76d72022-02-11 21:43:505387 message = (
Aaron Leventhal267119f2023-08-18 22:45:345388 "It appears that you are adding platform expectations for a"
Aaron Leventhal0de81072023-08-21 21:26:525389 "\ndump_accessibility_events* test, but have not included"
Sam Maiera6e76d72022-02-11 21:43:505390 "\na corresponding change for Android."
Aaron Leventhal267119f2023-08-18 22:45:345391 "\nPlease include the test from:"
Sam Maiera6e76d72022-02-11 21:43:505392 "\n content/public/android/javatests/src/org/chromium/"
5393 "content/browser/accessibility/"
5394 "WebContentsAccessibilityEventsTest.java"
5395 "\nIf this message is confusing or annoying, please contact"
5396 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:395397
Sam Maiera6e76d72022-02-11 21:43:505398 # If no message was set, return empty.
5399 if not len(message):
5400 return []
5401
5402 return [output_api.PresubmitPromptWarning(message)]
5403
Mark Schillacie5a0be22022-01-19 00:38:395404
5405def CheckAccessibilityTreeTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505406 """Checks that commits that include a newly added, renamed/moved, or deleted
5407 test in the DumpAccessibilityTreeTest suite also includes a corresponding
5408 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:395409
Sam Maiera6e76d72022-02-11 21:43:505410 def FilePathFilter(affected_file):
5411 paths = _ACCESSIBILITY_TREE_TEST_PATH
5412 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395413
Sam Maiera6e76d72022-02-11 21:43:505414 def AndroidFilePathFilter(affected_file):
5415 paths = _ACCESSIBILITY_ANDROID_TREE_TEST_PATH
5416 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395417
Sam Maiera6e76d72022-02-11 21:43:505418 # Only consider changes in the various tree test data paths with html type.
5419 if not any(
5420 input_api.AffectedFiles(include_deletes=True,
5421 file_filter=FilePathFilter)):
5422 return []
Mark Schillacie5a0be22022-01-19 00:38:395423
Sam Maiera6e76d72022-02-11 21:43:505424 # If the commit contains any change to the Android test file, ignore.
5425 if any(
5426 input_api.AffectedFiles(include_deletes=True,
5427 file_filter=AndroidFilePathFilter)):
5428 return []
Mark Schillacie5a0be22022-01-19 00:38:395429
Sam Maiera6e76d72022-02-11 21:43:505430 # Only consider changes that are adding/renaming or deleting a file
5431 message = []
5432 for f in input_api.AffectedFiles(include_deletes=True,
5433 file_filter=FilePathFilter):
Aaron Leventhal0de81072023-08-21 21:26:525434 if f.Action() == 'A':
Sam Maiera6e76d72022-02-11 21:43:505435 message = (
Aaron Leventhal0de81072023-08-21 21:26:525436 "It appears that you are adding platform expectations for a"
5437 "\ndump_accessibility_tree* test, but have not included"
Sam Maiera6e76d72022-02-11 21:43:505438 "\na corresponding change for Android."
5439 "\nPlease include (or remove) the test from:"
5440 "\n content/public/android/javatests/src/org/chromium/"
5441 "content/browser/accessibility/"
5442 "WebContentsAccessibilityTreeTest.java"
5443 "\nIf this message is confusing or annoying, please contact"
5444 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:395445
Sam Maiera6e76d72022-02-11 21:43:505446 # If no message was set, return empty.
5447 if not len(message):
5448 return []
5449
5450 return [output_api.PresubmitPromptWarning(message)]
Mark Schillacie5a0be22022-01-19 00:38:395451
5452
Bruce Dawson33806592022-11-16 01:44:515453def CheckEsLintConfigChanges(input_api, output_api):
5454 """Suggest using "git cl presubmit --files" when .eslintrc.js files are
5455 modified. This is important because enabling an error in .eslintrc.js can
5456 trigger errors in any .js or .ts files in its directory, leading to hidden
5457 presubmit errors."""
5458 results = []
5459 eslint_filter = lambda f: input_api.FilterSourceFile(
5460 f, files_to_check=[r'.*\.eslintrc\.js$'])
5461 for f in input_api.AffectedFiles(include_deletes=False,
5462 file_filter=eslint_filter):
5463 local_dir = input_api.os_path.dirname(f.LocalPath())
5464 # Use / characters so that the commands printed work on any OS.
5465 local_dir = local_dir.replace(input_api.os_path.sep, '/')
5466 if local_dir:
5467 local_dir += '/'
5468 results.append(
5469 output_api.PresubmitNotifyResult(
5470 '%(file)s modified. Consider running \'git cl presubmit --files '
5471 '"%(dir)s*.js;%(dir)s*.ts"\' in order to check and fix the affected '
5472 'files before landing this change.' %
5473 { 'file' : f.LocalPath(), 'dir' : local_dir}))
5474 return results
5475
5476
seanmccullough4a9356252021-04-08 19:54:095477# string pattern, sequence of strings to show when pattern matches,
5478# error flag. True if match is a presubmit error, otherwise it's a warning.
5479_NON_INCLUSIVE_TERMS = (
5480 (
5481 # Note that \b pattern in python re is pretty particular. In this
5482 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
5483 # ...' will not. This may require some tweaking to catch these cases
5484 # without triggering a lot of false positives. Leaving it naive and
5485 # less matchy for now.
seanmccullough56d1e3cf2021-12-03 18:18:325486 r'/\b(?i)((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:095487 (
5488 'Please don\'t use blacklist, whitelist, ' # nocheck
5489 'or slave in your', # nocheck
5490 'code and make every effort to use other terms. Using "// nocheck"',
5491 '"# nocheck" or "<!-- nocheck -->"',
5492 'at the end of the offending line will bypass this PRESUBMIT error',
5493 'but avoid using this whenever possible. Reach out to',
5494 '[email protected] if you have questions'),
5495 True),)
5496
Saagar Sanghavifceeaae2020-08-12 16:40:365497def ChecksCommon(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505498 """Checks common to both upload and commit."""
5499 results = []
Eric Boren6fd2b932018-01-25 15:05:085500 results.extend(
Sam Maiera6e76d72022-02-11 21:43:505501 input_api.canned_checks.PanProjectChecks(
5502 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:085503
Sam Maiera6e76d72022-02-11 21:43:505504 author = input_api.change.author_email
5505 if author and author not in _KNOWN_ROBOTS:
5506 results.extend(
5507 input_api.canned_checks.CheckAuthorizedAuthor(
5508 input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:245509
Sam Maiera6e76d72022-02-11 21:43:505510 results.extend(
5511 input_api.canned_checks.CheckChangeHasNoTabs(
5512 input_api,
5513 output_api,
5514 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
5515 results.extend(
5516 input_api.RunTests(
5517 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Edward Lesmesce51df52020-08-04 22:10:175518
Bruce Dawsonc8054482022-03-28 15:33:375519 dirmd = 'dirmd.bat' if input_api.is_windows else 'dirmd'
Sam Maiera6e76d72022-02-11 21:43:505520 dirmd_bin = input_api.os_path.join(input_api.PresubmitLocalPath(),
Bruce Dawsonc8054482022-03-28 15:33:375521 'third_party', 'depot_tools', dirmd)
Sam Maiera6e76d72022-02-11 21:43:505522 results.extend(
5523 input_api.RunTests(
5524 input_api.canned_checks.CheckDirMetadataFormat(
5525 input_api, output_api, dirmd_bin)))
5526 results.extend(
5527 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
5528 input_api, output_api))
5529 results.extend(
5530 input_api.canned_checks.CheckNoNewMetadataInOwners(
5531 input_api, output_api))
5532 results.extend(
5533 input_api.canned_checks.CheckInclusiveLanguage(
5534 input_api,
5535 output_api,
5536 excluded_directories_relative_path=[
5537 'infra', 'inclusive_language_presubmit_exempt_dirs.txt'
5538 ],
5539 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Dirk Prankee3c9c62d2021-05-18 18:35:595540
Aleksey Khoroshilov2978c942022-06-13 16:14:125541 presubmit_py_filter = lambda f: input_api.FilterSourceFile(
Bruce Dawson696963f2022-09-13 01:15:475542 f, files_to_check=[r'.*PRESUBMIT\.py$'])
Aleksey Khoroshilov2978c942022-06-13 16:14:125543 for f in input_api.AffectedFiles(include_deletes=False,
5544 file_filter=presubmit_py_filter):
5545 full_path = input_api.os_path.dirname(f.AbsoluteLocalPath())
5546 test_file = input_api.os_path.join(full_path, 'PRESUBMIT_test.py')
5547 # The PRESUBMIT.py file (and the directory containing it) might have
5548 # been affected by being moved or removed, so only try to run the tests
5549 # if they still exist.
5550 if not input_api.os_path.exists(test_file):
5551 continue
Sam Maiera6e76d72022-02-11 21:43:505552
Aleksey Khoroshilov2978c942022-06-13 16:14:125553 results.extend(
5554 input_api.canned_checks.RunUnitTestsInDirectory(
5555 input_api,
5556 output_api,
5557 full_path,
Takuto Ikuta40def482023-06-02 02:23:495558 files_to_check=[r'^PRESUBMIT_test\.py$']))
Sam Maiera6e76d72022-02-11 21:43:505559 return results
[email protected]1f7b4172010-01-28 01:17:345560
[email protected]b337cb5b2011-01-23 21:24:055561
Saagar Sanghavifceeaae2020-08-12 16:40:365562def CheckPatchFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505563 problems = [
5564 f.LocalPath() for f in input_api.AffectedFiles()
5565 if f.LocalPath().endswith(('.orig', '.rej'))
5566 ]
5567 # Cargo.toml.orig files are part of third-party crates downloaded from
5568 # crates.io and should be included.
5569 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
5570 if problems:
5571 return [
5572 output_api.PresubmitError("Don't commit .rej and .orig files.",
5573 problems)
5574 ]
5575 else:
5576 return []
[email protected]b8079ae4a2012-12-05 19:56:495577
5578
Saagar Sanghavifceeaae2020-08-12 16:40:365579def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505580 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
5581 macro_re = input_api.re.compile(
5582 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
5583 include_re = input_api.re.compile(r'^#include\s+"build/build_config.h"',
5584 input_api.re.MULTILINE)
5585 extension_re = input_api.re.compile(r'\.[a-z]+$')
5586 errors = []
Bruce Dawsonf7679202022-08-09 20:24:005587 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:505588 for f in input_api.AffectedFiles(include_deletes=False):
Bruce Dawsonf7679202022-08-09 20:24:005589 # The build-config macros are allowed to be used in build_config.h
5590 # without including itself.
5591 if f.LocalPath() == config_h_file:
5592 continue
Sam Maiera6e76d72022-02-11 21:43:505593 if not f.LocalPath().endswith(
5594 ('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
5595 continue
5596 found_line_number = None
5597 found_macro = None
5598 all_lines = input_api.ReadFile(f, 'r').splitlines()
5599 for line_num, line in enumerate(all_lines):
5600 match = macro_re.search(line)
5601 if match:
5602 found_line_number = line_num
5603 found_macro = match.group(2)
5604 break
5605 if not found_line_number:
5606 continue
Kent Tamura5a8755d2017-06-29 23:37:075607
Sam Maiera6e76d72022-02-11 21:43:505608 found_include_line = -1
5609 for line_num, line in enumerate(all_lines):
5610 if include_re.search(line):
5611 found_include_line = line_num
5612 break
5613 if found_include_line >= 0 and found_include_line < found_line_number:
5614 continue
Kent Tamura5a8755d2017-06-29 23:37:075615
Sam Maiera6e76d72022-02-11 21:43:505616 if not f.LocalPath().endswith('.h'):
5617 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
5618 try:
5619 content = input_api.ReadFile(primary_header_path, 'r')
5620 if include_re.search(content):
5621 continue
5622 except IOError:
5623 pass
5624 errors.append('%s:%d %s macro is used without first including build/'
5625 'build_config.h.' %
5626 (f.LocalPath(), found_line_number, found_macro))
5627 if errors:
5628 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
5629 return []
Kent Tamura5a8755d2017-06-29 23:37:075630
5631
Lei Zhang1c12a22f2021-05-12 11:28:455632def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505633 stl_include_re = input_api.re.compile(r'^#include\s+<('
5634 r'algorithm|'
5635 r'array|'
5636 r'limits|'
5637 r'list|'
5638 r'map|'
5639 r'memory|'
5640 r'queue|'
5641 r'set|'
5642 r'string|'
5643 r'unordered_map|'
5644 r'unordered_set|'
5645 r'utility|'
5646 r'vector)>')
5647 std_namespace_re = input_api.re.compile(r'std::')
5648 errors = []
5649 for f in input_api.AffectedFiles():
5650 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
5651 continue
Lei Zhang1c12a22f2021-05-12 11:28:455652
Sam Maiera6e76d72022-02-11 21:43:505653 uses_std_namespace = False
5654 has_stl_include = False
5655 for line in f.NewContents():
5656 if has_stl_include and uses_std_namespace:
5657 break
Lei Zhang1c12a22f2021-05-12 11:28:455658
Sam Maiera6e76d72022-02-11 21:43:505659 if not has_stl_include and stl_include_re.search(line):
5660 has_stl_include = True
5661 continue
Lei Zhang1c12a22f2021-05-12 11:28:455662
Bruce Dawson4a5579a2022-04-08 17:11:365663 if not uses_std_namespace and (std_namespace_re.search(line)
5664 or 'no-std-usage-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:505665 uses_std_namespace = True
5666 continue
Lei Zhang1c12a22f2021-05-12 11:28:455667
Sam Maiera6e76d72022-02-11 21:43:505668 if has_stl_include and not uses_std_namespace:
5669 errors.append(
5670 '%s: Includes STL header(s) but does not reference std::' %
5671 f.LocalPath())
5672 if errors:
5673 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
5674 return []
Lei Zhang1c12a22f2021-05-12 11:28:455675
5676
Xiaohan Wang42d96c22022-01-20 17:23:115677def _CheckForDeprecatedOSMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:505678 """Check for sensible looking, totally invalid OS macros."""
5679 preprocessor_statement = input_api.re.compile(r'^\s*#')
5680 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
5681 results = []
5682 for lnum, line in f.ChangedContents():
5683 if preprocessor_statement.search(line):
5684 for match in os_macro.finditer(line):
5685 results.append(
5686 ' %s:%d: %s' %
5687 (f.LocalPath(), lnum, 'defined(OS_' + match.group(1) +
5688 ') -> BUILDFLAG(IS_' + match.group(1) + ')'))
5689 return results
[email protected]b00342e7f2013-03-26 16:21:545690
5691
Xiaohan Wang42d96c22022-01-20 17:23:115692def CheckForDeprecatedOSMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505693 """Check all affected files for invalid OS macros."""
5694 bad_macros = []
Bruce Dawsonf7679202022-08-09 20:24:005695 # The OS_ macros are allowed to be used in build/build_config.h.
5696 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:505697 for f in input_api.AffectedSourceFiles(None):
Bruce Dawsonf7679202022-08-09 20:24:005698 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')) \
5699 and f.LocalPath() != config_h_file:
Sam Maiera6e76d72022-02-11 21:43:505700 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
[email protected]b00342e7f2013-03-26 16:21:545701
Sam Maiera6e76d72022-02-11 21:43:505702 if not bad_macros:
5703 return []
[email protected]b00342e7f2013-03-26 16:21:545704
Sam Maiera6e76d72022-02-11 21:43:505705 return [
5706 output_api.PresubmitError(
5707 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
5708 'defined in build_config.h):', bad_macros)
5709 ]
[email protected]b00342e7f2013-03-26 16:21:545710
lliabraa35bab3932014-10-01 12:16:445711
5712def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:505713 """Check all affected files for invalid "if defined" macros."""
5714 ALWAYS_DEFINED_MACROS = (
5715 "TARGET_CPU_PPC",
5716 "TARGET_CPU_PPC64",
5717 "TARGET_CPU_68K",
5718 "TARGET_CPU_X86",
5719 "TARGET_CPU_ARM",
5720 "TARGET_CPU_MIPS",
5721 "TARGET_CPU_SPARC",
5722 "TARGET_CPU_ALPHA",
5723 "TARGET_IPHONE_SIMULATOR",
5724 "TARGET_OS_EMBEDDED",
5725 "TARGET_OS_IPHONE",
5726 "TARGET_OS_MAC",
5727 "TARGET_OS_UNIX",
5728 "TARGET_OS_WIN32",
5729 )
5730 ifdef_macro = input_api.re.compile(
5731 r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
5732 results = []
5733 for lnum, line in f.ChangedContents():
5734 for match in ifdef_macro.finditer(line):
5735 if match.group(1) in ALWAYS_DEFINED_MACROS:
5736 always_defined = ' %s is always defined. ' % match.group(1)
5737 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
5738 results.append(
5739 ' %s:%d %s\n\t%s' %
5740 (f.LocalPath(), lnum, always_defined, did_you_mean))
5741 return results
lliabraa35bab3932014-10-01 12:16:445742
5743
Saagar Sanghavifceeaae2020-08-12 16:40:365744def CheckForInvalidIfDefinedMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505745 """Check all affected files for invalid "if defined" macros."""
5746 bad_macros = []
5747 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
5748 for f in input_api.AffectedFiles():
5749 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
5750 continue
5751 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
5752 bad_macros.extend(
5753 _CheckForInvalidIfDefinedMacrosInFile(input_api, f))
lliabraa35bab3932014-10-01 12:16:445754
Sam Maiera6e76d72022-02-11 21:43:505755 if not bad_macros:
5756 return []
lliabraa35bab3932014-10-01 12:16:445757
Sam Maiera6e76d72022-02-11 21:43:505758 return [
5759 output_api.PresubmitError(
5760 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
5761 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
5762 bad_macros)
5763 ]
lliabraa35bab3932014-10-01 12:16:445764
5765
Saagar Sanghavifceeaae2020-08-12 16:40:365766def CheckForIPCRules(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505767 """Check for same IPC rules described in
5768 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
5769 """
5770 base_pattern = r'IPC_ENUM_TRAITS\('
5771 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
5772 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
mlamouria82272622014-09-16 18:45:045773
Sam Maiera6e76d72022-02-11 21:43:505774 problems = []
5775 for f in input_api.AffectedSourceFiles(None):
5776 local_path = f.LocalPath()
5777 if not local_path.endswith('.h'):
5778 continue
5779 for line_number, line in f.ChangedContents():
5780 if inclusion_pattern.search(
5781 line) and not comment_pattern.search(line):
5782 problems.append('%s:%d\n %s' %
5783 (local_path, line_number, line.strip()))
mlamouria82272622014-09-16 18:45:045784
Sam Maiera6e76d72022-02-11 21:43:505785 if problems:
5786 return [
5787 output_api.PresubmitPromptWarning(_IPC_ENUM_TRAITS_DEPRECATED,
5788 problems)
5789 ]
5790 else:
5791 return []
mlamouria82272622014-09-16 18:45:045792
[email protected]b00342e7f2013-03-26 16:21:545793
Saagar Sanghavifceeaae2020-08-12 16:40:365794def CheckForLongPathnames(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505795 """Check to make sure no files being submitted have long paths.
5796 This causes issues on Windows.
5797 """
5798 problems = []
5799 for f in input_api.AffectedTestableFiles():
5800 local_path = f.LocalPath()
5801 # Windows has a path limit of 260 characters. Limit path length to 200 so
5802 # that we have some extra for the prefix on dev machines and the bots.
5803 if len(local_path) > 200:
5804 problems.append(local_path)
Stephen Martinis97a394142018-06-07 23:06:055805
Sam Maiera6e76d72022-02-11 21:43:505806 if problems:
5807 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
5808 else:
5809 return []
Stephen Martinis97a394142018-06-07 23:06:055810
5811
Saagar Sanghavifceeaae2020-08-12 16:40:365812def CheckForIncludeGuards(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505813 """Check that header files have proper guards against multiple inclusion.
5814 If a file should not have such guards (and it probably should) then it
Bruce Dawson4a5579a2022-04-08 17:11:365815 should include the string "no-include-guard-because-multiply-included" or
5816 "no-include-guard-because-pch-file".
Sam Maiera6e76d72022-02-11 21:43:505817 """
Daniel Bratell8ba52722018-03-02 16:06:145818
Sam Maiera6e76d72022-02-11 21:43:505819 def is_chromium_header_file(f):
5820 # We only check header files under the control of the Chromium
5821 # project. That is, those outside third_party apart from
5822 # third_party/blink.
5823 # We also exclude *_message_generator.h headers as they use
5824 # include guards in a special, non-typical way.
5825 file_with_path = input_api.os_path.normpath(f.LocalPath())
5826 return (file_with_path.endswith('.h')
5827 and not file_with_path.endswith('_message_generator.h')
Bruce Dawson4c4c2922022-05-02 18:07:335828 and not file_with_path.endswith('com_imported_mstscax.h')
Sam Maiera6e76d72022-02-11 21:43:505829 and (not file_with_path.startswith('third_party')
5830 or file_with_path.startswith(
5831 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:145832
Sam Maiera6e76d72022-02-11 21:43:505833 def replace_special_with_underscore(string):
5834 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:145835
Sam Maiera6e76d72022-02-11 21:43:505836 errors = []
Daniel Bratell8ba52722018-03-02 16:06:145837
Sam Maiera6e76d72022-02-11 21:43:505838 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
5839 guard_name = None
5840 guard_line_number = None
5841 seen_guard_end = False
Daniel Bratell8ba52722018-03-02 16:06:145842
Sam Maiera6e76d72022-02-11 21:43:505843 file_with_path = input_api.os_path.normpath(f.LocalPath())
5844 base_file_name = input_api.os_path.splitext(
5845 input_api.os_path.basename(file_with_path))[0]
5846 upper_base_file_name = base_file_name.upper()
Daniel Bratell8ba52722018-03-02 16:06:145847
Sam Maiera6e76d72022-02-11 21:43:505848 expected_guard = replace_special_with_underscore(
5849 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:145850
Sam Maiera6e76d72022-02-11 21:43:505851 # For "path/elem/file_name.h" we should really only accept
5852 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
5853 # are too many (1000+) files with slight deviations from the
5854 # coding style. The most important part is that the include guard
5855 # is there, and that it's unique, not the name so this check is
5856 # forgiving for existing files.
5857 #
5858 # As code becomes more uniform, this could be made stricter.
Daniel Bratell8ba52722018-03-02 16:06:145859
Sam Maiera6e76d72022-02-11 21:43:505860 guard_name_pattern_list = [
5861 # Anything with the right suffix (maybe with an extra _).
5862 r'\w+_H__?',
Daniel Bratell8ba52722018-03-02 16:06:145863
Sam Maiera6e76d72022-02-11 21:43:505864 # To cover include guards with old Blink style.
5865 r'\w+_h',
Daniel Bratell8ba52722018-03-02 16:06:145866
Sam Maiera6e76d72022-02-11 21:43:505867 # Anything including the uppercase name of the file.
5868 r'\w*' + input_api.re.escape(
5869 replace_special_with_underscore(upper_base_file_name)) +
5870 r'\w*',
5871 ]
5872 guard_name_pattern = '|'.join(guard_name_pattern_list)
5873 guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
5874 guard_name_pattern + ')')
Daniel Bratell8ba52722018-03-02 16:06:145875
Sam Maiera6e76d72022-02-11 21:43:505876 for line_number, line in enumerate(f.NewContents()):
Bruce Dawson4a5579a2022-04-08 17:11:365877 if ('no-include-guard-because-multiply-included' in line
5878 or 'no-include-guard-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:505879 guard_name = 'DUMMY' # To not trigger check outside the loop.
5880 break
Daniel Bratell8ba52722018-03-02 16:06:145881
Sam Maiera6e76d72022-02-11 21:43:505882 if guard_name is None:
5883 match = guard_pattern.match(line)
5884 if match:
5885 guard_name = match.group(1)
5886 guard_line_number = line_number
Daniel Bratell8ba52722018-03-02 16:06:145887
Sam Maiera6e76d72022-02-11 21:43:505888 # We allow existing files to use include guards whose names
5889 # don't match the chromium style guide, but new files should
5890 # get it right.
Bruce Dawson6cc154e2022-04-12 20:39:495891 if guard_name != expected_guard:
Bruce Dawson95eb7562022-09-14 15:27:165892 if f.Action() == 'A': # If file was just 'A'dded
Sam Maiera6e76d72022-02-11 21:43:505893 errors.append(
5894 output_api.PresubmitPromptWarning(
5895 'Header using the wrong include guard name %s'
5896 % guard_name, [
5897 '%s:%d' %
5898 (f.LocalPath(), line_number + 1)
5899 ], 'Expected: %r\nFound: %r' %
5900 (expected_guard, guard_name)))
5901 else:
5902 # The line after #ifndef should have a #define of the same name.
5903 if line_number == guard_line_number + 1:
5904 expected_line = '#define %s' % guard_name
5905 if line != expected_line:
5906 errors.append(
5907 output_api.PresubmitPromptWarning(
5908 'Missing "%s" for include guard' %
5909 expected_line,
5910 ['%s:%d' % (f.LocalPath(), line_number + 1)],
5911 'Expected: %r\nGot: %r' %
5912 (expected_line, line)))
Daniel Bratell8ba52722018-03-02 16:06:145913
Sam Maiera6e76d72022-02-11 21:43:505914 if not seen_guard_end and line == '#endif // %s' % guard_name:
5915 seen_guard_end = True
5916 elif seen_guard_end:
5917 if line.strip() != '':
5918 errors.append(
5919 output_api.PresubmitPromptWarning(
5920 'Include guard %s not covering the whole file'
5921 % (guard_name), [f.LocalPath()]))
5922 break # Nothing else to check and enough to warn once.
Daniel Bratell8ba52722018-03-02 16:06:145923
Sam Maiera6e76d72022-02-11 21:43:505924 if guard_name is None:
5925 errors.append(
5926 output_api.PresubmitPromptWarning(
Bruce Dawson32114b62022-04-11 16:45:495927 'Missing include guard in %s\n'
Sam Maiera6e76d72022-02-11 21:43:505928 'Recommended name: %s\n'
5929 'This check can be disabled by having the string\n'
Bruce Dawson4a5579a2022-04-08 17:11:365930 '"no-include-guard-because-multiply-included" or\n'
5931 '"no-include-guard-because-pch-file" in the header.'
Sam Maiera6e76d72022-02-11 21:43:505932 % (f.LocalPath(), expected_guard)))
5933
5934 return errors
Daniel Bratell8ba52722018-03-02 16:06:145935
5936
Saagar Sanghavifceeaae2020-08-12 16:40:365937def CheckForWindowsLineEndings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505938 """Check source code and known ascii text files for Windows style line
5939 endings.
5940 """
Bruce Dawson5efbdc652022-04-11 19:29:515941 known_text_files = r'.*\.(txt|html|htm|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:235942
Sam Maiera6e76d72022-02-11 21:43:505943 file_inclusion_pattern = (known_text_files,
5944 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
5945 r'.+%s' % _HEADER_EXTENSIONS)
mostynbb639aca52015-01-07 20:31:235946
Sam Maiera6e76d72022-02-11 21:43:505947 problems = []
5948 source_file_filter = lambda f: input_api.FilterSourceFile(
5949 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
5950 for f in input_api.AffectedSourceFiles(source_file_filter):
Bruce Dawson5efbdc652022-04-11 19:29:515951 # Ignore test files that contain crlf intentionally.
5952 if f.LocalPath().endswith('crlf.txt'):
Daniel Chenga37c03db2022-05-12 17:20:345953 continue
Sam Maiera6e76d72022-02-11 21:43:505954 include_file = False
5955 for line in input_api.ReadFile(f, 'r').splitlines(True):
5956 if line.endswith('\r\n'):
5957 include_file = True
5958 if include_file:
5959 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:235960
Sam Maiera6e76d72022-02-11 21:43:505961 if problems:
5962 return [
5963 output_api.PresubmitPromptWarning(
5964 'Are you sure that you want '
5965 'these files to contain Windows style line endings?\n' +
5966 '\n'.join(problems))
5967 ]
mostynbb639aca52015-01-07 20:31:235968
Sam Maiera6e76d72022-02-11 21:43:505969 return []
5970
mostynbb639aca52015-01-07 20:31:235971
Evan Stade6cfc964c12021-05-18 20:21:165972def CheckIconFilesForLicenseHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505973 """Check that .icon files (which are fragments of C++) have license headers.
5974 """
Evan Stade6cfc964c12021-05-18 20:21:165975
Sam Maiera6e76d72022-02-11 21:43:505976 icon_files = (r'.*\.icon$', )
Evan Stade6cfc964c12021-05-18 20:21:165977
Sam Maiera6e76d72022-02-11 21:43:505978 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
5979 return input_api.canned_checks.CheckLicense(input_api,
5980 output_api,
5981 source_file_filter=icons)
5982
Evan Stade6cfc964c12021-05-18 20:21:165983
Jose Magana2b456f22021-03-09 23:26:405984def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505985 """Check source code for use of Chrome App technologies being
5986 deprecated.
5987 """
Jose Magana2b456f22021-03-09 23:26:405988
Sam Maiera6e76d72022-02-11 21:43:505989 def _CheckForDeprecatedTech(input_api,
5990 output_api,
5991 detection_list,
5992 files_to_check=None,
5993 files_to_skip=None):
Jose Magana2b456f22021-03-09 23:26:405994
Sam Maiera6e76d72022-02-11 21:43:505995 if (files_to_check or files_to_skip):
5996 source_file_filter = lambda f: input_api.FilterSourceFile(
5997 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
5998 else:
5999 source_file_filter = None
6000
6001 problems = []
6002
6003 for f in input_api.AffectedSourceFiles(source_file_filter):
6004 if f.Action() == 'D':
6005 continue
6006 for _, line in f.ChangedContents():
6007 if any(detect in line for detect in detection_list):
6008 problems.append(f.LocalPath())
6009
6010 return problems
6011
6012 # to avoid this presubmit script triggering warnings
6013 files_to_skip = ['PRESUBMIT.py', 'PRESUBMIT_test.py']
Jose Magana2b456f22021-03-09 23:26:406014
6015 problems = []
6016
Sam Maiera6e76d72022-02-11 21:43:506017 # NMF: any files with extensions .nmf or NMF
6018 _NMF_FILES = r'\.(nmf|NMF)$'
6019 problems += _CheckForDeprecatedTech(
6020 input_api,
6021 output_api,
6022 detection_list=[''], # any change to the file will trigger warning
6023 files_to_check=[r'.+%s' % _NMF_FILES])
Jose Magana2b456f22021-03-09 23:26:406024
Sam Maiera6e76d72022-02-11 21:43:506025 # MANIFEST: any manifest.json that in its diff includes "app":
6026 _MANIFEST_FILES = r'(manifest\.json)$'
6027 problems += _CheckForDeprecatedTech(
6028 input_api,
6029 output_api,
6030 detection_list=['"app":'],
6031 files_to_check=[r'.*%s' % _MANIFEST_FILES])
Jose Magana2b456f22021-03-09 23:26:406032
Sam Maiera6e76d72022-02-11 21:43:506033 # NaCl / PNaCl: any file that in its diff contains the strings in the list
6034 problems += _CheckForDeprecatedTech(
6035 input_api,
6036 output_api,
6037 detection_list=['config=nacl', 'enable-nacl', 'cpu=pnacl', 'nacl_io'],
Bruce Dawson40fece62022-09-16 19:58:316038 files_to_skip=files_to_skip + [r"^native_client_sdk/"])
Jose Magana2b456f22021-03-09 23:26:406039
Gao Shenga79ebd42022-08-08 17:25:596040 # PPAPI: any C/C++ file that in its diff includes a ppapi library
Sam Maiera6e76d72022-02-11 21:43:506041 problems += _CheckForDeprecatedTech(
6042 input_api,
6043 output_api,
6044 detection_list=['#include "ppapi', '#include <ppapi'],
6045 files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,
6046 r'.+%s' % _IMPLEMENTATION_EXTENSIONS),
Bruce Dawson40fece62022-09-16 19:58:316047 files_to_skip=[r"^ppapi/"])
Jose Magana2b456f22021-03-09 23:26:406048
Sam Maiera6e76d72022-02-11 21:43:506049 if problems:
6050 return [
6051 output_api.PresubmitPromptWarning(
6052 'You are adding/modifying code'
6053 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
6054 ' PNaCl, PPAPI). See this blog post for more details:\n'
6055 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
6056 'and this documentation for options to replace these technologies:\n'
6057 'https://developer.chrome.com/docs/apps/migration/\n' +
6058 '\n'.join(problems))
6059 ]
Jose Magana2b456f22021-03-09 23:26:406060
Sam Maiera6e76d72022-02-11 21:43:506061 return []
Jose Magana2b456f22021-03-09 23:26:406062
mostynbb639aca52015-01-07 20:31:236063
Saagar Sanghavifceeaae2020-08-12 16:40:366064def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
Sam Maiera6e76d72022-02-11 21:43:506065 """Checks that all source files use SYSLOG properly."""
6066 syslog_files = []
6067 for f in input_api.AffectedSourceFiles(src_file_filter):
6068 for line_number, line in f.ChangedContents():
6069 if 'SYSLOG' in line:
6070 syslog_files.append(f.LocalPath() + ':' + str(line_number))
pastarmovj032ba5bc2017-01-12 10:41:566071
Sam Maiera6e76d72022-02-11 21:43:506072 if syslog_files:
6073 return [
6074 output_api.PresubmitPromptWarning(
6075 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
6076 ' calls.\nFiles to check:\n',
6077 items=syslog_files)
6078 ]
6079 return []
pastarmovj89f7ee12016-09-20 14:58:136080
6081
[email protected]1f7b4172010-01-28 01:17:346082def CheckChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506083 if input_api.version < [2, 0, 0]:
6084 return [
6085 output_api.PresubmitError(
6086 "Your depot_tools is out of date. "
6087 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
6088 "but your version is %d.%d.%d" % tuple(input_api.version))
6089 ]
6090 results = []
6091 results.extend(
6092 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
6093 return results
[email protected]ca8d1982009-02-19 16:33:126094
6095
6096def CheckChangeOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506097 if input_api.version < [2, 0, 0]:
6098 return [
6099 output_api.PresubmitError(
6100 "Your depot_tools is out of date. "
6101 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
6102 "but your version is %d.%d.%d" % tuple(input_api.version))
6103 ]
Saagar Sanghavifceeaae2020-08-12 16:40:366104
Sam Maiera6e76d72022-02-11 21:43:506105 results = []
6106 # Make sure the tree is 'open'.
6107 results.extend(
6108 input_api.canned_checks.CheckTreeIsOpen(
6109 input_api,
6110 output_api,
6111 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:276112
Sam Maiera6e76d72022-02-11 21:43:506113 results.extend(
6114 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
6115 results.extend(
6116 input_api.canned_checks.CheckChangeHasBugField(input_api, output_api))
6117 results.extend(
6118 input_api.canned_checks.CheckChangeHasNoUnwantedTags(
6119 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:506120 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146121
6122
Saagar Sanghavifceeaae2020-08-12 16:40:366123def CheckStrings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506124 """Check string ICU syntax validity and if translation screenshots exist."""
6125 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
6126 # footer is set to true.
6127 git_footers = input_api.change.GitFootersFromDescription()
6128 skip_screenshot_check_footer = [
6129 footer.lower() for footer in git_footers.get(
6130 u'Skip-Translation-Screenshots-Check', [])
6131 ]
6132 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:026133
Sam Maiera6e76d72022-02-11 21:43:506134 import os
6135 import re
6136 import sys
6137 from io import StringIO
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146138
Sam Maiera6e76d72022-02-11 21:43:506139 new_or_added_paths = set(f.LocalPath() for f in input_api.AffectedFiles()
6140 if (f.Action() == 'A' or f.Action() == 'M'))
6141 removed_paths = set(f.LocalPath()
6142 for f in input_api.AffectedFiles(include_deletes=True)
6143 if f.Action() == 'D')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146144
Sam Maiera6e76d72022-02-11 21:43:506145 affected_grds = [
6146 f for f in input_api.AffectedFiles()
6147 if f.LocalPath().endswith(('.grd', '.grdp'))
6148 ]
6149 affected_grds = [
6150 f for f in affected_grds if not 'testdata' in f.LocalPath()
6151 ]
6152 if not affected_grds:
6153 return []
meacer8c0d3832019-12-26 21:46:166154
Sam Maiera6e76d72022-02-11 21:43:506155 affected_png_paths = [
6156 f.AbsoluteLocalPath() for f in input_api.AffectedFiles()
6157 if (f.LocalPath().endswith('.png'))
6158 ]
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146159
Sam Maiera6e76d72022-02-11 21:43:506160 # Check for screenshots. Developers can upload screenshots using
6161 # tools/translation/upload_screenshots.py which finds and uploads
6162 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
6163 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
6164 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
6165 #
6166 # The logic here is as follows:
6167 #
6168 # - If the CL has a .png file under the screenshots directory for a grd
6169 # file, warn the developer. Actual images should never be checked into the
6170 # Chrome repo.
6171 #
6172 # - If the CL contains modified or new messages in grd files and doesn't
6173 # contain the corresponding .sha1 files, warn the developer to add images
6174 # and upload them via tools/translation/upload_screenshots.py.
6175 #
6176 # - If the CL contains modified or new messages in grd files and the
6177 # corresponding .sha1 files, everything looks good.
6178 #
6179 # - If the CL contains removed messages in grd files but the corresponding
6180 # .sha1 files aren't removed, warn the developer to remove them.
6181 unnecessary_screenshots = []
Jens Mueller054652c2023-05-10 15:12:306182 invalid_sha1 = []
Sam Maiera6e76d72022-02-11 21:43:506183 missing_sha1 = []
Bruce Dawson55776c42022-12-09 17:23:476184 missing_sha1_modified = []
Sam Maiera6e76d72022-02-11 21:43:506185 unnecessary_sha1_files = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146186
Sam Maiera6e76d72022-02-11 21:43:506187 # This checks verifies that the ICU syntax of messages this CL touched is
6188 # valid, and reports any found syntax errors.
6189 # Without this presubmit check, ICU syntax errors in Chromium strings can land
6190 # without developers being aware of them. Later on, such ICU syntax errors
6191 # break message extraction for translation, hence would block Chromium
6192 # translations until they are fixed.
6193 icu_syntax_errors = []
Jens Mueller054652c2023-05-10 15:12:306194 sha1_pattern = input_api.re.compile(r'^[a-fA-F0-9]{40}$',
6195 input_api.re.MULTILINE)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146196
Sam Maiera6e76d72022-02-11 21:43:506197 def _CheckScreenshotAdded(screenshots_dir, message_id):
6198 sha1_path = input_api.os_path.join(screenshots_dir,
6199 message_id + '.png.sha1')
6200 if sha1_path not in new_or_added_paths:
6201 missing_sha1.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306202 elif not _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256203 invalid_sha1.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146204
Bruce Dawson55776c42022-12-09 17:23:476205 def _CheckScreenshotModified(screenshots_dir, message_id):
6206 sha1_path = input_api.os_path.join(screenshots_dir,
6207 message_id + '.png.sha1')
6208 if sha1_path not in new_or_added_paths:
6209 missing_sha1_modified.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306210 elif not _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256211 invalid_sha1.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306212
6213 def _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256214 return sha1_pattern.search(
6215 next("\n".join(f.NewContents()) for f in input_api.AffectedFiles()
6216 if f.LocalPath() == sha1_path))
Bruce Dawson55776c42022-12-09 17:23:476217
Sam Maiera6e76d72022-02-11 21:43:506218 def _CheckScreenshotRemoved(screenshots_dir, message_id):
6219 sha1_path = input_api.os_path.join(screenshots_dir,
6220 message_id + '.png.sha1')
6221 if input_api.os_path.exists(
6222 sha1_path) and sha1_path not in removed_paths:
6223 unnecessary_sha1_files.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146224
Sam Maiera6e76d72022-02-11 21:43:506225 def _ValidateIcuSyntax(text, level, signatures):
6226 """Validates ICU syntax of a text string.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146227
Sam Maiera6e76d72022-02-11 21:43:506228 Check if text looks similar to ICU and checks for ICU syntax correctness
6229 in this case. Reports various issues with ICU syntax and values of
6230 variants. Supports checking of nested messages. Accumulate information of
6231 each ICU messages found in the text for further checking.
Rainhard Findlingfc31844c52020-05-15 09:58:266232
Sam Maiera6e76d72022-02-11 21:43:506233 Args:
6234 text: a string to check.
6235 level: a number of current nesting level.
6236 signatures: an accumulator, a list of tuple of (level, variable,
6237 kind, variants).
Rainhard Findlingfc31844c52020-05-15 09:58:266238
Sam Maiera6e76d72022-02-11 21:43:506239 Returns:
6240 None if a string is not ICU or no issue detected.
6241 A tuple of (message, start index, end index) if an issue detected.
6242 """
6243 valid_types = {
6244 'plural': (frozenset(
6245 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
6246 'other']), frozenset(['=1', 'other'])),
6247 'selectordinal': (frozenset(
6248 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
6249 'other']), frozenset(['one', 'other'])),
6250 'select': (frozenset(), frozenset(['other'])),
6251 }
Rainhard Findlingfc31844c52020-05-15 09:58:266252
Sam Maiera6e76d72022-02-11 21:43:506253 # Check if the message looks like an attempt to use ICU
6254 # plural. If yes - check if its syntax strictly matches ICU format.
6255 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b',
6256 text)
6257 if not like:
6258 signatures.append((level, None, None, None))
6259 return
Rainhard Findlingfc31844c52020-05-15 09:58:266260
Sam Maiera6e76d72022-02-11 21:43:506261 # Check for valid prefix and suffix
6262 m = re.match(
6263 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
6264 r'(plural|selectordinal|select),\s*'
6265 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
6266 if not m:
6267 return (('This message looks like an ICU plural, '
6268 'but does not follow ICU syntax.'), like.start(),
6269 like.end())
6270 starting, variable, kind, variant_pairs = m.groups()
6271 variants, depth, last_pos = _ParseIcuVariants(variant_pairs,
6272 m.start(4))
6273 if depth:
6274 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
6275 len(text))
6276 first = text[0]
6277 ending = text[last_pos:]
6278 if not starting:
6279 return ('Invalid ICU format. No initial opening bracket',
6280 last_pos - 1, last_pos)
6281 if not ending or '}' not in ending:
6282 return ('Invalid ICU format. No final closing bracket',
6283 last_pos - 1, last_pos)
6284 elif first != '{':
6285 return ((
6286 'Invalid ICU format. Extra characters at the start of a complex '
6287 'message (go/icu-message-migration): "%s"') % starting, 0,
6288 len(starting))
6289 elif ending != '}':
6290 return ((
6291 'Invalid ICU format. Extra characters at the end of a complex '
6292 'message (go/icu-message-migration): "%s"') % ending,
6293 last_pos - 1, len(text) - 1)
6294 if kind not in valid_types:
6295 return (('Unknown ICU message type %s. '
6296 'Valid types are: plural, select, selectordinal') % kind,
6297 0, 0)
6298 known, required = valid_types[kind]
6299 defined_variants = set()
6300 for variant, variant_range, value, value_range in variants:
6301 start, end = variant_range
6302 if variant in defined_variants:
6303 return ('Variant "%s" is defined more than once' % variant,
6304 start, end)
6305 elif known and variant not in known:
6306 return ('Variant "%s" is not valid for %s message' %
6307 (variant, kind), start, end)
6308 defined_variants.add(variant)
6309 # Check for nested structure
6310 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
6311 if res:
6312 return (res[0], res[1] + value_range[0] + 1,
6313 res[2] + value_range[0] + 1)
6314 missing = required - defined_variants
6315 if missing:
6316 return ('Required variants missing: %s' % ', '.join(missing), 0,
6317 len(text))
6318 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:266319
Sam Maiera6e76d72022-02-11 21:43:506320 def _ParseIcuVariants(text, offset=0):
6321 """Parse variants part of ICU complex message.
Rainhard Findlingfc31844c52020-05-15 09:58:266322
Sam Maiera6e76d72022-02-11 21:43:506323 Builds a tuple of variant names and values, as well as
6324 their offsets in the input string.
Rainhard Findlingfc31844c52020-05-15 09:58:266325
Sam Maiera6e76d72022-02-11 21:43:506326 Args:
6327 text: a string to parse
6328 offset: additional offset to add to positions in the text to get correct
6329 position in the complete ICU string.
Rainhard Findlingfc31844c52020-05-15 09:58:266330
Sam Maiera6e76d72022-02-11 21:43:506331 Returns:
6332 List of tuples, each tuple consist of four fields: variant name,
6333 variant name span (tuple of two integers), variant value, value
6334 span (tuple of two integers).
6335 """
6336 depth, start, end = 0, -1, -1
6337 variants = []
6338 key = None
6339 for idx, char in enumerate(text):
6340 if char == '{':
6341 if not depth:
6342 start = idx
6343 chunk = text[end + 1:start]
6344 key = chunk.strip()
6345 pos = offset + end + 1 + chunk.find(key)
6346 span = (pos, pos + len(key))
6347 depth += 1
6348 elif char == '}':
6349 if not depth:
6350 return variants, depth, offset + idx
6351 depth -= 1
6352 if not depth:
6353 end = idx
6354 variants.append((key, span, text[start:end + 1],
6355 (offset + start, offset + end + 1)))
6356 return variants, depth, offset + end + 1
Rainhard Findlingfc31844c52020-05-15 09:58:266357
Sam Maiera6e76d72022-02-11 21:43:506358 try:
6359 old_sys_path = sys.path
6360 sys.path = sys.path + [
6361 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
6362 'translation')
6363 ]
6364 from helper import grd_helper
6365 finally:
6366 sys.path = old_sys_path
Rainhard Findlingfc31844c52020-05-15 09:58:266367
Sam Maiera6e76d72022-02-11 21:43:506368 for f in affected_grds:
6369 file_path = f.LocalPath()
6370 old_id_to_msg_map = {}
6371 new_id_to_msg_map = {}
6372 # Note that this code doesn't check if the file has been deleted. This is
6373 # OK because it only uses the old and new file contents and doesn't load
6374 # the file via its path.
6375 # It's also possible that a file's content refers to a renamed or deleted
6376 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
6377 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
6378 # .grdp files.
6379 if file_path.endswith('.grdp'):
6380 if f.OldContents():
6381 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6382 '\n'.join(f.OldContents()))
6383 if f.NewContents():
6384 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6385 '\n'.join(f.NewContents()))
6386 else:
6387 file_dir = input_api.os_path.dirname(file_path) or '.'
6388 if f.OldContents():
6389 old_id_to_msg_map = grd_helper.GetGrdMessages(
6390 StringIO('\n'.join(f.OldContents())), file_dir)
6391 if f.NewContents():
6392 new_id_to_msg_map = grd_helper.GetGrdMessages(
6393 StringIO('\n'.join(f.NewContents())), file_dir)
Rainhard Findlingfc31844c52020-05-15 09:58:266394
Sam Maiera6e76d72022-02-11 21:43:506395 grd_name, ext = input_api.os_path.splitext(
6396 input_api.os_path.basename(file_path))
6397 screenshots_dir = input_api.os_path.join(
6398 input_api.os_path.dirname(file_path),
6399 grd_name + ext.replace('.', '_'))
Rainhard Findlingfc31844c52020-05-15 09:58:266400
Sam Maiera6e76d72022-02-11 21:43:506401 # Compute added, removed and modified message IDs.
6402 old_ids = set(old_id_to_msg_map)
6403 new_ids = set(new_id_to_msg_map)
6404 added_ids = new_ids - old_ids
6405 removed_ids = old_ids - new_ids
6406 modified_ids = set([])
6407 for key in old_ids.intersection(new_ids):
6408 if (old_id_to_msg_map[key].ContentsAsXml('', True) !=
6409 new_id_to_msg_map[key].ContentsAsXml('', True)):
6410 # The message content itself changed. Require an updated screenshot.
6411 modified_ids.add(key)
6412 elif old_id_to_msg_map[key].attrs['meaning'] != \
6413 new_id_to_msg_map[key].attrs['meaning']:
Jens Mueller054652c2023-05-10 15:12:306414 # The message meaning changed. We later check for a screenshot.
6415 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146416
Sam Maiera6e76d72022-02-11 21:43:506417 if run_screenshot_check:
6418 # Check the screenshot directory for .png files. Warn if there is any.
6419 for png_path in affected_png_paths:
6420 if png_path.startswith(screenshots_dir):
6421 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146422
Sam Maiera6e76d72022-02-11 21:43:506423 for added_id in added_ids:
6424 _CheckScreenshotAdded(screenshots_dir, added_id)
Rainhard Findlingd8d04372020-08-13 13:30:096425
Sam Maiera6e76d72022-02-11 21:43:506426 for modified_id in modified_ids:
Bruce Dawson55776c42022-12-09 17:23:476427 _CheckScreenshotModified(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146428
Sam Maiera6e76d72022-02-11 21:43:506429 for removed_id in removed_ids:
6430 _CheckScreenshotRemoved(screenshots_dir, removed_id)
6431
6432 # Check new and changed strings for ICU syntax errors.
6433 for key in added_ids.union(modified_ids):
6434 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
6435 err = _ValidateIcuSyntax(msg, 0, [])
6436 if err is not None:
6437 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
6438
6439 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:266440 if run_screenshot_check:
Sam Maiera6e76d72022-02-11 21:43:506441 if unnecessary_screenshots:
6442 results.append(
6443 output_api.PresubmitError(
6444 'Do not include actual screenshots in the changelist. Run '
6445 'tools/translate/upload_screenshots.py to upload them instead:',
6446 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146447
Sam Maiera6e76d72022-02-11 21:43:506448 if missing_sha1:
6449 results.append(
6450 output_api.PresubmitError(
Bruce Dawson55776c42022-12-09 17:23:476451 'You are adding UI strings.\n'
Sam Maiera6e76d72022-02-11 21:43:506452 'To ensure the best translations, take screenshots of the relevant UI '
6453 '(https://g.co/chrome/translation) and add these files to your '
6454 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146455
Jens Mueller054652c2023-05-10 15:12:306456 if invalid_sha1:
6457 results.append(
6458 output_api.PresubmitError(
6459 'The following files do not seem to contain valid sha1 hashes. '
6460 'Make sure they contain hashes created by '
6461 'tools/translate/upload_screenshots.py:', sorted(invalid_sha1)))
6462
Bruce Dawson55776c42022-12-09 17:23:476463 if missing_sha1_modified:
6464 results.append(
6465 output_api.PresubmitError(
6466 'You are modifying UI strings or their meanings.\n'
6467 'To ensure the best translations, take screenshots of the relevant UI '
6468 '(https://g.co/chrome/translation) and add these files to your '
6469 'changelist:', sorted(missing_sha1_modified)))
6470
Sam Maiera6e76d72022-02-11 21:43:506471 if unnecessary_sha1_files:
6472 results.append(
6473 output_api.PresubmitError(
6474 'You removed strings associated with these files. Remove:',
6475 sorted(unnecessary_sha1_files)))
6476 else:
6477 results.append(
6478 output_api.PresubmitPromptOrNotify('Skipping translation '
6479 'screenshots check.'))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146480
Sam Maiera6e76d72022-02-11 21:43:506481 if icu_syntax_errors:
6482 results.append(
6483 output_api.PresubmitPromptWarning(
6484 'ICU syntax errors were found in the following strings (problems or '
6485 'feedback? Contact [email protected]):',
6486 items=icu_syntax_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:266487
Sam Maiera6e76d72022-02-11 21:43:506488 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:126489
6490
Saagar Sanghavifceeaae2020-08-12 16:40:366491def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:126492 repo_root=None,
6493 translation_expectations_path=None,
6494 grd_files=None):
Sam Maiera6e76d72022-02-11 21:43:506495 import sys
6496 affected_grds = [
6497 f for f in input_api.AffectedFiles()
6498 if (f.LocalPath().endswith('.grd') or f.LocalPath().endswith('.grdp'))
6499 ]
6500 if not affected_grds:
6501 return []
6502
6503 try:
6504 old_sys_path = sys.path
6505 sys.path = sys.path + [
6506 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
6507 'translation')
6508 ]
6509 from helper import git_helper
6510 from helper import translation_helper
6511 finally:
6512 sys.path = old_sys_path
6513
6514 # Check that translation expectations can be parsed and we can get a list of
6515 # translatable grd files. |repo_root| and |translation_expectations_path| are
6516 # only passed by tests.
6517 if not repo_root:
6518 repo_root = input_api.PresubmitLocalPath()
6519 if not translation_expectations_path:
6520 translation_expectations_path = input_api.os_path.join(
6521 repo_root, 'tools', 'gritsettings', 'translation_expectations.pyl')
6522 if not grd_files:
6523 grd_files = git_helper.list_grds_in_repository(repo_root)
6524
6525 # Ignore bogus grd files used only for testing
Gao Shenga79ebd42022-08-08 17:25:596526 # ui/webui/resources/tools/generate_grd.py.
Sam Maiera6e76d72022-02-11 21:43:506527 ignore_path = input_api.os_path.join('ui', 'webui', 'resources', 'tools',
6528 'tests')
6529 grd_files = [p for p in grd_files if ignore_path not in p]
6530
6531 try:
6532 translation_helper.get_translatable_grds(
6533 repo_root, grd_files, translation_expectations_path)
6534 except Exception as e:
6535 return [
6536 output_api.PresubmitNotifyResult(
6537 'Failed to get a list of translatable grd files. This happens when:\n'
6538 ' - One of the modified grd or grdp files cannot be parsed or\n'
6539 ' - %s is not updated.\n'
6540 'Stack:\n%s' % (translation_expectations_path, str(e)))
6541 ]
Mustafa Emre Acer51f2f742020-03-09 19:41:126542 return []
6543
Ken Rockotc31f4832020-05-29 18:58:516544
Saagar Sanghavifceeaae2020-08-12 16:40:366545def CheckStableMojomChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506546 """Changes to [Stable] mojom types must preserve backward-compatibility."""
6547 changed_mojoms = input_api.AffectedFiles(
6548 include_deletes=True,
6549 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:526550
Bruce Dawson344ab262022-06-04 11:35:106551 if not changed_mojoms or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:506552 return []
6553
6554 delta = []
6555 for mojom in changed_mojoms:
Sam Maiera6e76d72022-02-11 21:43:506556 delta.append({
6557 'filename': mojom.LocalPath(),
6558 'old': '\n'.join(mojom.OldContents()) or None,
6559 'new': '\n'.join(mojom.NewContents()) or None,
6560 })
6561
6562 process = input_api.subprocess.Popen([
Takuto Ikutadca10222022-04-13 02:51:216563 input_api.python3_executable,
Sam Maiera6e76d72022-02-11 21:43:506564 input_api.os_path.join(
6565 input_api.PresubmitLocalPath(), 'mojo', 'public', 'tools', 'mojom',
6566 'check_stable_mojom_compatibility.py'), '--src-root',
6567 input_api.PresubmitLocalPath()
6568 ],
6569 stdin=input_api.subprocess.PIPE,
6570 stdout=input_api.subprocess.PIPE,
6571 stderr=input_api.subprocess.PIPE,
6572 universal_newlines=True)
6573 (x, error) = process.communicate(input=input_api.json.dumps(delta))
6574 if process.returncode:
6575 return [
6576 output_api.PresubmitError(
6577 'One or more [Stable] mojom definitions appears to have been changed '
6578 'in a way that is not backward-compatible.',
6579 long_text=error)
6580 ]
Erik Staabc734cd7a2021-11-23 03:11:526581 return []
6582
Dominic Battre645d42342020-12-04 16:14:106583def CheckDeprecationOfPreferences(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506584 """Removing a preference should come with a deprecation."""
Dominic Battre645d42342020-12-04 16:14:106585
Sam Maiera6e76d72022-02-11 21:43:506586 def FilterFile(affected_file):
6587 """Accept only .cc files and the like."""
6588 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
6589 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
6590 input_api.DEFAULT_FILES_TO_SKIP)
6591 return input_api.FilterSourceFile(
6592 affected_file,
6593 files_to_check=file_inclusion_pattern,
6594 files_to_skip=files_to_skip)
Dominic Battre645d42342020-12-04 16:14:106595
Sam Maiera6e76d72022-02-11 21:43:506596 def ModifiedLines(affected_file):
6597 """Returns a list of tuples (line number, line text) of added and removed
6598 lines.
Dominic Battre645d42342020-12-04 16:14:106599
Sam Maiera6e76d72022-02-11 21:43:506600 Deleted lines share the same line number as the previous line.
Dominic Battre645d42342020-12-04 16:14:106601
Sam Maiera6e76d72022-02-11 21:43:506602 This relies on the scm diff output describing each changed code section
6603 with a line of the form
Dominic Battre645d42342020-12-04 16:14:106604
Sam Maiera6e76d72022-02-11 21:43:506605 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
6606 """
6607 line_num = 0
6608 modified_lines = []
6609 for line in affected_file.GenerateScmDiff().splitlines():
6610 # Extract <new line num> of the patch fragment (see format above).
6611 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@',
6612 line)
6613 if m:
6614 line_num = int(m.groups(1)[0])
6615 continue
6616 if ((line.startswith('+') and not line.startswith('++'))
6617 or (line.startswith('-') and not line.startswith('--'))):
6618 modified_lines.append((line_num, line))
Dominic Battre645d42342020-12-04 16:14:106619
Sam Maiera6e76d72022-02-11 21:43:506620 if not line.startswith('-'):
6621 line_num += 1
6622 return modified_lines
Dominic Battre645d42342020-12-04 16:14:106623
Sam Maiera6e76d72022-02-11 21:43:506624 def FindLineWith(lines, needle):
6625 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
Dominic Battre645d42342020-12-04 16:14:106626
Sam Maiera6e76d72022-02-11 21:43:506627 If 0 or >1 lines contain `needle`, -1 is returned.
6628 """
6629 matching_line_numbers = [
6630 # + 1 for 1-based counting of line numbers.
6631 i + 1 for i, line in enumerate(lines) if needle in line
6632 ]
6633 return matching_line_numbers[0] if len(
6634 matching_line_numbers) == 1 else -1
Dominic Battre645d42342020-12-04 16:14:106635
Sam Maiera6e76d72022-02-11 21:43:506636 def ModifiedPrefMigration(affected_file):
6637 """Returns whether the MigrateObsolete.*Pref functions were modified."""
6638 # Determine first and last lines of MigrateObsolete.*Pref functions.
6639 new_contents = affected_file.NewContents()
6640 range_1 = (FindLineWith(new_contents,
6641 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
6642 FindLineWith(new_contents,
6643 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
6644 range_2 = (FindLineWith(new_contents,
6645 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
6646 FindLineWith(new_contents,
6647 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
6648 if (-1 in range_1 + range_2):
6649 raise Exception(
6650 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.'
6651 )
Dominic Battre645d42342020-12-04 16:14:106652
Sam Maiera6e76d72022-02-11 21:43:506653 # Check whether any of the modified lines are part of the
6654 # MigrateObsolete.*Pref functions.
6655 for line_nr, line in ModifiedLines(affected_file):
6656 if (range_1[0] <= line_nr <= range_1[1]
6657 or range_2[0] <= line_nr <= range_2[1]):
6658 return True
6659 return False
Dominic Battre645d42342020-12-04 16:14:106660
Sam Maiera6e76d72022-02-11 21:43:506661 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
6662 browser_prefs_file_pattern = input_api.re.compile(
6663 r'chrome/browser/prefs/browser_prefs.cc')
Dominic Battre645d42342020-12-04 16:14:106664
Sam Maiera6e76d72022-02-11 21:43:506665 changes = input_api.AffectedFiles(include_deletes=True,
6666 file_filter=FilterFile)
6667 potential_problems = []
6668 for f in changes:
6669 for line in f.GenerateScmDiff().splitlines():
6670 # Check deleted lines for pref registrations.
6671 if (line.startswith('-') and not line.startswith('--')
6672 and register_pref_pattern.search(line)):
6673 potential_problems.append('%s: %s' % (f.LocalPath(), line))
Dominic Battre645d42342020-12-04 16:14:106674
Sam Maiera6e76d72022-02-11 21:43:506675 if browser_prefs_file_pattern.search(f.LocalPath()):
6676 # If the developer modified the MigrateObsolete.*Prefs() functions, we
6677 # assume that they knew that they have to deprecate preferences and don't
6678 # warn.
6679 try:
6680 if ModifiedPrefMigration(f):
6681 return []
6682 except Exception as e:
6683 return [output_api.PresubmitError(str(e))]
Dominic Battre645d42342020-12-04 16:14:106684
Sam Maiera6e76d72022-02-11 21:43:506685 if potential_problems:
6686 return [
6687 output_api.PresubmitPromptWarning(
6688 'Discovered possible removal of preference registrations.\n\n'
6689 'Please make sure to properly deprecate preferences by clearing their\n'
6690 'value for a couple of milestones before finally removing the code.\n'
6691 'Otherwise data may stay in the preferences files forever. See\n'
6692 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
6693 'chrome/browser/prefs/README.md for examples.\n'
6694 'This may be a false positive warning (e.g. if you move preference\n'
6695 'registrations to a different place).\n', potential_problems)
6696 ]
6697 return []
6698
Matt Stark6ef08872021-07-29 01:21:466699
6700def CheckConsistentGrdChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506701 """Changes to GRD files must be consistent for tools to read them."""
6702 changed_grds = input_api.AffectedFiles(
6703 include_deletes=False,
6704 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
6705 errors = []
6706 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
6707 for matcher, msg in _INVALID_GRD_FILE_LINE]
6708 for grd in changed_grds:
6709 for i, line in enumerate(grd.NewContents()):
6710 for matcher, msg in invalid_file_regexes:
6711 if matcher.search(line):
6712 errors.append(
6713 output_api.PresubmitError(
6714 'Problem on {grd}:{i} - {msg}'.format(
6715 grd=grd.LocalPath(), i=i + 1, msg=msg)))
6716 return errors
6717
Kevin McNee967dd2d22021-11-15 16:09:296718
Henrique Ferreiro2a4b55942021-11-29 23:45:366719def CheckAssertAshOnlyCode(input_api, output_api):
6720 """Errors if a BUILD.gn file in an ash/ directory doesn't include
6721 assert(is_chromeos_ash).
6722 """
6723
6724 def FileFilter(affected_file):
6725 """Includes directories known to be Ash only."""
6726 return input_api.FilterSourceFile(
6727 affected_file,
6728 files_to_check=(
6729 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
6730 r'.*/ash/.*BUILD\.gn'), # Any path component.
6731 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
6732
6733 errors = []
6734 pattern = input_api.re.compile(r'assert\(is_chromeos_ash')
Jameson Thies0ce669f2021-12-09 15:56:566735 for f in input_api.AffectedFiles(include_deletes=False,
6736 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:366737 if (not pattern.search(input_api.ReadFile(f))):
6738 errors.append(
6739 output_api.PresubmitError(
6740 'Please add assert(is_chromeos_ash) to %s. If that\'s not '
6741 'possible, please create and issue and add a comment such '
6742 'as:\n # TODO(https://crbug.com/XXX): add '
6743 'assert(is_chromeos_ash) when ...' % f.LocalPath()))
6744 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:276745
6746
Kalvin Lee84ad17a2023-09-25 11:14:416747def _IsMiraclePtrDisallowed(input_api, affected_file):
Sam Maiera6e76d72022-02-11 21:43:506748 path = affected_file.LocalPath()
6749 if not _IsCPlusPlusFile(input_api, path):
6750 return False
6751
Kalvin Lee84ad17a2023-09-25 11:14:416752 # Renderer code is generally allowed to use MiraclePtr.
6753 # These directories, however, are specifically disallowed.
6754 if ("third_party/blink/renderer/core/" in path
6755 or "third_party/blink/renderer/platform/heap/" in path
6756 or "third_party/blink/renderer/platform/wtf/" in path):
Sam Maiera6e76d72022-02-11 21:43:506757 return True
6758
6759 # Blink's public/web API is only used/included by Renderer-only code. Note
6760 # that public/platform API may be used in non-Renderer processes (e.g. there
6761 # are some includes in code used by Utility, PDF, or Plugin processes).
6762 if "/blink/public/web/" in path:
6763 return True
6764
6765 # We assume that everything else may be used outside of Renderer processes.
Lukasz Anforowicz7016d05e2021-11-30 03:56:276766 return False
6767
Lukasz Anforowicz7016d05e2021-11-30 03:56:276768# TODO(https://crbug.com/1273182): Remove these checks, once they are replaced
6769# by the Chromium Clang Plugin (which will be preferable because it will
6770# 1) report errors earlier - at compile-time and 2) cover more rules).
6771def CheckRawPtrUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506772 """Rough checks that raw_ptr<T> usage guidelines are followed."""
6773 errors = []
6774 # The regex below matches "raw_ptr<" following a word boundary, but not in a
6775 # C++ comment.
6776 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
Kalvin Lee84ad17a2023-09-25 11:14:416777 file_filter = lambda f: _IsMiraclePtrDisallowed(input_api, f)
Sam Maiera6e76d72022-02-11 21:43:506778 for f, line_num, line in input_api.RightHandSideLines(file_filter):
6779 if raw_ptr_matcher.search(line):
6780 errors.append(
6781 output_api.PresubmitError(
6782 'Problem on {path}:{line} - '\
Kalvin Lee84ad17a2023-09-25 11:14:416783 'raw_ptr<T> should not be used in this renderer code '\
Sam Maiera6e76d72022-02-11 21:43:506784 '(as documented in the "Pointers to unprotected memory" '\
6785 'section in //base/memory/raw_ptr.md)'.format(
6786 path=f.LocalPath(), line=line_num)))
6787 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:566788
mikt9337567c2023-09-08 18:38:176789def CheckAdvancedMemorySafetyChecksUsage(input_api, output_api):
6790 """Checks that ADVANCED_MEMORY_SAFETY_CHECKS() macro is neither added nor
6791 removed as it is managed by the memory safety team internally.
6792 Do not add / remove it manually."""
6793 paths = set([])
6794 # The regex below matches "ADVANCED_MEMORY_SAFETY_CHECKS(" following a word
6795 # boundary, but not in a C++ comment.
6796 macro_matcher = input_api.re.compile(
6797 r'^((?!//).)*\bADVANCED_MEMORY_SAFETY_CHECKS\(', input_api.re.MULTILINE)
6798 for f in input_api.AffectedFiles():
6799 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
6800 continue
6801 if macro_matcher.search(f.GenerateScmDiff()):
6802 paths.add(f.LocalPath())
6803 if not paths:
6804 return []
6805 return [output_api.PresubmitPromptWarning(
6806 'ADVANCED_MEMORY_SAFETY_CHECKS() macro is managed by ' \
6807 'the memory safety team (chrome-memory-safety@). ' \
6808 'Please contact us to add/delete the uses of the macro.',
6809 paths)]
Henrique Ferreirof9819f2e32021-11-30 13:31:566810
6811def CheckPythonShebang(input_api, output_api):
6812 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
6813 system-wide python.
6814 """
6815 errors = []
6816 sources = lambda affected_file: input_api.FilterSourceFile(
6817 affected_file,
6818 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
6819 r'third_party/blink/web_tests/external/') + input_api.
6820 DEFAULT_FILES_TO_SKIP),
6821 files_to_check=[r'.*\.py$'])
6822 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:276823 for line_num, line in f.ChangedContents():
6824 if line_num == 1 and line.startswith('#!/usr/bin/python'):
6825 errors.append(f.LocalPath())
6826 break
Henrique Ferreirof9819f2e32021-11-30 13:31:566827
6828 result = []
6829 for file in errors:
6830 result.append(
6831 output_api.PresubmitError(
6832 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
6833 file))
6834 return result
James Shen81cc0e22022-06-15 21:10:456835
6836
6837def CheckBatchAnnotation(input_api, output_api):
6838 """Checks that tests have either @Batch or @DoNotBatch annotation. If this
6839 is not an instrumentation test, disregard."""
6840
6841 batch_annotation = input_api.re.compile(r'^\s*@Batch')
6842 do_not_batch_annotation = input_api.re.compile(r'^\s*@DoNotBatch')
6843 robolectric_test = input_api.re.compile(r'[rR]obolectric')
6844 test_class_declaration = input_api.re.compile(r'^\s*public\sclass.*Test')
6845 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
Mark Schillaci8ef0d872023-07-18 22:07:596846 test_annotation_declaration = input_api.re.compile(r'^\s*public\s@interface\s.*{')
James Shen81cc0e22022-06-15 21:10:456847
ckitagawae8fd23b2022-06-17 15:29:386848 missing_annotation_errors = []
6849 extra_annotation_errors = []
James Shen81cc0e22022-06-15 21:10:456850
6851 def _FilterFile(affected_file):
6852 return input_api.FilterSourceFile(
6853 affected_file,
6854 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
6855 files_to_check=[r'.*Test\.java$'])
6856
6857 for f in input_api.AffectedSourceFiles(_FilterFile):
6858 batch_matched = None
6859 do_not_batch_matched = None
6860 is_instrumentation_test = True
Mark Schillaci8ef0d872023-07-18 22:07:596861 test_annotation_declaration_matched = None
James Shen81cc0e22022-06-15 21:10:456862 for line in f.NewContents():
6863 if robolectric_test.search(line) or uiautomator_test.search(line):
6864 # Skip Robolectric and UiAutomator tests.
6865 is_instrumentation_test = False
6866 break
6867 if not batch_matched:
6868 batch_matched = batch_annotation.search(line)
6869 if not do_not_batch_matched:
6870 do_not_batch_matched = do_not_batch_annotation.search(line)
6871 test_class_declaration_matched = test_class_declaration.search(
6872 line)
Mark Schillaci8ef0d872023-07-18 22:07:596873 test_annotation_declaration_matched = test_annotation_declaration.search(line)
6874 if test_class_declaration_matched or test_annotation_declaration_matched:
James Shen81cc0e22022-06-15 21:10:456875 break
Mark Schillaci8ef0d872023-07-18 22:07:596876 if test_annotation_declaration_matched:
6877 continue
James Shen81cc0e22022-06-15 21:10:456878 if (is_instrumentation_test and
6879 not batch_matched and
6880 not do_not_batch_matched):
Sam Maier4cef9242022-10-03 14:21:246881 missing_annotation_errors.append(str(f.LocalPath()))
ckitagawae8fd23b2022-06-17 15:29:386882 if (not is_instrumentation_test and
6883 (batch_matched or
6884 do_not_batch_matched)):
Sam Maier4cef9242022-10-03 14:21:246885 extra_annotation_errors.append(str(f.LocalPath()))
James Shen81cc0e22022-06-15 21:10:456886
6887 results = []
6888
ckitagawae8fd23b2022-06-17 15:29:386889 if missing_annotation_errors:
James Shen81cc0e22022-06-15 21:10:456890 results.append(
6891 output_api.PresubmitPromptWarning(
6892 """
Andrew Grieve43a5cf82023-09-08 15:09:466893A change was made to an on-device test that has neither been annotated with
6894@Batch nor @DoNotBatch. If this is a new test, please add the annotation. If
6895this is an existing test, please consider adding it if you are sufficiently
6896familiar with the test (but do so as a separate change).
6897
Jens Mueller2085ff82023-02-27 11:54:496898See https://source.chromium.org/chromium/chromium/src/+/main:docs/testing/batching_instrumentation_tests.md
ckitagawae8fd23b2022-06-17 15:29:386899""", missing_annotation_errors))
6900 if extra_annotation_errors:
6901 results.append(
6902 output_api.PresubmitPromptWarning(
6903 """
6904Robolectric tests do not need a @Batch or @DoNotBatch annotations.
6905""", extra_annotation_errors))
James Shen81cc0e22022-06-15 21:10:456906
6907 return results
Sam Maier4cef9242022-10-03 14:21:246908
6909
6910def CheckMockAnnotation(input_api, output_api):
6911 """Checks that we have annotated all Mockito.mock()-ed or Mockito.spy()-ed
6912 classes with @Mock or @Spy. If this is not an instrumentation test,
6913 disregard."""
6914
6915 # This is just trying to be approximately correct. We are not writing a
6916 # Java parser, so special cases like statically importing mock() then
6917 # calling an unrelated non-mockito spy() function will cause a false
6918 # positive.
6919 package_name = input_api.re.compile(r'^package\s+(\w+(?:\.\w+)+);')
6920 mock_static_import = input_api.re.compile(
6921 r'^import\s+static\s+org.mockito.Mockito.(?:mock|spy);')
6922 import_class = input_api.re.compile(r'import\s+((?:\w+\.)+)(\w+);')
6923 mock_annotation = input_api.re.compile(r'^\s*@(?:Mock|Spy)')
6924 field_type = input_api.re.compile(r'(\w+)(?:<\w+>)?\s+\w+\s*(?:;|=)')
6925 mock_or_spy_function_call = r'(?:mock|spy)\(\s*(?:new\s*)?(\w+)(?:\.class|\()'
6926 fully_qualified_mock_function = input_api.re.compile(
6927 r'Mockito\.' + mock_or_spy_function_call)
6928 statically_imported_mock_function = input_api.re.compile(
6929 r'\W' + mock_or_spy_function_call)
6930 robolectric_test = input_api.re.compile(r'[rR]obolectric')
6931 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
6932
6933 def _DoClassLookup(class_name, class_name_map, package):
6934 found = class_name_map.get(class_name)
6935 if found is not None:
6936 return found
6937 else:
6938 return package + '.' + class_name
6939
6940 def _FilterFile(affected_file):
6941 return input_api.FilterSourceFile(
6942 affected_file,
6943 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
6944 files_to_check=[r'.*Test\.java$'])
6945
6946 mocked_by_function_classes = set()
6947 mocked_by_annotation_classes = set()
6948 class_to_filename = {}
6949 for f in input_api.AffectedSourceFiles(_FilterFile):
6950 mock_function_regex = fully_qualified_mock_function
6951 next_line_is_annotated = False
6952 fully_qualified_class_map = {}
6953 package = None
6954
6955 for line in f.NewContents():
6956 if robolectric_test.search(line) or uiautomator_test.search(line):
6957 # Skip Robolectric and UiAutomator tests.
6958 break
6959
6960 m = package_name.search(line)
6961 if m:
6962 package = m.group(1)
6963 continue
6964
6965 if mock_static_import.search(line):
6966 mock_function_regex = statically_imported_mock_function
6967 continue
6968
6969 m = import_class.search(line)
6970 if m:
6971 fully_qualified_class_map[m.group(2)] = m.group(1) + m.group(2)
6972 continue
6973
6974 if next_line_is_annotated:
6975 next_line_is_annotated = False
6976 fully_qualified_class = _DoClassLookup(
6977 field_type.search(line).group(1), fully_qualified_class_map,
6978 package)
6979 mocked_by_annotation_classes.add(fully_qualified_class)
6980 continue
6981
6982 if mock_annotation.search(line):
6983 next_line_is_annotated = True
6984 continue
6985
6986 m = mock_function_regex.search(line)
6987 if m:
6988 fully_qualified_class = _DoClassLookup(m.group(1),
6989 fully_qualified_class_map, package)
6990 # Skipping builtin classes, since they don't get optimized.
6991 if fully_qualified_class.startswith(
6992 'android.') or fully_qualified_class.startswith(
6993 'java.'):
6994 continue
6995 class_to_filename[fully_qualified_class] = str(f.LocalPath())
6996 mocked_by_function_classes.add(fully_qualified_class)
6997
6998 results = []
6999 missed_classes = mocked_by_function_classes - mocked_by_annotation_classes
7000 if missed_classes:
7001 error_locations = []
7002 for c in missed_classes:
7003 error_locations.append(c + ' in ' + class_to_filename[c])
7004 results.append(
7005 output_api.PresubmitPromptWarning(
7006 """
7007Mockito.mock()/spy() cause issues with our Java optimizer. You have 3 options:
70081) If the mocked variable can be a class member, annotate the member with
7009 @Mock/@Spy.
70102) If the mocked variable cannot be a class member, create a dummy member
7011 variable of that type, annotated with @Mock/@Spy. This dummy does not need
7012 to be used or initialized in any way.
70133) If the mocked type is definitely not going to be optimized, whether it's a
7014 builtin type which we don't ship, or a class you know R8 will treat
7015 specially, you can ignore this warning.
7016""", error_locations))
7017
7018 return results
Mike Dougherty1b8be712022-10-20 00:15:137019
7020def CheckNoJsInIos(input_api, output_api):
7021 """Checks to make sure that JavaScript files are not used on iOS."""
7022
7023 def _FilterFile(affected_file):
7024 return input_api.FilterSourceFile(
7025 affected_file,
7026 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP +
Daniel White44b8bd02023-08-22 16:20:367027 (r'^ios/third_party/*', r'^ios/tools/*', r'^third_party/*',
7028 r'^components/autofill/ios/form_util/resources/*'),
Mike Dougherty1b8be712022-10-20 00:15:137029 files_to_check=[r'^ios/.*\.js$', r'.*/ios/.*\.js$'])
7030
Mike Dougherty4d1050b2023-03-14 15:59:537031 deleted_files = []
7032
7033 # Collect filenames of all removed JS files.
7034 for f in input_api.AffectedSourceFiles(_FilterFile):
7035 local_path = f.LocalPath()
7036
7037 if input_api.os_path.splitext(local_path)[1] == '.js' and f.Action() == 'D':
7038 deleted_files.append(input_api.os_path.basename(local_path))
7039
Mike Dougherty1b8be712022-10-20 00:15:137040 error_paths = []
Mike Dougherty4d1050b2023-03-14 15:59:537041 moved_paths = []
Mike Dougherty1b8be712022-10-20 00:15:137042 warning_paths = []
7043
7044 for f in input_api.AffectedSourceFiles(_FilterFile):
7045 local_path = f.LocalPath()
7046
7047 if input_api.os_path.splitext(local_path)[1] == '.js':
7048 if f.Action() == 'A':
Mike Dougherty4d1050b2023-03-14 15:59:537049 if input_api.os_path.basename(local_path) in deleted_files:
7050 # This script was probably moved rather than newly created.
7051 # Present a warning instead of an error for these cases.
7052 moved_paths.append(local_path)
7053 else:
7054 error_paths.append(local_path)
Mike Dougherty1b8be712022-10-20 00:15:137055 elif f.Action() != 'D':
7056 warning_paths.append(local_path)
7057
7058 results = []
7059
7060 if warning_paths:
7061 results.append(output_api.PresubmitPromptWarning(
7062 'TypeScript is now fully supported for iOS feature scripts. '
7063 'Consider converting JavaScript files to TypeScript. See '
7064 '//ios/web/public/js_messaging/README.md for more details.',
7065 warning_paths))
7066
Mike Dougherty4d1050b2023-03-14 15:59:537067 if moved_paths:
7068 results.append(output_api.PresubmitPromptWarning(
7069 'Do not use JavaScript on iOS for new files as TypeScript is '
7070 'fully supported. (If this is a moved file, you may leave the '
7071 'script unconverted.) See //ios/web/public/js_messaging/README.md '
7072 'for help using scripts on iOS.', moved_paths))
7073
Mike Dougherty1b8be712022-10-20 00:15:137074 if error_paths:
7075 results.append(output_api.PresubmitError(
7076 'Do not use JavaScript on iOS as TypeScript is fully supported. '
7077 'See //ios/web/public/js_messaging/README.md for help using '
7078 'scripts on iOS.', error_paths))
7079
7080 return results
Hans Wennborg23a81d52023-03-24 16:38:137081
7082def CheckLibcxxRevisionsMatch(input_api, output_api):
7083 """Check to make sure the libc++ version matches across deps files."""
Andrew Grieve21bb6792023-03-27 19:06:487084 # Disable check for changes to sub-repositories.
7085 if input_api.PresubmitLocalPath() != input_api.change.RepositoryRoot():
Sam Maierb926c58c2023-08-08 19:58:257086 return []
Hans Wennborg23a81d52023-03-24 16:38:137087
7088 DEPS_FILES = [ 'DEPS', 'buildtools/deps_revisions.gni' ]
7089
7090 file_filter = lambda f: f.LocalPath().replace(
7091 input_api.os_path.sep, '/') in DEPS_FILES
7092 changed_deps_files = input_api.AffectedFiles(file_filter=file_filter)
7093 if not changed_deps_files:
7094 return []
7095
7096 def LibcxxRevision(file):
7097 file = input_api.os_path.join(input_api.PresubmitLocalPath(),
7098 *file.split('/'))
7099 return input_api.re.search(
7100 r'libcxx_revision.*[:=].*[\'"](\w+)[\'"]',
7101 input_api.ReadFile(file)).group(1)
7102
7103 if len(set([LibcxxRevision(f) for f in DEPS_FILES])) == 1:
7104 return []
7105
7106 return [output_api.PresubmitError(
7107 'libcxx_revision not equal across %s' % ', '.join(DEPS_FILES),
7108 changed_deps_files)]
Arthur Sonzogni7109bd32023-10-03 10:34:427109
7110
7111def CheckDanglingUntriaged(input_api, output_api):
7112 """Warn developers adding DanglingUntriaged raw_ptr."""
7113
7114 # Ignore during git presubmit --all.
7115 #
7116 # This would be too costly, because this would check every lines of every
7117 # C++ files. Check from _BANNED_CPP_FUNCTIONS are also reading the whole
7118 # source code, but only once to apply every checks. It seems the bots like
7119 # `win-presubmit` are particularly sensitive to reading the files. Adding
7120 # this check caused the bot to run 2x longer. See https://crbug.com/1486612.
7121 if input_api.no_diffs:
7122 return []
7123
7124 def FilterFile(file):
7125 return input_api.FilterSourceFile(
7126 file,
7127 files_to_check=[r".*\.(h|cc|cpp|cxx|m|mm)$"],
7128 files_to_skip=[r"^base/allocator.*"],
7129 )
7130
7131 count = 0
7132 for f in input_api.AffectedSourceFiles(FilterFile):
7133 count -= f.OldContents().count("DanglingUntriaged")
7134 count += f.NewContents().count("DanglingUntriaged")
7135
7136 # Most likely, nothing changed:
7137 if count == 0:
7138 return []
7139
7140 # Congrats developers for improving it:
7141 if count < 0:
7142 message = (
7143 f"DanglingUntriaged pointers removed: {-count}",
7144 f"Thank you!",
7145 )
7146 return [output_api.PresubmitNotifyResult(message)]
7147
7148 # Check for 'DanglingUntriaged-notes' in the description:
7149 notes_regex = input_api.re.compile("DanglingUntriaged-notes[:=]")
7150 if any(
7151 notes_regex.match(line)
7152 for line in input_api.change.DescriptionText().splitlines()):
7153 return []
7154
7155 # Check for DanglingUntriaged-notes in the git footer:
7156 if input_api.change.GitFootersFromDescription().get(
7157 "DanglingUntriaged-notes", []):
7158 return []
7159
7160 message = (
7161 "Unexpected new occurrences of `DanglingUntriaged` detected. Please",
7162 "avoid adding new ones",
7163 "",
7164 "See documentation:",
7165 "https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr.md",
7166 "",
7167 "See also the guide to fix dangling pointers:",
7168 "https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr_guide.md",
7169 "",
7170 "To disable this warning, please add in the commit description:",
7171 "DanglingUntriaged-notes: <rational for new untriaged dangling "
7172 "pointers>",
7173 )
7174 return [output_api.PresubmitPromptWarning(message)]