blob: aebe187757dc6c7828b0d1bb62a4febf1b47ac5c [file] [log] [blame]
Avi Drissman24976592022-09-12 15:24:311# Copyright 2012 The Chromium Authors
[email protected]ca8d19842009-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.
[email protected]ca8d19842009-02-19 16:33:124"""Top-level presubmit script for Chromium.
5
Daniel Chengd88244472022-05-16 09:08:476See https://www.chromium.org/developers/how-tos/depottools/presubmit-scripts/
tfarina78bb92f42015-01-31 00:20:487for more details about the presubmit API built into depot_tools.
[email protected]ca8d19842009-02-19 16:33:128"""
Daniel Chenga44a1bcd2022-03-15 20:00:159
Daniel Chenga37c03db2022-05-12 17:20:3410from typing import Callable
Daniel Chenga44a1bcd2022-03-15 20:00:1511from typing import Optional
12from typing import Sequence
mikt19226ff22024-08-27 05:28:2113from typing import Tuple
Daniel Chenga44a1bcd2022-03-15 20:00:1514from dataclasses import dataclass
15
Saagar Sanghavifceeaae2020-08-12 16:40:3616PRESUBMIT_VERSION = '2.0.0'
[email protected]eea609a2011-11-18 13:10:1217
[email protected]379e7dd2010-01-28 17:39:2118_EXCLUDED_PATHS = (
Bruce Dawson7f8566b2022-05-06 16:22:1819 # Generated file
Bruce Dawson40fece62022-09-16 19:58:3120 (r"chrome/android/webapk/shell_apk/src/org/chromium"
21 r"/webapk/lib/runtime_library/IWebApkApi.java"),
Mila Greene3aa7222021-09-07 16:34:0822 # File needs to write to stdout to emulate a tool it's replacing.
Bruce Dawson40fece62022-09-16 19:58:3123 r"chrome/updater/mac/keystone/ksadmin.mm",
Ilya Shermane8a7d2d2020-07-25 04:33:4724 # Generated file.
Bruce Dawson40fece62022-09-16 19:58:3125 (r"^components/variations/proto/devtools/"
Ilya Shermanc167a962020-08-18 18:40:2626 r"client_variations.js"),
Bruce Dawson3bd976c2022-05-06 22:47:5227 # These are video files, not typescript.
Bruce Dawson40fece62022-09-16 19:58:3128 r"^media/test/data/.*.ts",
29 r"^native_client_sdksrc/build_tools/make_rules.py",
30 r"^native_client_sdk/src/build_tools/make_simple.py",
31 r"^native_client_sdk/src/tools/.*.mk",
32 r"^net/tools/spdyshark/.*",
33 r"^skia/.*",
34 r"^third_party/blink/.*",
35 r"^third_party/breakpad/.*",
Darwin Huangd74a9d32019-07-17 17:58:4636 # sqlite is an imported third party dependency.
Bruce Dawson40fece62022-09-16 19:58:3137 r"^third_party/sqlite/.*",
38 r"^v8/.*",
[email protected]3e4eb112011-01-18 03:29:5439 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5340 r".+_autogen\.h$",
Yue Shecf1380552022-08-23 20:59:2041 r".+_pb2(_grpc)?\.py$",
Bruce Dawson40fece62022-09-16 19:58:3142 r".+/pnacl_shim\.c$",
43 r"^gpu/config/.*_list_json\.cc$",
44 r"tools/md_browser/.*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1445 # Test pages for Maps telemetry tests.
Bruce Dawson40fece62022-09-16 19:58:3146 r"tools/perf/page_sets/maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5447 # Test pages for WebRTC telemetry tests.
Bruce Dawson40fece62022-09-16 19:58:3148 r"tools/perf/page_sets/webrtc_cases.*",
dpapad2efd4452023-04-06 01:43:4549 # Test file compared with generated output.
50 r"tools/polymer/tests/html_to_wrapper/.*.html.ts$",
dpapada45be36c2024-08-07 20:19:3551 # Third-party dependency frozen at a fixed version.
52 r"chrome/test/data/webui/chromeos/chai_v4.js$",
[email protected]4306417642009-06-11 00:33:4053)
[email protected]ca8d19842009-02-19 16:33:1254
John Abd-El-Malek759fea62021-03-13 03:41:1455_EXCLUDED_SET_NO_PARENT_PATHS = (
56 # It's for historical reasons that blink isn't a top level directory, where
57 # it would be allowed to have "set noparent" to avoid top level owners
58 # accidentally +1ing changes.
Daniel Cheng6303eed2025-05-03 00:12:3359 'third_party/blink/OWNERS', )
wnwenbdc444e2016-05-25 13:44:1560
[email protected]06e6d0ff2012-12-11 01:36:4461# Fragment of a regular expression that matches C++ and Objective-C++
62# implementation files.
63_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
64
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1965# Fragment of a regular expression that matches C++ and Objective-C++
66# header files.
67_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
68
Aleksey Khoroshilov9b28c032022-06-03 16:35:3269# Paths with sources that don't use //base.
70_NON_BASE_DEPENDENT_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:3171 r"^chrome/browser/browser_switcher/bho/",
72 r"^tools/win/",
Aleksey Khoroshilov9b28c032022-06-03 16:35:3273)
74
[email protected]06e6d0ff2012-12-11 01:36:4475# Regular expression that matches code only used for test binaries
76# (best effort).
77_TEST_CODE_EXCLUDED_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:3178 r'.*/(fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
Marijn Kruisselbrink2a2d5fc2024-05-15 15:23:4979 # Test support files, like:
80 # foo_test_support.cc
81 # bar_test_util_linux.cc (suffix)
82 # baz_test_base.cc
83 r'.+_test_(base|support|util)(_[a-z]+)?%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' %
Daniel Cheng6303eed2025-05-03 00:12:3389 _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
Daniel Cheng6303eed2025-05-03 00:12:33106 r'codelabs/*')
[email protected]ca8d19842009-02-19 16:33:12107
Daniel Bratell609102be2019-03-27 20:53:21108_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:15109
[email protected]eea609a2011-11-18 13:10:12110_TEST_ONLY_WARNING = (
111 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:55112 'production code. If you are doing this from inside another method\n'
113 'named as *ForTesting(), then consider exposing things to have tests\n'
114 'make that same call directly.\n'
115 'If that is not possible, you may put a comment on the same line with\n'
116 ' // IN-TEST \n'
117 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
118 'method and can be ignored. Do not do this inside production code.\n'
119 'The android-binary-size trybot will block if the method exists in the\n'
Yulun Zeng08d7d8c2024-02-01 18:46:54120 'release apk.\n'
121 'Note: this warning might be a false positive (crbug.com/1196548).')
[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.
mikt19226ff22024-08-27 05:28:21131 explanation: Tuple[str, ...]
Daniel Chenga37c03db2022-05-12 17:20:34132 # 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
Ben Pastenee79d66112025-04-23 19:46:15139 # If True, surfaces any violation as a Gerrit comment on the CL after
140 # running the CQ.
141 surface_as_gerrit_lint: Optional[bool] = None
[email protected]cf9b78f2012-11-14 11:40:28142
Daniel Chenga44a1bcd2022-03-15 20:00:15143
Daniel Cheng6303eed2025-05-03 00:12:33144_BANNED_JAVA_IMPORTS: Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15145 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33146 'import java.net.URI;',
147 ('Use org.chromium.url.GURL instead of java.net.URI, where possible.',
148 ),
149 excluded_paths=(
150 (r'net/android/javatests/src/org/chromium/net/'
151 r'AndroidProxySelectorTest\.java'),
152 r'components/cronet/',
153 r'third_party/robolectric/local/',
154 ),
Michael Thiessen44457642020-02-06 00:24:15155 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15156 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33157 'import android.annotation.TargetApi;',
158 ('Do not use TargetApi, use @androidx.annotation.RequiresApi instead. '
159 'RequiresApi ensures that any calls are guarded by the appropriate '
160 'SDK_INT check. See https://crbug.com/1116486.', ),
Daniel Chenga44a1bcd2022-03-15 20:00:15161 ),
162 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33163 'import androidx.test.rule.ActivityTestRule;',
164 ('Do not use ActivityTestRule, use '
165 'org.chromium.base.test.BaseActivityTestRule instead.', ),
166 excluded_paths=('components/cronet/', ),
Daniel Chenga44a1bcd2022-03-15 20:00:15167 ),
Min Qinbc44383c2023-02-22 17:25:26168 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33169 'import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;',
170 ('Do not use VectorDrawableCompat, use getResources().getDrawable() to '
171 'avoid extra indirections. Please also add trace event as the call '
172 'might take more than 20 ms to complete.', ),
Min Qinbc44383c2023-02-22 17:25:26173 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15174)
wnwenbdc444e2016-05-25 13:44:15175
Daniel Cheng6303eed2025-05-03 00:12:33176_BANNED_JAVA_FUNCTIONS: Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15177 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33178 'StrictMode.allowThreadDiskReads()',
179 ('Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
180 'directly.', ),
181 False,
Eric Stevensona9a980972017-09-23 00:04:41182 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15183 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33184 'StrictMode.allowThreadDiskWrites()',
185 ('Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
186 'directly.', ),
187 False,
Eric Stevensona9a980972017-09-23 00:04:41188 ),
Daniel Cheng917ce542022-03-15 20:46:57189 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33190 '.waitForIdleSync()',
191 ('Do not use waitForIdleSync as it masks underlying issues. There is '
192 'almost always something else you should wait on instead.', ),
193 False,
Michael Thiessen0f2547e2020-07-27 21:55:36194 ),
Ashley Newson09cbd602022-10-26 11:40:14195 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33196 r'/(?<!\bsuper\.)(?<!\bIntent )\bregisterReceiver\(',
197 ('Do not call android.content.Context.registerReceiver (or an override) '
198 'directly. Use one of the wrapper methods defined in '
199 'org.chromium.base.ContextUtils, such as '
200 'registerProtectedBroadcastReceiver, '
201 'registerExportedBroadcastReceiver, or '
202 'registerNonExportedBroadcastReceiver. See their documentation for '
203 'which one to use.', ),
204 True,
205 excluded_paths=(
206 r'.*Test[^a-z]',
207 r'third_party/',
208 'base/android/java/src/org/chromium/base/ContextUtils.java',
209 'chromecast/browser/android/apk/src/org/chromium/chromecast/shell/BroadcastReceiverScope.java',
210 ),
Ashley Newson09cbd602022-10-26 11:40:14211 ),
Ted Chocd5b327b12022-11-05 02:13:22212 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33213 r'/(?:extends|new)\s*(?:android.util.)?Property<[A-Za-z.]+,\s*(?:Integer|Float)>',
214 ('Do not use Property<..., Integer|Float>, but use FloatProperty or '
215 'IntProperty because it will avoid unnecessary autoboxing of '
216 'primitives.', ),
Ted Chocd5b327b12022-11-05 02:13:22217 ),
Peilin Wangbba4a8652022-11-10 16:33:57218 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33219 'requestLayout()',
220 ('Layouts can be expensive. Prefer using ViewUtils.requestLayout(), '
221 'which emits a trace event with additional information to help with '
222 'scroll jank investigations. See http://crbug.com/1354176.', ),
223 False,
224 excluded_paths=(
225 'ui/android/java/src/org/chromium/ui/base/ViewUtils.java', ),
Peilin Wangbba4a8652022-11-10 16:33:57226 ),
Ted Chocf40ea9152023-02-14 19:02:39227 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33228 'ProfileManager.getLastUsedRegularProfile()',
229 ('Prefer passing in the Profile reference instead of relying on the '
230 'static getLastUsedRegularProfile() call. Only top level entry points '
231 '(e.g. Activities) should call this method. Otherwise, the Profile '
232 'should either be passed in explicitly or retreived from an existing '
233 'entity with a reference to the Profile (e.g. WebContents).', ),
234 False,
235 excluded_paths=(r'.*Test[A-Z]?.*\.java', ),
Ted Chocf40ea9152023-02-14 19:02:39236 ),
Min Qinbc44383c2023-02-22 17:25:26237 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33238 r'/(ResourcesCompat|getResources\(\))\.getDrawable\(\)',
239 ('getDrawable() can be expensive. If you have a lot of calls to '
240 'GetDrawable() or your code may introduce janks, please put your calls '
241 'inside a trace().', ),
242 False,
243 excluded_paths=(r'.*Test[A-Z]?.*\.java', ),
Min Qinbc44383c2023-02-22 17:25:26244 ),
Henrique Nakashimabbf2b262023-03-10 17:21:39245 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33246 r'/RecordHistogram\.getHistogram(ValueCount|TotalCount|Samples)ForTesting\(',
247 ('Raw histogram counts are easy to misuse; for example they don\'t reset '
248 'between batched tests. Use HistogramWatcher to check histogram records '
249 'instead.', ),
250 False,
251 excluded_paths=(
252 'base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java',
253 'base/test/android/javatests/src/org/chromium/base/test/util/HistogramWatcher.java',
254 ),
Henrique Nakashimabbf2b262023-03-10 17:21:39255 ),
Jenna Himawan859865d2025-02-25 22:22:31256 BanRule(
257 r'/((announceForAccessibility\()|TYPE_ANNOUNCEMENT)',
258 ('Android 16 deprecates accessibility announcements, characterized by '
259 'the use of announceForAccessibility or the dispatch of '
260 'TYPE_ANNOUNCEMENT accessibility events. See '
261 'https://developer.android.com/about/versions/16/behavior-changes-all#disruptive-a11y'
262 ' for more details and suggested replacements.', ),
263 False,
264 ),
Nate Fischerd541ff82025-03-11 21:34:19265 BanRule(
266 pattern=(r'IS_DESKTOP_ANDROID'),
267 explanation=(
Eric Lokc26a46662025-05-02 01:04:03268 'Do not add new uses of IS_DESKTOP_ANDROID build flag until you '
269 'have the approval of tedchoc@ or twellington@. '
270 'Background: it is highly important to reduce the divergence of '
271 'features across platforms. '
272 'Allowances may be granted to only the directories below: '
273 '[build/, chrome/, components/, extensions/, infra/, tools/] ',
274 'Note: in particular we need to avoid components shared with '
275 'WebView.',
276 ),
Nate Fischerd541ff82025-03-11 21:34:19277 treat_as_error=False,
Ben Pastenee79d66112025-04-23 19:46:15278 surface_as_gerrit_lint=True,
Nate Fischerd541ff82025-03-11 21:34:19279 ),
Eric Stevensona9a980972017-09-23 00:04:41280)
281
Daniel Cheng6303eed2025-05-03 00:12:33282_BANNED_JAVASCRIPT_FUNCTIONS: Sequence[BanRule] = (
Clement Yan9b330cb2022-11-17 05:25:29283 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33284 r'/\bchrome\.send\b',
285 (
286 '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).',
287 'Please use mojo instead for new webuis. https://docs.google.com/document/d/1RF-GSUoveYa37eoyZ9EhwMtaIwoW7Z88pIgNZ9YzQi4/edit#heading=h.gkk22wgk6wff',
288 ),
289 True,
290 (
291 r'^(?!ash\/webui).+',
292 # TODO(crbug.com/1385601): pre-existing violations still need to be
293 # cleaned up.
294 'ash/webui/common/resources/cr.m.js',
295 'ash/webui/common/resources/multidevice_setup/multidevice_setup_browser_proxy.js',
296 'ash/webui/common/resources/quick_unlock/lock_screen_constants.ts',
297 'ash/webui/common/resources/smb_shares/smb_browser_proxy.js',
298 'ash/webui/connectivity_diagnostics/resources/connectivity_diagnostics.ts',
299 'ash/webui/diagnostics_ui/resources/diagnostics_browser_proxy.ts',
300 'ash/webui/multidevice_debug/resources/logs.js',
301 'ash/webui/multidevice_debug/resources/webui.js',
302 'ash/webui/projector_app/resources/annotator/trusted/annotator_browser_proxy.js',
303 'ash/webui/projector_app/resources/app/trusted/projector_browser_proxy.js',
304 # TODO(b/301634378): Remove violation exception once Scanning App
305 # migrated off usage of `chrome.send`.
306 'ash/webui/scanning/resources/scanning_browser_proxy.ts',
307 ),
308 ), )
Clement Yan9b330cb2022-11-17 05:25:29309
Daniel Cheng6303eed2025-05-03 00:12:33310_BANNED_OBJC_FUNCTIONS: Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15311 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33312 'addTrackingRect:',
313 (
314 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
315 'prohibited. Please use CrTrackingArea instead.',
316 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
317 ),
318 False,
[email protected]127f18ec2012-06-16 05:05:59319 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15320 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33321 r'/NSTrackingArea\W',
322 (
323 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
324 'instead.',
325 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
326 ),
327 False,
[email protected]127f18ec2012-06-16 05:05:59328 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15329 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33330 'convertPointFromBase:',
331 (
332 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
333 'Please use |convertPoint:(point) fromView:nil| instead.',
334 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
335 ),
336 True,
[email protected]127f18ec2012-06-16 05:05:59337 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15338 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33339 'convertPointToBase:',
340 (
341 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
342 'Please use |convertPoint:(point) toView:nil| instead.',
343 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
344 ),
345 True,
[email protected]127f18ec2012-06-16 05:05:59346 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15347 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33348 'convertRectFromBase:',
349 (
350 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
351 'Please use |convertRect:(point) fromView:nil| instead.',
352 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
353 ),
354 True,
[email protected]127f18ec2012-06-16 05:05:59355 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15356 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33357 'convertRectToBase:',
358 (
359 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
360 'Please use |convertRect:(point) toView:nil| instead.',
361 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
362 ),
363 True,
[email protected]127f18ec2012-06-16 05:05:59364 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15365 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33366 'convertSizeFromBase:',
367 (
368 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
369 'Please use |convertSize:(point) fromView:nil| instead.',
370 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
371 ),
372 True,
[email protected]127f18ec2012-06-16 05:05:59373 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15374 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33375 'convertSizeToBase:',
376 (
377 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
378 'Please use |convertSize:(point) toView:nil| instead.',
379 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
380 ),
381 True,
[email protected]127f18ec2012-06-16 05:05:59382 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15383 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33384 r"/\s+UTF8String\s*]",
385 (
386 'The use of -[NSString UTF8String] is dangerous as it can return null',
387 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
388 'Please use |SysNSStringToUTF8| instead.',
389 ),
390 True,
391 excluded_paths=('^third_party/ocmock/OCMock/', ),
jif65398702016-10-27 10:19:48392 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15393 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33394 r'__unsafe_unretained',
395 (
396 'The use of __unsafe_unretained is almost certainly wrong, unless',
397 'when interacting with NSFastEnumeration or NSInvocation.',
398 'Please use __weak in files build with ARC, nothing otherwise.',
399 ),
400 False,
Sylvain Defresne4cf1d182017-09-18 14:16:34401 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15402 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33403 'freeWhenDone:NO',
404 (
405 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
406 'Foundation types is prohibited.',
407 ),
408 True,
Avi Drissman7382afa02019-04-29 23:27:13409 ),
Avi Drissman3d243a42023-08-01 16:53:59410 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33411 'This file requires ARC support.',
412 (
413 'ARC compilation is default in Chromium; do not add boilerplate to ',
414 'files that require ARC.',
415 ),
416 True,
Avi Drissman3d243a42023-08-01 16:53:59417 ),
[email protected]127f18ec2012-06-16 05:05:59418)
419
Sylvain Defresnea8b73d252018-02-28 15:45:54420_BANNED_IOS_OBJC_FUNCTIONS = (
Daniel Chenga44a1bcd2022-03-15 20:00:15421 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33422 r'/\bTEST[(]',
423 ('TEST() macro should not be used in Objective-C++ code as it does not ',
424 'drain the autorelease pool at the end of the test. Use TEST_F() ',
425 'macro instead with a fixture inheriting from PlatformTest (or a ',
426 'typedef).'),
427 True,
Sylvain Defresnea8b73d252018-02-28 15:45:54428 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15429 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33430 r'/\btesting::Test\b',
431 ('testing::Test should not be used in Objective-C++ code as it does ',
432 'not drain the autorelease pool at the end of the test. Use ',
433 'PlatformTest instead.'),
434 True,
Sylvain Defresnea8b73d252018-02-28 15:45:54435 ),
Ewann2ecc8d72022-07-18 07:41:23436 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33437 ' systemImageNamed:',
438 ('+[UIImage systemImageNamed:] should not be used to create symbols.',
439 'Instead use a wrapper defined in:',
440 'ios/chrome/browser/shared/ui/symbols/symbol_helpers.h'),
441 True,
442 excluded_paths=(
443 'ios/chrome/browser/shared/ui/symbols/symbol_helpers.mm',
444 'ios/chrome/common',
445 # App extensions have restricted dependencies and thus can't use the
446 # wrappers.
447 r'^ios/chrome/\w+_extension/',
448 ),
Ewann2ecc8d72022-07-18 07:41:23449 ),
Sylvain Defresne781b9f92024-12-11 09:36:18450 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33451 r'public (RefCounted)?BrowserStateKeyedServiceFactory',
452 ('KeyedService factories in //ios/chrome/browser should inherit from',
453 '(Refcounted)?ProfileKeyedServieFactoryIOS, not directory from',
454 '(Refcounted)?BrowserStateKeyedServiceFactory.'),
455 treat_as_error=True,
456 excluded_paths=(
457 'ios/components',
458 'ios/web_view',
459 ),
Sylvain Defresne781b9f92024-12-11 09:36:18460 ),
Sylvain Defresnea8b73d252018-02-28 15:45:54461)
462
Daniel Cheng6303eed2025-05-03 00:12:33463_BANNED_IOS_EGTEST_FUNCTIONS: Sequence[BanRule] = (BanRule(
464 r'/\bEXPECT_OCMOCK_VERIFY\b',
465 ('EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
466 'it is meant for GTests. Use [mock verify] instead.'),
467 True,
468), )
Peter K. Lee6c03ccff2019-07-15 14:40:05469
Daniel Cheng566634ff2024-06-29 14:56:53470_BANNED_CPP_FUNCTIONS: Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15471 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53472 '%#0',
473 (
474 'Zero-padded values that use "#" to add prefixes don\'t exhibit ',
475 'consistent behavior, since the prefix is not prepended for zero ',
476 'values. Use "0x%0..." instead.',
477 ),
478 False,
479 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting7c0d98a2023-10-06 15:42:39480 ),
481 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53482 r'/\busing namespace ',
483 (
484 'Using directives ("using namespace x") are banned by the Google Style',
485 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
486 'Explicitly qualify symbols or use using declarations ("using x::foo").',
487 ),
488 True,
489 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting94a56c42019-10-25 21:54:04490 ),
Antonio Gomes07300d02019-03-13 20:59:57491 # Make sure that gtest's FRIEND_TEST() macro is not used; the
492 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
493 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
Daniel Chenga44a1bcd2022-03-15 20:00:15494 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53495 'FRIEND_TEST(',
496 (
497 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
498 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
499 ),
500 False,
501 excluded_paths=(
502 "base/gtest_prod_util.h",
503 "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/gtest_prod_util.h",
504 ),
[email protected]23e6cbc2012-06-16 18:51:20505 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15506 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53507 'setMatrixClip',
508 (
509 'Overriding setMatrixClip() is prohibited; ',
510 'the base function is deprecated. ',
511 ),
512 True,
513 (),
tomhudsone2c14d552016-05-26 17:07:46514 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15515 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53516 'SkRefPtr',
517 ('The use of SkRefPtr is prohibited. ', 'Please use sk_sp<> instead.'),
518 True,
519 (),
[email protected]52657f62013-05-20 05:30:31520 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15521 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53522 'SkAutoRef',
523 ('The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
524 'Please use sk_sp<> instead.'),
525 True,
526 (),
[email protected]52657f62013-05-20 05:30:31527 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15528 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53529 'SkAutoTUnref',
530 ('The use of SkAutoTUnref is dangerous because it implicitly ',
531 'converts to a raw pointer. Please use sk_sp<> instead.'),
532 True,
533 (),
[email protected]52657f62013-05-20 05:30:31534 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15535 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53536 'SkAutoUnref',
537 ('The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
538 'because it implicitly converts to a raw pointer. ',
539 'Please use sk_sp<> instead.'),
540 True,
541 (),
[email protected]52657f62013-05-20 05:30:31542 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15543 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53544 r'/HANDLE_EINTR\(.*close',
545 ('HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
546 'descriptor will be closed, and it is incorrect to retry the close.',
547 'Either call close directly and ignore its return value, or wrap close',
548 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
549 ),
550 True,
551 (),
[email protected]d89eec82013-12-03 14:10:59552 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15553 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53554 r'/IGNORE_EINTR\((?!.*close)',
555 (
556 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
557 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
558 ),
559 True,
560 (
561 # Files that #define IGNORE_EINTR.
562 r'^base/posix/eintr_wrapper\.h$',
563 r'^ppapi/tests/test_broker\.cc$',
564 ),
[email protected]d89eec82013-12-03 14:10:59565 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15566 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53567 r'/v8::Extension\(',
568 (
569 'Do not introduce new v8::Extensions into the code base, use',
570 'gin::Wrappable instead. See http://crbug.com/334679',
571 ),
572 True,
573 (r'extensions/renderer/safe_builtins\.*', ),
[email protected]ec5b3f02014-04-04 18:43:43574 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15575 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53576 '#pragma comment(lib,',
577 ('Specify libraries to link with in build files and not in the source.',
578 ),
579 True,
580 (
581 r'^base/third_party/symbolize/.*',
582 r'^third_party/abseil-cpp/.*',
Victor Hugo Vianna Silvac86846c02025-03-07 06:56:37583 r'^third_party/grpc/source/.*',
Daniel Cheng566634ff2024-06-29 14:56:53584 ),
jame2d1a952016-04-02 00:27:10585 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15586 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53587 r'/base::SequenceChecker\b',
588 ('Consider using SEQUENCE_CHECKER macros instead of the class directly.',
589 ),
590 False,
591 (),
gabd52c912a2017-05-11 04:15:59592 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15593 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53594 r'/base::ThreadChecker\b',
595 ('Consider using THREAD_CHECKER macros instead of the class directly.',
596 ),
597 False,
598 (),
gabd52c912a2017-05-11 04:15:59599 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15600 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53601 r'/\b(?!(Sequenced|SingleThread))\w*TaskRunner::(GetCurrentDefault|CurrentDefaultHandle)',
602 (
603 'It is not allowed to call these methods from the subclasses ',
604 'of Sequenced or SingleThread task runners.',
605 ),
606 True,
607 (),
Sean Maher03efef12022-09-23 22:43:13608 ),
609 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53610 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
611 (
612 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
613 'deprecated (http://crbug.com/634507). Please avoid converting away',
614 'from the Time types in Chromium code, especially if any math is',
615 'being done on time values. For interfacing with platform/library',
616 'APIs, use base::Time::(From,To)DeltaSinceWindowsEpoch() or',
617 'base::{TimeDelta::In}Microseconds(), or one of the other type',
618 'converter methods instead. For faking TimeXXX values (for unit',
619 'testing only), use TimeXXX() + Microseconds(N). For',
620 'other use cases, please contact base/time/OWNERS.',
621 ),
622 False,
623 excluded_paths=(
624 "base/time/time.h",
625 "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/time/time.h",
626 ),
Yuri Wiitala2f8de5c2017-07-21 00:11:06627 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15628 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53629 'CallJavascriptFunctionUnsafe',
630 (
631 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
632 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
633 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
634 ),
635 False,
636 (
637 r'^content/browser/webui/web_ui_impl\.(cc|h)$',
638 r'^content/public/browser/web_ui\.h$',
639 r'^content/public/test/test_web_ui\.(cc|h)$',
640 ),
dbeamb6f4fde2017-06-15 04:03:06641 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15642 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53643 'leveldb::DB::Open',
644 (
645 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
646 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
647 "Chrome's tracing, making their memory usage visible.",
648 ),
649 True,
650 (r'^third_party/leveldatabase/.*\.(cc|h)$', ),
Gabriel Charette0592c3a2017-07-26 12:02:04651 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15652 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53653 'leveldb::NewMemEnv',
654 (
655 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
656 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
657 "to Chrome's tracing, making their memory usage visible.",
658 ),
659 True,
660 (r'^third_party/leveldatabase/.*\.(cc|h)$', ),
Chris Mumfordc38afb62017-10-09 17:55:08661 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15662 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53663 'base::ScopedMockTimeMessageLoopTaskRunner',
664 (
665 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
666 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
667 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
668 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
669 'with gab@ first if you think you need it)',
670 ),
671 False,
672 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57673 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15674 BanRule(
Peter Kasting5fdcd782025-01-13 14:57:07675 '\bstd::aligned_(storage|union)\b',
Daniel Cheng6303eed2025-05-03 00:12:33676 ('std::aligned_storage and std::aligned_union are deprecated in',
677 'C++23. Use an aligned char array instead.'),
Peter Kasting5fdcd782025-01-13 14:57:07678 True,
679 (),
680 ),
681 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53682 'std::regex',
683 (
684 'Using std::regex adds unnecessary binary size to Chrome. Please use',
685 're2::RE2 instead (crbug.com/755321)',
686 ),
687 True,
688 [
689 # Abseil's benchmarks never linked into chrome.
690 'third_party/abseil-cpp/.*_benchmark.cc',
691 ],
Francois Doray43670e32017-09-27 12:40:38692 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15693 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53694 r'/\bstd::sto(i|l|ul|ll|ull)\b',
695 (
696 'std::sto{i,l,ul,ll,ull}() use exceptions to communicate results. ',
697 'Use base::StringTo[U]Int[64]() instead.',
698 ),
699 True,
700 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting991618a62019-06-17 22:00:09701 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15702 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53703 r'/\bstd::sto(f|d|ld)\b',
704 (
705 'std::sto{f,d,ld}() use exceptions to communicate results. ',
706 'For locale-independent values, e.g. reading numbers from disk',
707 'profiles, use base::StringToDouble().',
708 'For user-visible values, parse using ICU.',
709 ),
710 True,
711 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting991618a62019-06-17 22:00:09712 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15713 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53714 r'/\bstd::to_string\b',
715 (
716 'std::to_string() is locale dependent and slower than alternatives.',
717 'For locale-independent strings, e.g. writing numbers to disk',
718 'profiles, use base::NumberToString().',
719 'For user-visible strings, use base::FormatNumber() and',
720 'the related functions in base/i18n/number_formatting.h.',
721 ),
722 True,
723 [
724 # TODO(crbug.com/335672557): Please do not add to this list. Existing
725 # uses should removed.
Daniel Cheng566634ff2024-06-29 14:56:53726 "third_party/blink/renderer/core/css/parser/css_proto_converter.cc",
727 "third_party/blink/renderer/core/editing/ime/edit_context.cc",
728 "third_party/blink/renderer/platform/graphics/bitmap_image_test.cc",
Daniel Cheng566634ff2024-06-29 14:56:53729 _THIRD_PARTY_EXCEPT_BLINK
730 ],
Daniel Bratell69334cc2019-03-26 11:07:45731 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15732 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53733 r'/#include <(cctype|ctype\.h|cwctype|wctype.h)>',
734 (
735 '<cctype>/<ctype.h>/<cwctype>/<wctype.h> are banned. Use',
736 '"third_party/abseil-cpp/absl/strings/ascii.h" instead.',
737 ),
738 True,
739 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting6f79b202023-08-09 21:25:41740 ),
741 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53742 r'/\bstd::shared_ptr\b',
743 ('std::shared_ptr is banned. Use scoped_refptr instead.', ),
744 True,
745 [
746 # Needed for interop with third-party library.
Dirk Prankee4df27972025-02-26 18:39:35747 r'^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
748 r'array_buffer_contents\.(cc|h)',
749 r'^third_party/blink/renderer/core/typed_arrays/dom_array_buffer\.cc',
Daniel Cheng566634ff2024-06-29 14:56:53750 '^third_party/blink/renderer/bindings/core/v8/' +
751 'v8_wasm_response_extensions.cc',
Dirk Prankee4df27972025-02-26 18:39:35752 r'^gin/array_buffer\.(cc|h)',
753 r'^gin/per_isolate_data\.(cc|h)',
Daniel Cheng566634ff2024-06-29 14:56:53754 '^chrome/services/sharing/nearby/',
755 # Needed for interop with third-party library libunwindstack.
Dirk Prankee4df27972025-02-26 18:39:35756 r'^base/profiler/libunwindstack_unwinder_android\.(cc|h)',
757 r'^base/profiler/native_unwinder_android_memory_regions_map_impl.(cc|h)',
Daniel Cheng566634ff2024-06-29 14:56:53758 # Needed for interop with third-party boringssl cert verifier
759 '^third_party/boringssl/',
760 '^net/cert/',
761 '^net/tools/cert_verify_tool/',
762 '^services/cert_verifier/',
763 '^components/certificate_transparency/',
764 '^components/media_router/common/providers/cast/certificate/',
Nina Satragnoe447f2d2025-05-08 16:32:19765 '^components/trusted_vault/',
Daniel Cheng566634ff2024-06-29 14:56:53766 # gRPC provides some C++ libraries that use std::shared_ptr<>.
767 '^chromeos/ash/services/libassistant/grpc/',
768 '^chromecast/cast_core/grpc',
769 '^chromecast/cast_core/runtime/browser',
Dirk Prankee4df27972025-02-26 18:39:35770 r'^ios/chrome/test/earl_grey/chrome_egtest_plugin_client\.(mm|h)',
Daniel Cheng566634ff2024-06-29 14:56:53771 # Fuchsia provides C++ libraries that use std::shared_ptr<>.
Dirk Prankee4df27972025-02-26 18:39:35772 r'^base/fuchsia/.*\.(cc|h)',
773 r'.*fuchsia.*test\.(cc|h)',
Daniel Cheng566634ff2024-06-29 14:56:53774 # Clang plugins have different build config.
775 '^tools/clang/plugins/',
776 _THIRD_PARTY_EXCEPT_BLINK
777 ], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21778 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15779 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53780 r'/\bstd::weak_ptr\b',
781 ('std::weak_ptr is banned. Use base::WeakPtr instead.', ),
782 True,
783 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting991618a62019-06-17 22:00:09784 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15785 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53786 r'/\blong long\b',
787 ('long long is banned. Use [u]int64_t instead.', ),
788 False, # Only a warning since it is already used.
789 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21790 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15791 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53792 r'/\b(absl|std)::any\b',
793 (
794 '{absl,std}::any are banned due to incompatibility with the component ',
795 'build.',
796 ),
797 True,
798 # Not an error in third party folders, though it probably should be :)
799 [_THIRD_PARTY_EXCEPT_BLINK],
Daniel Chengc05fcc62022-01-12 16:54:29800 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15801 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53802 r'/\bstd::bind\b',
803 (
804 'std::bind() is banned because of lifetime risks. Use ',
805 'base::Bind{Once,Repeating}() instead.',
806 ),
807 True,
808 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21809 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15810 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53811 (r'/\bstd::(?:'
812 r'linear_congruential_engine|mersenne_twister_engine|'
813 r'subtract_with_carry_engine|discard_block_engine|'
814 r'independent_bits_engine|shuffle_order_engine|'
815 r'minstd_rand0?|mt19937(_64)?|ranlux(24|48)(_base)?|knuth_b|'
816 r'default_random_engine|'
817 r'random_device|'
818 r'seed_seq'
819 r')\b'),
820 (
821 'STL random number engines and generators are banned. Use the ',
822 'helpers in base/rand_util.h instead, e.g. base::RandBytes() or ',
823 'base::RandomBitGenerator.'
824 '',
825 'Please reach out to [email protected] if the base APIs are ',
826 'insufficient for your needs.',
827 ),
828 True,
829 [
830 # Not an error in third_party folders.
831 _THIRD_PARTY_EXCEPT_BLINK,
832 # Various tools which build outside of Chrome.
833 r'testing/libfuzzer',
Steinar H. Gundersone5689e42024-08-07 18:17:19834 r'testing/perf/confidence',
Daniel Cheng566634ff2024-06-29 14:56:53835 r'tools/android/io_benchmark/',
836 # Fuzzers are allowed to use standard library random number generators
837 # since fuzzing speed + reproducibility is important.
838 r'tools/ipc_fuzzer/',
839 r'.+_fuzzer\.cc$',
840 r'.+_fuzzertest\.cc$',
841 # TODO(https://crbug.com/1380528): These are all unsanctioned uses of
842 # the standard library's random number generators, and should be
843 # migrated to the //base equivalent.
844 r'ash/ambient/model/ambient_topic_queue\.cc',
845 r'base/allocator/partition_allocator/src/partition_alloc/partition_alloc_unittest\.cc',
Daniel Cheng566634ff2024-06-29 14:56:53846 r'base/test/launcher/test_launcher\.cc',
847 r'cc/metrics/video_playback_roughness_reporter_unittest\.cc',
848 r'chrome/browser/apps/app_service/metrics/website_metrics\.cc',
849 r'chrome/browser/ash/power/auto_screen_brightness/monotone_cubic_spline_unittest\.cc',
850 r'chrome/browser/ash/printing/zeroconf_printer_detector_unittest\.cc',
851 r'chrome/browser/nearby_sharing/contacts/nearby_share_contact_manager_impl_unittest\.cc',
852 r'chrome/browser/nearby_sharing/contacts/nearby_share_contacts_sorter_unittest\.cc',
853 r'chrome/browser/privacy_budget/mesa_distribution_unittest\.cc',
854 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
855 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
856 r'chrome/browser/win/conflicts/module_blocklist_cache_util_unittest\.cc',
857 r'chromeos/ash/components/memory/userspace_swap/swap_storage_unittest\.cc',
858 r'chromeos/ash/components/memory/userspace_swap/userspace_swap\.cc',
859 r'components/metrics/metrics_state_manager\.cc',
860 r'components/omnibox/browser/history_quick_provider_performance_unittest\.cc',
861 r'components/zucchini/disassembler_elf_unittest\.cc',
862 r'content/browser/webid/federated_auth_request_impl\.cc',
863 r'content/browser/webid/federated_auth_request_impl\.cc',
864 r'media/cast/test/utility/udp_proxy\.h',
865 r'sql/recover_module/module_unittest\.cc',
Nicolas Dossou-Gbeteaf9023d2025-04-07 17:44:38866 r'components/regional_capabilities/regional_capabilities_utils.cc',
Daniel Cheng566634ff2024-06-29 14:56:53867 # Do not add new entries to this list. If you have a use case which is
868 # not satisfied by the current APIs (i.e. you need an explicitly-seeded
869 # sequence, or stability of some sort is required), please contact
870 # [email protected].
871 ],
Daniel Cheng192683f2022-11-01 20:52:44872 ),
873 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53874 r'/\b(absl,std)::bind_front\b',
875 ('{absl,std}::bind_front() are banned. Use base::Bind{Once,Repeating}() '
876 'instead.', ),
877 True,
878 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12879 ),
880 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53881 r'/\bABSL_FLAG\b',
882 ('ABSL_FLAG is banned. Use base::CommandLine instead.', ),
883 True,
884 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12885 ),
886 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53887 r'/\babsl::c_',
Daniel Cheng6303eed2025-05-03 00:12:33888 ('Abseil container utilities are banned. Use std::ranges:: instead.',
889 ),
Daniel Cheng566634ff2024-06-29 14:56:53890 True,
891 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12892 ),
893 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53894 r'/\babsl::FixedArray\b',
895 ('absl::FixedArray is banned. Use base::FixedArray instead.', ),
896 True,
897 [
898 # base::FixedArray provides canonical access.
899 r'^base/types/fixed_array.h',
900 # Not an error in third_party folders.
901 _THIRD_PARTY_EXCEPT_BLINK,
902 ],
Peter Kasting431239a2023-09-29 03:11:44903 ),
904 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53905 r'/\babsl::FunctionRef\b',
906 ('absl::FunctionRef is banned. Use base::FunctionRef instead.', ),
907 True,
908 [
909 # base::Bind{Once,Repeating} references absl::FunctionRef to disallow
910 # interoperability.
911 r'^base/functional/bind_internal\.h',
912 # base::FunctionRef is implemented on top of absl::FunctionRef.
913 r'^base/functional/function_ref.*\..+',
914 # Not an error in third_party folders.
915 _THIRD_PARTY_EXCEPT_BLINK,
916 ],
Peter Kasting4f35bfc2022-10-18 18:39:12917 ),
918 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53919 r'/\babsl::(Insecure)?BitGen\b',
920 ('absl random number generators are banned. Use the helpers in '
921 'base/rand_util.h instead, e.g. base::RandBytes() or ',
922 'base::RandomBitGenerator.'),
923 True,
924 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12925 ),
926 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33927 pattern=r'/\babsl::(optional|nullopt|make_optional)\b',
Peter Kasting3b77a0c2024-08-22 00:22:26928 explanation=('absl::optional is banned. Use std::optional instead.', ),
929 treat_as_error=True,
930 excluded_paths=[
931 _THIRD_PARTY_EXCEPT_BLINK,
932 ]),
933 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53934 r'/(\babsl::Span\b|#include <span>|\bstd::span\b)',
Daniel Cheng6303eed2025-05-03 00:12:33935 ('absl::Span and std::span are banned. Use base::span instead.', ),
Daniel Cheng566634ff2024-06-29 14:56:53936 True,
937 [
938 # Included for conversions between base and std.
939 r'base/containers/span.h',
940 # Test base::span<> compatibility against std::span<>.
941 r'base/containers/span_unittest.cc',
942 # //base/numerics can't use base or absl. So it uses std.
943 r'base/numerics/.*'
Lei Zhang1f9d9ec42024-06-20 18:42:27944
Daniel Cheng566634ff2024-06-29 14:56:53945 # Needed to use QUICHE API.
Ciara McMullinc029c8e2024-08-21 14:22:32946 r'android_webview/browser/ip_protection/.*',
Daniel Cheng566634ff2024-06-29 14:56:53947 r'chrome/browser/ip_protection/.*',
948 r'components/ip_protection/.*',
949 r'net/third_party/quiche/overrides/quiche_platform_impl/quiche_stack_trace_impl\.*',
950 r'services/network/web_transport\.cc',
Lei Zhang1f9d9ec42024-06-20 18:42:27951
Daniel Cheng566634ff2024-06-29 14:56:53952 # Not an error in third_party folders.
953 _THIRD_PARTY_EXCEPT_BLINK,
954 ],
Peter Kasting4f35bfc2022-10-18 18:39:12955 ),
956 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53957 r'/\babsl::StatusOr\b',
958 ('absl::StatusOr is banned. Use base::expected instead.', ),
959 True,
960 [
961 # Needed to use liburlpattern API.
962 r'components/url_pattern/.*',
963 r'services/network/shared_dictionary/simple_url_pattern_matcher\.cc',
964 r'third_party/blink/renderer/core/url_pattern/.*',
965 r'third_party/blink/renderer/modules/manifest/manifest_parser\.cc',
Lei Zhang1f9d9ec42024-06-20 18:42:27966
Daniel Cheng566634ff2024-06-29 14:56:53967 # Needed to use QUICHE API.
Ciara McMullinc029c8e2024-08-21 14:22:32968 r'android_webview/browser/ip_protection/.*',
Daniel Cheng566634ff2024-06-29 14:56:53969 r'chrome/browser/ip_protection/.*',
970 r'components/ip_protection/.*',
Victor Vasiliev435ec102025-05-07 08:33:39971 r'net/quic/dedicated_web_transport_http3_client\.cc',
Lei Zhang1f9d9ec42024-06-20 18:42:27972
Daniel Cheng566634ff2024-06-29 14:56:53973 # Needed to use MediaPipe API.
974 r'components/media_effects/.*\.cc',
975 # Not an error in third_party folders.
976 _THIRD_PARTY_EXCEPT_BLINK
977 ],
Peter Kasting4f35bfc2022-10-18 18:39:12978 ),
979 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53980 r'/\babsl::(StrSplit|StrJoin|StrCat|StrAppend|Substitute|StrContains)\b',
981 ('Abseil string utilities are banned. Use base/strings instead.', ),
982 True,
983 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12984 ),
985 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53986 r'/\babsl::(Mutex|CondVar|Notification|Barrier|BlockingCounter)\b',
987 (
988 'Abseil synchronization primitives are banned. Use',
989 'base/synchronization instead.',
990 ),
991 True,
992 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12993 ),
994 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53995 r'/\babsl::(Duration|Time|TimeZone|CivilDay)\b',
996 ('Abseil\'s time library is banned. Use base/time instead.', ),
997 True,
998 [
999 # Needed to use QUICHE API.
Ciara McMullinc029c8e2024-08-21 14:22:321000 r'android_webview/browser/ip_protection/.*',
Daniel Cheng566634ff2024-06-29 14:56:531001 r'chrome/browser/ip_protection/.*',
1002 r'components/ip_protection/.*',
Lei Zhang1f9d9ec42024-06-20 18:42:271003
Daniel Cheng566634ff2024-06-29 14:56:531004 # Needed to integrate with //third_party/nearby
1005 r'components/cross_device/nearby/system_clock.cc',
1006 _THIRD_PARTY_EXCEPT_BLINK # Not an error in third_party folders.
1007 ],
1008 ),
1009 BanRule(
Victor Hugo Vianna Silva6e84e8d42025-03-19 00:32:001010 r'/absl::(bad_variant_access|get|holds_alternative|monostate|variant|'
1011 r'visit)',
1012 ('Abseil\'s variant library is banned, use std.', ),
Victor Hugo Vianna Silvad9139fbe2025-03-19 20:59:081013 True,
Daniel Cheng6303eed2025-05-03 00:12:331014 [_THIRD_PARTY_EXCEPT_BLINK],
Victor Hugo Vianna Silva6e84e8d42025-03-19 00:32:001015 ),
1016 BanRule(
1017 r'/absl::(apply|exchange|forward|in_place|index_sequence|'
1018 r'integer_sequence|make_from_tuple|make_index_sequence|'
1019 r'make_integer_sequence|move)',
1020 ('Abseil\'s util library is banned, use std.', ),
Victor Hugo Vianna Silvad9139fbe2025-03-19 20:59:081021 True,
Daniel Cheng6303eed2025-05-03 00:12:331022 [_THIRD_PARTY_EXCEPT_BLINK],
Victor Hugo Vianna Silva6e84e8d42025-03-19 00:32:001023 ),
1024 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531025 r'/#include <chrono>',
1026 ('<chrono> is banned. Use base/time instead.', ),
1027 True,
1028 [
1029 # Not an error in third_party folders:
1030 _THIRD_PARTY_EXCEPT_BLINK,
Daniel Cheng566634ff2024-06-29 14:56:531031 # This uses openscreen API depending on std::chrono.
1032 "components/openscreen_platform/task_runner.cc",
1033 ]),
1034 BanRule(
1035 r'/#include <exception>',
1036 ('Exceptions are banned and disabled in Chromium.', ),
1037 True,
1038 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1039 ),
1040 BanRule(
1041 r'/\bstd::function\b',
1042 ('std::function is banned. Use base::{Once,Repeating}Callback instead.',
1043 ),
1044 True,
1045 [
1046 # Has tests that template trait helpers don't unintentionally match
1047 # std::function.
1048 r'base/functional/callback_helpers_unittest\.cc',
1049 # Required to implement interfaces from the third-party perfetto
1050 # library.
1051 r'base/tracing/perfetto_task_runner\.cc',
1052 r'base/tracing/perfetto_task_runner\.h',
1053 # Needed for interop with the third-party nearby library type
1054 # location::nearby::connections::ResultCallback.
Dirk Prankee4df27972025-02-26 18:39:351055 r'chrome/services/sharing/nearby/nearby_connections_conversions\.cc'
Daniel Cheng566634ff2024-06-29 14:56:531056 # Needed for interop with the internal libassistant library.
Dirk Prankee4df27972025-02-26 18:39:351057 r'chromeos/ash/services/libassistant/callback_utils\.h',
Daniel Cheng566634ff2024-06-29 14:56:531058 # Needed for interop with Fuchsia fidl APIs.
Dirk Prankee4df27972025-02-26 18:39:351059 r'fuchsia_web/webengine/browser/context_impl_browsertest\.cc',
1060 r'fuchsia_web/webengine/browser/cookie_manager_impl_unittest\.cc',
1061 r'fuchsia_web/webengine/browser/media_player_impl_unittest\.cc',
Daniel Cheng566634ff2024-06-29 14:56:531062 # Required to interop with interfaces from the third-party ChromeML
1063 # library API.
Dirk Prankee4df27972025-02-26 18:39:351064 r'services/on_device_model/ml/chrome_ml_api\.h',
1065 r'services/on_device_model/ml/on_device_model_executor\.cc',
1066 r'services/on_device_model/ml/on_device_model_executor\.h',
Daniel Cheng566634ff2024-06-29 14:56:531067 # Required to interop with interfaces from the third-party perfetto
1068 # library.
Dirk Prankee4df27972025-02-26 18:39:351069 r'components/tracing/common/etw_consumer_win_unittest\.cc',
1070 r'services/tracing/public/cpp/perfetto/custom_event_recorder\.cc',
1071 r'services/tracing/public/cpp/perfetto/perfetto_traced_process\.cc',
1072 r'services/tracing/public/cpp/perfetto/perfetto_traced_process\.h',
1073 r'services/tracing/public/cpp/perfetto/perfetto_tracing_backend\.cc',
1074 r'services/tracing/public/cpp/perfetto/producer_client\.cc',
1075 r'services/tracing/public/cpp/perfetto/producer_client\.h',
1076 r'services/tracing/public/cpp/perfetto/producer_test_utils\.cc',
1077 r'services/tracing/public/cpp/perfetto/producer_test_utils\.h',
Daniel Cheng566634ff2024-06-29 14:56:531078 # Required for interop with the third-party webrtc library.
Dirk Prankee4df27972025-02-26 18:39:351079 r'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.cc',
1080 r'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.h',
Daniel Cheng566634ff2024-06-29 14:56:531081 # TODO(https://crbug.com/1364577): Various uses that should be
1082 # migrated to something else.
1083 # Should use base::OnceCallback or base::RepeatingCallback.
Dirk Prankee4df27972025-02-26 18:39:351084 r'base/allocator/dispatcher/initializer_unittest\.cc',
1085 r'chrome/browser/ash/accessibility/speech_monitor\.cc',
1086 r'chrome/browser/ash/accessibility/speech_monitor\.h',
1087 r'chrome/browser/ash/login/ash_hud_login_browsertest\.cc',
1088 r'chromecast/base/observer_unittest\.cc',
1089 r'chromecast/browser/cast_web_view\.h',
1090 r'chromecast/public/cast_media_shlib\.h',
1091 r'device/bluetooth/floss/exported_callback_manager\.h',
1092 r'device/bluetooth/floss/floss_dbus_client\.h',
1093 r'device/fido/cable/v2_handshake_unittest\.cc',
1094 r'device/fido/pin\.cc',
1095 r'services/tracing/perfetto/test_utils\.h',
Daniel Cheng566634ff2024-06-29 14:56:531096 # Should use base::FunctionRef.
Dirk Prankee4df27972025-02-26 18:39:351097 r'chrome/browser/media/webrtc/test_stats_dictionary\.cc',
1098 r'chrome/browser/media/webrtc/test_stats_dictionary\.h',
1099 r'chromeos/ash/services/libassistant/device_settings_controller\.cc',
1100 r'components/browser_ui/client_certificate/android/ssl_client_certificate_request\.cc',
1101 r'components/gwp_asan/client/sampling_malloc_shims_unittest\.cc',
1102 r'content/browser/font_unique_name_lookup/font_unique_name_lookup_unittest\.cc',
Daniel Cheng566634ff2024-06-29 14:56:531103 # Does not need std::function at all.
Dirk Prankee4df27972025-02-26 18:39:351104 r'components/omnibox/browser/autocomplete_result\.cc',
1105 r'device/fido/win/webauthn_api\.cc',
1106 r'media/audio/alsa/alsa_util\.cc',
1107 r'media/remoting/stream_provider\.h',
1108 r'sql/vfs_wrapper\.cc',
Daniel Cheng566634ff2024-06-29 14:56:531109 # TODO(https://crbug.com/1364585): Remove usage and exception list
1110 # entries.
Dirk Prankee4df27972025-02-26 18:39:351111 r'extensions/renderer/api/automation/automation_internal_custom_bindings\.cc',
1112 r'extensions/renderer/api/automation/automation_internal_custom_bindings\.h',
Daniel Cheng566634ff2024-06-29 14:56:531113 # TODO(https://crbug.com/1364579): Remove usage and exception list
1114 # entry.
Dirk Prankee4df27972025-02-26 18:39:351115 r'ui/views/controls/focus_ring\.h',
Lei Zhang1f9d9ec42024-06-20 18:42:271116
Daniel Cheng566634ff2024-06-29 14:56:531117 # Various pre-existing uses in //tools that is low-priority to fix.
Dirk Prankee4df27972025-02-26 18:39:351118 r'tools/binary_size/libsupersize/viewer/caspian/diff\.cc',
1119 r'tools/binary_size/libsupersize/viewer/caspian/model\.cc',
1120 r'tools/binary_size/libsupersize/viewer/caspian/model\.h',
1121 r'tools/binary_size/libsupersize/viewer/caspian/tree_builder\.h',
1122 r'tools/clang/base_bind_rewriters/BaseBindRewriters\.cpp',
Daniel Chenge5583e3c2022-09-22 00:19:411123
Daniel Cheng566634ff2024-06-29 14:56:531124 # Not an error in third_party folders.
1125 _THIRD_PARTY_EXCEPT_BLINK
1126 ],
Daniel Bratell609102be2019-03-27 20:53:211127 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151128 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531129 r'/#include <X11/',
1130 ('Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.', ),
1131 True,
1132 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Tom Andersona95e12042020-09-09 23:08:001133 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151134 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531135 r'/\bstd::ratio\b',
1136 ('std::ratio is banned by the Google Style Guide.', ),
1137 True,
1138 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:451139 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151140 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531141 r'/\bstd::aligned_alloc\b',
1142 (
1143 'std::aligned_alloc() is not yet allowed (crbug.com/1412818). Use ',
1144 'base::AlignedAlloc() instead.',
1145 ),
1146 True,
1147 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181148 ),
1149 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531150 r'/#include <(barrier|latch|semaphore|stop_token)>',
1151 ('The thread support library is banned. Use base/synchronization '
1152 'instead.', ),
1153 True,
1154 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181155 ),
1156 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531157 r'/\bstd::execution::(par|seq)\b',
1158 ('std::execution::(par|seq) is banned; they do not fit into '
1159 ' Chrome\'s threading model, and libc++ doesn\'t have full '
mikt19226ff22024-08-27 05:28:211160 'support.', ),
Daniel Cheng566634ff2024-06-29 14:56:531161 True,
1162 [_THIRD_PARTY_EXCEPT_BLINK],
Helmut Januschka7cc8a84f2024-02-07 22:50:411163 ),
1164 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531165 r'/\bstd::bit_cast\b',
1166 ('std::bit_cast is banned; use base::bit_cast instead for values and '
1167 'standard C++ casting when pointers are involved.', ),
1168 True,
1169 [
1170 # Don't warn in third_party folders.
1171 _THIRD_PARTY_EXCEPT_BLINK,
1172 # //base/numerics can't use base or absl.
1173 r'base/numerics/.*'
1174 ],
Avi Drissman70cb7f72023-12-12 17:44:371175 ),
1176 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531177 r'/\bstd::(c8rtomb|mbrtoc8)\b',
1178 ('std::c8rtomb() and std::mbrtoc8() are banned.', ),
1179 True,
1180 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181181 ),
1182 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531183 r'/\bchar8_t|std::u8string\b',
1184 (
1185 'char8_t and std::u8string are not yet allowed. Can you use [unsigned]',
1186 ' char and std::string instead?',
1187 ),
1188 True,
1189 [
1190 # The demangler does not use this type but needs to know about it.
Dirk Prankee4df27972025-02-26 18:39:351191 r'base/third_party/symbolize/demangle\.cc',
Daniel Cheng566634ff2024-06-29 14:56:531192 # Don't warn in third_party folders.
1193 _THIRD_PARTY_EXCEPT_BLINK
1194 ],
Peter Kastinge2c5ee82023-02-15 17:23:081195 ),
1196 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531197 r'/(\b(co_await|co_return|co_yield)\b|#include <coroutine>)',
1198 ('Coroutines are not yet allowed (https://crbug.com/1403840).', ),
1199 True,
1200 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081201 ),
1202 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531203 r'/^\s*(export\s|import\s+["<:\w]|module(;|\s+[:\w]))',
1204 ('Modules are disallowed for now due to lack of toolchain support.', ),
1205 True,
1206 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting69357dc2023-03-14 01:34:291207 ),
1208 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531209 r'/\[\[(\w*::)?no_unique_address\]\]',
1210 (
1211 '[[no_unique_address]] does not work as expected on Windows ',
1212 '(https://crbug.com/1414621). Use NO_UNIQUE_ADDRESS instead.',
1213 ),
1214 True,
1215 [
1216 # NO_UNIQUE_ADDRESS / PA_NO_UNIQUE_ADDRESS provide canonical access.
1217 r'^base/compiler_specific\.h',
1218 r'^base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/compiler_specific\.h',
1219 # Not an error in third_party folders.
1220 _THIRD_PARTY_EXCEPT_BLINK,
1221 ],
Peter Kasting8bc046d22023-11-14 00:38:031222 ),
1223 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531224 r'/#include <format>',
1225 ('<format> is not yet allowed. Use base::StringPrintf() instead.', ),
1226 True,
1227 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081228 ),
1229 BanRule(
Daniel Cheng89719222024-07-04 04:59:291230 pattern='std::views',
Daniel Cheng6303eed2025-05-03 00:12:331231 explanation=('Use of std::views is banned in Chrome. If you need this '
1232 'functionality, please contact [email protected].', ),
Daniel Cheng89719222024-07-04 04:59:291233 treat_as_error=True,
1234 excluded_paths=[
1235 # Don't warn in third_party folders.
1236 _THIRD_PARTY_EXCEPT_BLINK
1237 ],
1238 ),
1239 BanRule(
1240 # Ban everything except specifically allowlisted constructs.
Daniel Cheng70a35272025-05-06 16:41:341241 pattern=r'/std::ranges::(?!(?:' + '|'.join((
Daniel Cheng89719222024-07-04 04:59:291242 # From https://en.cppreference.com/w/cpp/ranges:
1243 # Range access
1244 'begin',
1245 'end',
1246 'cbegin',
1247 'cend',
1248 'rbegin',
1249 'rend',
1250 'crbegin',
1251 'crend',
1252 'size',
1253 'ssize',
1254 'empty',
1255 'data',
1256 'cdata',
1257 # Range primitives
1258 'iterator_t',
1259 'const_iterator_t',
1260 'sentinel_t',
1261 'const_sentinel_t',
1262 'range_difference_t',
1263 'range_size_t',
1264 'range_value_t',
1265 'range_reference_t',
1266 'range_const_reference_t',
1267 'range_rvalue_reference_t',
1268 'range_common_reference_t',
1269 # Dangling iterator handling
1270 'dangling',
1271 'borrowed_iterator_t',
1272 # Banned: borrowed_subrange_t
1273 # Range concepts
1274 'range',
1275 'borrowed_range',
1276 'sized_range',
1277 'view',
1278 'input_range',
1279 'output_range',
1280 'forward_range',
1281 'bidirectional_range',
1282 'random_access_range',
1283 'contiguous_range',
1284 'common_range',
1285 'viewable_range',
1286 'constant_range',
Michael Tang626d8982025-05-08 23:24:291287 # Views
1288 'subrange',
Daniel Cheng89719222024-07-04 04:59:291289 # Banned: Range factories
1290 # Banned: Range adaptors
Peter Kastinga7f93752024-10-24 22:15:401291 # Incidentally listed on
1292 # https://en.cppreference.com/w/cpp/header/ranges:
1293 'enable_borrowed_range',
1294 'enable_view',
Daniel Cheng89719222024-07-04 04:59:291295 # From https://en.cppreference.com/w/cpp/algorithm/ranges:
1296 # Constrained algorithms: non-modifying sequence operations
1297 'all_of',
1298 'any_of',
1299 'none_of',
1300 'for_each',
1301 'for_each_n',
1302 'count',
1303 'count_if',
1304 'mismatch',
1305 'equal',
1306 'lexicographical_compare',
1307 'find',
1308 'find_if',
1309 'find_if_not',
1310 'find_end',
1311 'find_first_of',
1312 'adjacent_find',
1313 'search',
1314 'search_n',
1315 # Constrained algorithms: modifying sequence operations
1316 'copy',
1317 'copy_if',
1318 'copy_n',
1319 'copy_backward',
1320 'move',
1321 'move_backward',
1322 'fill',
1323 'fill_n',
1324 'transform',
1325 'generate',
1326 'generate_n',
1327 'remove',
1328 'remove_if',
1329 'remove_copy',
1330 'remove_copy_if',
1331 'replace',
1332 'replace_if',
1333 'replace_copy',
1334 'replace_copy_if',
1335 'swap_ranges',
1336 'reverse',
1337 'reverse_copy',
1338 'rotate',
1339 'rotate_copy',
1340 'shuffle',
1341 'sample',
1342 'unique',
1343 'unique_copy',
1344 # Constrained algorithms: partitioning operations
1345 'is_partitioned',
1346 'partition',
1347 'partition_copy',
1348 'stable_partition',
1349 'partition_point',
1350 # Constrained algorithms: sorting operations
1351 'is_sorted',
1352 'is_sorted_until',
1353 'sort',
1354 'partial_sort',
1355 'partial_sort_copy',
1356 'stable_sort',
1357 'nth_element',
1358 # Constrained algorithms: binary search operations (on sorted ranges)
1359 'lower_bound',
1360 'upper_bound',
1361 'binary_search',
1362 'equal_range',
1363 # Constrained algorithms: set operations (on sorted ranges)
1364 'merge',
1365 'inplace_merge',
1366 'includes',
1367 'set_difference',
1368 'set_intersection',
1369 'set_symmetric_difference',
1370 'set_union',
1371 # Constrained algorithms: heap operations
1372 'is_heap',
1373 'is_heap_until',
1374 'make_heap',
1375 'push_heap',
1376 'pop_heap',
1377 'sort_heap',
1378 # Constrained algorithms: minimum/maximum operations
1379 'max',
1380 'max_element',
1381 'min',
1382 'min_element',
1383 'minmax',
1384 'minmax_element',
1385 'clamp',
1386 # Constrained algorithms: permutation operations
1387 'is_permutation',
1388 'next_permutation',
1389 'prev_premutation',
1390 # Constrained uninitialized memory algorithms
1391 'uninitialized_copy',
1392 'uninitialized_copy_n',
1393 'uninitialized_fill',
1394 'uninitialized_fill_n',
1395 'uninitialized_move',
1396 'uninitialized_move_n',
1397 'uninitialized_default_construct',
1398 'uninitialized_default_construct_n',
1399 'uninitialized_value_construct',
1400 'uninitialized_value_construct_n',
1401 'destroy',
1402 'destroy_n',
1403 'destroy_at',
1404 'construct_at',
1405 # Return types
1406 'in_fun_result',
1407 'in_in_result',
1408 'in_out_result',
1409 'in_in_out_result',
1410 'in_out_out_result',
1411 'min_max_result',
1412 'in_found_result',
Peter Kastingf379c022025-01-13 14:01:001413 # From https://en.cppreference.com/w/cpp/header/functional
1414 'equal_to',
1415 'not_equal_to',
1416 'greater',
1417 'less',
1418 'greater_equal',
1419 'less_equal',
danakj91c715b2024-07-10 13:24:261420 # From https://en.cppreference.com/w/cpp/iterator
1421 'advance',
1422 'distance',
1423 'next',
1424 'prev',
Daniel Cheng70a35272025-05-06 16:41:341425 # Require a word boundary at the end of negative lookahead
1426 # assertion, e.g. to ensure that even though `view` is allowed (and
1427 # should not match this regex), `views` is still treated as
1428 # disallowed (and matches the regex).
1429 )) + r')\b)\w+',
Daniel Cheng89719222024-07-04 04:59:291430 explanation=(
1431 'Use of range views and associated helpers is banned in Chrome. '
1432 'If you need this functionality, please contact [email protected].',
1433 ),
1434 treat_as_error=True,
1435 excluded_paths=[
1436 # Don't warn in third_party folders.
1437 _THIRD_PARTY_EXCEPT_BLINK
1438 ],
Peter Kastinge2c5ee82023-02-15 17:23:081439 ),
1440 BanRule(
Peter Kasting31879d82024-10-07 20:18:391441 r'/#include <regex>',
Daniel Cheng6303eed2025-05-03 00:12:331442 ('<regex> is not allowed. Use third_party/re2 instead.', ),
Peter Kasting31879d82024-10-07 20:18:391443 True,
1444 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1445 ),
1446 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531447 r'/#include <source_location>',
1448 ('<source_location> is not yet allowed. Use base/location.h instead.',
1449 ),
1450 True,
1451 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081452 ),
1453 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531454 r'/\bstd::to_address\b',
1455 (
1456 'std::to_address is banned because it is not guaranteed to be',
1457 'SFINAE-compatible. Use base::to_address from base/types/to_address.h',
1458 'instead.',
1459 ),
1460 True,
1461 [
1462 # Needed in base::to_address implementation.
1463 r'base/types/to_address.h',
1464 _THIRD_PARTY_EXCEPT_BLINK
1465 ], # Not an error in third_party folders.
Nick Diego Yamanee522ae82024-02-27 04:23:221466 ),
1467 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531468 r'/#include <syncstream>',
1469 ('<syncstream> is banned.', ),
1470 True,
1471 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181472 ),
1473 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531474 r'/\bRunMessageLoop\b',
1475 ('RunMessageLoop is deprecated, use RunLoop instead.', ),
1476 False,
1477 (),
Gabriel Charette147335ea2018-03-22 15:59:191478 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151479 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531480 'RunAllPendingInMessageLoop()',
1481 (
1482 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
1483 "if you're convinced you need this.",
1484 ),
1485 False,
1486 (),
Gabriel Charette147335ea2018-03-22 15:59:191487 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151488 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531489 'RunAllPendingInMessageLoop(BrowserThread',
1490 (
1491 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
1492 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
1493 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
1494 'async events instead of flushing threads.',
1495 ),
1496 False,
1497 (),
Gabriel Charette147335ea2018-03-22 15:59:191498 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151499 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531500 r'MessageLoopRunner',
1501 ('MessageLoopRunner is deprecated, use RunLoop instead.', ),
1502 False,
1503 (),
Gabriel Charette147335ea2018-03-22 15:59:191504 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151505 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531506 'GetDeferredQuitTaskForRunLoop',
1507 (
1508 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
1509 "gab@ if you found a use case where this is the only solution.",
1510 ),
1511 False,
1512 (),
Gabriel Charette147335ea2018-03-22 15:59:191513 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151514 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531515 'sqlite3_initialize(',
1516 (
1517 'Instead of calling sqlite3_initialize(), depend on //sql, ',
1518 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
1519 ),
1520 True,
1521 (
1522 r'^sql/initialization\.(cc|h)$',
1523 r'^third_party/sqlite/.*\.(c|cc|h)$',
1524 ),
Victor Costan3653df62018-02-08 21:38:161525 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151526 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531527 'CREATE VIEW',
1528 (
1529 'SQL views are disabled in Chromium feature code',
1530 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-views',
1531 ),
1532 True,
1533 (
1534 _THIRD_PARTY_EXCEPT_BLINK,
1535 # sql/ itself uses views when using memory-mapped IO.
1536 r'^sql/.*',
1537 # Various performance tools that do not build as part of Chrome.
1538 r'^infra/.*',
1539 r'^tools/perf.*',
1540 r'.*perfetto.*',
1541 ),
Austin Sullivand661ab52022-11-16 08:55:151542 ),
1543 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531544 'CREATE VIRTUAL TABLE',
1545 (
1546 'SQL virtual tables are disabled in Chromium feature code',
1547 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-virtual-tables',
1548 ),
1549 True,
1550 (
1551 _THIRD_PARTY_EXCEPT_BLINK,
1552 # sql/ itself uses virtual tables in the recovery module and tests.
1553 r'^sql/.*',
Daniel Cheng566634ff2024-06-29 14:56:531554 # Various performance tools that do not build as part of Chrome.
1555 r'^tools/perf.*',
1556 r'.*perfetto.*',
1557 ),
Austin Sullivand661ab52022-11-16 08:55:151558 ),
1559 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531560 'std::random_shuffle',
1561 ('std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
1562 'base::RandomShuffle instead.'),
1563 True,
1564 (),
tzik5de2157f2018-05-08 03:42:471565 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151566 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531567 'ios/web/public/test/http_server',
1568 ('web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
1569 ),
1570 False,
1571 (),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:241572 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151573 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531574 'GetAddressOf',
1575 ('Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
1576 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
1577 'operator& is generally recommended. So always use operator& instead. ',
1578 'See http://crbug.com/914910 for more conversion guidance.'),
1579 True,
1580 (),
Robert Liao764c9492019-01-24 18:46:281581 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151582 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531583 'SHFileOperation',
1584 ('SHFileOperation was deprecated in Windows Vista, and there are less ',
1585 'complex functions to achieve the same goals. Use IFileOperation for ',
1586 'any esoteric actions instead.'),
1587 True,
1588 (),
Ben Lewisa9514602019-04-29 17:53:051589 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151590 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531591 'StringFromGUID2',
1592 ('StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
1593 'Use base::win::WStringFromGUID instead.'),
1594 True,
1595 (r'/base/win/win_util_unittest.cc', ),
Cliff Smolinsky81951642019-04-30 21:39:511596 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151597 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531598 'StringFromCLSID',
1599 ('StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
1600 'Use base::win::WStringFromGUID instead.'),
1601 True,
1602 (r'/base/win/win_util_unittest.cc', ),
Cliff Smolinsky81951642019-04-30 21:39:511603 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151604 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531605 'kCFAllocatorNull',
1606 (
1607 'The use of kCFAllocatorNull with the NoCopy creation of ',
1608 'CoreFoundation types is prohibited.',
1609 ),
1610 True,
1611 (),
Avi Drissman7382afa02019-04-29 23:27:131612 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151613 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531614 'mojo::ConvertTo',
1615 ('mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1616 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1617 'StringTraits if you would like to convert between custom types and',
1618 'the wire format of mojom types.'),
1619 False,
1620 (
1621 r'^fuchsia_web/webengine/browser/url_request_rewrite_rules_manager\.cc$',
1622 r'^fuchsia_web/webengine/url_request_rewrite_type_converters\.cc$',
1623 r'^third_party/blink/.*\.(cc|h)$',
1624 r'^content/renderer/.*\.(cc|h)$',
1625 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291626 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151627 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531628 'GetInterfaceProvider',
1629 ('InterfaceProvider is deprecated.',
1630 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1631 'or Platform::GetBrowserInterfaceBroker.'),
1632 False,
1633 (),
Oksana Zhuravlovac8222d22019-12-19 19:21:161634 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151635 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531636 'CComPtr',
1637 ('New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1638 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1639 'details.'),
1640 False,
1641 (),
Robert Liao1d78df52019-11-11 20:02:011642 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151643 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531644 r'/\b(IFACE|STD)METHOD_?\(',
1645 ('IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1646 'Instead, always use IFACEMETHODIMP in the declaration.'),
1647 False,
1648 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Xiaohan Wang72bd2ba2020-02-18 21:38:201649 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151650 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531651 'RemoveAllChildViewsWithoutDeleting',
1652 ('RemoveAllChildViewsWithoutDeleting is deprecated.',
1653 'This method is deemed dangerous as, unless raw pointers are re-added,',
1654 'calls to this method introduce memory leaks.'),
1655 False,
1656 (),
Peter Boström7ff41522021-07-29 03:43:271657 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151658 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531659 r'/\bTRACE_EVENT_ASYNC_',
1660 (
1661 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1662 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1663 ),
1664 False,
1665 (
1666 r'^base/trace_event/.*',
1667 r'^base/tracing/.*',
1668 ),
Eric Secklerbe6f48d2020-05-06 18:09:121669 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151670 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531671 'RoInitialize',
1672 ('Improper use of [base::win]::RoInitialize() has been implicated in a ',
1673 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
1674 'instead. See http://crbug.com/1197722 for more information.'),
1675 True,
1676 (
1677 r'^base/win/scoped_winrt_initializer\.cc$',
1678 r'^third_party/abseil-cpp/absl/.*',
1679 ),
Robert Liao22f66a52021-04-10 00:57:521680 ),
Patrick Monettec343bb982022-06-01 17:18:451681 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531682 r'base::Watchdog',
1683 (
1684 'base::Watchdog is deprecated because it creates its own thread.',
1685 'Instead, manually start a timer on a SequencedTaskRunner.',
1686 ),
1687 False,
1688 (),
Patrick Monettec343bb982022-06-01 17:18:451689 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091690 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531691 'base::Passed',
1692 ('Do not use base::Passed. It is a legacy helper for capturing ',
1693 'move-only types with base::BindRepeating, but invoking the ',
1694 'resulting RepeatingCallback moves the captured value out of ',
1695 'the callback storage, and subsequent invocations may pass the ',
1696 'value in a valid but undefined state. Prefer base::BindOnce().',
1697 'See http://crbug.com/1326449 for context.'),
1698 False,
1699 (
1700 # False positive, but it is also fine to let bind internals reference
1701 # base::Passed.
1702 r'^base[\\/]functional[\\/]bind\.h',
1703 r'^base[\\/]functional[\\/]bind_internal\.h',
1704 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091705 ),
Daniel Cheng2248b332022-07-27 06:16:591706 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531707 r'base::Feature k',
1708 ('Please use BASE_DECLARE_FEATURE() or BASE_FEATURE() instead of ',
1709 'directly declaring/defining features.'),
1710 True,
1711 [
1712 # Implements BASE_DECLARE_FEATURE().
1713 r'^base/feature_list\.h',
1714 ],
Daniel Chengba3bc2e2022-10-03 02:45:431715 ),
Robert Ogden92101dcb2022-10-19 23:49:361716 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531717 r'/\bchartorune\b',
1718 ('chartorune is not memory-safe, unless you can guarantee the input ',
1719 'string is always null-terminated. Otherwise, please use charntorune ',
1720 'from libphonenumber instead.'),
1721 True,
1722 [
1723 _THIRD_PARTY_EXCEPT_BLINK,
1724 # Exceptions to this rule should have a fuzzer.
1725 ],
Robert Ogden92101dcb2022-10-19 23:49:361726 ),
Arthur Sonzogni1da65fa2023-03-27 16:01:521727 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531728 r'/\b#include "base/atomicops\.h"\b',
1729 ('Do not use base::subtle atomics, but std::atomic, which are simpler '
1730 'to use, have better understood, clearer and richer semantics, and are '
1731 'harder to mis-use. See details in base/atomicops.h.', ),
1732 False,
1733 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Benoit Lize79cf0592023-01-27 10:01:571734 ),
Daniel Cheng566634ff2024-06-29 14:56:531735 BanRule(r'CrossThreadPersistent<', (
Arthur Sonzogni60348572e2023-04-07 10:22:521736 'Do not use blink::CrossThreadPersistent, but '
Daniel Cheng566634ff2024-06-29 14:56:531737 'blink::CrossThreadHandle. It is harder to mis-use.', 'More info: '
Arthur Sonzogni60348572e2023-04-07 10:22:521738 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1739 'Please contact platform-architecture-dev@ before adding new instances.'
Daniel Cheng566634ff2024-06-29 14:56:531740 ), False, []),
1741 BanRule(r'CrossThreadWeakPersistent<', (
Arthur Sonzogni60348572e2023-04-07 10:22:521742 'Do not use blink::CrossThreadWeakPersistent, but '
Daniel Cheng566634ff2024-06-29 14:56:531743 'blink::CrossThreadWeakHandle. It is harder to mis-use.', 'More info: '
Arthur Sonzogni60348572e2023-04-07 10:22:521744 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1745 'Please contact platform-architecture-dev@ before adding new instances.'
Daniel Cheng566634ff2024-06-29 14:56:531746 ), False, []),
1747 BanRule(r'objc/objc.h', (
Avi Drissman491617c2023-04-13 17:33:151748 'Do not include <objc/objc.h>. It defines away ARC lifetime '
1749 'annotations, and is thus dangerous.',
1750 'Please use the pimpl pattern; search for `ObjCStorage` for examples.',
1751 'For further reading on how to safely mix C++ and Obj-C, see',
1752 'https://chromium.googlesource.com/chromium/src/+/main/docs/mac/mixing_cpp_and_objc.md'
Daniel Cheng566634ff2024-06-29 14:56:531753 ), True, []),
1754 BanRule(
1755 r'/#include <filesystem>',
1756 ('libc++ <filesystem> is banned per the Google C++ styleguide.', ),
1757 True,
1758 # This fuzzing framework is a standalone open source project and
1759 # cannot rely on Chromium base.
1760 (r'third_party/centipede'),
Avi Drissman491617c2023-04-13 17:33:151761 ),
Grace Park8d59b54b2023-04-26 17:53:351762 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531763 r'TopDocument()',
1764 ('TopDocument() does not work correctly with out-of-process iframes. '
1765 'Please do not introduce new uses.', ),
1766 True,
1767 (
1768 # TODO(crbug.com/617677): Remove all remaining uses.
1769 r'^third_party/blink/renderer/core/dom/document\.cc',
1770 r'^third_party/blink/renderer/core/dom/document\.h',
1771 r'^third_party/blink/renderer/core/dom/element\.cc',
1772 r'^third_party/blink/renderer/core/exported/web_disallow_transition_scope_test\.cc',
1773 r'^third_party/blink/renderer/core/exported/web_document_test\.cc',
1774 r'^third_party/blink/renderer/core/html/html_anchor_element\.cc',
1775 r'^third_party/blink/renderer/core/html/html_dialog_element\.cc',
1776 r'^third_party/blink/renderer/core/html/html_element\.cc',
1777 r'^third_party/blink/renderer/core/html/html_frame_owner_element\.cc',
1778 r'^third_party/blink/renderer/core/html/media/video_wake_lock\.cc',
1779 r'^third_party/blink/renderer/core/loader/anchor_element_interaction_tracker\.cc',
1780 r'^third_party/blink/renderer/core/page/scrolling/root_scroller_controller\.cc',
1781 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.cc',
1782 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.h',
1783 r'^third_party/blink/renderer/core/script/classic_pending_script\.cc',
1784 r'^third_party/blink/renderer/core/script/script_loader\.cc',
1785 ),
Grace Park8d59b54b2023-04-26 17:53:351786 ),
Daniel Cheng72153e02023-05-18 21:18:141787 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531788 pattern=r'base::raw_ptr<',
1789 explanation=('Do not use base::raw_ptr, use raw_ptr.', ),
1790 treat_as_error=True,
1791 excluded_paths=(
1792 '^base/',
1793 '^tools/',
1794 ),
Daniel Cheng72153e02023-05-18 21:18:141795 ),
Arthur Sonzognif0eea302023-08-18 19:20:311796 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531797 pattern=r'base:raw_ref<',
1798 explanation=('Do not use base::raw_ref, use raw_ref.', ),
1799 treat_as_error=True,
1800 excluded_paths=(
1801 '^base/',
1802 '^tools/',
1803 ),
Arthur Sonzognif0eea302023-08-18 19:20:311804 ),
1805 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531806 pattern=r'/raw_ptr<[^;}]*\w{};',
1807 explanation=(
1808 'Do not use {} for raw_ptr initialization, use = nullptr instead.',
1809 ),
1810 treat_as_error=True,
1811 excluded_paths=(
1812 '^base/',
1813 '^tools/',
1814 ),
Arthur Sonzognif0eea302023-08-18 19:20:311815 ),
Anton Maliev66751812023-08-24 16:28:131816 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531817 pattern=r'/#include "base/allocator/.*/raw_'
1818 r'(ptr|ptr_cast|ptr_exclusion|ref).h"',
1819 explanation=(
1820 'Please include the corresponding facade headers:',
1821 '- #include "base/memory/raw_ptr.h"',
1822 '- #include "base/memory/raw_ptr_cast.h"',
1823 '- #include "base/memory/raw_ptr_exclusion.h"',
1824 '- #include "base/memory/raw_ref.h"',
1825 ),
1826 treat_as_error=True,
1827 excluded_paths=(
1828 '^base/',
1829 '^tools/',
1830 ),
Tom Sepez41eb158d2023-09-12 16:16:221831 ),
1832 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531833 pattern=r'ContentSettingsType::COOKIES',
1834 explanation=
1835 ('Do not use ContentSettingsType::COOKIES to check whether cookies are '
1836 'supported in the provided context. Instead rely on the '
1837 'content_settings::CookieSettings API. If you are using '
1838 'ContentSettingsType::COOKIES to check the user preference setting '
1839 'specifically, disregard this warning.', ),
1840 treat_as_error=False,
1841 excluded_paths=(
1842 '^chrome/browser/ui/content_settings/',
1843 '^components/content_settings/',
1844 '^services/network/cookie_settings.cc',
1845 '.*test.cc',
1846 ),
Arthur Sonzogni48c6aea22023-09-04 22:25:201847 ),
1848 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531849 pattern=r'ContentSettingsType::TRACKING_PROTECTION',
1850 explanation=
1851 ('Do not directly use ContentSettingsType::TRACKING_PROTECTION to check '
1852 'for tracking protection exceptions. Instead rely on the '
1853 'privacy_sandbox::TrackingProtectionSettings API.', ),
1854 treat_as_error=False,
1855 excluded_paths=(
1856 '^chrome/browser/ui/content_settings/',
1857 '^components/content_settings/',
1858 '^components/privacy_sandbox/tracking_protection_settings.cc',
1859 '.*test.cc',
1860 ),
Anton Maliev66751812023-08-24 16:28:131861 ),
Tom Andersoncd522072023-10-03 00:52:351862 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531863 pattern=r'/\bg_signal_connect',
1864 explanation=('Use ScopedGSignal instead of g_signal_connect*()', ),
1865 treat_as_error=True,
1866 excluded_paths=('^ui/base/glib/scoped_gsignal.h', ),
Michelle Abreo6b7437822024-04-26 17:29:041867 ),
1868 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531869 pattern=r'features::kIsolatedWebApps',
1870 explanation=(
1871 'Do not use `features::kIsolatedWebApps` directly to guard Isolated ',
1872 'Web App code. ',
Andrew Rayskiy7ae2b5d2025-02-28 16:59:381873 'Use `content::AreIsolatedWebAppsEnabled()` in the browser process '
1874 'or check the `kEnableIsolatedWebAppsInRenderer` command line flag '
1875 'in the renderer process.',
Daniel Cheng566634ff2024-06-29 14:56:531876 ),
1877 treat_as_error=True,
Andrew Rayskiy7ae2b5d2025-02-28 16:59:381878 excluded_paths=_TEST_CODE_EXCLUDED_PATHS + (
1879 '^chrome/browser/about_flags.cc',
1880 '^chrome/browser/component_updater/iwa_key_distribution_component_installer.cc',
1881 '^chrome/browser/web_applications/isolated_web_apps/chrome_content_browser_client_isolated_web_apps_part.cc',
1882 '^chrome/browser/ui/startup/bad_flags_prompt.cc',
1883 '^content/shell/browser/shell_content_browser_client.cc',
1884 )),
Daniel Cheng566634ff2024-06-29 14:56:531885 BanRule(
1886 pattern=r'features::kIsolatedWebAppDevMode',
1887 explanation=(
1888 'Do not use `features::kIsolatedWebAppDevMode` directly to guard code ',
1889 'related to Isolated Web App Developer Mode. ',
1890 'Use `web_app::IsIwaDevModeEnabled()` instead.',
1891 ),
1892 treat_as_error=True,
1893 excluded_paths=_TEST_CODE_EXCLUDED_PATHS + (
1894 '^chrome/browser/about_flags.cc',
1895 '^chrome/browser/web_applications/isolated_web_apps/isolated_web_app_features.cc',
1896 '^chrome/browser/ui/startup/bad_flags_prompt.cc',
1897 )),
1898 BanRule(
1899 pattern=r'features::kIsolatedWebAppUnmanagedInstall',
1900 explanation=(
1901 'Do not use `features::kIsolatedWebAppUnmanagedInstall` directly to ',
1902 'guard code related to unmanaged install flow for Isolated Web Apps. ',
1903 'Use `web_app::IsIwaUnmanagedInstallEnabled()` instead.',
1904 ),
1905 treat_as_error=True,
1906 excluded_paths=_TEST_CODE_EXCLUDED_PATHS + (
1907 '^chrome/browser/about_flags.cc',
1908 '^chrome/browser/web_applications/isolated_web_apps/isolated_web_app_features.cc',
1909 )),
1910 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531911 pattern='/(CUIAutomation|AccessibleObjectFromWindow)',
1912 explanation=
1913 ('Direct usage of UIAutomation or IAccessible2 in client code is '
1914 'discouraged in Chromium, as it is not an assistive technology and '
1915 'should not rely on accessibility APIs directly. These APIs can '
1916 'introduce significant performance overhead. However, if you believe '
1917 'your use case warrants an exception, please discuss it with an '
1918 'accessibility owner before proceeding. For more information on the '
1919 'performance implications, see https://docs.google.com/document/d/1jN4itpCe_bDXF0BhFaYwv4xVLsCWkL9eULdzjmLzkuk/edit#heading=h.pwth3nbwdub0.',
1920 ),
1921 treat_as_error=False,
Andrew Rayskiycdd45e732024-03-20 14:32:391922 ),
1923 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531924 pattern=r'/WIDGET_OWNS_NATIVE_WIDGET|'
1925 r'NATIVE_WIDGET_OWNS_WIDGET',
1926 explanation=
1927 ('WIDGET_OWNS_NATIVE_WIDGET and NATIVE_WIDGET_OWNS_WIDGET are in the '
1928 'process of being deprecated. Consider using the new '
1929 'CLIENT_OWNS_WIDGET ownership model. Eventually, this will be the only '
1930 'available ownership model available and the associated enumeration'
1931 'will be removed.', ),
1932 treat_as_error=False,
Andrew Rayskiycdd45e732024-03-20 14:32:391933 ),
1934 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531935 pattern='ProfileManager::GetLastUsedProfile',
1936 explanation=
1937 ('Most code should already be scoped to a Profile. Pass in a Profile* '
1938 'or retreive from an existing entity with a reference to the Profile '
1939 '(e.g. WebContents).', ),
1940 treat_as_error=False,
Arthur Sonzogni5cbd3e32024-02-08 17:51:321941 ),
Helmut Januschkab3f71ab52024-03-12 02:48:051942 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531943 pattern=(r'/FindBrowserWithUiElementContext|'
1944 r'FindBrowserWithTab|'
1945 r'FindBrowserWithGroup|'
1946 r'FindTabbedBrowser|'
1947 r'FindAnyBrowser|'
1948 r'FindBrowserWithProfile|'
Erik Chen5f02eb4c2024-08-23 06:30:441949 r'FindLastActive|'
Daniel Cheng566634ff2024-06-29 14:56:531950 r'FindBrowserWithActiveWindow'),
1951 explanation=
1952 ('Most code should already be scoped to a Browser. Pass in a Browser* '
1953 'or retreive from an existing entity with a reference to the Browser.',
1954 ),
1955 treat_as_error=False,
Helmut Januschkab3f71ab52024-03-12 02:48:051956 ),
1957 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531958 pattern='BrowserUserData',
1959 explanation=
1960 ('Do not use BrowserUserData to store state on a Browser instance. '
1961 'Instead use BrowserWindowFeatures. BrowserWindowFeatures is '
1962 'functionally identical but has two benefits: it does not force a '
1963 'dependency onto class Browser, and lifetime semantics are explicit '
1964 'rather than implicit. See BrowserUserData header file for more '
1965 'details.', ),
1966 treat_as_error=False,
Mike Doughertyab1bdec2024-08-06 16:39:011967 excluded_paths=(
Daniel Cheng6303eed2025-05-03 00:12:331968 # Exclude iOS as the iOS implementation of BrowserUserData is separate
1969 # and still in use.
1970 '^ios/', ),
Erik Chen87358e82024-06-04 02:13:121971 ),
Tom Sepezea67b6e2024-08-08 18:17:271972 BanRule(
Tom Sepezd3272cd2025-02-21 19:11:311973 pattern=r'subspan(0u,',
Daniel Cheng6303eed2025-05-03 00:12:331974 explanation=(
1975 'Prefer first(n) over subspan(0u, n) as it is shorter, and the '
1976 'compiler may have to emit a branch for the n == dynamic_extent '
1977 'case of subspan().', ),
Tom Sepezd3272cd2025-02-21 19:11:311978 treat_as_error=False,
1979 ),
1980 BanRule(
Tom Sepezea67b6e2024-08-08 18:17:271981 pattern=r'UNSAFE_TODO(',
Daniel Cheng6303eed2025-05-03 00:12:331982 explanation=(
1983 'Do not use UNSAFE_TODO() to write new unsafe code. Use only when '
1984 'removing a pre-existing file-wide allow_unsafe_buffers pragma, or '
1985 'when incrementally converting code off of unsafe interfaces', ),
Tom Sepezea67b6e2024-08-08 18:17:271986 treat_as_error=False,
1987 ),
1988 BanRule(
Claudio DeSouzaad1d1f252025-04-22 23:38:581989 pattern='#pragma allow_unsafe_buffers',
1990 explanation=
1991 ('Do not use allow_unsafe_buffers to write new unsafe code. Use only '
Daniel Cheng6303eed2025-05-03 00:12:331992 'when enabling unsafe buffers checks under a new uncovered path.', ),
Claudio DeSouzaad1d1f252025-04-22 23:38:581993 treat_as_error=False,
1994 ),
1995 BanRule(
Tom Sepezea67b6e2024-08-08 18:17:271996 pattern=r'UNSAFE_BUFFERS(',
1997 explanation=
Tom Sepeza90f92b2024-08-15 16:01:351998 ('Try to avoid using UNSAFE_BUFFERS() if at all possible. Otherwise, '
1999 'be sure to justify in a // SAFETY comment why other options are not '
Daniel Cheng6303eed2025-05-03 00:12:332000 'available, and why the code is safe.', ),
Tom Sepezea67b6e2024-08-08 18:17:272001 treat_as_error=False,
2002 ),
Erik Chend086ae02024-08-20 22:53:332003 BanRule(
2004 pattern='BrowserWithTestWindowTest',
2005 explanation=
2006 ('Do not use BrowserWithTestWindowTest. By instantiating an instance '
2007 'of class Browser, the test is no longer a unit test but is instead a '
2008 'browser test. The class BrowserWithTestWindowTest forces production '
2009 'logic to take on test-only conditionals, which is an anti-pattern. '
2010 'Features should be performing dependency injection rather than '
2011 'directly using class Browser. See '
Daniel Cheng6303eed2025-05-03 00:12:332012 'docs/chrome_browser_design_principles.md for more details.', ),
Erik Chend086ae02024-08-20 22:53:332013 treat_as_error=False,
2014 ),
Erik Chen8cf3a652024-08-23 17:13:302015 BanRule(
Erik Chen959cdd72024-08-29 02:11:212016 pattern='TestWithBrowserView',
2017 explanation=
Daniel Cheng6303eed2025-05-03 00:12:332018 ('Do not use TestWithBrowserView. See '
2019 'docs/chrome_browser_design_principles.md for details. If you want '
2020 'to write a test that has both a Browser and a BrowserView, create '
2021 'a browser_test. If you want to write a unit_test, your code must '
2022 'not reference Browser*.', ),
Erik Chen959cdd72024-08-29 02:11:212023 treat_as_error=False,
2024 ),
2025 BanRule(
Erik Chene89ebe32025-02-22 02:46:492026 pattern='CreateBrowserWithTestWindow',
2027 explanation=
Daniel Cheng6303eed2025-05-03 00:12:332028 ('Do not use CreateBrowserWithTestWindow. See '
2029 'docs/chrome_browser_design_principles.md for details. If you want '
2030 'to write a test that has a Browser, create a browser_test. If you '
2031 'want to write a unit_test, your code must not reference Browser*.',
Erik Chene89ebe32025-02-22 02:46:492032 ),
2033 treat_as_error=False,
2034 ),
2035 BanRule(
Erik Chenf12a06642025-03-13 23:30:342036 pattern='CreateBrowserWithTestWindowForParams',
2037 explanation=
Daniel Cheng6303eed2025-05-03 00:12:332038 ('Do not use CreateBrowserWithTestWindowForParams. See '
2039 'docs/chrome_browser_design_principles.md for details. If you want '
2040 'to write a test that has a Browser, create a browser_test and use '
2041 'Browser::Browser. If you want to write a unit_test, your code must '
2042 'not reference Browser*.', ),
Erik Chenf12a06642025-03-13 23:30:342043 treat_as_error=False,
2044 ),
2045 BanRule(
Mikita Kuchyn383c9bab2025-05-23 15:15:232046 pattern='TestBrowserWindow',
2047 explanation=(
2048 'Do not use TestBrowserWindow. See '
2049 'docs/chrome_browser_design_principles.md for details. If you want '
2050 'to write a test that has a Browser, create a browser_test. If you'
2051 'want to write a unit_test, your code should not reference Browser'
2052 'or BrowserWindow.',
2053 ),
2054 treat_as_error=False,
2055 ),
2056 BanRule(
Erik Chen8cf3a652024-08-23 17:13:302057 pattern='RunUntilIdle',
2058 explanation=
2059 ('Do not RunUntilIdle. If possible, explicitly quit the run loop using '
2060 'run_loop.Quit() or run_loop.QuitClosure() if completion can be '
2061 'observed using a lambda or callback. Otherwise, wait for the '
Daniel Cheng6303eed2025-05-03 00:12:332062 'condition to be true via base::test::RunUntil().', ),
Erik Chen8cf3a652024-08-23 17:13:302063 treat_as_error=False,
2064 ),
Daniel Chengddde13a2024-09-05 21:39:282065 BanRule(
2066 pattern=r'/\bstd::(literals|string_literals|string_view_literals)\b',
Daniel Cheng6303eed2025-05-03 00:12:332067 explanation=(
Daniel Chengddde13a2024-09-05 21:39:282068 'User-defined literals are banned by the Google C++ style guide. '
2069 'Exceptions are provided in Chrome for string and string_view '
Daniel Cheng6303eed2025-05-03 00:12:332070 'literals that embed \\0.', ),
Daniel Chengddde13a2024-09-05 21:39:282071 treat_as_error=True,
2072 excluded_paths=(
2073 # Various tests or test helpers that embed NUL in strings or
2074 # string_views.
Daniel Chengddde13a2024-09-05 21:39:282075 r'^base/strings/string_util_unittest\.cc',
2076 r'^base/strings/utf_string_conversions_unittest\.cc',
Hidehiko Abe51601812025-01-12 16:17:352077 r'^chromeos/ash/experiences/arc/session/serial_number_util_unittest\.cc',
Daniel Chengddde13a2024-09-05 21:39:282078 r'^components/history/core/browser/visit_annotations_database\.cc',
2079 r'^components/history/core/browser/visit_annotations_database_unittest\.cc',
2080 r'^components/os_crypt/sync/os_crypt_unittest\.cc',
2081 r'^components/password_manager/core/browser/credentials_cleaner_unittest\.cc',
2082 r'^content/browser/file_system_access/file_system_access_file_writer_impl_unittest\.cc',
2083 r'^net/cookies/parsed_cookie_unittest\.cc',
2084 r'^third_party/blink/renderer/modules/webcodecs/test_helpers\.cc',
2085 r'^third_party/blink/renderer/modules/websockets/websocket_channel_impl_test\.cc',
2086 ),
Erik Chenba8b0cd32024-10-01 08:36:362087 ),
2088 BanRule(
2089 pattern='BUILDFLAG(GOOGLE_CHROME_BRANDING)',
2090 explanation=
2091 ('Code gated by GOOGLE_CHROME_BRANDING is effectively untested. This '
2092 'is typically wrong. Valid use cases are glue for private modules '
Daniel Cheng6303eed2025-05-03 00:12:332093 'shipped alongside Chrome, and installation-related logic.', ),
Erik Chenba8b0cd32024-10-01 08:36:362094 treat_as_error=False,
2095 ),
2096 BanRule(
2097 pattern='defined(OFFICIAL_BUILD)',
2098 explanation=
2099 ('Code gated by OFFICIAL_BUILD is effectively untested. This '
2100 'is typically wrong. One valid use case is low-level code that '
2101 'handles subtleties related to high-levels of optimizations that come '
Daniel Cheng6303eed2025-05-03 00:12:332102 'with OFFICIAL_BUILD.', ),
Erik Chenba8b0cd32024-10-01 08:36:362103 treat_as_error=False,
2104 ),
Erik Chen95b9c782024-11-08 03:26:272105 BanRule(
2106 pattern='WebContentsDestroyed',
2107 explanation=
2108 ('Do not use this method. It is invoked half-way through the '
2109 'destructor of WebContentsImpl and using it often results in crashes '
2110 'or surprising behavior. Conceptually, this is only necessary by '
2111 'objects that depend on, but outlive the WebContents. These objects '
2112 'should instead coordinate with the owner of the WebContents which is '
Daniel Cheng6303eed2025-05-03 00:12:332113 'responsible for destroying the WebContents.', ),
Erik Chen95b9c782024-11-08 03:26:272114 treat_as_error=False,
2115 ),
Maksim Sisovc98fdfa2024-11-16 20:12:272116 BanRule(
Georg Neisa7f94e62025-02-28 07:01:482117 pattern='IS_CHROMEOS_ASH',
Maksim Sisovc98fdfa2024-11-16 20:12:272118 explanation=
Georg Neisa7f94e62025-02-28 07:01:482119 ('IS_CHROMEOS_ASH is deprecated. Please use the equivalent IS_CHROMEOS '
Daniel Cheng6303eed2025-05-03 00:12:332120 'instead (Lacros is gone).', ),
Maksim Sisovc98fdfa2024-11-16 20:12:272121 treat_as_error=False,
2122 ),
Erik Chen1396bbe2025-01-27 23:39:362123 BanRule(
2124 pattern=(r'namespace {'),
2125 explanation=
2126 ('Anonymous namespaces are disallowed in C++ header files. See '
2127 'https://google.github.io/styleguide/cppguide.html#Internal_Linkage '
Daniel Cheng6303eed2025-05-03 00:12:332128 ' for details.', ),
Erik Chen1396bbe2025-01-27 23:39:362129 treat_as_error=False,
2130 excluded_paths=[
Daniel Cheng6303eed2025-05-03 00:12:332131 _THIRD_PARTY_EXCEPT_BLINK, # Don't warn in third_party folders.
2132 r'^(?!.*\.h$).*$', # Exclude all files except those that end in .h
Erik Chen1396bbe2025-01-27 23:39:362133 ],
2134 ),
Keren Zhuf06d757d2025-03-04 05:32:362135 BanRule(
2136 pattern=('AddChildViewRaw'),
2137 explanation=(
2138 'Do not use AddChildViewRaw. It is prone to memory leaks and '
2139 'use-after-free bugs. Instead, use AddChildView(std::unique_ptr). '
2140 'See https://crbug.com/40485510 for more details.', ),
2141 treat_as_error=False,
2142 ),
Nate Fischerd541ff82025-03-11 21:34:192143 BanRule(
2144 pattern=(r'IS_DESKTOP_ANDROID'),
2145 explanation=(
Eric Lokc26a46662025-05-02 01:04:032146 'Do not add new uses of IS_DESKTOP_ANDROID build flag until you '
2147 'have the approval of tedchoc@ or twellington@. '
2148 'Background: it is highly important to reduce the divergence of '
2149 'features across platforms. '
2150 'Allowances may be granted to only the directories below: '
2151 '[build/, chrome/, components/, extensions/, infra/, tools/] ',
2152 'Note: in particular we need to avoid components shared with '
2153 'WebView.',
2154 ),
Nate Fischerd541ff82025-03-11 21:34:192155 treat_as_error=False,
Ben Pastenee79d66112025-04-23 19:46:152156 surface_as_gerrit_lint=True,
Nate Fischerd541ff82025-03-11 21:34:192157 ),
[email protected]127f18ec2012-06-16 05:05:592158)
2159
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152160_DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING = (
Daniel Cheng6303eed2025-05-03 00:12:332161 'Used a predicate related to signin::ConsentLevel::kSync which will always '
2162 'return false in the future (crbug.com/40066949). Prefer using a predicate '
2163 'that also supports signin::ConsentLevel::kSignin when appropriate. It is '
2164 'safe to ignore this warning if you are just moving an existing call, or if '
2165 'you want special handling for users in the legacy state. In doubt, reach '
2166 'out to //components/sync/OWNERS.', )
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152167
2168# C++ functions related to signin::ConsentLevel::kSync which are deprecated.
Daniel Cheng6303eed2025-05-03 00:12:332169_DEPRECATED_SYNC_CONSENT_CPP_FUNCTIONS: Sequence[BanRule] = (
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152170 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:332171 'HasSyncConsent',
2172 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2173 False,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152174 ),
2175 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:332176 'CanSyncFeatureStart',
2177 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2178 False,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152179 ),
2180 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:332181 'IsSyncFeatureEnabled',
2182 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2183 False,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152184 ),
2185 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:332186 'IsSyncFeatureActive',
2187 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2188 False,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152189 ),
2190)
2191
2192# Java functions related to signin::ConsentLevel::kSync which are deprecated.
Daniel Cheng6303eed2025-05-03 00:12:332193_DEPRECATED_SYNC_CONSENT_JAVA_FUNCTIONS: Sequence[BanRule] = (
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152194 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:332195 'hasSyncConsent',
2196 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2197 False,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152198 ),
2199 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:332200 'canSyncFeatureStart',
2201 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2202 False,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152203 ),
2204 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:332205 'isSyncFeatureEnabled',
2206 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2207 False,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152208 ),
2209 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:332210 'isSyncFeatureActive',
2211 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2212 False,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152213 ),
2214)
2215
Justin Lulejian09fd06872025-04-01 22:03:282216_BANNED_MOJOM_PATTERNS: Sequence[BanRule] = (
Daniel Cheng92c15e32022-03-16 17:48:222217 BanRule(
2218 'handle<shared_buffer>',
2219 (
Justin Lulejian09fd06872025-04-01 22:03:282220 'Please use one of the more specific shared memory types instead:',
2221 ' mojo_base.mojom.ReadOnlySharedMemoryRegion',
2222 ' mojo_base.mojom.WritableSharedMemoryRegion',
2223 ' mojo_base.mojom.UnsafeSharedMemoryRegion',
Daniel Cheng92c15e32022-03-16 17:48:222224 ),
2225 True,
2226 ),
Justin Lulejian09fd06872025-04-01 22:03:282227 BanRule(
2228 'string extension_id',
2229 (
2230 'Please use the extensions::mojom::ExtensionId struct when '
2231 'passing extensions::ExtensionIds as mojom messages in order to ',
2232 'provide message validation.',
2233 ),
2234 True,
2235 # Only apply this to (mojom) files in a subdirectory of extensions.
2236 excluded_paths=(r'^((?!extensions/).)*$', ),
2237 ),
Daniel Cheng92c15e32022-03-16 17:48:222238)
2239
mlamouria82272622014-09-16 18:45:042240_IPC_ENUM_TRAITS_DEPRECATED = (
2241 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:502242 'See http://www.chromium.org/Home/chromium-security/education/'
2243 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:042244
Stephen Martinis97a394142018-06-07 23:06:052245_LONG_PATH_ERROR = (
2246 'Some files included in this CL have file names that are too long (> 200'
2247 ' characters). If committed, these files will cause issues on Windows. See'
Daniel Cheng6303eed2025-05-03 00:12:332248 ' https://crbug.com/612667 for more details.')
Stephen Martinis97a394142018-06-07 23:06:052249
Shenghua Zhangbfaa38b82017-11-16 21:58:022250_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Bruce Dawson40fece62022-09-16 19:58:312251 r".*/BuildHooksAndroidImpl\.java",
2252 r".*/LicenseContentProvider\.java",
2253 r".*/PlatformServiceBridgeImpl.java",
2254 r".*chrome/android/feed/dummy/.*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:022255]
[email protected]127f18ec2012-06-16 05:05:592256
Mohamed Heikald048240a2019-11-12 16:57:372257# List of image extensions that are used as resources in chromium.
2258_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
2259
Sean Kau46e29bc2017-08-28 16:31:162260# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:402261_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Bruce Dawson40fece62022-09-16 19:58:312262 r'test/data/',
2263 r'testing/buildbot/',
2264 r'^components/policy/resources/policy_templates\.json$',
2265 r'^third_party/protobuf/',
Camillo Bruni1411a352023-05-24 12:39:032266 r'^third_party/blink/perf_tests/speedometer.*/resources/todomvc/learn\.json',
Bruce Dawson40fece62022-09-16 19:58:312267 r'^third_party/blink/renderer/devtools/protocol\.json$',
2268 r'^third_party/blink/web_tests/external/wpt/',
2269 r'^tools/perf/',
2270 r'^tools/traceline/svgui/startup-release.json',
Daniel Cheng2d4c2d192022-07-01 01:38:312271 # vscode configuration files allow comments
Bruce Dawson40fece62022-09-16 19:58:312272 r'^tools/vscode/',
Sean Kau46e29bc2017-08-28 16:31:162273]
2274
Andrew Grieveb773bad2020-06-05 18:00:382275# These are not checked on the public chromium-presubmit trybot.
2276# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:042277# checkouts.
agrievef32bcc72016-04-04 14:57:402278_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:382279 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382280]
2281
Andrew Grieveb773bad2020-06-05 18:00:382282_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:042283 'android_webview/tools/run_cts.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:362284 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042285 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362286 'build/android/gyp/aar.pydeps',
2287 'build/android/gyp/aidl.pydeps',
2288 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:382289 'build/android/gyp/assert_static_initializers.pydeps',
Mohamed Heikal133e1f22023-04-18 20:04:372290 'build/android/gyp/binary_baseline_profile.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:022291 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:222292 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieveacac4242024-12-20 19:39:422293 'build/android/gyp/check_for_missing_direct_deps.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:112294 'build/android/gyp/compile_java.pydeps',
Peter Weneaa963f2023-01-20 19:40:302295 'build/android/gyp/compile_kt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362296 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362297 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362298 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:112299 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042300 'build/android/gyp/create_app_bundle_apks.pydeps',
2301 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362302 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:122303 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:092304 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:222305 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve2d972e5f2025-01-28 18:28:142306 'build/android/gyp/create_stub_manifest.pydeps',
Peter Wene6e017e2022-07-27 21:40:402307 'build/android/gyp/create_test_apk_wrapper_script.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002308 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362309 'build/android/gyp/dex.pydeps',
2310 'build/android/gyp/dist_aar.pydeps',
Andrew Grieve651ddb32025-01-23 03:27:342311 'build/android/gyp/errorprone.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362312 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:212313 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362314 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:362315 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362316 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:582317 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362318 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:142319 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:262320 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:472321 'build/android/gyp/java_google_api_keys.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042322 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362323 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362324 'build/android/gyp/merge_manifest.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:102325 'build/android/gyp/optimize_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362326 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:222327 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362328 'build/android/gyp/proguard.pydeps',
Mohamed Heikaldd52b452024-09-10 17:10:502329 'build/android/gyp/rename_java_classes.pydeps',
Andrew Grievee3a775ab2022-05-16 15:59:222330 'build/android/gyp/system_image_apks.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:102331 'build/android/gyp/trace_event_bytecode_rewriter.pydeps',
Andrew Grieve170b9782025-02-03 15:54:532332 'build/android/gyp/tracereferences.pydeps',
Peter Wen578730b2020-03-19 19:55:462333 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:302334 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:242335 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362336 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:462337 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:562338 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362339 'build/android/incremental_install/generate_android_manifest.pydeps',
2340 'build/android/incremental_install/write_installer_json.pydeps',
Stephanie Kim392913b452022-06-15 17:25:322341 'build/android/pylib/results/presentation/test_results_presentation.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042342 'build/android/resource_sizes.pydeps',
2343 'build/android/test_runner.pydeps',
2344 'build/android/test_wrapper/logdog_wrapper.pydeps',
zijiehe-google-com356980f2025-05-08 20:58:152345 'build/fuchsia/test/component_storage_test.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362346 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:322347 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:272348 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
2349 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Bailey Myers-Morganbd122132025-03-26 23:09:162350 'chrome/test/media_router/performance/performance_test.pydeps',
Junbo Kedcd3a452021-03-19 17:55:042351 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Mohannad Farrag19102742023-12-01 01:16:302352 'components/cronet/tools/check_combined_proguard_file.pydeps',
2353 'components/cronet/tools/generate_proguard_file.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002354 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382355 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002356 'content/public/android/generate_child_service.pydeps',
Hzj_jie77bdb802024-07-22 18:14:512357 'fuchsia_web/av_testing/av_sync_tests.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382358 'net/tools/testserver/testserver.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:182359 'testing/scripts/run_isolated_script_test.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:412360 'testing/merge_scripts/standard_isolated_script_merge.pydeps',
2361 'testing/merge_scripts/standard_gtest_merge.pydeps',
2362 'testing/merge_scripts/code_coverage/merge_results.pydeps',
2363 'testing/merge_scripts/code_coverage/merge_steps.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042364 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:422365 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
Yuki Shiino38eeaad12022-08-11 06:40:252366 'third_party/blink/renderer/bindings/scripts/check_generated_file_list.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:422367 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:132368 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Yuki Shiinoea477d32023-08-21 06:24:342369 'third_party/blink/renderer/bindings/scripts/generate_event_interface_names.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:502370 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:412371 'third_party/blink/tools/blinkpy/web_tests/merge_results.pydeps',
2372 'third_party/blink/tools/merge_web_test_results.pydeps',
John Budorickbc3571aa2019-04-25 02:20:062373 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:222374 'tools/binary_size/supersize.pydeps',
Peter Wen2dcfa6e2025-03-04 22:42:522375 'tools/cygprofile/generate_orderfile.pydeps',
Ben Pastene028104a2022-08-10 19:17:452376 'tools/perf/process_perf_results.pydeps',
Peter Wence103e12024-10-09 19:23:512377 'tools/pgo/generate_profile.pydeps',
agrievef32bcc72016-04-04 14:57:402378]
2379
2380_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
2381
Eric Boren6fd2b932018-01-25 15:05:082382# Bypass the AUTHORS check for these accounts.
Daniel Cheng6303eed2025-05-03 00:12:332383_KNOWN_ROBOTS = set() | set('%[email protected]' % s for s in (
2384 'findit-for-me', 'luci-bisection', 'predator-for-me-staging',
2385 'predator-for-me')) | set(
2386 '%[email protected]' % s
2387 for s in ('3su6n15k.default', )) | set(
2388 '%[email protected]' % s
2389 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
2390 'wpt-autoroller', 'chrome-weblayer-builder',
2391 'skylab-test-cros-roller', 'infra-try-recipes-tester',
2392 'chrome-automated-expectation',
2393 'chromium-automated-expectation', 'chrome-branch-day',
2394 'chrome-cherry-picker', 'chromium-autosharder')
2395 ) | set(
2396 '%[email protected]' % s
2397 for s in ('chromium-autoroll', 'chromium-release-autoroll')) | set(
2398 '%[email protected]' % s
2399 for s in ('chromium-internal-autoroll', )
2400 ) | set(
2401 '%[email protected]' %
2402 s for s in ('chrome-screen-ai-releaser', 'crash-eng', 'crash')
2403 ) | set(
2404 '%[email protected]' % s
2405 for s in ('swarming-tasks', )) | set(
2406 '%[email protected]' % s
2407 for s in ('global-integration-try-builder',
Rachael Newitte5664ef92025-05-08 14:00:232408 'global-integration-ci-builder')
2409 ) | set('%[email protected]' % s for s in (
2410 'chops-security-borg',
2411 'chops-security-cronjobs-cpesuggest')) | set(
2412 '%[email protected]' % s
2413 for s in ('chromeos-ci-release', ))
Eric Boren6fd2b932018-01-25 15:05:082414
Daniel Cheng6303eed2025-05-03 00:12:332415_INVALID_GRD_FILE_LINE = [(r'<file lang=.* path=.*',
2416 'Path should come before lang in GRD files.')]
2417
Eric Boren6fd2b932018-01-25 15:05:082418
Daniel Bratell65b033262019-04-23 08:17:062419def _IsCPlusPlusFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502420 """Returns True if this file contains C++-like code (and not Python,
2421 Go, Java, MarkDown, ...)"""
Daniel Bratell65b033262019-04-23 08:17:062422
Sam Maiera6e76d72022-02-11 21:43:502423 ext = input_api.os_path.splitext(file_path)[1]
2424 # This list is compatible with CppChecker.IsCppFile but we should
2425 # consider adding ".c" to it. If we do that we can use this function
2426 # at more places in the code.
2427 return ext in (
2428 '.h',
2429 '.cc',
2430 '.cpp',
2431 '.m',
2432 '.mm',
2433 )
2434
Daniel Bratell65b033262019-04-23 08:17:062435
2436def _IsCPlusPlusHeaderFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502437 return input_api.os_path.splitext(file_path)[1] == ".h"
Daniel Bratell65b033262019-04-23 08:17:062438
2439
2440def _IsJavaFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502441 return input_api.os_path.splitext(file_path)[1] == ".java"
Daniel Bratell65b033262019-04-23 08:17:062442
2443
2444def _IsProtoFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502445 return input_api.os_path.splitext(file_path)[1] == ".proto"
Daniel Bratell65b033262019-04-23 08:17:062446
Mohamed Heikal5e5b7922020-10-29 18:57:592447
Erik Staabc734cd7a2021-11-23 03:11:522448def _IsXmlOrGrdFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502449 ext = input_api.os_path.splitext(file_path)[1]
2450 return ext in ('.grd', '.xml')
Erik Staabc734cd7a2021-11-23 03:11:522451
2452
Sven Zheng76a79ea2022-12-21 21:25:242453def _IsMojomFile(input_api, file_path):
2454 return input_api.os_path.splitext(file_path)[1] == ".mojom"
2455
2456
Mohamed Heikal5e5b7922020-10-29 18:57:592457def CheckNoUpstreamDepsOnClank(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502458 """Prevent additions of dependencies from the upstream repo on //clank."""
2459 # clank can depend on clank
2460 if input_api.change.RepositoryRoot().endswith('clank'):
2461 return []
2462 build_file_patterns = [
2463 r'(.+/)?BUILD\.gn',
2464 r'.+\.gni',
2465 ]
2466 excluded_files = [r'build[/\\]config[/\\]android[/\\]config\.gni']
2467 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
Mohamed Heikal5e5b7922020-10-29 18:57:592468
Sam Maiera6e76d72022-02-11 21:43:502469 error_message = 'Disallowed import on //clank in an upstream build file:'
Mohamed Heikal5e5b7922020-10-29 18:57:592470
Sam Maiera6e76d72022-02-11 21:43:502471 def FilterFile(affected_file):
2472 return input_api.FilterSourceFile(affected_file,
2473 files_to_check=build_file_patterns,
2474 files_to_skip=excluded_files)
Mohamed Heikal5e5b7922020-10-29 18:57:592475
Sam Maiera6e76d72022-02-11 21:43:502476 problems = []
2477 for f in input_api.AffectedSourceFiles(FilterFile):
2478 local_path = f.LocalPath()
2479 for line_number, line in f.ChangedContents():
2480 if (bad_pattern.search(line)):
2481 problems.append('%s:%d\n %s' %
2482 (local_path, line_number, line.strip()))
2483 if problems:
2484 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
2485 else:
2486 return []
Mohamed Heikal5e5b7922020-10-29 18:57:592487
2488
Saagar Sanghavifceeaae2020-08-12 16:40:362489def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502490 """Attempts to prevent use of functions intended only for testing in
2491 non-testing code. For now this is just a best-effort implementation
2492 that ignores header files and may have some false positives. A
2493 better implementation would probably need a proper C++ parser.
2494 """
2495 # We only scan .cc files and the like, as the declaration of
2496 # for-testing functions in header files are hard to distinguish from
2497 # calls to such functions without a proper C++ parser.
2498 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:192499
Sam Maiera6e76d72022-02-11 21:43:502500 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
2501 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' %
2502 base_function_pattern)
2503 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
2504 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
2505 exclusion_pattern = input_api.re.compile(
2506 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' %
2507 (base_function_pattern, base_function_pattern))
2508 # Avoid a false positive in this case, where the method name, the ::, and
2509 # the closing { are all on different lines due to line wrapping.
2510 # HelperClassForTesting::
2511 # HelperClassForTesting(
2512 # args)
2513 # : member(0) {}
2514 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:192515
Sam Maiera6e76d72022-02-11 21:43:502516 def FilterFile(affected_file):
2517 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2518 input_api.DEFAULT_FILES_TO_SKIP)
2519 return input_api.FilterSourceFile(
2520 affected_file,
2521 files_to_check=file_inclusion_pattern,
2522 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:192523
Sam Maiera6e76d72022-02-11 21:43:502524 problems = []
2525 for f in input_api.AffectedSourceFiles(FilterFile):
2526 local_path = f.LocalPath()
2527 in_method_defn = False
2528 for line_number, line in f.ChangedContents():
2529 if (inclusion_pattern.search(line)
2530 and not comment_pattern.search(line)
2531 and not exclusion_pattern.search(line)
2532 and not allowlist_pattern.search(line)
2533 and not in_method_defn):
2534 problems.append('%s:%d\n %s' %
2535 (local_path, line_number, line.strip()))
2536 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:192537
Sam Maiera6e76d72022-02-11 21:43:502538 if problems:
2539 return [
2540 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
2541 ]
2542 else:
2543 return []
[email protected]55459852011-08-10 15:17:192544
2545
Saagar Sanghavifceeaae2020-08-12 16:40:362546def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502547 """This is a simplified version of
2548 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
2549 """
2550 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
2551 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
2552 name_pattern = r'ForTest(s|ing)?'
2553 # Describes an occurrence of "ForTest*" inside a // comment.
2554 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
2555 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
2556 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
2557 # Catch calls.
2558 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
2559 # Ignore definitions. (Comments are ignored separately.)
2560 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
Andrew Grieve40f451d2023-07-06 19:46:512561 allowlist_re = input_api.re.compile(r'// IN-TEST$')
Vaclav Brozek7dbc28c2018-03-27 08:35:232562
Sam Maiera6e76d72022-02-11 21:43:502563 problems = []
2564 sources = lambda x: input_api.FilterSourceFile(
2565 x,
Daniel Cheng6303eed2025-05-03 00:12:332566 files_to_skip=(
2567 ('(?i).*test', r'.*\/junit\/') + input_api.DEFAULT_FILES_TO_SKIP),
Sam Maiera6e76d72022-02-11 21:43:502568 files_to_check=[r'.*\.java$'])
2569 for f in input_api.AffectedFiles(include_deletes=False,
2570 file_filter=sources):
2571 local_path = f.LocalPath()
Vaclav Brozek7dbc28c2018-03-27 08:35:232572 is_inside_javadoc = False
Sam Maiera6e76d72022-02-11 21:43:502573 for line_number, line in f.ChangedContents():
2574 if is_inside_javadoc and javadoc_end_re.search(line):
2575 is_inside_javadoc = False
2576 if not is_inside_javadoc and javadoc_start_re.search(line):
2577 is_inside_javadoc = True
2578 if is_inside_javadoc:
2579 continue
2580 if (inclusion_re.search(line) and not comment_re.search(line)
2581 and not annotation_re.search(line)
Andrew Grieve40f451d2023-07-06 19:46:512582 and not allowlist_re.search(line)
Sam Maiera6e76d72022-02-11 21:43:502583 and not exclusion_re.search(line)):
2584 problems.append('%s:%d\n %s' %
2585 (local_path, line_number, line.strip()))
Vaclav Brozek7dbc28c2018-03-27 08:35:232586
Sam Maiera6e76d72022-02-11 21:43:502587 if problems:
2588 return [
2589 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
2590 ]
2591 else:
2592 return []
Vaclav Brozek7dbc28c2018-03-27 08:35:232593
2594
Saagar Sanghavifceeaae2020-08-12 16:40:362595def CheckNoIOStreamInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502596 """Checks to make sure no .h files include <iostream>."""
2597 files = []
2598 pattern = input_api.re.compile(r'^#include\s*<iostream>',
2599 input_api.re.MULTILINE)
2600 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2601 if not f.LocalPath().endswith('.h'):
2602 continue
2603 contents = input_api.ReadFile(f)
2604 if pattern.search(contents):
2605 files.append(f)
[email protected]10689ca2011-09-02 02:31:542606
Sam Maiera6e76d72022-02-11 21:43:502607 if len(files):
2608 return [
2609 output_api.PresubmitError(
2610 'Do not #include <iostream> in header files, since it inserts static '
2611 'initialization into every file including the header. Instead, '
2612 '#include <ostream>. See http://crbug.com/94794', files)
2613 ]
2614 return []
2615
[email protected]10689ca2011-09-02 02:31:542616
Aleksey Khoroshilov9b28c032022-06-03 16:35:322617def CheckNoStrCatRedefines(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502618 """Checks no windows headers with StrCat redefined are included directly."""
2619 files = []
Aleksey Khoroshilov9b28c032022-06-03 16:35:322620 files_to_check = (r'.+%s' % _HEADER_EXTENSIONS,
2621 r'.+%s' % _IMPLEMENTATION_EXTENSIONS)
2622 files_to_skip = (input_api.DEFAULT_FILES_TO_SKIP +
2623 _NON_BASE_DEPENDENT_PATHS)
2624 sources_filter = lambda f: input_api.FilterSourceFile(
2625 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
2626
Sam Maiera6e76d72022-02-11 21:43:502627 pattern_deny = input_api.re.compile(
2628 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
2629 input_api.re.MULTILINE)
2630 pattern_allow = input_api.re.compile(
2631 r'^#include\s"base/win/windows_defines.inc"', input_api.re.MULTILINE)
Aleksey Khoroshilov9b28c032022-06-03 16:35:322632 for f in input_api.AffectedSourceFiles(sources_filter):
Sam Maiera6e76d72022-02-11 21:43:502633 contents = input_api.ReadFile(f)
2634 if pattern_deny.search(
2635 contents) and not pattern_allow.search(contents):
2636 files.append(f.LocalPath())
Danil Chapovalov3518f362018-08-11 16:13:432637
Sam Maiera6e76d72022-02-11 21:43:502638 if len(files):
2639 return [
2640 output_api.PresubmitError(
2641 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
2642 'directly since they pollute code with StrCat macro. Instead, '
2643 'include matching header from base/win. See http://crbug.com/856536',
2644 files)
2645 ]
2646 return []
Danil Chapovalov3518f362018-08-11 16:13:432647
[email protected]10689ca2011-09-02 02:31:542648
Andrew Williamsc9f69b482023-07-10 16:07:362649def _CheckNoUNIT_TESTInSourceFiles(input_api, f):
2650 problems = []
2651
2652 unit_test_macro = input_api.re.compile(
Daniel Cheng6303eed2025-05-03 00:12:332653 r'^\s*#.*(?:ifn?def\s+UNIT_TEST|defined\s*\(?\s*UNIT_TEST\s*\)?)(?:$|\s+)'
2654 )
Andrew Williamsc9f69b482023-07-10 16:07:362655 for line_num, line in f.ChangedContents():
2656 if unit_test_macro.match(line):
2657 problems.append(' %s:%d' % (f.LocalPath(), line_num))
2658
2659 return problems
2660
2661
Saagar Sanghavifceeaae2020-08-12 16:40:362662def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502663 """Checks to make sure no source files use UNIT_TEST."""
2664 problems = []
2665 for f in input_api.AffectedFiles():
2666 if (not f.LocalPath().endswith(('.cc', '.mm'))):
2667 continue
Daniel Cheng6303eed2025-05-03 00:12:332668 problems.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, f))
[email protected]72df4e782012-06-21 16:28:182669
Sam Maiera6e76d72022-02-11 21:43:502670 if not problems:
2671 return []
2672 return [
2673 output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
2674 '\n'.join(problems))
2675 ]
2676
[email protected]72df4e782012-06-21 16:28:182677
Saagar Sanghavifceeaae2020-08-12 16:40:362678def CheckNoDISABLETypoInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502679 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
Dominic Battre033531052018-09-24 15:45:342680
Sam Maiera6e76d72022-02-11 21:43:502681 This test warns if somebody tries to disable a test with the DISABLE_ prefix
2682 instead of DISABLED_. To filter false positives, reports are only generated
2683 if a corresponding MAYBE_ line exists.
2684 """
2685 problems = []
Dominic Battre033531052018-09-24 15:45:342686
Sam Maiera6e76d72022-02-11 21:43:502687 # The following two patterns are looked for in tandem - is a test labeled
2688 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
2689 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
2690 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
Dominic Battre033531052018-09-24 15:45:342691
Sam Maiera6e76d72022-02-11 21:43:502692 # This is for the case that a test is disabled on all platforms.
2693 full_disable_pattern = input_api.re.compile(
2694 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
2695 input_api.re.MULTILINE)
Dominic Battre033531052018-09-24 15:45:342696
Arthur Sonzognic66e9c82024-04-23 07:53:042697 for f in input_api.AffectedFiles(include_deletes=False):
Sam Maiera6e76d72022-02-11 21:43:502698 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2699 continue
Dominic Battre033531052018-09-24 15:45:342700
Arthur Sonzognic66e9c82024-04-23 07:53:042701 # Search for MAYBE_, DISABLE_ pairs.
Sam Maiera6e76d72022-02-11 21:43:502702 disable_lines = {} # Maps of test name to line number.
2703 maybe_lines = {}
2704 for line_num, line in f.ChangedContents():
2705 disable_match = disable_pattern.search(line)
2706 if disable_match:
2707 disable_lines[disable_match.group(1)] = line_num
2708 maybe_match = maybe_pattern.search(line)
2709 if maybe_match:
2710 maybe_lines[maybe_match.group(1)] = line_num
Dominic Battre033531052018-09-24 15:45:342711
Sam Maiera6e76d72022-02-11 21:43:502712 # Search for DISABLE_ occurrences within a TEST() macro.
2713 disable_tests = set(disable_lines.keys())
2714 maybe_tests = set(maybe_lines.keys())
2715 for test in disable_tests.intersection(maybe_tests):
2716 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
Dominic Battre033531052018-09-24 15:45:342717
Sam Maiera6e76d72022-02-11 21:43:502718 contents = input_api.ReadFile(f)
2719 full_disable_match = full_disable_pattern.search(contents)
2720 if full_disable_match:
2721 problems.append(' %s' % f.LocalPath())
Dominic Battre033531052018-09-24 15:45:342722
Sam Maiera6e76d72022-02-11 21:43:502723 if not problems:
2724 return []
2725 return [
2726 output_api.PresubmitPromptWarning(
2727 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
2728 '\n'.join(problems))
2729 ]
2730
Dominic Battre033531052018-09-24 15:45:342731
Nina Satragnof7660532021-09-20 18:03:352732def CheckForgettingMAYBEInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502733 """Checks to make sure tests disabled conditionally are not missing a
2734 corresponding MAYBE_ prefix.
2735 """
2736 # Expect at least a lowercase character in the test name. This helps rule out
2737 # false positives with macros wrapping the actual tests name.
2738 define_maybe_pattern = input_api.re.compile(
2739 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
Bruce Dawsonffc55292022-04-20 04:18:192740 # The test_maybe_pattern needs to handle all of these forms. The standard:
2741 # IN_PROC_TEST_F(SyncTest, MAYBE_Start) {
2742 # With a wrapper macro around the test name:
2743 # IN_PROC_TEST_F(SyncTest, E2E_ENABLED(MAYBE_Start)) {
2744 # And the odd-ball NACL_BROWSER_TEST_f format:
2745 # NACL_BROWSER_TEST_F(NaClBrowserTest, SimpleLoad, {
2746 # The optional E2E_ENABLED-style is handled with (\w*\()?
2747 # The NACL_BROWSER_TEST_F pattern is handled by allowing a trailing comma or
2748 # trailing ')'.
2749 test_maybe_pattern = (
2750 r'^\s*\w*TEST[^(]*\(\s*\w+,\s*(\w*\()?MAYBE_{test_name}[\),]')
Sam Maiera6e76d72022-02-11 21:43:502751 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
2752 warnings = []
Nina Satragnof7660532021-09-20 18:03:352753
Sam Maiera6e76d72022-02-11 21:43:502754 # Read the entire files. We can't just read the affected lines, forgetting to
2755 # add MAYBE_ on a change would not show up otherwise.
Arthur Sonzognic66e9c82024-04-23 07:53:042756 for f in input_api.AffectedFiles(include_deletes=False):
Sam Maiera6e76d72022-02-11 21:43:502757 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2758 continue
2759 contents = input_api.ReadFile(f)
2760 lines = contents.splitlines(True)
2761 current_position = 0
2762 warning_test_names = set()
2763 for line_num, line in enumerate(lines, start=1):
2764 current_position += len(line)
2765 maybe_match = define_maybe_pattern.search(line)
2766 if maybe_match:
2767 test_name = maybe_match.group('test_name')
2768 # Do not warn twice for the same test.
2769 if (test_name in warning_test_names):
2770 continue
2771 warning_test_names.add(test_name)
Nina Satragnof7660532021-09-20 18:03:352772
Sam Maiera6e76d72022-02-11 21:43:502773 # Attempt to find the corresponding MAYBE_ test or suite, starting from
2774 # the current position.
2775 test_match = input_api.re.compile(
2776 test_maybe_pattern.format(test_name=test_name),
2777 input_api.re.MULTILINE).search(contents, current_position)
2778 suite_match = input_api.re.compile(
2779 suite_maybe_pattern.format(test_name=test_name),
2780 input_api.re.MULTILINE).search(contents, current_position)
2781 if not test_match and not suite_match:
2782 warnings.append(
2783 output_api.PresubmitPromptWarning(
2784 '%s:%d found MAYBE_ defined without corresponding test %s'
2785 % (f.LocalPath(), line_num, test_name)))
2786 return warnings
2787
[email protected]72df4e782012-06-21 16:28:182788
Saagar Sanghavifceeaae2020-08-12 16:40:362789def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502790 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
2791 errors = []
Kalvin Lee4a3b79de2022-05-26 16:00:162792 pattern = input_api.re.compile(r'\bDCHECK_IS_ON\b(?!\(\))',
Sam Maiera6e76d72022-02-11 21:43:502793 input_api.re.MULTILINE)
2794 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2795 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
2796 continue
2797 for lnum, line in f.ChangedContents():
2798 if input_api.re.search(pattern, line):
2799 errors.append(
2800 output_api.PresubmitError((
2801 '%s:%d: Use of DCHECK_IS_ON() must be written as "#if '
2802 + 'DCHECK_IS_ON()", not forgetting the parentheses.') %
2803 (f.LocalPath(), lnum)))
2804 return errors
danakj61c1aa22015-10-26 19:55:522805
2806
Weilun Shia487fad2020-10-28 00:10:342807# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
2808# more reliable way. See
2809# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:192810
wnwenbdc444e2016-05-25 13:44:152811
Saagar Sanghavifceeaae2020-08-12 16:40:362812def CheckFlakyTestUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502813 """Check that FlakyTest annotation is our own instead of the android one"""
2814 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
2815 files = []
2816 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2817 if f.LocalPath().endswith('Test.java'):
2818 if pattern.search(input_api.ReadFile(f)):
2819 files.append(f)
2820 if len(files):
2821 return [
2822 output_api.PresubmitError(
2823 'Use org.chromium.base.test.util.FlakyTest instead of '
2824 'android.test.FlakyTest', files)
2825 ]
2826 return []
mcasasb7440c282015-02-04 14:52:192827
wnwenbdc444e2016-05-25 13:44:152828
Saagar Sanghavifceeaae2020-08-12 16:40:362829def CheckNoDEPSGIT(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502830 """Make sure .DEPS.git is never modified manually."""
2831 if any(f.LocalPath().endswith('.DEPS.git')
2832 for f in input_api.AffectedFiles()):
2833 return [
2834 output_api.PresubmitError(
2835 'Never commit changes to .DEPS.git. This file is maintained by an\n'
2836 'automated system based on what\'s in DEPS and your changes will be\n'
2837 'overwritten.\n'
2838 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
2839 'get-the-code#Rolling_DEPS\n'
2840 'for more information')
2841 ]
2842 return []
[email protected]2a8ac9c2011-10-19 17:20:442843
2844
Sven Zheng76a79ea2022-12-21 21:25:242845def CheckCrosApiNeedBrowserTest(input_api, output_api):
2846 """Check new crosapi should add browser test."""
2847 has_new_crosapi = False
2848 has_browser_test = False
2849 for f in input_api.AffectedFiles():
Anton Bershanskyi4253349482025-02-11 21:01:272850 path = f.UnixLocalPath()
Daniel Cheng6303eed2025-05-03 00:12:332851 if (path.startswith('chromeos/crosapi/mojom')
2852 and _IsMojomFile(input_api, path) and f.Action() == 'A'):
Sven Zheng76a79ea2022-12-21 21:25:242853 has_new_crosapi = True
2854 if path.endswith('browsertest.cc') or path.endswith('browser_test.cc'):
2855 has_browser_test = True
2856 if has_new_crosapi and not has_browser_test:
2857 return [
2858 output_api.PresubmitPromptWarning(
2859 'You are adding a new crosapi, but there is no file ends with '
2860 'browsertest.cc file being added or modified. It is important '
2861 'to add crosapi browser test coverage to avoid version '
2862 ' skew issues.\n'
2863 'Check //docs/lacros/test_instructions.md for more information.'
Daniel Cheng6303eed2025-05-03 00:12:332864 )
Sven Zheng76a79ea2022-12-21 21:25:242865 ]
2866 return []
2867
2868
Mario Sanchez Prada2472cab2019-09-18 10:58:312869def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152870 ban_rule):
Allen Bauer84778682022-09-22 16:28:562871 """Helper method for checking for banned constructs.
Mario Sanchez Prada2472cab2019-09-18 10:58:312872
Sam Maiera6e76d72022-02-11 21:43:502873 Returns an string composed of the name of the file, the line number where the
2874 match has been found and the additional text passed as |message| in case the
2875 target type name matches the text inside the line passed as parameter.
2876 """
2877 result = []
Peng Huang9c5949a02020-06-11 19:20:542878
Daniel Chenga44a1bcd2022-03-15 20:00:152879 # Ignore comments about banned types.
2880 if input_api.re.search(r"^ *//", line):
Sam Maiera6e76d72022-02-11 21:43:502881 return result
Daniel Chenga44a1bcd2022-03-15 20:00:152882 # A // nocheck comment will bypass this error.
2883 if line.endswith(" nocheck"):
Sam Maiera6e76d72022-02-11 21:43:502884 return result
2885
2886 matched = False
Daniel Chenga44a1bcd2022-03-15 20:00:152887 if ban_rule.pattern[0:1] == '/':
2888 regex = ban_rule.pattern[1:]
Sam Maiera6e76d72022-02-11 21:43:502889 if input_api.re.search(regex, line):
2890 matched = True
Daniel Chenga44a1bcd2022-03-15 20:00:152891 elif ban_rule.pattern in line:
Sam Maiera6e76d72022-02-11 21:43:502892 matched = True
2893
2894 if matched:
2895 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
Daniel Chenga44a1bcd2022-03-15 20:00:152896 for line in ban_rule.explanation:
2897 result.append(' %s' % line)
Sam Maiera6e76d72022-02-11 21:43:502898
danakjd18e8892020-12-17 17:42:012899 return result
Mario Sanchez Prada2472cab2019-09-18 10:58:312900
2901
Saagar Sanghavifceeaae2020-08-12 16:40:362902def CheckNoBannedFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502903 """Make sure that banned functions are not used."""
Daniel Cheng6303eed2025-05-03 00:12:332904 results = []
[email protected]127f18ec2012-06-16 05:05:592905
Sam Maiera6e76d72022-02-11 21:43:502906 def IsExcludedFile(affected_file, excluded_paths):
Daniel Chenga44a1bcd2022-03-15 20:00:152907 if not excluded_paths:
2908 return False
2909
Anton Bershanskyi4253349482025-02-11 21:01:272910 local_path = affected_file.UnixLocalPath()
Sam Maiera6e76d72022-02-11 21:43:502911 for item in excluded_paths:
2912 if input_api.re.match(item, local_path):
2913 return True
2914 return False
wnwenbdc444e2016-05-25 13:44:152915
Sam Maiera6e76d72022-02-11 21:43:502916 def IsIosObjcFile(affected_file):
2917 local_path = affected_file.LocalPath()
2918 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m',
2919 '.h'):
2920 return False
2921 basename = input_api.os_path.basename(local_path)
2922 if 'ios' in basename.split('_'):
2923 return True
2924 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
2925 if sep and 'ios' in local_path.split(sep):
2926 return True
2927 return False
Sylvain Defresnea8b73d252018-02-28 15:45:542928
Daniel Chenga44a1bcd2022-03-15 20:00:152929 def CheckForMatch(affected_file, line_num: int, line: str,
2930 ban_rule: BanRule):
2931 if IsExcludedFile(affected_file, ban_rule.excluded_paths):
2932 return
2933
Ben Pastenee79d66112025-04-23 19:46:152934 message = _GetMessageForMatchingType(input_api, f, line_num, line,
2935 ban_rule)
2936 if message:
2937 result_loc = []
2938 if ban_rule.surface_as_gerrit_lint:
Daniel Cheng6303eed2025-05-03 00:12:332939 result_loc.append(
2940 output_api.PresubmitResultLocation(
2941 file_path=affected_file.LocalPath(),
2942 start_line=line_num,
2943 end_line=line_num,
2944 ))
Daniel Chenga44a1bcd2022-03-15 20:00:152945 if ban_rule.treat_as_error is not None and ban_rule.treat_as_error:
Ben Pastenee79d66112025-04-23 19:46:152946 results.append(
2947 output_api.PresubmitError('A banned function was used.\n' +
2948 '\n'.join(message),
2949 locations=result_loc))
2950
Sam Maiera6e76d72022-02-11 21:43:502951 else:
Ben Pastenee79d66112025-04-23 19:46:152952 results.append(
Daniel Cheng6303eed2025-05-03 00:12:332953 output_api.PresubmitPromptWarning(
2954 'A banned function was used.\n' + '\n'.join(message),
2955 locations=result_loc))
wnwenbdc444e2016-05-25 13:44:152956
Sam Maiera6e76d72022-02-11 21:43:502957 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2958 for f in input_api.AffectedFiles(file_filter=file_filter):
2959 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152960 for ban_rule in _BANNED_JAVA_FUNCTIONS:
2961 CheckForMatch(f, line_num, line, ban_rule)
Eric Stevensona9a980972017-09-23 00:04:412962
Clement Yan9b330cb2022-11-17 05:25:292963 file_filter = lambda f: f.LocalPath().endswith(('.js', '.ts'))
2964 for f in input_api.AffectedFiles(file_filter=file_filter):
2965 for line_num, line in f.ChangedContents():
2966 for ban_rule in _BANNED_JAVASCRIPT_FUNCTIONS:
2967 CheckForMatch(f, line_num, line, ban_rule)
2968
Sam Maiera6e76d72022-02-11 21:43:502969 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
2970 for f in input_api.AffectedFiles(file_filter=file_filter):
2971 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152972 for ban_rule in _BANNED_OBJC_FUNCTIONS:
2973 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:592974
Sam Maiera6e76d72022-02-11 21:43:502975 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
2976 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152977 for ban_rule in _BANNED_IOS_OBJC_FUNCTIONS:
2978 CheckForMatch(f, line_num, line, ban_rule)
Sylvain Defresnea8b73d252018-02-28 15:45:542979
Sam Maiera6e76d72022-02-11 21:43:502980 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
2981 for f in input_api.AffectedFiles(file_filter=egtest_filter):
2982 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152983 for ban_rule in _BANNED_IOS_EGTEST_FUNCTIONS:
2984 CheckForMatch(f, line_num, line, ban_rule)
Peter K. Lee6c03ccff2019-07-15 14:40:052985
Sam Maiera6e76d72022-02-11 21:43:502986 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
2987 for f in input_api.AffectedFiles(file_filter=file_filter):
2988 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152989 for ban_rule in _BANNED_CPP_FUNCTIONS:
2990 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:592991
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152992 # As of 05/2024, iOS fully migrated ConsentLevel::kSync to kSignin, and
2993 # Android is in the process of preventing new users from entering kSync.
2994 # So the warning is restricted to those platforms.
Riley Wong49be8a882025-02-27 00:38:232995 ios_pattern = input_api.re.compile(r'(^|[\W_])ios[\W_]')
Daniel Cheng6303eed2025-05-03 00:12:332996 file_filter = lambda f: (
2997 f.LocalPath().endswith(('.cc', '.mm', '.h')) and
2998 ('android' in f.LocalPath() or
2999 # Simply checking for an 'ios' substring would
3000 # catch unrelated cases, use a regex.
3001 ios_pattern.search(f.LocalPath())))
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:153002 for f in input_api.AffectedFiles(file_filter=file_filter):
3003 for line_num, line in f.ChangedContents():
3004 for ban_rule in _DEPRECATED_SYNC_CONSENT_CPP_FUNCTIONS:
3005 CheckForMatch(f, line_num, line, ban_rule)
3006
3007 file_filter = lambda f: f.LocalPath().endswith(('.java'))
3008 for f in input_api.AffectedFiles(file_filter=file_filter):
3009 for line_num, line in f.ChangedContents():
3010 for ban_rule in _DEPRECATED_SYNC_CONSENT_JAVA_FUNCTIONS:
3011 CheckForMatch(f, line_num, line, ban_rule)
3012
Daniel Cheng92c15e32022-03-16 17:48:223013 file_filter = lambda f: f.LocalPath().endswith(('.mojom'))
3014 for f in input_api.AffectedFiles(file_filter=file_filter):
3015 for line_num, line in f.ChangedContents():
3016 for ban_rule in _BANNED_MOJOM_PATTERNS:
3017 CheckForMatch(f, line_num, line, ban_rule)
3018
Ben Pastenee79d66112025-04-23 19:46:153019 return results
Daniel Cheng92c15e32022-03-16 17:48:223020
[email protected]127f18ec2012-06-16 05:05:593021
Michael Thiessen44457642020-02-06 00:24:153022def _CheckAndroidNoBannedImports(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503023 """Make sure that banned java imports are not used."""
3024 errors = []
Michael Thiessen44457642020-02-06 00:24:153025
Sam Maiera6e76d72022-02-11 21:43:503026 file_filter = lambda f: f.LocalPath().endswith(('.java'))
3027 for f in input_api.AffectedFiles(file_filter=file_filter):
3028 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:153029 for ban_rule in _BANNED_JAVA_IMPORTS:
3030 # Consider merging this into the above function. There is no
3031 # real difference anymore other than helping with a little
3032 # bit of boilerplate text. Doing so means things like
3033 # `treat_as_error` will also be uniformly handled.
Sam Maiera6e76d72022-02-11 21:43:503034 problems = _GetMessageForMatchingType(input_api, f, line_num,
Daniel Chenga44a1bcd2022-03-15 20:00:153035 line, ban_rule)
Sam Maiera6e76d72022-02-11 21:43:503036 if problems:
3037 errors.extend(problems)
3038 result = []
3039 if (errors):
3040 result.append(
3041 output_api.PresubmitError('Banned imports were used.\n' +
3042 '\n'.join(errors)))
3043 return result
Michael Thiessen44457642020-02-06 00:24:153044
3045
Saagar Sanghavifceeaae2020-08-12 16:40:363046def CheckNoPragmaOnce(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503047 """Make sure that banned functions are not used."""
3048 files = []
3049 pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
3050 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
3051 if not f.LocalPath().endswith('.h'):
3052 continue
Bruce Dawson4c4c2922022-05-02 18:07:333053 if f.LocalPath().endswith('com_imported_mstscax.h'):
3054 continue
Sam Maiera6e76d72022-02-11 21:43:503055 contents = input_api.ReadFile(f)
3056 if pattern.search(contents):
3057 files.append(f)
[email protected]6c063c62012-07-11 19:11:063058
Sam Maiera6e76d72022-02-11 21:43:503059 if files:
3060 return [
3061 output_api.PresubmitError(
3062 'Do not use #pragma once in header files.\n'
3063 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
3064 files)
3065 ]
3066 return []
[email protected]6c063c62012-07-11 19:11:063067
[email protected]127f18ec2012-06-16 05:05:593068
Saagar Sanghavifceeaae2020-08-12 16:40:363069def CheckNoTrinaryTrueFalse(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503070 """Checks to make sure we don't introduce use of foo ? true : false."""
3071 problems = []
3072 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
3073 for f in input_api.AffectedFiles():
3074 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
3075 continue
[email protected]e7479052012-09-19 00:26:123076
Sam Maiera6e76d72022-02-11 21:43:503077 for line_num, line in f.ChangedContents():
3078 if pattern.match(line):
3079 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]e7479052012-09-19 00:26:123080
Sam Maiera6e76d72022-02-11 21:43:503081 if not problems:
3082 return []
3083 return [
3084 output_api.PresubmitPromptWarning(
3085 'Please consider avoiding the "? true : false" pattern if possible.\n'
3086 + '\n'.join(problems))
3087 ]
[email protected]e7479052012-09-19 00:26:123088
3089
Saagar Sanghavifceeaae2020-08-12 16:40:363090def CheckUnwantedDependencies(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503091 """Runs checkdeps on #include and import statements added in this
3092 change. Breaking - rules is an error, breaking ! rules is a
3093 warning.
3094 """
3095 # Return early if no relevant file types were modified.
3096 for f in input_api.AffectedFiles():
3097 path = f.LocalPath()
3098 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path)
3099 or _IsJavaFile(input_api, path)):
3100 break
[email protected]55f9f382012-07-31 11:02:183101 else:
Sam Maiera6e76d72022-02-11 21:43:503102 return []
rhalavati08acd232017-04-03 07:23:283103
Sam Maiera6e76d72022-02-11 21:43:503104 import sys
3105 # We need to wait until we have an input_api object and use this
3106 # roundabout construct to import checkdeps because this file is
3107 # eval-ed and thus doesn't have __file__.
3108 original_sys_path = sys.path
3109 try:
3110 sys.path = sys.path + [
3111 input_api.os_path.join(input_api.PresubmitLocalPath(),
3112 'buildtools', 'checkdeps')
3113 ]
3114 import checkdeps
3115 from rules import Rule
3116 finally:
3117 # Restore sys.path to what it was before.
3118 sys.path = original_sys_path
[email protected]55f9f382012-07-31 11:02:183119
Sam Maiera6e76d72022-02-11 21:43:503120 added_includes = []
3121 added_imports = []
3122 added_java_imports = []
3123 for f in input_api.AffectedFiles():
3124 if _IsCPlusPlusFile(input_api, f.LocalPath()):
3125 changed_lines = [line for _, line in f.ChangedContents()]
3126 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
3127 elif _IsProtoFile(input_api, f.LocalPath()):
3128 changed_lines = [line for _, line in f.ChangedContents()]
3129 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
3130 elif _IsJavaFile(input_api, f.LocalPath()):
3131 changed_lines = [line for _, line in f.ChangedContents()]
3132 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:243133
Sam Maiera6e76d72022-02-11 21:43:503134 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
3135
3136 error_descriptions = []
3137 warning_descriptions = []
3138 error_subjects = set()
3139 warning_subjects = set()
3140
3141 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
3142 added_includes):
3143 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3144 description_with_path = '%s\n %s' % (path, rule_description)
3145 if rule_type == Rule.DISALLOW:
3146 error_descriptions.append(description_with_path)
3147 error_subjects.add("#includes")
3148 else:
3149 warning_descriptions.append(description_with_path)
3150 warning_subjects.add("#includes")
3151
3152 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
3153 added_imports):
3154 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3155 description_with_path = '%s\n %s' % (path, rule_description)
3156 if rule_type == Rule.DISALLOW:
3157 error_descriptions.append(description_with_path)
3158 error_subjects.add("imports")
3159 else:
3160 warning_descriptions.append(description_with_path)
3161 warning_subjects.add("imports")
3162
3163 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
3164 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
3165 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3166 description_with_path = '%s\n %s' % (path, rule_description)
3167 if rule_type == Rule.DISALLOW:
3168 error_descriptions.append(description_with_path)
3169 error_subjects.add("imports")
3170 else:
3171 warning_descriptions.append(description_with_path)
3172 warning_subjects.add("imports")
3173
3174 results = []
3175 if error_descriptions:
3176 results.append(
3177 output_api.PresubmitError(
3178 'You added one or more %s that violate checkdeps rules.' %
3179 " and ".join(error_subjects), error_descriptions))
3180 if warning_descriptions:
3181 results.append(
3182 output_api.PresubmitPromptOrNotify(
3183 'You added one or more %s of files that are temporarily\n'
3184 'allowed but being removed. Can you avoid introducing the\n'
3185 '%s? See relevant DEPS file(s) for details and contacts.' %
3186 (" and ".join(warning_subjects), "/".join(warning_subjects)),
3187 warning_descriptions))
3188 return results
[email protected]55f9f382012-07-31 11:02:183189
3190
Saagar Sanghavifceeaae2020-08-12 16:40:363191def CheckFilePermissions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503192 """Check that all files have their permissions properly set."""
3193 if input_api.platform == 'win32':
3194 return []
3195 checkperms_tool = input_api.os_path.join(input_api.PresubmitLocalPath(),
3196 'tools', 'checkperms',
3197 'checkperms.py')
3198 args = [
Bruce Dawson8a43cf72022-05-13 17:10:323199 input_api.python3_executable, checkperms_tool, '--root',
Sam Maiera6e76d72022-02-11 21:43:503200 input_api.change.RepositoryRoot()
3201 ]
3202 with input_api.CreateTemporaryFile() as file_list:
3203 for f in input_api.AffectedFiles():
3204 # checkperms.py file/directory arguments must be relative to the
3205 # repository.
3206 file_list.write((f.LocalPath() + '\n').encode('utf8'))
3207 file_list.close()
3208 args += ['--file-list', file_list.name]
3209 try:
3210 input_api.subprocess.check_output(args)
3211 return []
3212 except input_api.subprocess.CalledProcessError as error:
3213 return [
3214 output_api.PresubmitError('checkperms.py failed:',
3215 long_text=error.output.decode(
3216 'utf-8', 'ignore'))
3217 ]
[email protected]fbcafe5a2012-08-08 15:31:223218
3219
Saagar Sanghavifceeaae2020-08-12 16:40:363220def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503221 """Makes sure we don't include ui/aura/window_property.h
3222 in header files.
3223 """
3224 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
3225 errors = []
3226 for f in input_api.AffectedFiles():
3227 if not f.LocalPath().endswith('.h'):
3228 continue
3229 for line_num, line in f.ChangedContents():
3230 if pattern.match(line):
3231 errors.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]c8278b32012-10-30 20:35:493232
Sam Maiera6e76d72022-02-11 21:43:503233 results = []
3234 if errors:
3235 results.append(
3236 output_api.PresubmitError(
3237 'Header files should not include ui/aura/window_property.h',
3238 errors))
3239 return results
[email protected]c8278b32012-10-30 20:35:493240
3241
Omer Katzcc77ea92021-04-26 10:23:283242def CheckNoInternalHeapIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503243 """Makes sure we don't include any headers from
3244 third_party/blink/renderer/platform/heap/impl or
3245 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
3246 third_party/blink/renderer/platform/heap
3247 """
3248 impl_pattern = input_api.re.compile(
3249 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
3250 v8_wrapper_pattern = input_api.re.compile(
3251 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"'
3252 )
3253 file_filter = lambda f: not input_api.re.match(
Daniel Cheng6303eed2025-05-03 00:12:333254 r"^third_party/blink/renderer/platform/heap/.*", f.UnixLocalPath())
Sam Maiera6e76d72022-02-11 21:43:503255 errors = []
Omer Katzcc77ea92021-04-26 10:23:283256
Sam Maiera6e76d72022-02-11 21:43:503257 for f in input_api.AffectedFiles(file_filter=file_filter):
3258 for line_num, line in f.ChangedContents():
3259 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
3260 errors.append(' %s:%d' % (f.LocalPath(), line_num))
Omer Katzcc77ea92021-04-26 10:23:283261
Sam Maiera6e76d72022-02-11 21:43:503262 results = []
3263 if errors:
3264 results.append(
3265 output_api.PresubmitError(
3266 'Do not include files from third_party/blink/renderer/platform/heap/impl'
3267 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
3268 'relevant counterparts from third_party/blink/renderer/platform/heap',
3269 errors))
3270 return results
Omer Katzcc77ea92021-04-26 10:23:283271
3272
[email protected]70ca77752012-11-20 03:45:033273def _CheckForVersionControlConflictsInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:503274 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
3275 errors = []
3276 for line_num, line in f.ChangedContents():
3277 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
3278 # First-level headers in markdown look a lot like version control
3279 # conflict markers. http://daringfireball.net/projects/markdown/basics
3280 continue
3281 if pattern.match(line):
3282 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
3283 return errors
[email protected]70ca77752012-11-20 03:45:033284
3285
Saagar Sanghavifceeaae2020-08-12 16:40:363286def CheckForVersionControlConflicts(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503287 """Usually this is not intentional and will cause a compile failure."""
3288 errors = []
3289 for f in input_api.AffectedFiles():
3290 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
[email protected]70ca77752012-11-20 03:45:033291
Sam Maiera6e76d72022-02-11 21:43:503292 results = []
3293 if errors:
3294 results.append(
3295 output_api.PresubmitError(
3296 'Version control conflict markers found, please resolve.',
3297 errors))
3298 return results
[email protected]70ca77752012-11-20 03:45:033299
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203300
Saagar Sanghavifceeaae2020-08-12 16:40:363301def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
Dirk Prankee4df27972025-02-26 18:39:353302 pattern = input_api.re.compile(r'support\.google\.com\/chrome.*/answer')
Sam Maiera6e76d72022-02-11 21:43:503303 errors = []
3304 for f in input_api.AffectedFiles():
3305 for line_num, line in f.ChangedContents():
3306 if pattern.search(line):
3307 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
estadee17314a02017-01-12 16:22:163308
Sam Maiera6e76d72022-02-11 21:43:503309 results = []
3310 if errors:
3311 results.append(
3312 output_api.PresubmitPromptWarning(
3313 'Found Google support URL addressed by answer number. Please replace '
3314 'with a p= identifier instead. See crbug.com/679462\n',
3315 errors))
3316 return results
estadee17314a02017-01-12 16:22:163317
[email protected]70ca77752012-11-20 03:45:033318
Saagar Sanghavifceeaae2020-08-12 16:40:363319def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
Daniel Cheng6303eed2025-05-03 00:12:333320
Sam Maiera6e76d72022-02-11 21:43:503321 def FilterFile(affected_file):
3322 """Filter function for use with input_api.AffectedSourceFiles,
3323 below. This filters out everything except non-test files from
3324 top-level directories that generally speaking should not hard-code
3325 service URLs (e.g. src/android_webview/, src/content/ and others).
3326 """
3327 return input_api.FilterSourceFile(
3328 affected_file,
Bruce Dawson40fece62022-09-16 19:58:313329 files_to_check=[r'^(android_webview|base|content|net)/.*'],
Sam Maiera6e76d72022-02-11 21:43:503330 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3331 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:443332
Dirk Prankee4df27972025-02-26 18:39:353333 base_pattern = (r'"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
3334 r'\.(com|net)[^"]*"')
Sam Maiera6e76d72022-02-11 21:43:503335 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
3336 pattern = input_api.re.compile(base_pattern)
3337 problems = [] # items are (filename, line_number, line)
3338 for f in input_api.AffectedSourceFiles(FilterFile):
3339 for line_num, line in f.ChangedContents():
3340 if not comment_pattern.search(line) and pattern.search(line):
3341 problems.append((f.LocalPath(), line_num, line))
[email protected]06e6d0ff2012-12-11 01:36:443342
Sam Maiera6e76d72022-02-11 21:43:503343 if problems:
3344 return [
3345 output_api.PresubmitPromptOrNotify(
3346 'Most layers below src/chrome/ should not hardcode service URLs.\n'
3347 'Are you sure this is correct?', [
3348 ' %s:%d: %s' % (problem[0], problem[1], problem[2])
3349 for problem in problems
3350 ])
3351 ]
3352 else:
3353 return []
[email protected]06e6d0ff2012-12-11 01:36:443354
3355
Saagar Sanghavifceeaae2020-08-12 16:40:363356def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503357 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
James Cook6b6597c2019-11-06 22:05:293358
Sam Maiera6e76d72022-02-11 21:43:503359 def FileFilter(affected_file):
3360 """Includes directories known to be Chrome OS only."""
3361 return input_api.FilterSourceFile(
3362 affected_file,
3363 files_to_check=(
3364 '^ash/',
3365 '^chromeos/', # Top-level src/chromeos.
3366 '.*/chromeos/', # Any path component.
3367 '^components/arc',
3368 '^components/exo'),
3369 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:293370
Sam Maiera6e76d72022-02-11 21:43:503371 prefs = []
3372 priority_prefs = []
3373 for f in input_api.AffectedFiles(file_filter=FileFilter):
3374 for line_num, line in f.ChangedContents():
3375 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF',
3376 line):
3377 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
3378 prefs.append(' %s' % line)
3379 if input_api.re.search(
3380 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
3381 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
3382 priority_prefs.append(' %s' % line)
3383
3384 results = []
3385 if (prefs):
3386 results.append(
3387 output_api.PresubmitPromptWarning(
3388 'Preferences were registered as SYNCABLE_PREF and will be controlled '
3389 'by browser sync settings. If these prefs should be controlled by OS '
3390 'sync settings use SYNCABLE_OS_PREF instead.\n' +
3391 '\n'.join(prefs)))
3392 if (priority_prefs):
3393 results.append(
3394 output_api.PresubmitPromptWarning(
3395 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
3396 'controlled by browser sync settings. If these prefs should be '
3397 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
3398 'instead.\n' + '\n'.join(prefs)))
3399 return results
James Cook6b6597c2019-11-06 22:05:293400
3401
Saagar Sanghavifceeaae2020-08-12 16:40:363402def CheckNoAbbreviationInPngFileName(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503403 """Makes sure there are no abbreviations in the name of PNG files.
3404 The native_client_sdk directory is excluded because it has auto-generated PNG
3405 files for documentation.
3406 """
3407 errors = []
Yuanqing Zhu9eef02832022-12-04 14:42:173408 files_to_check = [r'.*\.png$']
Daniel Cheng6303eed2025-05-03 00:12:333409 files_to_skip = [
3410 r'^native_client_sdk/',
3411 r'^services/test/',
3412 r'^third_party/blink/web_tests/',
3413 ]
Sam Maiera6e76d72022-02-11 21:43:503414 file_filter = lambda f: input_api.FilterSourceFile(
3415 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Dirk Prankee4df27972025-02-26 18:39:353416 abbreviation = input_api.re.compile(r'.+_[a-z]\.png|.+_[a-z]_.*\.png')
Sam Maiera6e76d72022-02-11 21:43:503417 for f in input_api.AffectedFiles(include_deletes=False,
3418 file_filter=file_filter):
Yuanqing Zhu9eef02832022-12-04 14:42:173419 file_name = input_api.os_path.split(f.LocalPath())[1]
3420 if abbreviation.search(file_name):
3421 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:273422
Sam Maiera6e76d72022-02-11 21:43:503423 results = []
3424 if errors:
3425 results.append(
3426 output_api.PresubmitError(
3427 'The name of PNG files should not have abbreviations. \n'
3428 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
3429 'Contact [email protected] if you have questions.', errors))
3430 return results
[email protected]d2530012013-01-25 16:39:273431
Daniel Cheng6303eed2025-05-03 00:12:333432
Evan Stade7cd4a2c2022-08-04 23:37:253433def CheckNoProductIconsAddedToPublicRepo(input_api, output_api):
3434 """Heuristically identifies product icons based on their file name and reminds
3435 contributors not to add them to the Chromium repository.
3436 """
Peter Kotwiczf634d072025-04-28 22:48:153437
3438 if input_api.change.RepositoryRoot().endswith('clank'):
Daniel Cheng6303eed2025-05-03 00:12:333439 # TODO(crbug.com/414435241): Change check to compute whether change
3440 # belongs to internal repository instead of relying on string matching.
3441 return []
Peter Kotwiczf634d072025-04-28 22:48:153442
Evan Stade7cd4a2c2022-08-04 23:37:253443 errors = []
3444 files_to_check = [r'.*google.*\.png$|.*google.*\.svg$|.*google.*\.icon$']
3445 file_filter = lambda f: input_api.FilterSourceFile(
3446 f, files_to_check=files_to_check)
3447 for f in input_api.AffectedFiles(include_deletes=False,
3448 file_filter=file_filter):
3449 errors.append(' %s' % f.LocalPath())
3450
3451 results = []
3452 if errors:
Bruce Dawson3bcf0c92022-08-12 00:03:083453 # Give warnings instead of errors on presubmit --all and presubmit
3454 # --files.
Daniel Cheng6303eed2025-05-03 00:12:333455 message_type = (output_api.PresubmitNotifyResult
3456 if input_api.no_diffs else output_api.PresubmitError)
Evan Stade7cd4a2c2022-08-04 23:37:253457 results.append(
Bruce Dawson3bcf0c92022-08-12 00:03:083458 message_type(
Evan Stade7cd4a2c2022-08-04 23:37:253459 'Trademarked images should not be added to the public repo. '
3460 'See crbug.com/944754', errors))
3461 return results
3462
[email protected]d2530012013-01-25 16:39:273463
Daniel Cheng4dcdb6b2017-04-13 08:30:173464def _ExtractAddRulesFromParsedDeps(parsed_deps):
Sam Maiera6e76d72022-02-11 21:43:503465 """Extract the rules that add dependencies from a parsed DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:173466
Sam Maiera6e76d72022-02-11 21:43:503467 Args:
3468 parsed_deps: the locals dictionary from evaluating the DEPS file."""
3469 add_rules = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:173470 add_rules.update([
Sam Maiera6e76d72022-02-11 21:43:503471 rule[1:] for rule in parsed_deps.get('include_rules', [])
Daniel Cheng4dcdb6b2017-04-13 08:30:173472 if rule.startswith('+') or rule.startswith('!')
3473 ])
Sam Maiera6e76d72022-02-11 21:43:503474 for _, rules in parsed_deps.get('specific_include_rules', {}).items():
3475 add_rules.update([
3476 rule[1:] for rule in rules
3477 if rule.startswith('+') or rule.startswith('!')
3478 ])
3479 return add_rules
Daniel Cheng4dcdb6b2017-04-13 08:30:173480
3481
3482def _ParseDeps(contents):
Sam Maiera6e76d72022-02-11 21:43:503483 """Simple helper for parsing DEPS files."""
Daniel Cheng4dcdb6b2017-04-13 08:30:173484
Sam Maiera6e76d72022-02-11 21:43:503485 # Stubs for handling special syntax in the root DEPS file.
3486 class _VarImpl:
Daniel Cheng6303eed2025-05-03 00:12:333487
Sam Maiera6e76d72022-02-11 21:43:503488 def __init__(self, local_scope):
3489 self._local_scope = local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:173490
Sam Maiera6e76d72022-02-11 21:43:503491 def Lookup(self, var_name):
3492 """Implements the Var syntax."""
3493 try:
3494 return self._local_scope['vars'][var_name]
3495 except KeyError:
3496 raise Exception('Var is not defined: %s' % var_name)
Daniel Cheng4dcdb6b2017-04-13 08:30:173497
Sam Maiera6e76d72022-02-11 21:43:503498 local_scope = {}
3499 global_scope = {
3500 'Var': _VarImpl(local_scope).Lookup,
3501 'Str': str,
3502 }
Dirk Pranke1b9e06382021-05-14 01:16:223503
Sam Maiera6e76d72022-02-11 21:43:503504 exec(contents, global_scope, local_scope)
3505 return local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:173506
3507
Andrew Grieveb77ac762024-11-29 15:01:483508def _FindAllDepsFilesForSubpath(input_api, subpath):
3509 ret = []
3510 while subpath:
Daniel Cheng6303eed2025-05-03 00:12:333511 cur = input_api.os_path.join(input_api.change.RepositoryRoot(),
3512 subpath, 'DEPS')
Joanna Wang130e7bdd2024-12-10 17:39:033513 if input_api.os_path.isfile(cur):
Andrew Grieveb77ac762024-11-29 15:01:483514 ret.append(cur)
3515 subpath = input_api.os_path.dirname(subpath)
3516 return ret
3517
3518
3519def _FindAddedDepsThatRequireReview(input_api, depended_on_paths):
3520 """Filters to those whose DEPS set new_usages_require_review=True"""
3521 ret = set()
3522 cache = {}
3523 for target_path in depended_on_paths:
3524 for subpath in _FindAllDepsFilesForSubpath(input_api, target_path):
3525 config = cache.get(subpath)
3526 if config is None:
3527 config = _ParseDeps(input_api.ReadFile(subpath))
3528 cache[subpath] = config
3529 if config.get('new_usages_require_review'):
3530 ret.add(target_path)
3531 break
3532 return ret
3533
3534
Daniel Cheng4dcdb6b2017-04-13 08:30:173535def _CalculateAddedDeps(os_path, old_contents, new_contents):
Sam Maiera6e76d72022-02-11 21:43:503536 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
3537 a set of DEPS entries that we should look up.
[email protected]14a6131c2014-01-08 01:15:413538
Sam Maiera6e76d72022-02-11 21:43:503539 For a directory (rather than a specific filename) we fake a path to
3540 a specific filename by adding /DEPS. This is chosen as a file that
3541 will seldom or never be subject to per-file include_rules.
3542 """
3543 # We ignore deps entries on auto-generated directories.
3544 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:083545
Sam Maiera6e76d72022-02-11 21:43:503546 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
3547 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
Daniel Cheng4dcdb6b2017-04-13 08:30:173548
Sam Maiera6e76d72022-02-11 21:43:503549 added_deps = new_deps.difference(old_deps)
Daniel Cheng4dcdb6b2017-04-13 08:30:173550
Sam Maiera6e76d72022-02-11 21:43:503551 results = set()
3552 for added_dep in added_deps:
3553 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
3554 continue
3555 # Assume that a rule that ends in .h is a rule for a specific file.
3556 if added_dep.endswith('.h'):
3557 results.add(added_dep)
3558 else:
3559 results.add(os_path.join(added_dep, 'DEPS'))
3560 return results
[email protected]f32e2d1e2013-07-26 21:39:083561
Daniel Cheng6303eed2025-05-03 00:12:333562
Stephanie Kimec4f55a2024-04-24 16:54:023563def CheckForNewDEPSDownloadFromGoogleStorageHooks(input_api, output_api):
3564 """Checks that there are no new download_from_google_storage hooks"""
3565 for f in input_api.AffectedFiles(include_deletes=False):
3566 if f.LocalPath() == 'DEPS':
3567 old_hooks = _ParseDeps('\n'.join(f.OldContents()))['hooks']
3568 new_hooks = _ParseDeps('\n'.join(f.NewContents()))['hooks']
3569 old_name_to_hook = {hook['name']: hook for hook in old_hooks}
3570 new_name_to_hook = {hook['name']: hook for hook in new_hooks}
3571 added_hook_names = set(new_name_to_hook.keys()) - set(
3572 old_name_to_hook.keys())
3573 if not added_hook_names:
3574 return []
3575 new_download_from_google_storage_hooks = []
3576 for new_hook in added_hook_names:
3577 hook = new_name_to_hook[new_hook]
3578 action_cmd = hook['action']
3579 if any('download_from_google_storage' in arg
Daniel Cheng6303eed2025-05-03 00:12:333580 for arg in action_cmd):
Stephanie Kimec4f55a2024-04-24 16:54:023581 new_download_from_google_storage_hooks.append(new_hook)
3582 if new_download_from_google_storage_hooks:
3583 return [
3584 output_api.PresubmitError(
3585 'Please do not add new download_from_google_storage '
3586 'hooks. Instead, add a `gcs` dep_type entry to `deps`. '
3587 'See https://chromium.googlesource.com/chromium/src.git'
3588 '/+/refs/heads/main/docs/gcs_dependencies.md for more '
3589 'info. Added hooks:',
3590 items=new_download_from_google_storage_hooks)
3591 ]
3592 return []
3593
[email protected]f32e2d1e2013-07-26 21:39:083594
Rasika Navarangec2d33d22024-05-23 15:19:023595def CheckEachPerfettoTestDataFileHasDepsEntry(input_api, output_api):
3596 test_data_filter = lambda f: input_api.FilterSourceFile(
Rasika Navarange08e542162024-05-31 13:31:263597 f, files_to_check=[r'^base/tracing/test/data_sha256/.*\.sha256'])
Rasika Navarangec2d33d22024-05-23 15:19:023598 if not any(input_api.AffectedFiles(file_filter=test_data_filter)):
3599 return []
3600
3601 # Find DEPS entry
3602 deps_entry = []
Rasika Navarange277cd662024-06-04 10:14:593603 old_deps_entry = []
Rasika Navarangec2d33d22024-05-23 15:19:023604 for f in input_api.AffectedFiles(include_deletes=False):
3605 if f.LocalPath() == 'DEPS':
3606 new_deps = _ParseDeps('\n'.join(f.NewContents()))['deps']
3607 deps_entry = new_deps['src/base/tracing/test/data']
Rasika Navarange277cd662024-06-04 10:14:593608 old_deps = _ParseDeps('\n'.join(f.OldContents()))['deps']
3609 old_deps_entry = old_deps['src/base/tracing/test/data']
Rasika Navarangec2d33d22024-05-23 15:19:023610 if not deps_entry:
Rasika Navarange08e542162024-05-31 13:31:263611 # TODO(312895063):Add back error when .sha256 files have been moved.
Daniel Cheng6303eed2025-05-03 00:12:333612 return [
3613 output_api.PresubmitError(
3614 'You must update the DEPS file when you update a '
3615 '.sha256 file in base/tracing/test/data_sha256')
3616 ]
Rasika Navarangec2d33d22024-05-23 15:19:023617
3618 output = []
3619 for f in input_api.AffectedFiles(file_filter=test_data_filter):
3620 objects = deps_entry['objects']
3621 if not f.NewContents():
3622 # Deleted file so check that DEPS entry removed
3623 sha256_from_file = f.OldContents()[0]
3624 object_entry = next(
Daniel Cheng6303eed2025-05-03 00:12:333625 (item
3626 for item in objects if item["sha256sum"] == sha256_from_file),
Rasika Navarangec2d33d22024-05-23 15:19:023627 None)
Daniel Cheng6303eed2025-05-03 00:12:333628 old_entry = next((item for item in old_deps_entry['objects']
3629 if item["sha256sum"] == sha256_from_file), None)
Rasika Navarangec2d33d22024-05-23 15:19:023630 if object_entry:
Rasika Navarange277cd662024-06-04 10:14:593631 # Allow renaming of objects with the same hash
3632 if object_entry['object_name'] != old_entry['object_name']:
3633 continue
Daniel Cheng6303eed2025-05-03 00:12:333634 output.append(
3635 output_api.PresubmitError(
3636 'You deleted %s so you must also remove the corresponding DEPS entry.'
3637 % f.LocalPath()))
Rasika Navarangec2d33d22024-05-23 15:19:023638 continue
3639
3640 sha256_from_file = f.NewContents()[0]
3641 object_entry = next(
Daniel Cheng6303eed2025-05-03 00:12:333642 (item
3643 for item in objects if item["sha256sum"] == sha256_from_file),
Rasika Navarangec2d33d22024-05-23 15:19:023644 None)
3645 if not object_entry:
Daniel Cheng6303eed2025-05-03 00:12:333646 output.append(
3647 output_api.PresubmitError(
3648 'No corresponding DEPS entry found for %s. '
3649 'Run `base/tracing/test/test_data.py get_deps --filepath %s` '
3650 'to generate the DEPS entry.' %
3651 (f.LocalPath(), f.LocalPath())))
Rasika Navarangec2d33d22024-05-23 15:19:023652
3653 if output:
Daniel Cheng6303eed2025-05-03 00:12:333654 output.append(
3655 output_api.PresubmitError(
3656 'The DEPS entry for `src/base/tracing/test/data` in the DEPS file has not been '
3657 'updated properly. Run `base/tracing/test/test_data.py get_all_deps` to see what '
3658 'the DEPS entry should look like.'))
Rasika Navarangec2d33d22024-05-23 15:19:023659 return output
3660
3661
Saagar Sanghavifceeaae2020-08-12 16:40:363662def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503663 """When a dependency prefixed with + is added to a DEPS file, we
3664 want to make sure that the change is reviewed by an OWNER of the
3665 target file or directory, to avoid layering violations from being
3666 introduced. This check verifies that this happens.
3667 """
3668 # We rely on Gerrit's code-owners to check approvals.
3669 # input_api.gerrit is always set for Chromium, but other projects
3670 # might not use Gerrit.
Bruce Dawson344ab262022-06-04 11:35:103671 if not input_api.gerrit or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:503672 return []
Bruce Dawsonb357aeb2022-08-09 15:38:303673 if 'PRESUBMIT_SKIP_NETWORK' in input_api.environ:
Sam Maiera6e76d72022-02-11 21:43:503674 return []
Bruce Dawsonb357aeb2022-08-09 15:38:303675 try:
Daniel Cheng6303eed2025-05-03 00:12:333676 if (input_api.change.issue
3677 and input_api.gerrit.IsOwnersOverrideApproved(
3678 input_api.change.issue)):
Bruce Dawsonb357aeb2022-08-09 15:38:303679 # Skip OWNERS check when Owners-Override label is approved. This is
3680 # intended for global owners, trusted bots, and on-call sheriffs.
3681 # Review is still required for these changes.
3682 return []
3683 except Exception as e:
Daniel Cheng6303eed2025-05-03 00:12:333684 return [
3685 output_api.PresubmitPromptWarning(
3686 'Failed to retrieve owner override status - %s' % str(e))
3687 ]
Edward Lesmes6fba51082021-01-20 04:20:233688
Andrew Grieveb77ac762024-11-29 15:01:483689 # A set of paths (that might not exist) that are being added as DEPS
3690 # (via lines like "+foo/bar/baz").
3691 depended_on_paths = set()
jochen53efcdd2016-01-29 05:09:243692
Daniel Cheng6303eed2025-05-03 00:12:333693 file_filter = lambda f: not input_api.re.match(r"^third_party/blink/.*",
3694 f.UnixLocalPath())
Sam Maiera6e76d72022-02-11 21:43:503695 for f in input_api.AffectedFiles(include_deletes=False,
3696 file_filter=file_filter):
3697 filename = input_api.os_path.basename(f.LocalPath())
3698 if filename == 'DEPS':
Andrew Grieveb77ac762024-11-29 15:01:483699 depended_on_paths.update(
Sam Maiera6e76d72022-02-11 21:43:503700 _CalculateAddedDeps(input_api.os_path,
3701 '\n'.join(f.OldContents()),
3702 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:553703
Andrew Grieveb77ac762024-11-29 15:01:483704 # Requiring reviews is opt-in as of https://crbug.com/365797506
Daniel Cheng6303eed2025-05-03 00:12:333705 depended_on_paths = _FindAddedDepsThatRequireReview(
3706 input_api, depended_on_paths)
Andrew Grieveb77ac762024-11-29 15:01:483707 if not depended_on_paths:
Sam Maiera6e76d72022-02-11 21:43:503708 return []
[email protected]e871964c2013-05-13 14:14:553709
Sam Maiera6e76d72022-02-11 21:43:503710 if input_api.is_committing:
3711 if input_api.tbr:
3712 return [
3713 output_api.PresubmitNotifyResult(
3714 '--tbr was specified, skipping OWNERS check for DEPS additions'
3715 )
3716 ]
Daniel Cheng3008dc12022-05-13 04:02:113717 # TODO(dcheng): Make this generate an error on dry runs if the reviewer
3718 # is not added, to prevent review serialization.
Sam Maiera6e76d72022-02-11 21:43:503719 if input_api.dry_run:
3720 return [
3721 output_api.PresubmitNotifyResult(
3722 'This is a dry run, skipping OWNERS check for DEPS additions'
3723 )
3724 ]
3725 if not input_api.change.issue:
3726 return [
3727 output_api.PresubmitError(
3728 "DEPS approval by OWNERS check failed: this change has "
3729 "no change number, so we can't check it for approvals.")
3730 ]
3731 output = output_api.PresubmitError
[email protected]14a6131c2014-01-08 01:15:413732 else:
Sam Maiera6e76d72022-02-11 21:43:503733 output = output_api.PresubmitNotifyResult
[email protected]e871964c2013-05-13 14:14:553734
Sam Maiera6e76d72022-02-11 21:43:503735 owner_email, reviewers = (
3736 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3737 input_api, None, approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:553738
Sam Maiera6e76d72022-02-11 21:43:503739 owner_email = owner_email or input_api.change.author_email
3740
3741 approval_status = input_api.owners_client.GetFilesApprovalStatus(
Andrew Grieveb77ac762024-11-29 15:01:483742 depended_on_paths, reviewers.union([owner_email]), [])
Sam Maiera6e76d72022-02-11 21:43:503743 missing_files = [
Andrew Grieveb77ac762024-11-29 15:01:483744 p for p in depended_on_paths
3745 if approval_status[p] != input_api.owners_client.APPROVED
Sam Maiera6e76d72022-02-11 21:43:503746 ]
3747
3748 # We strip the /DEPS part that was added by
3749 # _FilesToCheckForIncomingDeps to fake a path to a file in a
3750 # directory.
3751 def StripDeps(path):
3752 start_deps = path.rfind('/DEPS')
3753 if start_deps != -1:
3754 return path[:start_deps]
3755 else:
3756 return path
3757
Scott Leebf6a0942024-06-26 22:59:393758 submodule_paths = set(input_api.ListSubmodules())
Daniel Cheng6303eed2025-05-03 00:12:333759
Scott Leebf6a0942024-06-26 22:59:393760 def is_from_submodules(path, submodule_paths):
3761 path = input_api.os_path.normpath(path)
3762 while path:
3763 if path in submodule_paths:
3764 return True
3765
3766 # All deps should be a relative path from the checkout.
3767 # i.e., shouldn't start with "/" or "c:\", for example.
3768 #
3769 # That said, this is to prevent an infinite loop, just in case
3770 # an input dep path starts with "/", because
3771 # os.path.dirname("/") => "/"
3772 parent = input_api.os_path.dirname(path)
3773 if parent == path:
3774 break
3775 path = parent
3776
3777 return False
3778
Sam Maiera6e76d72022-02-11 21:43:503779 unapproved_dependencies = [
3780 "'+%s'," % StripDeps(path) for path in missing_files
Scott Leebf6a0942024-06-26 22:59:393781 # if a newly added dep is from a submodule, it becomes trickier
3782 # to get suggested owners, especially it is from a different host.
3783 #
3784 # skip the review enforcement for cross-repo deps.
3785 if not is_from_submodules(path, submodule_paths)
Sam Maiera6e76d72022-02-11 21:43:503786 ]
3787
3788 if unapproved_dependencies:
3789 output_list = [
3790 output(
3791 'You need LGTM from owners of depends-on paths in DEPS that were '
3792 'modified in this CL:\n %s' %
3793 '\n '.join(sorted(unapproved_dependencies)))
3794 ]
3795 suggested_owners = input_api.owners_client.SuggestOwners(
3796 missing_files, exclude=[owner_email])
3797 output_list.append(
3798 output('Suggested missing target path OWNERS:\n %s' %
3799 '\n '.join(suggested_owners or [])))
3800 return output_list
3801
3802 return []
[email protected]e871964c2013-05-13 14:14:553803
3804
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493805# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:363806def CheckSpamLogging(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503807 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3808 files_to_skip = (
3809 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3810 input_api.DEFAULT_FILES_TO_SKIP + (
Jaewon Jung2f323bb2022-12-07 23:55:013811 r"^base/fuchsia/scoped_fx_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313812 r"^base/logging\.h$",
3813 r"^base/logging\.cc$",
3814 r"^base/task/thread_pool/task_tracker\.cc$",
3815 r"^chrome/app/chrome_main_delegate\.cc$",
Yao Li359937b2023-02-15 23:43:033816 r"^chrome/browser/ash/arc/enterprise/cert_store/arc_cert_installer\.cc$",
3817 r"^chrome/browser/ash/policy/remote_commands/user_command_arc_job\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313818 r"^chrome/browser/chrome_browser_main\.cc$",
3819 r"^chrome/browser/ui/startup/startup_browser_creator\.cc$",
3820 r"^chrome/browser/browser_switcher/bho/.*",
3821 r"^chrome/browser/diagnostics/diagnostics_writer\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313822 r"^chrome/chrome_elf/dll_hash/dll_hash_main\.cc$",
3823 r"^chrome/installer/setup/.*",
Daniel Ruberyad36eea2024-08-01 01:38:323824 # crdmg runs as a separate binary which intentionally does
3825 # not depend on base logging.
3826 r"^chrome/utility/safe_browsing/mac/crdmg\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313827 r"^chromecast/",
Vigen Issahhanjane2d93822023-06-30 15:57:203828 r"^components/cast",
Bruce Dawson40fece62022-09-16 19:58:313829 r"^components/media_control/renderer/media_playback_options\.cc$",
Salma Elmahallawy52976452023-01-27 17:04:493830 r"^components/policy/core/common/policy_logger\.cc$",
Tomek Jurkiewicz06fd6a72025-06-18 15:24:283831 r"^components/supervised_user/core/browser/android/content_filters_observer_bridge\.cc",
Bruce Dawson40fece62022-09-16 19:58:313832 r"^components/viz/service/display/"
Sam Maiera6e76d72022-02-11 21:43:503833 r"overlay_strategy_underlay_cast\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313834 r"^components/zucchini/.*",
Sam Maiera6e76d72022-02-11 21:43:503835 # TODO(peter): Remove exception. https://crbug.com/534537
Bruce Dawson40fece62022-09-16 19:58:313836 r"^content/browser/notifications/"
Sam Maiera6e76d72022-02-11 21:43:503837 r"notification_event_dispatcher_impl\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313838 r"^content/common/gpu/client/gl_helper_benchmark\.cc$",
3839 r"^courgette/courgette_minimal_tool\.cc$",
3840 r"^courgette/courgette_tool\.cc$",
3841 r"^extensions/renderer/logging_native_handler\.cc$",
3842 r"^fuchsia_web/common/init_logging\.cc$",
3843 r"^fuchsia_web/runners/common/web_component\.cc$",
Caroline Liua7050132023-02-13 22:23:153844 r"^fuchsia_web/shell/.*\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313845 r"^headless/app/headless_shell\.cc$",
3846 r"^ipc/ipc_logging\.cc$",
3847 r"^native_client_sdk/",
3848 r"^remoting/base/logging\.h$",
3849 r"^remoting/host/.*",
3850 r"^sandbox/linux/.*",
Austin Sullivana6054e02024-05-20 16:31:293851 r"^services/webnn/tflite/graph_impl_tflite\.cc$",
3852 r"^services/webnn/coreml/graph_impl_coreml\.mm$",
Bruce Dawson40fece62022-09-16 19:58:313853 r"^storage/browser/file_system/dump_file_system\.cc$",
Steinar H. Gundersone5689e42024-08-07 18:17:193854 r"^testing/perf/",
Bruce Dawson40fece62022-09-16 19:58:313855 r"^tools/",
3856 r"^ui/base/resource/data_pack\.cc$",
3857 r"^ui/aura/bench/bench_main\.cc$",
3858 r"^ui/ozone/platform/cast/",
3859 r"^ui/base/x/xwmstartupcheck/"
Sam Maiera6e76d72022-02-11 21:43:503860 r"xwmstartupcheck\.cc$"))
3861 source_file_filter = lambda x: input_api.FilterSourceFile(
3862 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:403863
Sam Maiera6e76d72022-02-11 21:43:503864 log_info = set([])
3865 printf = set([])
[email protected]85218562013-11-22 07:41:403866
Sam Maiera6e76d72022-02-11 21:43:503867 for f in input_api.AffectedSourceFiles(source_file_filter):
3868 for _, line in f.ChangedContents():
3869 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
3870 log_info.add(f.LocalPath())
3871 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
3872 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:373873
Sam Maiera6e76d72022-02-11 21:43:503874 if input_api.re.search(r"\bprintf\(", line):
3875 printf.add(f.LocalPath())
3876 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
3877 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:403878
Sam Maiera6e76d72022-02-11 21:43:503879 if log_info:
3880 return [
3881 output_api.PresubmitError(
3882 'These files spam the console log with LOG(INFO):',
3883 items=log_info)
3884 ]
3885 if printf:
3886 return [
3887 output_api.PresubmitError(
3888 'These files spam the console log with printf/fprintf:',
3889 items=printf)
3890 ]
3891 return []
[email protected]85218562013-11-22 07:41:403892
3893
Saagar Sanghavifceeaae2020-08-12 16:40:363894def CheckForAnonymousVariables(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503895 """These types are all expected to hold locks while in scope and
3896 so should never be anonymous (which causes them to be immediately
3897 destroyed)."""
3898 they_who_must_be_named = [
3899 'base::AutoLock',
3900 'base::AutoReset',
3901 'base::AutoUnlock',
3902 'SkAutoAlphaRestore',
3903 'SkAutoBitmapShaderInstall',
3904 'SkAutoBlitterChoose',
3905 'SkAutoBounderCommit',
3906 'SkAutoCallProc',
3907 'SkAutoCanvasRestore',
3908 'SkAutoCommentBlock',
3909 'SkAutoDescriptor',
3910 'SkAutoDisableDirectionCheck',
3911 'SkAutoDisableOvalCheck',
3912 'SkAutoFree',
3913 'SkAutoGlyphCache',
3914 'SkAutoHDC',
3915 'SkAutoLockColors',
3916 'SkAutoLockPixels',
3917 'SkAutoMalloc',
3918 'SkAutoMaskFreeImage',
3919 'SkAutoMutexAcquire',
3920 'SkAutoPathBoundsUpdate',
3921 'SkAutoPDFRelease',
3922 'SkAutoRasterClipValidate',
3923 'SkAutoRef',
3924 'SkAutoTime',
3925 'SkAutoTrace',
3926 'SkAutoUnref',
3927 ]
3928 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
3929 # bad: base::AutoLock(lock.get());
3930 # not bad: base::AutoLock lock(lock.get());
3931 bad_pattern = input_api.re.compile(anonymous)
3932 # good: new base::AutoLock(lock.get())
3933 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
3934 errors = []
[email protected]49aa76a2013-12-04 06:59:163935
Sam Maiera6e76d72022-02-11 21:43:503936 for f in input_api.AffectedFiles():
3937 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
3938 continue
3939 for linenum, line in f.ChangedContents():
3940 if bad_pattern.search(line) and not good_pattern.search(line):
3941 errors.append('%s:%d' % (f.LocalPath(), linenum))
[email protected]49aa76a2013-12-04 06:59:163942
Sam Maiera6e76d72022-02-11 21:43:503943 if errors:
3944 return [
3945 output_api.PresubmitError(
3946 'These lines create anonymous variables that need to be named:',
3947 items=errors)
3948 ]
3949 return []
[email protected]49aa76a2013-12-04 06:59:163950
3951
Saagar Sanghavifceeaae2020-08-12 16:40:363952def CheckUniquePtrOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503953 # Returns whether |template_str| is of the form <T, U...> for some types T
Glen Robertson9142ffd72024-05-16 01:37:473954 # and U, or is invalid due to mismatched angle bracket pairs. Assumes that
3955 # |template_str| is already in the form <...>.
3956 def HasMoreThanOneArgOrInvalid(template_str):
Sam Maiera6e76d72022-02-11 21:43:503957 # Level of <...> nesting.
3958 nesting = 0
3959 for c in template_str:
3960 if c == '<':
3961 nesting += 1
3962 elif c == '>':
3963 nesting -= 1
3964 elif c == ',' and nesting == 1:
3965 return True
Glen Robertson9142ffd72024-05-16 01:37:473966 if nesting != 0:
Daniel Cheng566634ff2024-06-29 14:56:533967 # Invalid.
3968 return True
Sam Maiera6e76d72022-02-11 21:43:503969 return False
Vaclav Brozekb7fadb692018-08-30 06:39:533970
Sam Maiera6e76d72022-02-11 21:43:503971 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3972 sources = lambda affected_file: input_api.FilterSourceFile(
3973 affected_file,
3974 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3975 DEFAULT_FILES_TO_SKIP),
3976 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:553977
Sam Maiera6e76d72022-02-11 21:43:503978 # Pattern to capture a single "<...>" block of template arguments. It can
3979 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
3980 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
3981 # latter would likely require counting that < and > match, which is not
3982 # expressible in regular languages. Should the need arise, one can introduce
3983 # limited counting (matching up to a total number of nesting depth), which
3984 # should cover all practical cases for already a low nesting limit.
3985 template_arg_pattern = (
3986 r'<[^>]*' # Opening block of <.
3987 r'>([^<]*>)?') # Closing block of >.
3988 # Prefix expressing that whatever follows is not already inside a <...>
3989 # block.
3990 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
3991 null_construct_pattern = input_api.re.compile(
3992 not_inside_template_arg_pattern + r'\bstd::unique_ptr' +
3993 template_arg_pattern + r'\(\)')
Vaclav Brozeka54c528b2018-04-06 19:23:553994
Sam Maiera6e76d72022-02-11 21:43:503995 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
3996 template_arg_no_array_pattern = (
3997 r'<[^>]*[^]]' # Opening block of <.
3998 r'>([^(<]*[^]]>)?') # Closing block of >.
3999 # Prefix saying that what follows is the start of an expression.
4000 start_of_expr_pattern = r'(=|\breturn|^)\s*'
4001 # Suffix saying that what follows are call parentheses with a non-empty list
4002 # of arguments.
4003 nonempty_arg_list_pattern = r'\(([^)]|$)'
4004 # Put the template argument into a capture group for deeper examination later.
4005 return_construct_pattern = input_api.re.compile(
4006 start_of_expr_pattern + r'std::unique_ptr' + '(?P<template_arg>' +
4007 template_arg_no_array_pattern + ')' + nonempty_arg_list_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:554008
Sam Maiera6e76d72022-02-11 21:43:504009 problems_constructor = []
4010 problems_nullptr = []
4011 for f in input_api.AffectedSourceFiles(sources):
4012 for line_number, line in f.ChangedContents():
4013 # Disallow:
4014 # return std::unique_ptr<T>(foo);
4015 # bar = std::unique_ptr<T>(foo);
4016 # But allow:
4017 # return std::unique_ptr<T[]>(foo);
4018 # bar = std::unique_ptr<T[]>(foo);
4019 # And also allow cases when the second template argument is present. Those
4020 # cases cannot be handled by std::make_unique:
4021 # return std::unique_ptr<T, U>(foo);
4022 # bar = std::unique_ptr<T, U>(foo);
4023 local_path = f.LocalPath()
4024 return_construct_result = return_construct_pattern.search(line)
Glen Robertson9142ffd72024-05-16 01:37:474025 if return_construct_result and not HasMoreThanOneArgOrInvalid(
Sam Maiera6e76d72022-02-11 21:43:504026 return_construct_result.group('template_arg')):
4027 problems_constructor.append(
4028 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4029 # Disallow:
4030 # std::unique_ptr<T>()
4031 if null_construct_pattern.search(line):
4032 problems_nullptr.append(
4033 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Vaclav Brozek851d9602018-04-04 16:13:054034
Sam Maiera6e76d72022-02-11 21:43:504035 errors = []
4036 if problems_nullptr:
4037 errors.append(
4038 output_api.PresubmitPromptWarning(
4039 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
4040 problems_nullptr))
4041 if problems_constructor:
4042 errors.append(
4043 output_api.PresubmitError(
4044 'The following files use explicit std::unique_ptr constructor. '
4045 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
4046 'std::make_unique is not an option.', problems_constructor))
4047 return errors
Peter Kasting4844e46e2018-02-23 07:27:104048
4049
Saagar Sanghavifceeaae2020-08-12 16:40:364050def CheckUserActionUpdate(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504051 """Checks if any new user action has been added."""
4052 if any('actions.xml' == input_api.os_path.basename(f)
4053 for f in input_api.LocalPaths()):
4054 # If actions.xml is already included in the changelist, the PRESUBMIT
4055 # for actions.xml will do a more complete presubmit check.
4056 return []
4057
4058 file_inclusion_pattern = [r'.*\.(cc|mm)$']
4059 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
4060 input_api.DEFAULT_FILES_TO_SKIP)
4061 file_filter = lambda f: input_api.FilterSourceFile(
4062 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
4063
4064 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
4065 current_actions = None
4066 for f in input_api.AffectedFiles(file_filter=file_filter):
4067 for line_num, line in f.ChangedContents():
4068 match = input_api.re.search(action_re, line)
4069 if match:
4070 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
4071 # loaded only once.
4072 if not current_actions:
Bruce Dawson6cb2d4d2023-03-01 21:35:094073 with open('tools/metrics/actions/actions.xml',
4074 encoding='utf-8') as actions_f:
Sam Maiera6e76d72022-02-11 21:43:504075 current_actions = actions_f.read()
4076 # Search for the matched user action name in |current_actions|.
4077 for action_name in match.groups():
4078 action = 'name="{0}"'.format(action_name)
4079 if action not in current_actions:
4080 return [
4081 output_api.PresubmitPromptWarning(
4082 'File %s line %d: %s is missing in '
4083 'tools/metrics/actions/actions.xml. Please run '
4084 'tools/metrics/actions/extract_actions.py to update.'
4085 % (f.LocalPath(), line_num, action_name))
4086 ]
[email protected]999261d2014-03-03 20:08:084087 return []
4088
[email protected]999261d2014-03-03 20:08:084089
Daniel Cheng13ca61a882017-08-25 15:11:254090def _ImportJSONCommentEater(input_api):
Sam Maiera6e76d72022-02-11 21:43:504091 import sys
4092 sys.path = sys.path + [
4093 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4094 'json_comment_eater')
4095 ]
4096 import json_comment_eater
4097 return json_comment_eater
Daniel Cheng13ca61a882017-08-25 15:11:254098
4099
[email protected]99171a92014-06-03 08:44:474100def _GetJSONParseError(input_api, filename, eat_comments=True):
dchenge07de812016-06-20 19:27:174101 try:
Sam Maiera6e76d72022-02-11 21:43:504102 contents = input_api.ReadFile(filename)
4103 if eat_comments:
4104 json_comment_eater = _ImportJSONCommentEater(input_api)
4105 contents = json_comment_eater.Nom(contents)
dchenge07de812016-06-20 19:27:174106
Sam Maiera6e76d72022-02-11 21:43:504107 input_api.json.loads(contents)
4108 except ValueError as e:
4109 return e
Andrew Grieve4deedb12022-02-03 21:34:504110 return None
4111
4112
Sam Maiera6e76d72022-02-11 21:43:504113def _GetIDLParseError(input_api, filename):
4114 try:
4115 contents = input_api.ReadFile(filename)
Devlin Croninf7582a12022-04-21 21:14:284116 for i, char in enumerate(contents):
Daniel Chenga37c03db2022-05-12 17:20:344117 if not char.isascii():
4118 return (
4119 'Non-ascii character "%s" (ord %d) found at offset %d.' %
4120 (char, ord(char), i))
Sam Maiera6e76d72022-02-11 21:43:504121 idl_schema = input_api.os_path.join(input_api.PresubmitLocalPath(),
4122 'tools', 'json_schema_compiler',
4123 'idl_schema.py')
4124 process = input_api.subprocess.Popen(
Bruce Dawson679fb082022-04-14 00:47:284125 [input_api.python3_executable, idl_schema],
Sam Maiera6e76d72022-02-11 21:43:504126 stdin=input_api.subprocess.PIPE,
4127 stdout=input_api.subprocess.PIPE,
4128 stderr=input_api.subprocess.PIPE,
4129 universal_newlines=True)
4130 (_, error) = process.communicate(input=contents)
4131 return error or None
4132 except ValueError as e:
4133 return e
agrievef32bcc72016-04-04 14:57:404134
agrievef32bcc72016-04-04 14:57:404135
Sam Maiera6e76d72022-02-11 21:43:504136def CheckParseErrors(input_api, output_api):
4137 """Check that IDL and JSON files do not contain syntax errors."""
4138 actions = {
4139 '.idl': _GetIDLParseError,
4140 '.json': _GetJSONParseError,
4141 }
4142 # Most JSON files are preprocessed and support comments, but these do not.
4143 json_no_comments_patterns = [
Bruce Dawson40fece62022-09-16 19:58:314144 r'^testing/',
Sam Maiera6e76d72022-02-11 21:43:504145 ]
4146 # Only run IDL checker on files in these directories.
4147 idl_included_patterns = [
Bruce Dawson40fece62022-09-16 19:58:314148 r'^chrome/common/extensions/api/',
4149 r'^extensions/common/api/',
Sam Maiera6e76d72022-02-11 21:43:504150 ]
agrievef32bcc72016-04-04 14:57:404151
Sam Maiera6e76d72022-02-11 21:43:504152 def get_action(affected_file):
4153 filename = affected_file.LocalPath()
4154 return actions.get(input_api.os_path.splitext(filename)[1])
agrievef32bcc72016-04-04 14:57:404155
Sam Maiera6e76d72022-02-11 21:43:504156 def FilterFile(affected_file):
4157 action = get_action(affected_file)
4158 if not action:
4159 return False
Anton Bershanskyi4253349482025-02-11 21:01:274160 path = affected_file.UnixLocalPath()
agrievef32bcc72016-04-04 14:57:404161
Sam Maiera6e76d72022-02-11 21:43:504162 if _MatchesFile(input_api,
4163 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS, path):
4164 return False
4165
4166 if (action == _GetIDLParseError
4167 and not _MatchesFile(input_api, idl_included_patterns, path)):
4168 return False
4169 return True
4170
4171 results = []
4172 for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
4173 include_deletes=False):
4174 action = get_action(affected_file)
4175 kwargs = {}
4176 if (action == _GetJSONParseError
4177 and _MatchesFile(input_api, json_no_comments_patterns,
Anton Bershanskyi4253349482025-02-11 21:01:274178 affected_file.UnixLocalPath())):
Sam Maiera6e76d72022-02-11 21:43:504179 kwargs['eat_comments'] = False
4180 parse_error = action(input_api, affected_file.AbsoluteLocalPath(),
4181 **kwargs)
4182 if parse_error:
4183 results.append(
4184 output_api.PresubmitError(
4185 '%s could not be parsed: %s' %
4186 (affected_file.LocalPath(), parse_error)))
4187 return results
4188
4189
4190def CheckJavaStyle(input_api, output_api):
4191 """Runs checkstyle on changed java files and returns errors if any exist."""
4192
4193 # Return early if no java files were modified.
4194 if not any(
4195 _IsJavaFile(input_api, f.LocalPath())
4196 for f in input_api.AffectedFiles()):
4197 return []
4198
4199 import sys
4200 original_sys_path = sys.path
4201 try:
4202 sys.path = sys.path + [
4203 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4204 'android', 'checkstyle')
4205 ]
4206 import checkstyle
4207 finally:
4208 # Restore sys.path to what it was before.
4209 sys.path = original_sys_path
4210
Daniel Cheng6303eed2025-05-03 00:12:334211 return checkstyle.run_presubmit(input_api,
4212 output_api,
4213 files_to_skip=_EXCLUDED_PATHS +
4214 input_api.DEFAULT_FILES_TO_SKIP)
Sam Maiera6e76d72022-02-11 21:43:504215
4216
4217def CheckPythonDevilInit(input_api, output_api):
4218 """Checks to make sure devil is initialized correctly in python scripts."""
4219 script_common_initialize_pattern = input_api.re.compile(
4220 r'script_common\.InitializeEnvironment\(')
4221 devil_env_config_initialize = input_api.re.compile(
4222 r'devil_env\.config\.Initialize\(')
4223
4224 errors = []
4225
4226 sources = lambda affected_file: input_api.FilterSourceFile(
4227 affected_file,
4228 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314229 r'^build/android/devil_chromium\.py',
Sven Zheng8e079562024-05-10 20:11:064230 r'^tools/bisect-builds\.py',
Bruce Dawson40fece62022-09-16 19:58:314231 r'^third_party/.*',
Sam Maiera6e76d72022-02-11 21:43:504232 )),
4233 files_to_check=[r'.*\.py$'])
4234
4235 for f in input_api.AffectedSourceFiles(sources):
4236 for line_num, line in f.ChangedContents():
4237 if (script_common_initialize_pattern.search(line)
4238 or devil_env_config_initialize.search(line)):
4239 errors.append("%s:%d" % (f.LocalPath(), line_num))
4240
4241 results = []
4242
4243 if errors:
4244 results.append(
4245 output_api.PresubmitError(
4246 'Devil initialization should always be done using '
4247 'devil_chromium.Initialize() in the chromium project, to use better '
4248 'defaults for dependencies (ex. up-to-date version of adb).',
4249 errors))
4250
4251 return results
4252
4253
4254def _MatchesFile(input_api, patterns, path):
4255 for pattern in patterns:
4256 if input_api.re.search(pattern, path):
4257 return True
4258 return False
4259
4260
Daniel Chenga37c03db2022-05-12 17:20:344261def _ChangeHasSecurityReviewer(input_api, owners_file):
4262 """Returns True iff the CL has a reviewer from SECURITY_OWNERS.
Sam Maiera6e76d72022-02-11 21:43:504263
Daniel Chenga37c03db2022-05-12 17:20:344264 Args:
4265 input_api: The presubmit input API.
4266 owners_file: OWNERS file with required reviewers. Typically, this is
4267 something like ipc/SECURITY_OWNERS.
4268
4269 Note: if the presubmit is running for commit rather than for upload, this
4270 only returns True if a security reviewer has also approved the CL.
Sam Maiera6e76d72022-02-11 21:43:504271 """
Daniel Chengd88244472022-05-16 09:08:474272 # Owners-Override should bypass all additional OWNERS enforcement checks.
4273 # A CR+1 vote will still be required to land this change.
4274 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
4275 input_api.change.issue)):
4276 return True
4277
Daniel Chenga37c03db2022-05-12 17:20:344278 owner_email, reviewers = (
4279 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
Daniel Cheng3008dc12022-05-13 04:02:114280 input_api,
4281 None,
4282 approval_needed=input_api.is_committing and not input_api.dry_run))
Sam Maiera6e76d72022-02-11 21:43:504283
Daniel Chenga37c03db2022-05-12 17:20:344284 security_owners = input_api.owners_client.ListOwners(owners_file)
4285 return any(owner in reviewers for owner in security_owners)
Sam Maiera6e76d72022-02-11 21:43:504286
Daniel Chenga37c03db2022-05-12 17:20:344287
4288@dataclass
Daniel Cheng171dad8d2022-05-21 00:40:254289class _SecurityProblemWithItems:
4290 problem: str
4291 items: Sequence[str]
4292
4293
4294@dataclass
Daniel Chenga37c03db2022-05-12 17:20:344295class _MissingSecurityOwnersResult:
Daniel Cheng171dad8d2022-05-21 00:40:254296 owners_file_problems: Sequence[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:344297 has_security_sensitive_files: bool
Daniel Cheng171dad8d2022-05-21 00:40:254298 missing_reviewer_problem: Optional[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:344299
4300
Daniel Cheng6303eed2025-05-03 00:12:334301def _FindMissingSecurityOwners(
4302 input_api,
4303 output_api,
4304 file_patterns: Sequence[str],
4305 excluded_patterns: Sequence[str],
4306 required_owners_file: str,
4307 custom_rule_function: Optional[Callable] = None
4308) -> _MissingSecurityOwnersResult:
Daniel Chenga37c03db2022-05-12 17:20:344309 """Find OWNERS files missing per-file rules for security-sensitive files.
4310
4311 Args:
4312 input_api: the PRESUBMIT input API object.
4313 output_api: the PRESUBMIT output API object.
4314 file_patterns: basename patterns that require a corresponding per-file
4315 security restriction.
4316 excluded_patterns: path patterns that should be exempted from
4317 requiring a security restriction.
4318 required_owners_file: path to the required OWNERS file, e.g.
4319 ipc/SECURITY_OWNERS
4320 cc_alias: If not None, email that will be CCed automatically if the
4321 change contains security-sensitive files, as determined by
4322 `file_patterns` and `excluded_patterns`.
4323 custom_rule_function: If not None, will be called with `input_api` and
4324 the current file under consideration. Returning True will add an
4325 exact match per-file rule check for the current file.
4326 """
4327
4328 # `to_check` is a mapping of an OWNERS file path to Patterns.
4329 #
4330 # Patterns is a dictionary mapping glob patterns (suitable for use in
4331 # per-file rules) to a PatternEntry.
4332 #
Sam Maiera6e76d72022-02-11 21:43:504333 # PatternEntry is a dictionary with two keys:
4334 # - 'files': the files that are matched by this pattern
4335 # - 'rules': the per-file rules needed for this pattern
Daniel Chenga37c03db2022-05-12 17:20:344336 #
Sam Maiera6e76d72022-02-11 21:43:504337 # For example, if we expect OWNERS file to contain rules for *.mojom and
4338 # *_struct_traits*.*, Patterns might look like this:
4339 # {
4340 # '*.mojom': {
4341 # 'files': ...,
4342 # 'rules': [
4343 # 'per-file *.mojom=set noparent',
4344 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
4345 # ],
4346 # },
4347 # '*_struct_traits*.*': {
4348 # 'files': ...,
4349 # 'rules': [
4350 # 'per-file *_struct_traits*.*=set noparent',
4351 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
4352 # ],
4353 # },
4354 # }
4355 to_check = {}
Daniel Chenga37c03db2022-05-12 17:20:344356 files_to_review = []
Sam Maiera6e76d72022-02-11 21:43:504357
Daniel Chenga37c03db2022-05-12 17:20:344358 def AddPatternToCheck(file, pattern):
Sam Maiera6e76d72022-02-11 21:43:504359 owners_file = input_api.os_path.join(
Daniel Chengd88244472022-05-16 09:08:474360 input_api.os_path.dirname(file.LocalPath()), 'OWNERS')
Sam Maiera6e76d72022-02-11 21:43:504361 if owners_file not in to_check:
4362 to_check[owners_file] = {}
4363 if pattern not in to_check[owners_file]:
4364 to_check[owners_file][pattern] = {
4365 'files': [],
4366 'rules': [
Daniel Chenga37c03db2022-05-12 17:20:344367 f'per-file {pattern}=set noparent',
4368 f'per-file {pattern}=file://{required_owners_file}',
Sam Maiera6e76d72022-02-11 21:43:504369 ]
4370 }
Daniel Chenged57a162022-05-25 02:56:344371 to_check[owners_file][pattern]['files'].append(file.LocalPath())
Daniel Chenga37c03db2022-05-12 17:20:344372 files_to_review.append(file.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:504373
Daniel Chenga37c03db2022-05-12 17:20:344374 # Only enforce security OWNERS rules for a directory if that directory has a
4375 # file that matches `file_patterns`. For example, if a directory only
4376 # contains *.mojom files and no *_messages*.h files, the check should only
4377 # ensure that rules for *.mojom files are present.
4378 for file in input_api.AffectedFiles(include_deletes=False):
4379 file_basename = input_api.os_path.basename(file.LocalPath())
4380 if custom_rule_function is not None and custom_rule_function(
4381 input_api, file):
4382 AddPatternToCheck(file, file_basename)
4383 continue
Sam Maiera6e76d72022-02-11 21:43:504384
Daniel Chenga37c03db2022-05-12 17:20:344385 if any(
4386 input_api.fnmatch.fnmatch(file.LocalPath(), pattern)
4387 for pattern in excluded_patterns):
Sam Maiera6e76d72022-02-11 21:43:504388 continue
4389
4390 for pattern in file_patterns:
Daniel Chenga37c03db2022-05-12 17:20:344391 # Unlike `excluded_patterns`, `file_patterns` is checked only against the
4392 # file's basename.
4393 if input_api.fnmatch.fnmatch(file_basename, pattern):
4394 AddPatternToCheck(file, pattern)
Sam Maiera6e76d72022-02-11 21:43:504395 break
4396
Daniel Chenga37c03db2022-05-12 17:20:344397 has_security_sensitive_files = bool(to_check)
Daniel Cheng171dad8d2022-05-21 00:40:254398
4399 # Check if any newly added lines in OWNERS files intersect with required
4400 # per-file OWNERS lines. If so, ensure that a security reviewer is included.
4401 # This is a hack, but is needed because the OWNERS check (by design) ignores
4402 # new OWNERS entries; otherwise, a non-owner could add someone as a new
4403 # OWNER and have that newly-added OWNER self-approve their own addition.
4404 newly_covered_files = []
4405 for file in input_api.AffectedFiles(include_deletes=False):
4406 if not file.LocalPath() in to_check:
4407 continue
4408 for _, line in file.ChangedContents():
4409 for _, entry in to_check[file.LocalPath()].items():
4410 if line in entry['rules']:
4411 newly_covered_files.extend(entry['files'])
4412
4413 missing_reviewer_problems = None
4414 if newly_covered_files and not _ChangeHasSecurityReviewer(
Daniel Chenga37c03db2022-05-12 17:20:344415 input_api, required_owners_file):
Daniel Cheng171dad8d2022-05-21 00:40:254416 missing_reviewer_problems = _SecurityProblemWithItems(
4417 f'Review from an owner in {required_owners_file} is required for '
4418 'the following newly-added files:',
4419 [f'{file}' for file in sorted(set(newly_covered_files))])
Sam Maiera6e76d72022-02-11 21:43:504420
4421 # Go through the OWNERS files to check, filtering out rules that are already
4422 # present in that OWNERS file.
4423 for owners_file, patterns in to_check.items():
4424 try:
Daniel Cheng171dad8d2022-05-21 00:40:254425 lines = set(
4426 input_api.ReadFile(
4427 input_api.os_path.join(input_api.change.RepositoryRoot(),
4428 owners_file)).splitlines())
4429 for entry in patterns.values():
4430 entry['rules'] = [
4431 rule for rule in entry['rules'] if rule not in lines
4432 ]
Sam Maiera6e76d72022-02-11 21:43:504433 except IOError:
4434 # No OWNERS file, so all the rules are definitely missing.
4435 continue
4436
4437 # All the remaining lines weren't found in OWNERS files, so emit an error.
Daniel Cheng171dad8d2022-05-21 00:40:254438 owners_file_problems = []
Daniel Chenga37c03db2022-05-12 17:20:344439
Sam Maiera6e76d72022-02-11 21:43:504440 for owners_file, patterns in to_check.items():
4441 missing_lines = []
4442 files = []
4443 for _, entry in patterns.items():
Daniel Chenged57a162022-05-25 02:56:344444 files.extend(entry['files'])
Sam Maiera6e76d72022-02-11 21:43:504445 missing_lines.extend(entry['rules'])
Sam Maiera6e76d72022-02-11 21:43:504446 if missing_lines:
Daniel Cheng171dad8d2022-05-21 00:40:254447 joined_missing_lines = '\n'.join(line for line in missing_lines)
4448 owners_file_problems.append(
4449 _SecurityProblemWithItems(
4450 'Found missing OWNERS lines for security-sensitive files. '
4451 f'Please add the following lines to {owners_file}:\n'
4452 f'{joined_missing_lines}\n\nTo ensure security review for:',
4453 files))
Daniel Chenga37c03db2022-05-12 17:20:344454
Daniel Cheng171dad8d2022-05-21 00:40:254455 return _MissingSecurityOwnersResult(owners_file_problems,
Daniel Chenga37c03db2022-05-12 17:20:344456 has_security_sensitive_files,
Daniel Cheng171dad8d2022-05-21 00:40:254457 missing_reviewer_problems)
Daniel Chenga37c03db2022-05-12 17:20:344458
4459
4460def _CheckChangeForIpcSecurityOwners(input_api, output_api):
4461 # Whether or not a file affects IPC is (mostly) determined by a simple list
4462 # of filename patterns.
4463 file_patterns = [
4464 # Legacy IPC:
4465 '*_messages.cc',
4466 '*_messages*.h',
4467 '*_param_traits*.*',
4468 # Mojo IPC:
4469 '*.mojom',
4470 '*_mojom_traits*.*',
4471 '*_type_converter*.*',
4472 # Android native IPC:
4473 '*.aidl',
4474 ]
4475
Daniel Chenga37c03db2022-05-12 17:20:344476 excluded_patterns = [
Daniel Cheng518943f2022-05-12 22:15:464477 # These third_party directories do not contain IPCs, but contain files
4478 # matching the above patterns, which trigger false positives.
Daniel Chenga37c03db2022-05-12 17:20:344479 'third_party/crashpad/*',
4480 'third_party/blink/renderer/platform/bindings/*',
Evan Stade23a77da2025-02-06 21:15:314481 'third_party/protobuf/*',
Daniel Chenga37c03db2022-05-12 17:20:344482 'third_party/win_build_output/*',
Daniel Chengd88244472022-05-16 09:08:474483 # Enum-only mojoms used for web metrics, so no security review needed.
4484 'third_party/blink/public/mojom/use_counter/metrics/*',
Daniel Chenga37c03db2022-05-12 17:20:344485 # These files are just used to communicate between class loaders running
4486 # in the same process.
4487 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
4488 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
4489 ]
4490
4491 def IsMojoServiceManifestFile(input_api, file):
Dirk Prankee4df27972025-02-26 18:39:354492 manifest_pattern = input_api.re.compile(r'manifests?\.(cc|h)$')
Daniel Cheng6303eed2025-05-03 00:12:334493 test_manifest_pattern = input_api.re.compile(
4494 r'test_manifests?\.(cc|h)')
Daniel Chenga37c03db2022-05-12 17:20:344495 if not manifest_pattern.search(file.LocalPath()):
4496 return False
4497
4498 if test_manifest_pattern.search(file.LocalPath()):
4499 return False
4500
4501 # All actual service manifest files should contain at least one
4502 # qualified reference to service_manager::Manifest.
4503 return any('service_manager::Manifest' in line
4504 for line in file.NewContents())
4505
4506 return _FindMissingSecurityOwners(
4507 input_api,
4508 output_api,
4509 file_patterns,
4510 excluded_patterns,
4511 'ipc/SECURITY_OWNERS',
4512 custom_rule_function=IsMojoServiceManifestFile)
4513
4514
4515def _CheckChangeForFuchsiaSecurityOwners(input_api, output_api):
4516 file_patterns = [
4517 # Component specifications.
4518 '*.cml', # Component Framework v2.
4519 '*.cmx', # Component Framework v1.
4520
4521 # Fuchsia IDL protocol specifications.
4522 '*.fidl',
4523 ]
4524
4525 # Don't check for owners files for changes in these directories.
4526 excluded_patterns = [
4527 'third_party/crashpad/*',
4528 ]
4529
4530 return _FindMissingSecurityOwners(input_api, output_api, file_patterns,
4531 excluded_patterns,
4532 'build/fuchsia/SECURITY_OWNERS')
4533
4534
4535def CheckSecurityOwners(input_api, output_api):
4536 """Checks that various security-sensitive files have an IPC OWNERS rule."""
4537 ipc_results = _CheckChangeForIpcSecurityOwners(input_api, output_api)
4538 fuchsia_results = _CheckChangeForFuchsiaSecurityOwners(
4539 input_api, output_api)
4540
4541 if ipc_results.has_security_sensitive_files:
4542 output_api.AppendCC('[email protected]')
Sam Maiera6e76d72022-02-11 21:43:504543
4544 results = []
Daniel Chenga37c03db2022-05-12 17:20:344545
Daniel Cheng171dad8d2022-05-21 00:40:254546 missing_reviewer_problems = []
4547 if ipc_results.missing_reviewer_problem:
4548 missing_reviewer_problems.append(ipc_results.missing_reviewer_problem)
4549 if fuchsia_results.missing_reviewer_problem:
4550 missing_reviewer_problems.append(
4551 fuchsia_results.missing_reviewer_problem)
Daniel Chenga37c03db2022-05-12 17:20:344552
Daniel Cheng171dad8d2022-05-21 00:40:254553 # Missing reviewers are an error unless there's no issue number
4554 # associated with this branch; in that case, the presubmit is being run
4555 # with --all or --files.
4556 #
4557 # Note that upload should never be an error; otherwise, it would be
4558 # impossible to upload changes at all.
4559 if input_api.is_committing and input_api.change.issue:
4560 make_presubmit_message = output_api.PresubmitError
4561 else:
4562 make_presubmit_message = output_api.PresubmitNotifyResult
4563 for problem in missing_reviewer_problems:
Sam Maiera6e76d72022-02-11 21:43:504564 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:254565 make_presubmit_message(problem.problem, items=problem.items))
Daniel Chenga37c03db2022-05-12 17:20:344566
Daniel Cheng171dad8d2022-05-21 00:40:254567 owners_file_problems = []
4568 owners_file_problems.extend(ipc_results.owners_file_problems)
4569 owners_file_problems.extend(fuchsia_results.owners_file_problems)
Daniel Chenga37c03db2022-05-12 17:20:344570
Daniel Cheng171dad8d2022-05-21 00:40:254571 for problem in owners_file_problems:
Daniel Cheng3008dc12022-05-13 04:02:114572 # Missing per-file rules are always an error. While swarming and caching
4573 # means that uploading a patchset with updated OWNERS files and sending
4574 # it to the CQ again should not have a large incremental cost, it is
4575 # still frustrating to discover the error only after the change has
4576 # already been uploaded.
Daniel Chenga37c03db2022-05-12 17:20:344577 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:254578 output_api.PresubmitError(problem.problem, items=problem.items))
Sam Maiera6e76d72022-02-11 21:43:504579
4580 return results
4581
4582
4583def _GetFilesUsingSecurityCriticalFunctions(input_api):
4584 """Checks affected files for changes to security-critical calls. This
4585 function checks the full change diff, to catch both additions/changes
4586 and removals.
4587
4588 Returns a dict keyed by file name, and the value is a set of detected
4589 functions.
4590 """
4591 # Map of function pretty name (displayed in an error) to the pattern to
4592 # match it with.
4593 _PATTERNS_TO_CHECK = {
4594 'content::GetServiceSandboxType<>()': 'GetServiceSandboxType\\<'
4595 }
4596 _PATTERNS_TO_CHECK = {
4597 k: input_api.re.compile(v)
4598 for k, v in _PATTERNS_TO_CHECK.items()
4599 }
4600
Sam Maiera6e76d72022-02-11 21:43:504601 # We don't want to trigger on strings within this file.
4602 def presubmit_file_filter(f):
Daniel Chenga37c03db2022-05-12 17:20:344603 return 'PRESUBMIT.py' != input_api.os_path.split(f.LocalPath())[1]
Sam Maiera6e76d72022-02-11 21:43:504604
4605 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
4606 files_to_functions = {}
4607 for f in input_api.AffectedFiles(file_filter=presubmit_file_filter):
4608 diff = f.GenerateScmDiff()
4609 for line in diff.split('\n'):
4610 # Not using just RightHandSideLines() because removing a
4611 # call to a security-critical function can be just as important
4612 # as adding or changing the arguments.
4613 if line.startswith('-') or (line.startswith('+')
4614 and not line.startswith('++')):
4615 for name, pattern in _PATTERNS_TO_CHECK.items():
4616 if pattern.search(line):
4617 path = f.LocalPath()
4618 if not path in files_to_functions:
4619 files_to_functions[path] = set()
4620 files_to_functions[path].add(name)
4621 return files_to_functions
4622
4623
4624def CheckSecurityChanges(input_api, output_api):
4625 """Checks that changes involving security-critical functions are reviewed
4626 by the security team.
4627 """
4628 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
4629 if not len(files_to_functions):
4630 return []
4631
Sam Maiera6e76d72022-02-11 21:43:504632 owners_file = 'ipc/SECURITY_OWNERS'
Daniel Chenga37c03db2022-05-12 17:20:344633 if _ChangeHasSecurityReviewer(input_api, owners_file):
Sam Maiera6e76d72022-02-11 21:43:504634 return []
4635
Daniel Chenga37c03db2022-05-12 17:20:344636 msg = 'The following files change calls to security-sensitive functions\n' \
Sam Maiera6e76d72022-02-11 21:43:504637 'that need to be reviewed by {}.\n'.format(owners_file)
4638 for path, names in files_to_functions.items():
4639 msg += ' {}\n'.format(path)
4640 for name in names:
4641 msg += ' {}\n'.format(name)
4642 msg += '\n'
4643
4644 if input_api.is_committing:
4645 output = output_api.PresubmitError
Mohamed Heikale217fc852020-07-06 19:44:034646 else:
Sam Maiera6e76d72022-02-11 21:43:504647 output = output_api.PresubmitNotifyResult
4648 return [output(msg)]
4649
4650
4651def CheckSetNoParent(input_api, output_api):
4652 """Checks that set noparent is only used together with an OWNERS file in
4653 //build/OWNERS.setnoparent (see also
4654 //docs/code_reviews.md#owners-files-details)
4655 """
4656 # Return early if no OWNERS files were modified.
4657 if not any(f.LocalPath().endswith('OWNERS')
4658 for f in input_api.AffectedFiles(include_deletes=False)):
4659 return []
4660
4661 errors = []
4662
4663 allowed_owners_files_file = 'build/OWNERS.setnoparent'
4664 allowed_owners_files = set()
Bruce Dawson58a45d22023-02-27 11:24:164665 with open(allowed_owners_files_file, 'r', encoding='utf-8') as f:
Sam Maiera6e76d72022-02-11 21:43:504666 for line in f:
4667 line = line.strip()
4668 if not line or line.startswith('#'):
4669 continue
4670 allowed_owners_files.add(line)
4671
4672 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
4673
4674 for f in input_api.AffectedFiles(include_deletes=False):
4675 if not f.LocalPath().endswith('OWNERS'):
4676 continue
4677
4678 found_owners_files = set()
4679 found_set_noparent_lines = dict()
4680
4681 # Parse the OWNERS file.
4682 for lineno, line in enumerate(f.NewContents(), 1):
4683 line = line.strip()
4684 if line.startswith('set noparent'):
4685 found_set_noparent_lines[''] = lineno
4686 if line.startswith('file://'):
4687 if line in allowed_owners_files:
4688 found_owners_files.add('')
4689 if line.startswith('per-file'):
4690 match = per_file_pattern.match(line)
4691 if match:
4692 glob = match.group(1).strip()
4693 directive = match.group(2).strip()
4694 if directive == 'set noparent':
4695 found_set_noparent_lines[glob] = lineno
4696 if directive.startswith('file://'):
4697 if directive in allowed_owners_files:
4698 found_owners_files.add(glob)
4699
4700 # Check that every set noparent line has a corresponding file:// line
4701 # listed in build/OWNERS.setnoparent. An exception is made for top level
4702 # directories since src/OWNERS shouldn't review them.
Anton Bershanskyi4253349482025-02-11 21:01:274703 linux_path = f.UnixLocalPath()
Bruce Dawson6bb0d672022-04-06 15:13:494704 if (linux_path.count('/') != 1
4705 and (not linux_path in _EXCLUDED_SET_NO_PARENT_PATHS)):
Sam Maiera6e76d72022-02-11 21:43:504706 for set_noparent_line in found_set_noparent_lines:
4707 if set_noparent_line in found_owners_files:
4708 continue
Daniel Cheng6303eed2025-05-03 00:12:334709 errors.append(
4710 ' %s:%d' %
4711 (linux_path, found_set_noparent_lines[set_noparent_line]))
Sam Maiera6e76d72022-02-11 21:43:504712
4713 results = []
4714 if errors:
4715 if input_api.is_committing:
4716 output = output_api.PresubmitError
4717 else:
4718 output = output_api.PresubmitPromptWarning
4719 results.append(
4720 output(
4721 'Found the following "set noparent" restrictions in OWNERS files that '
4722 'do not include owners from build/OWNERS.setnoparent:',
4723 long_text='\n\n'.join(errors)))
4724 return results
4725
4726
4727def CheckUselessForwardDeclarations(input_api, output_api):
4728 """Checks that added or removed lines in non third party affected
4729 header files do not lead to new useless class or struct forward
4730 declaration.
4731 """
4732 results = []
4733 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
4734 input_api.re.MULTILINE)
4735 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
4736 input_api.re.MULTILINE)
4737 for f in input_api.AffectedFiles(include_deletes=False):
Anton Bershanskyi4253349482025-02-11 21:01:274738 local_path = f.UnixLocalPath()
4739 if (local_path.startswith('third_party')
4740 and not local_path.startswith('third_party/blink')):
Sam Maiera6e76d72022-02-11 21:43:504741 continue
4742
Anton Bershanskyi4253349482025-02-11 21:01:274743 if not local_path.endswith('.h'):
Sam Maiera6e76d72022-02-11 21:43:504744 continue
4745
4746 contents = input_api.ReadFile(f)
4747 fwd_decls = input_api.re.findall(class_pattern, contents)
4748 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
4749
4750 useless_fwd_decls = []
4751 for decl in fwd_decls:
4752 count = sum(1 for _ in input_api.re.finditer(
4753 r'\b%s\b' % input_api.re.escape(decl), contents))
4754 if count == 1:
4755 useless_fwd_decls.append(decl)
4756
4757 if not useless_fwd_decls:
4758 continue
4759
4760 for line in f.GenerateScmDiff().splitlines():
4761 if (line.startswith('-') and not line.startswith('--')
4762 or line.startswith('+') and not line.startswith('++')):
4763 for decl in useless_fwd_decls:
4764 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
4765 results.append(
4766 output_api.PresubmitPromptWarning(
4767 '%s: %s forward declaration is no longer needed'
4768 % (f.LocalPath(), decl)))
4769 useless_fwd_decls.remove(decl)
4770
4771 return results
4772
4773
4774def _CheckAndroidDebuggableBuild(input_api, output_api):
4775 """Checks that code uses BuildInfo.isDebugAndroid() instead of
4776 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
4777 this is a debuggable build of Android.
4778 """
4779 build_type_check_pattern = input_api.re.compile(
4780 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
4781
4782 errors = []
4783
4784 sources = lambda affected_file: input_api.FilterSourceFile(
4785 affected_file,
4786 files_to_skip=(
4787 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4788 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314789 r"^android_webview/support_library/boundary_interfaces/",
4790 r"^chrome/android/webapk/.*",
4791 r'^third_party/.*',
4792 r"tools/android/customtabs_benchmark/.*",
4793 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504794 )),
4795 files_to_check=[r'.*\.java$'])
4796
4797 for f in input_api.AffectedSourceFiles(sources):
4798 for line_num, line in f.ChangedContents():
4799 if build_type_check_pattern.search(line):
4800 errors.append("%s:%d" % (f.LocalPath(), line_num))
4801
4802 results = []
4803
4804 if errors:
4805 results.append(
4806 output_api.PresubmitPromptWarning(
4807 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
4808 ' Please use BuildInfo.isDebugAndroid() instead.', errors))
4809
4810 return results
4811
Daniel Cheng6303eed2025-05-03 00:12:334812
Sam Maiera6e76d72022-02-11 21:43:504813# TODO: add unit tests
4814def _CheckAndroidToastUsage(input_api, output_api):
4815 """Checks that code uses org.chromium.ui.widget.Toast instead of
4816 android.widget.Toast (Chromium Toast doesn't force hardware
4817 acceleration on low-end devices, saving memory).
4818 """
4819 toast_import_pattern = input_api.re.compile(
4820 r'^import android\.widget\.Toast;$')
4821
4822 errors = []
4823
4824 sources = lambda affected_file: input_api.FilterSourceFile(
4825 affected_file,
4826 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
Daniel Cheng6303eed2025-05-03 00:12:334827 DEFAULT_FILES_TO_SKIP +
4828 (r'^chromecast/.*', r'^remoting/.*')),
Sam Maiera6e76d72022-02-11 21:43:504829 files_to_check=[r'.*\.java$'])
4830
4831 for f in input_api.AffectedSourceFiles(sources):
4832 for line_num, line in f.ChangedContents():
4833 if toast_import_pattern.search(line):
4834 errors.append("%s:%d" % (f.LocalPath(), line_num))
4835
4836 results = []
4837
4838 if errors:
4839 results.append(
4840 output_api.PresubmitError(
4841 'android.widget.Toast usage is detected. Android toasts use hardware'
4842 ' acceleration, and can be\ncostly on low-end devices. Please use'
4843 ' org.chromium.ui.widget.Toast instead.\n'
4844 'Contact [email protected] if you have any questions.',
4845 errors))
4846
4847 return results
4848
4849
4850def _CheckAndroidCrLogUsage(input_api, output_api):
4851 """Checks that new logs using org.chromium.base.Log:
4852 - Are using 'TAG' as variable name for the tags (warn)
4853 - Are using a tag that is shorter than 20 characters (error)
4854 """
4855
4856 # Do not check format of logs in the given files
4857 cr_log_check_excluded_paths = [
4858 # //chrome/android/webapk cannot depend on //base
Bruce Dawson40fece62022-09-16 19:58:314859 r"^chrome/android/webapk/.*",
Sam Maiera6e76d72022-02-11 21:43:504860 # WebView license viewer code cannot depend on //base; used in stub APK.
Bruce Dawson40fece62022-09-16 19:58:314861 r"^android_webview/glue/java/src/com/android/"
4862 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504863 # The customtabs_benchmark is a small app that does not depend on Chromium
4864 # java pieces.
Bruce Dawson40fece62022-09-16 19:58:314865 r"tools/android/customtabs_benchmark/.*",
Sam Maiera6e76d72022-02-11 21:43:504866 ]
4867
4868 cr_log_import_pattern = input_api.re.compile(
4869 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
4870 class_in_base_pattern = input_api.re.compile(
4871 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
4872 has_some_log_import_pattern = input_api.re.compile(r'^import .*\.Log;$',
4873 input_api.re.MULTILINE)
4874 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
4875 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
4876 log_decl_pattern = input_api.re.compile(
4877 r'static final String TAG = "(?P<name>(.*))"')
4878 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
4879
4880 REF_MSG = ('See docs/android_logging.md for more info.')
4881 sources = lambda x: input_api.FilterSourceFile(
4882 x,
4883 files_to_check=[r'.*\.java$'],
4884 files_to_skip=cr_log_check_excluded_paths)
4885
4886 tag_decl_errors = []
Andrew Grieved3a35d82024-01-02 21:24:384887 tag_length_errors = []
Sam Maiera6e76d72022-02-11 21:43:504888 tag_errors = []
4889 tag_with_dot_errors = []
4890 util_log_errors = []
4891
4892 for f in input_api.AffectedSourceFiles(sources):
4893 file_content = input_api.ReadFile(f)
4894 has_modified_logs = False
4895 # Per line checks
4896 if (cr_log_import_pattern.search(file_content)
4897 or (class_in_base_pattern.search(file_content)
4898 and not has_some_log_import_pattern.search(file_content))):
4899 # Checks to run for files using cr log
4900 for line_num, line in f.ChangedContents():
4901 if rough_log_decl_pattern.search(line):
4902 has_modified_logs = True
4903
4904 # Check if the new line is doing some logging
4905 match = log_call_pattern.search(line)
4906 if match:
4907 has_modified_logs = True
4908
4909 # Make sure it uses "TAG"
4910 if not match.group('tag') == 'TAG':
4911 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
4912 else:
4913 # Report non cr Log function calls in changed lines
4914 for line_num, line in f.ChangedContents():
4915 if log_call_pattern.search(line):
4916 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
4917
4918 # Per file checks
4919 if has_modified_logs:
4920 # Make sure the tag is using the "cr" prefix and is not too long
4921 match = log_decl_pattern.search(file_content)
4922 tag_name = match.group('name') if match else None
4923 if not tag_name:
4924 tag_decl_errors.append(f.LocalPath())
Andrew Grieved3a35d82024-01-02 21:24:384925 elif len(tag_name) > 20:
4926 tag_length_errors.append(f.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:504927 elif '.' in tag_name:
4928 tag_with_dot_errors.append(f.LocalPath())
4929
4930 results = []
4931 if tag_decl_errors:
4932 results.append(
4933 output_api.PresubmitPromptWarning(
4934 'Please define your tags using the suggested format: .\n'
4935 '"private static final String TAG = "<package tag>".\n'
4936 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
4937 tag_decl_errors))
4938
Andrew Grieved3a35d82024-01-02 21:24:384939 if tag_length_errors:
4940 results.append(
4941 output_api.PresubmitError(
4942 'The tag length is restricted by the system to be at most '
4943 '20 characters.\n' + REF_MSG, tag_length_errors))
4944
Sam Maiera6e76d72022-02-11 21:43:504945 if tag_errors:
4946 results.append(
4947 output_api.PresubmitPromptWarning(
4948 'Please use a variable named "TAG" for your log tags.\n' +
4949 REF_MSG, tag_errors))
4950
4951 if util_log_errors:
4952 results.append(
4953 output_api.PresubmitPromptWarning(
4954 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
4955 util_log_errors))
4956
4957 if tag_with_dot_errors:
4958 results.append(
4959 output_api.PresubmitPromptWarning(
4960 'Dot in log tags cause them to be elided in crash reports.\n' +
4961 REF_MSG, tag_with_dot_errors))
4962
4963 return results
4964
4965
Sam Maiera6e76d72022-02-11 21:43:504966def _CheckAndroidTestAnnotationUsage(input_api, output_api):
4967 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
4968 deprecated_annotation_import_pattern = input_api.re.compile(
4969 r'^import android\.test\.suitebuilder\.annotation\..*;',
4970 input_api.re.MULTILINE)
4971 sources = lambda x: input_api.FilterSourceFile(
4972 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
4973 errors = []
4974 for f in input_api.AffectedFiles(file_filter=sources):
4975 for line_num, line in f.ChangedContents():
4976 if deprecated_annotation_import_pattern.search(line):
4977 errors.append("%s:%d" % (f.LocalPath(), line_num))
4978
4979 results = []
4980 if errors:
4981 results.append(
4982 output_api.PresubmitError(
4983 'Annotations in android.test.suitebuilder.annotation have been'
Mohamed Heikal3d7a94c2023-03-28 16:55:244984 ' deprecated since API level 24. Please use androidx.test.filters'
4985 ' from //third_party/androidx:androidx_test_runner_java instead.'
Sam Maiera6e76d72022-02-11 21:43:504986 ' Contact [email protected] if you have any questions.',
4987 errors))
4988 return results
4989
4990
4991def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
4992 """Checks if MDPI assets are placed in a correct directory."""
Daniel Cheng6303eed2025-05-03 00:12:334993 file_filter = lambda f: (f.UnixLocalPath().endswith('.png') and
4994 ('/res/drawable/' in f.UnixLocalPath() or
4995 '/res/drawable-ldrtl/' in f.UnixLocalPath()))
Sam Maiera6e76d72022-02-11 21:43:504996 errors = []
4997 for f in input_api.AffectedFiles(include_deletes=False,
4998 file_filter=file_filter):
4999 errors.append(' %s' % f.LocalPath())
5000
5001 results = []
5002 if errors:
5003 results.append(
5004 output_api.PresubmitError(
5005 'MDPI assets should be placed in /res/drawable-mdpi/ or '
5006 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
5007 '/res/drawable-ldrtl/.\n'
5008 'Contact [email protected] if you have questions.', errors))
5009 return results
5010
5011
5012def _CheckAndroidWebkitImports(input_api, output_api):
5013 """Checks that code uses org.chromium.base.Callback instead of
5014 android.webview.ValueCallback except in the WebView glue layer
5015 and WebLayer.
5016 """
5017 valuecallback_import_pattern = input_api.re.compile(
5018 r'^import android\.webkit\.ValueCallback;$')
5019
5020 errors = []
5021
5022 sources = lambda affected_file: input_api.FilterSourceFile(
5023 affected_file,
5024 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
5025 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:315026 r'^android_webview/glue/.*',
elabadysayedcbbaea72024-08-01 16:10:425027 r'^android_webview/support_library/.*',
Bruce Dawson40fece62022-09-16 19:58:315028 r'^weblayer/.*',
Sam Maiera6e76d72022-02-11 21:43:505029 )),
5030 files_to_check=[r'.*\.java$'])
5031
5032 for f in input_api.AffectedSourceFiles(sources):
5033 for line_num, line in f.ChangedContents():
5034 if valuecallback_import_pattern.search(line):
5035 errors.append("%s:%d" % (f.LocalPath(), line_num))
5036
5037 results = []
5038
5039 if errors:
5040 results.append(
5041 output_api.PresubmitError(
5042 'android.webkit.ValueCallback usage is detected outside of the glue'
5043 ' layer. To stay compatible with the support library, android.webkit.*'
5044 ' classes should only be used inside the glue layer and'
5045 ' org.chromium.base.Callback should be used instead.', errors))
5046
5047 return results
5048
5049
5050def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
5051 """Checks Android XML styles """
5052
5053 # Return early if no relevant files were modified.
5054 if not any(
5055 _IsXmlOrGrdFile(input_api, f.LocalPath())
5056 for f in input_api.AffectedFiles(include_deletes=False)):
5057 return []
5058
5059 import sys
5060 original_sys_path = sys.path
5061 try:
5062 sys.path = sys.path + [
5063 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5064 'android', 'checkxmlstyle')
5065 ]
5066 import checkxmlstyle
5067 finally:
5068 # Restore sys.path to what it was before.
5069 sys.path = original_sys_path
5070
5071 if is_check_on_upload:
5072 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
5073 else:
5074 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
5075
5076
5077def _CheckAndroidInfoBarDeprecation(input_api, output_api):
5078 """Checks Android Infobar Deprecation """
5079
5080 import sys
5081 original_sys_path = sys.path
5082 try:
5083 sys.path = sys.path + [
5084 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5085 'android', 'infobar_deprecation')
5086 ]
5087 import infobar_deprecation
5088 finally:
5089 # Restore sys.path to what it was before.
5090 sys.path = original_sys_path
5091
5092 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
5093
5094
5095class _PydepsCheckerResult:
Daniel Cheng6303eed2025-05-03 00:12:335096
Sam Maiera6e76d72022-02-11 21:43:505097 def __init__(self, cmd, pydeps_path, process, old_contents):
5098 self._cmd = cmd
5099 self._pydeps_path = pydeps_path
5100 self._process = process
5101 self._old_contents = old_contents
5102
5103 def GetError(self):
5104 """Returns an error message, or None."""
5105 import difflib
Andrew Grieved27620b62023-07-13 16:35:075106 new_contents = self._process.stdout.read().splitlines()[2:]
Sam Maiera6e76d72022-02-11 21:43:505107 if self._process.wait() != 0:
5108 # STDERR should already be printed.
5109 return 'Command failed: ' + self._cmd
Sam Maiera6e76d72022-02-11 21:43:505110 if self._old_contents != new_contents:
5111 diff = '\n'.join(
5112 difflib.context_diff(self._old_contents, new_contents))
5113 return ('File is stale: {}\n'
5114 'Diff (apply to fix):\n'
5115 '{}\n'
5116 'To regenerate, run:\n\n'
5117 ' {}').format(self._pydeps_path, diff, self._cmd)
5118 return None
5119
5120
5121class PydepsChecker:
Daniel Cheng6303eed2025-05-03 00:12:335122
Sam Maiera6e76d72022-02-11 21:43:505123 def __init__(self, input_api, pydeps_files):
5124 self._file_cache = {}
5125 self._input_api = input_api
5126 self._pydeps_files = pydeps_files
5127
5128 def _LoadFile(self, path):
5129 """Returns the list of paths within a .pydeps file relative to //."""
5130 if path not in self._file_cache:
5131 with open(path, encoding='utf-8') as f:
5132 self._file_cache[path] = f.read()
5133 return self._file_cache[path]
5134
5135 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
Gao Shenga79ebd42022-08-08 17:25:595136 """Returns an iterable of paths within the .pydep, relativized to //."""
Sam Maiera6e76d72022-02-11 21:43:505137 pydeps_data = self._LoadFile(pydeps_path)
5138 uses_gn_paths = '--gn-paths' in pydeps_data
5139 entries = (l for l in pydeps_data.splitlines()
5140 if not l.startswith('#'))
5141 if uses_gn_paths:
5142 # Paths look like: //foo/bar/baz
5143 return (e[2:] for e in entries)
5144 else:
5145 # Paths look like: path/relative/to/file.pydeps
5146 os_path = self._input_api.os_path
5147 pydeps_dir = os_path.dirname(pydeps_path)
5148 return (os_path.normpath(os_path.join(pydeps_dir, e))
5149 for e in entries)
5150
5151 def _CreateFilesToPydepsMap(self):
5152 """Returns a map of local_path -> list_of_pydeps."""
5153 ret = {}
5154 for pydep_local_path in self._pydeps_files:
5155 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
5156 ret.setdefault(path, []).append(pydep_local_path)
5157 return ret
5158
5159 def ComputeAffectedPydeps(self):
5160 """Returns an iterable of .pydeps files that might need regenerating."""
5161 affected_pydeps = set()
5162 file_to_pydeps_map = None
5163 for f in self._input_api.AffectedFiles(include_deletes=True):
5164 local_path = f.LocalPath()
5165 # Changes to DEPS can lead to .pydeps changes if any .py files are in
5166 # subrepositories. We can't figure out which files change, so re-check
5167 # all files.
5168 # Changes to print_python_deps.py affect all .pydeps.
5169 if local_path in ('DEPS', 'PRESUBMIT.py'
5170 ) or local_path.endswith('print_python_deps.py'):
5171 return self._pydeps_files
5172 elif local_path.endswith('.pydeps'):
5173 if local_path in self._pydeps_files:
5174 affected_pydeps.add(local_path)
5175 elif local_path.endswith('.py'):
5176 if file_to_pydeps_map is None:
5177 file_to_pydeps_map = self._CreateFilesToPydepsMap()
5178 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
5179 return affected_pydeps
5180
5181 def DetermineIfStaleAsync(self, pydeps_path):
5182 """Runs print_python_deps.py to see if the files is stale."""
5183 import os
5184
5185 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
5186 if old_pydeps_data:
5187 cmd = old_pydeps_data[1][1:].strip()
5188 if '--output' not in cmd:
5189 cmd += ' --output ' + pydeps_path
5190 old_contents = old_pydeps_data[2:]
5191 else:
5192 # A default cmd that should work in most cases (as long as pydeps filename
5193 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
5194 # file is empty/new.
5195 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
5196 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
5197 old_contents = []
5198 env = dict(os.environ)
5199 env['PYTHONDONTWRITEBYTECODE'] = '1'
5200 process = self._input_api.subprocess.Popen(
5201 cmd + ' --output ""',
5202 shell=True,
5203 env=env,
5204 stdout=self._input_api.subprocess.PIPE,
5205 encoding='utf-8')
5206 return _PydepsCheckerResult(cmd, pydeps_path, process, old_contents)
agrievef32bcc72016-04-04 14:57:405207
5208
Tibor Goldschwendt360793f72019-06-25 18:23:495209def _ParseGclientArgs():
Sam Maiera6e76d72022-02-11 21:43:505210 args = {}
5211 with open('build/config/gclient_args.gni', 'r') as f:
5212 for line in f:
5213 line = line.strip()
5214 if not line or line.startswith('#'):
5215 continue
5216 attribute, value = line.split('=')
5217 args[attribute.strip()] = value.strip()
5218 return args
Tibor Goldschwendt360793f72019-06-25 18:23:495219
5220
Saagar Sanghavifceeaae2020-08-12 16:40:365221def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
Sam Maiera6e76d72022-02-11 21:43:505222 """Checks if a .pydeps file needs to be regenerated."""
5223 # This check is for Python dependency lists (.pydeps files), and involves
5224 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
5225 # doesn't work on Windows and Mac, so skip it on other platforms.
5226 if not input_api.platform.startswith('linux'):
5227 return []
Erik Staabc734cd7a2021-11-23 03:11:525228
Sam Maiera6e76d72022-02-11 21:43:505229 results = []
5230 # First, check for new / deleted .pydeps.
5231 for f in input_api.AffectedFiles(include_deletes=True):
5232 # Check whether we are running the presubmit check for a file in src.
Sam Maiera6e76d72022-02-11 21:43:505233 if f.LocalPath().endswith('.pydeps'):
Andrew Grieve713b89b2024-10-15 20:20:085234 # f.LocalPath is relative to repo (src, or internal repo).
5235 # os_path.exists is relative to src repo.
5236 # Therefore if os_path.exists is true, it means f.LocalPath is relative
5237 # to src and we can conclude that the pydeps is in src.
5238 exists = input_api.os_path.exists(f.LocalPath())
5239 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
5240 results.append(
5241 output_api.PresubmitError(
5242 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
5243 'remove %s' % f.LocalPath()))
5244 elif (f.Action() != 'D' and exists
5245 and f.LocalPath() not in _ALL_PYDEPS_FILES):
5246 results.append(
5247 output_api.PresubmitError(
5248 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
5249 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:405250
Sam Maiera6e76d72022-02-11 21:43:505251 if results:
5252 return results
5253
Gavin Mak23884402024-07-25 20:39:265254 try:
5255 parsed_args = _ParseGclientArgs()
5256 except FileNotFoundError:
5257 message = (
5258 'build/config/gclient_args.gni not found. Please make sure your '
Daniel Cheng6303eed2025-05-03 00:12:335259 'workspace has been initialized with gclient sync.')
Gavin Mak23884402024-07-25 20:39:265260 import sys
5261 original_sys_path = sys.path
5262 try:
5263 sys.path = sys.path + [
5264 input_api.os_path.join(input_api.PresubmitLocalPath(),
Daniel Cheng6303eed2025-05-03 00:12:335265 'third_party', 'depot_tools')
Gavin Mak23884402024-07-25 20:39:265266 ]
5267 import gclient_utils
5268 if gclient_utils.IsEnvCog():
5269 # Users will always hit this when they run presubmits before cog
5270 # workspace initialization finishes. The check shouldn't fail in
5271 # this case. This is an unavoidable workaround that's needed for
5272 # good presubmit UX for cog.
5273 results.append(output_api.PresubmitPromptWarning(message))
5274 else:
5275 results.append(output_api.PresubmitError(message))
5276 return results
5277 finally:
5278 # Restore sys.path to what it was before.
5279 sys.path = original_sys_path
5280
5281 is_android = parsed_args.get('checkout_android', 'false') == 'true'
Sam Maiera6e76d72022-02-11 21:43:505282 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
5283 affected_pydeps = set(checker.ComputeAffectedPydeps())
5284 affected_android_pydeps = affected_pydeps.intersection(
5285 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
5286 if affected_android_pydeps and not is_android:
5287 results.append(
5288 output_api.PresubmitPromptOrNotify(
5289 'You have changed python files that may affect pydeps for android\n'
Gao Shenga79ebd42022-08-08 17:25:595290 'specific scripts. However, the relevant presubmit check cannot be\n'
Sam Maiera6e76d72022-02-11 21:43:505291 'run because you are not using an Android checkout. To validate that\n'
5292 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
5293 'use the android-internal-presubmit optional trybot.\n'
5294 'Possibly stale pydeps files:\n{}'.format(
5295 '\n'.join(affected_android_pydeps))))
5296
5297 all_pydeps = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
5298 pydeps_to_check = affected_pydeps.intersection(all_pydeps)
5299 # Process these concurrently, as each one takes 1-2 seconds.
5300 pydep_results = [checker.DetermineIfStaleAsync(p) for p in pydeps_to_check]
5301 for result in pydep_results:
5302 error_msg = result.GetError()
5303 if error_msg:
5304 results.append(output_api.PresubmitError(error_msg))
5305
agrievef32bcc72016-04-04 14:57:405306 return results
5307
agrievef32bcc72016-04-04 14:57:405308
Saagar Sanghavifceeaae2020-08-12 16:40:365309def CheckSingletonInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505310 """Checks to make sure no header files have |Singleton<|."""
5311
5312 def FileFilter(affected_file):
5313 # It's ok for base/memory/singleton.h to have |Singleton<|.
5314 files_to_skip = (_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
Bruce Dawson40fece62022-09-16 19:58:315315 (r"^base/memory/singleton\.h$",
5316 r"^net/quic/platform/impl/quic_singleton_impl\.h$"))
Sam Maiera6e76d72022-02-11 21:43:505317 return input_api.FilterSourceFile(affected_file,
5318 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:435319
Sam Maiera6e76d72022-02-11 21:43:505320 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
5321 files = []
5322 for f in input_api.AffectedSourceFiles(FileFilter):
5323 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx')
5324 or f.LocalPath().endswith('.hpp')
5325 or f.LocalPath().endswith('.inl')):
5326 contents = input_api.ReadFile(f)
5327 for line in contents.splitlines(False):
5328 if (not line.lstrip().startswith('//')
5329 and # Strip C++ comment.
5330 pattern.search(line)):
5331 files.append(f)
5332 break
glidere61efad2015-02-18 17:39:435333
Sam Maiera6e76d72022-02-11 21:43:505334 if files:
5335 return [
5336 output_api.PresubmitError(
5337 'Found base::Singleton<T> in the following header files.\n' +
5338 'Please move them to an appropriate source file so that the ' +
5339 'template gets instantiated in a single compilation unit.',
5340 files)
5341 ]
5342 return []
glidere61efad2015-02-18 17:39:435343
5344
[email protected]fd20b902014-05-09 02:14:535345_DEPRECATED_CSS = [
Daniel Cheng6303eed2025-05-03 00:12:335346 # Values
5347 ("-webkit-box", "flex"),
5348 ("-webkit-inline-box", "inline-flex"),
5349 ("-webkit-flex", "flex"),
5350 ("-webkit-inline-flex", "inline-flex"),
5351 ("-webkit-min-content", "min-content"),
5352 ("-webkit-max-content", "max-content"),
[email protected]fd20b902014-05-09 02:14:535353
Daniel Cheng6303eed2025-05-03 00:12:335354 # Properties
5355 ("-webkit-background-clip", "background-clip"),
5356 ("-webkit-background-origin", "background-origin"),
5357 ("-webkit-background-size", "background-size"),
5358 ("-webkit-box-shadow", "box-shadow"),
5359 ("-webkit-user-select", "user-select"),
[email protected]fd20b902014-05-09 02:14:535360
Daniel Cheng6303eed2025-05-03 00:12:335361 # Functions
5362 ("-webkit-gradient", "gradient"),
5363 ("-webkit-repeating-gradient", "repeating-gradient"),
5364 ("-webkit-linear-gradient", "linear-gradient"),
5365 ("-webkit-repeating-linear-gradient", "repeating-linear-gradient"),
5366 ("-webkit-radial-gradient", "radial-gradient"),
5367 ("-webkit-repeating-radial-gradient", "repeating-radial-gradient"),
[email protected]fd20b902014-05-09 02:14:535368]
5369
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:205370
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:495371# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:365372def CheckNoDeprecatedCss(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505373 """ Make sure that we don't use deprecated CSS
5374 properties, functions or values. Our external
5375 documentation and iOS CSS for dom distiller
5376 (reader mode) are ignored by the hooks as it
5377 needs to be consumed by WebKit. """
5378 results = []
5379 file_inclusion_pattern = [r".+\.css$"]
Daniel Cheng6303eed2025-05-03 00:12:335380 files_to_skip = (
5381 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
5382 input_api.DEFAULT_FILES_TO_SKIP +
5383 ( # Legacy CSS file using deprecated CSS.
5384 r"^chrome/browser/resources/chromeos/arc_support/cr_overlay.css$",
5385 r"^chrome/common/extensions/docs",
5386 r"^chrome/docs",
5387 r"^native_client_sdk",
5388 # The NTP team prefers reserving -webkit-line-clamp for
5389 # ellipsis effect which can only be used with -webkit-box.
5390 r"ui/webui/resources/cr_components/most_visited/.*\.css$"))
Sam Maiera6e76d72022-02-11 21:43:505391 file_filter = lambda f: input_api.FilterSourceFile(
5392 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
5393 for fpath in input_api.AffectedFiles(file_filter=file_filter):
5394 for line_num, line in fpath.ChangedContents():
5395 for (deprecated_value, value) in _DEPRECATED_CSS:
5396 if deprecated_value in line:
5397 results.append(
5398 output_api.PresubmitError(
5399 "%s:%d: Use of deprecated CSS %s, use %s instead" %
5400 (fpath.LocalPath(), line_num, deprecated_value,
5401 value)))
5402 return results
[email protected]fd20b902014-05-09 02:14:535403
mohan.reddyf21db962014-10-16 12:26:475404
Saagar Sanghavifceeaae2020-08-12 16:40:365405def CheckForRelativeIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505406 bad_files = {}
5407 for f in input_api.AffectedFiles(include_deletes=False):
Anton Bershanskyi4253349482025-02-11 21:01:275408 if (f.UnixLocalPath().startswith('third_party')
5409 and not f.LocalPath().startswith('third_party/blink')):
Sam Maiera6e76d72022-02-11 21:43:505410 continue
rlanday6802cf632017-05-30 17:48:365411
Sam Maiera6e76d72022-02-11 21:43:505412 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
5413 continue
rlanday6802cf632017-05-30 17:48:365414
Sam Maiera6e76d72022-02-11 21:43:505415 relative_includes = [
5416 line for _, line in f.ChangedContents()
5417 if "#include" in line and "../" in line
5418 ]
5419 if not relative_includes:
5420 continue
5421 bad_files[f.LocalPath()] = relative_includes
rlanday6802cf632017-05-30 17:48:365422
Sam Maiera6e76d72022-02-11 21:43:505423 if not bad_files:
5424 return []
rlanday6802cf632017-05-30 17:48:365425
Sam Maiera6e76d72022-02-11 21:43:505426 error_descriptions = []
5427 for file_path, bad_lines in bad_files.items():
5428 error_description = file_path
5429 for line in bad_lines:
5430 error_description += '\n ' + line
5431 error_descriptions.append(error_description)
rlanday6802cf632017-05-30 17:48:365432
Sam Maiera6e76d72022-02-11 21:43:505433 results = []
5434 results.append(
5435 output_api.PresubmitError(
5436 'You added one or more relative #include paths (including "../").\n'
5437 'These shouldn\'t be used because they can be used to include headers\n'
5438 'from code that\'s not correctly specified as a dependency in the\n'
5439 'relevant BUILD.gn file(s).', error_descriptions))
rlanday6802cf632017-05-30 17:48:365440
Sam Maiera6e76d72022-02-11 21:43:505441 return results
rlanday6802cf632017-05-30 17:48:365442
Takeshi Yoshinoe387aa32017-08-02 13:16:135443
Saagar Sanghavifceeaae2020-08-12 16:40:365444def CheckForCcIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505445 """Check that nobody tries to include a cc file. It's a relatively
5446 common error which results in duplicate symbols in object
5447 files. This may not always break the build until someone later gets
5448 very confusing linking errors."""
5449 results = []
5450 for f in input_api.AffectedFiles(include_deletes=False):
5451 # We let third_party code do whatever it wants
Anton Bershanskyi4253349482025-02-11 21:01:275452 if (f.UnixLocalPath().startswith('third_party')
5453 and not f.LocalPath().startswith('third_party/blink')):
Sam Maiera6e76d72022-02-11 21:43:505454 continue
Daniel Bratell65b033262019-04-23 08:17:065455
Sam Maiera6e76d72022-02-11 21:43:505456 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
5457 continue
Daniel Bratell65b033262019-04-23 08:17:065458
Sam Maiera6e76d72022-02-11 21:43:505459 for _, line in f.ChangedContents():
5460 if line.startswith('#include "'):
5461 included_file = line.split('"')[1]
5462 if _IsCPlusPlusFile(input_api, included_file):
5463 # The most common naming for external files with C++ code,
5464 # apart from standard headers, is to call them foo.inc, but
5465 # Chromium sometimes uses foo-inc.cc so allow that as well.
5466 if not included_file.endswith(('.h', '-inc.cc')):
5467 results.append(
5468 output_api.PresubmitError(
5469 'Only header files or .inc files should be included in other\n'
5470 'C++ files. Compiling the contents of a cc file more than once\n'
5471 'will cause duplicate information in the build which may later\n'
5472 'result in strange link_errors.\n' +
5473 f.LocalPath() + ':\n ' + line))
Daniel Bratell65b033262019-04-23 08:17:065474
Sam Maiera6e76d72022-02-11 21:43:505475 return results
Daniel Bratell65b033262019-04-23 08:17:065476
5477
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205478def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
Sam Maiera6e76d72022-02-11 21:43:505479 if not isinstance(key, ast.Str):
5480 return 'Key at line %d must be a string literal' % key.lineno
5481 if not isinstance(value, ast.Dict):
5482 return 'Value at line %d must be a dict' % value.lineno
5483 if len(value.keys) != 1:
5484 return 'Dict at line %d must have single entry' % value.lineno
5485 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
5486 return (
5487 'Entry at line %d must have a string literal \'filepath\' as key' %
5488 value.lineno)
5489 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:135490
Takeshi Yoshinoe387aa32017-08-02 13:16:135491
Sergey Ulanov4af16052018-11-08 02:41:465492def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Sam Maiera6e76d72022-02-11 21:43:505493 if not isinstance(key, ast.Str):
5494 return 'Key at line %d must be a string literal' % key.lineno
5495 if not isinstance(value, ast.List):
5496 return 'Value at line %d must be a list' % value.lineno
5497 for element in value.elts:
5498 if not isinstance(element, ast.Str):
5499 return 'Watchlist elements on line %d is not a string' % key.lineno
5500 if not email_regex.match(element.s):
5501 return ('Watchlist element on line %d doesn\'t look like a valid '
5502 + 'email: %s') % (key.lineno, element.s)
5503 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:135504
Takeshi Yoshinoe387aa32017-08-02 13:16:135505
Sergey Ulanov4af16052018-11-08 02:41:465506def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Sam Maiera6e76d72022-02-11 21:43:505507 mismatch_template = (
5508 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
5509 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:135510
Sam Maiera6e76d72022-02-11 21:43:505511 email_regex = input_api.re.compile(
5512 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
Sergey Ulanov4af16052018-11-08 02:41:465513
Sam Maiera6e76d72022-02-11 21:43:505514 ast = input_api.ast
5515 i = 0
5516 last_key = ''
5517 while True:
5518 if i >= len(wd_dict.keys):
5519 if i >= len(w_dict.keys):
5520 return None
5521 return mismatch_template % ('missing',
5522 'line %d' % w_dict.keys[i].lineno)
5523 elif i >= len(w_dict.keys):
5524 return (mismatch_template %
5525 ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:135526
Sam Maiera6e76d72022-02-11 21:43:505527 wd_key = wd_dict.keys[i]
5528 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:135529
Sam Maiera6e76d72022-02-11 21:43:505530 result = _CheckWatchlistDefinitionsEntrySyntax(wd_key,
5531 wd_dict.values[i], ast)
5532 if result is not None:
5533 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:135534
Sam Maiera6e76d72022-02-11 21:43:505535 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast,
5536 email_regex)
5537 if result is not None:
5538 return 'Bad entry in WATCHLISTS dict: %s' % result
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205539
Sam Maiera6e76d72022-02-11 21:43:505540 if wd_key.s != w_key.s:
5541 return mismatch_template % ('%s at line %d' %
5542 (wd_key.s, wd_key.lineno),
5543 '%s at line %d' %
5544 (w_key.s, w_key.lineno))
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205545
Sam Maiera6e76d72022-02-11 21:43:505546 if wd_key.s < last_key:
5547 return (
5548 'WATCHLISTS dict is not sorted lexicographically at line %d and %d'
5549 % (wd_key.lineno, w_key.lineno))
5550 last_key = wd_key.s
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205551
Sam Maiera6e76d72022-02-11 21:43:505552 i = i + 1
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205553
5554
Sergey Ulanov4af16052018-11-08 02:41:465555def _CheckWATCHLISTSSyntax(expression, input_api):
Sam Maiera6e76d72022-02-11 21:43:505556 ast = input_api.ast
5557 if not isinstance(expression, ast.Expression):
5558 return 'WATCHLISTS file must contain a valid expression'
5559 dictionary = expression.body
5560 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
5561 return 'WATCHLISTS file must have single dict with exactly two entries'
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205562
Sam Maiera6e76d72022-02-11 21:43:505563 first_key = dictionary.keys[0]
5564 first_value = dictionary.values[0]
5565 second_key = dictionary.keys[1]
5566 second_value = dictionary.values[1]
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205567
Sam Maiera6e76d72022-02-11 21:43:505568 if (not isinstance(first_key, ast.Str)
5569 or first_key.s != 'WATCHLIST_DEFINITIONS'
5570 or not isinstance(first_value, ast.Dict)):
5571 return ('The first entry of the dict in WATCHLISTS file must be '
5572 'WATCHLIST_DEFINITIONS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205573
Sam Maiera6e76d72022-02-11 21:43:505574 if (not isinstance(second_key, ast.Str) or second_key.s != 'WATCHLISTS'
5575 or not isinstance(second_value, ast.Dict)):
5576 return ('The second entry of the dict in WATCHLISTS file must be '
5577 'WATCHLISTS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205578
Sam Maiera6e76d72022-02-11 21:43:505579 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:135580
5581
Saagar Sanghavifceeaae2020-08-12 16:40:365582def CheckWATCHLISTS(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505583 for f in input_api.AffectedFiles(include_deletes=False):
5584 if f.LocalPath() == 'WATCHLISTS':
5585 contents = input_api.ReadFile(f, 'r')
Takeshi Yoshinoe387aa32017-08-02 13:16:135586
Sam Maiera6e76d72022-02-11 21:43:505587 try:
5588 # First, make sure that it can be evaluated.
5589 input_api.ast.literal_eval(contents)
5590 # Get an AST tree for it and scan the tree for detailed style checking.
5591 expression = input_api.ast.parse(contents,
5592 filename='WATCHLISTS',
5593 mode='eval')
5594 except ValueError as e:
5595 return [
5596 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5597 long_text=repr(e))
5598 ]
5599 except SyntaxError as e:
5600 return [
5601 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5602 long_text=repr(e))
5603 ]
5604 except TypeError as e:
5605 return [
5606 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5607 long_text=repr(e))
5608 ]
Takeshi Yoshinoe387aa32017-08-02 13:16:135609
Sam Maiera6e76d72022-02-11 21:43:505610 result = _CheckWATCHLISTSSyntax(expression, input_api)
5611 if result is not None:
5612 return [output_api.PresubmitError(result)]
5613 break
Takeshi Yoshinoe387aa32017-08-02 13:16:135614
Sam Maiera6e76d72022-02-11 21:43:505615 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:135616
Daniel Cheng6303eed2025-05-03 00:12:335617
Sean Kaucb7c9b32022-10-25 21:25:525618def CheckGnRebasePath(input_api, output_api):
Terrence Reilly313f44ff2025-01-22 15:10:145619 """Checks that target_gen_dir is not used with "//" in rebase_path().
Sean Kaucb7c9b32022-10-25 21:25:525620
5621 Developers should use root_build_dir instead of "//" when using target_gen_dir because
5622 Chromium is sometimes built outside of the source tree.
5623 """
5624
5625 def gn_files(f):
5626 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
5627
Daniel Cheng6303eed2025-05-03 00:12:335628 rebase_path_regex = input_api.re.compile(
5629 r'rebase_path\(("\$target_gen_dir"|target_gen_dir), ("/"|"//")\)')
Sean Kaucb7c9b32022-10-25 21:25:525630 problems = []
5631 for f in input_api.AffectedSourceFiles(gn_files):
5632 for line_num, line in f.ChangedContents():
5633 if rebase_path_regex.search(line):
Daniel Cheng6303eed2025-05-03 00:12:335634 problems.append('Absolute path in rebase_path() in %s:%d' %
5635 (f.LocalPath(), line_num))
Sean Kaucb7c9b32022-10-25 21:25:525636
5637 if problems:
5638 return [
5639 output_api.PresubmitPromptWarning(
5640 'Using an absolute path in rebase_path()',
5641 items=sorted(problems),
5642 long_text=(
5643 'rebase_path() should use root_build_dir instead of "/" ',
5644 'since builds can be initiated from outside of the source ',
5645 'root.'))
5646 ]
5647 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:135648
Daniel Cheng6303eed2025-05-03 00:12:335649
Andrew Grieve1b290e4a22020-11-24 20:07:015650def CheckGnGlobForward(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505651 """Checks that forward_variables_from(invoker, "*") follows best practices.
Andrew Grieve1b290e4a22020-11-24 20:07:015652
Sam Maiera6e76d72022-02-11 21:43:505653 As documented at //build/docs/writing_gn_templates.md
5654 """
Andrew Grieve1b290e4a22020-11-24 20:07:015655
Sam Maiera6e76d72022-02-11 21:43:505656 def gn_files(f):
5657 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
Andrew Grieve1b290e4a22020-11-24 20:07:015658
Sam Maiera6e76d72022-02-11 21:43:505659 problems = []
5660 for f in input_api.AffectedSourceFiles(gn_files):
5661 for line_num, line in f.ChangedContents():
5662 if 'forward_variables_from(invoker, "*")' in line:
5663 problems.append(
5664 'Bare forward_variables_from(invoker, "*") in %s:%d' %
5665 (f.LocalPath(), line_num))
5666
5667 if problems:
5668 return [
5669 output_api.PresubmitPromptWarning(
5670 'forward_variables_from("*") without exclusions',
5671 items=sorted(problems),
5672 long_text=(
Gao Shenga79ebd42022-08-08 17:25:595673 'The variables "visibility" and "test_only" should be '
Sam Maiera6e76d72022-02-11 21:43:505674 'explicitly listed in forward_variables_from(). For more '
5675 'details, see:\n'
5676 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
5677 'build/docs/writing_gn_templates.md'
5678 '#Using-forward_variables_from'))
5679 ]
5680 return []
Andrew Grieve1b290e4a22020-11-24 20:07:015681
Daniel Cheng6303eed2025-05-03 00:12:335682
Saagar Sanghavifceeaae2020-08-12 16:40:365683def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505684 """Checks that newly added header files have corresponding GN changes.
5685 Note that this is only a heuristic. To be precise, run script:
5686 build/check_gn_headers.py.
5687 """
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195688
Sam Maiera6e76d72022-02-11 21:43:505689 def headers(f):
5690 return input_api.FilterSourceFile(
5691 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195692
Sam Maiera6e76d72022-02-11 21:43:505693 new_headers = []
5694 for f in input_api.AffectedSourceFiles(headers):
5695 if f.Action() != 'A':
5696 continue
5697 new_headers.append(f.LocalPath())
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195698
Sam Maiera6e76d72022-02-11 21:43:505699 def gn_files(f):
5700 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195701
Sam Maiera6e76d72022-02-11 21:43:505702 all_gn_changed_contents = ''
5703 for f in input_api.AffectedSourceFiles(gn_files):
5704 for _, line in f.ChangedContents():
5705 all_gn_changed_contents += line
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195706
Sam Maiera6e76d72022-02-11 21:43:505707 problems = []
5708 for header in new_headers:
5709 basename = input_api.os_path.basename(header)
5710 if basename not in all_gn_changed_contents:
5711 problems.append(header)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195712
Sam Maiera6e76d72022-02-11 21:43:505713 if problems:
5714 return [
5715 output_api.PresubmitPromptWarning(
5716 'Missing GN changes for new header files',
5717 items=sorted(problems),
5718 long_text=
5719 'Please double check whether newly added header files need '
5720 'corresponding changes in gn or gni files.\nThis checking is only a '
5721 'heuristic. Run build/check_gn_headers.py to be precise.\n'
5722 'Read https://crbug.com/661774 for more info.')
5723 ]
5724 return []
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195725
5726
Saagar Sanghavifceeaae2020-08-12 16:40:365727def CheckCorrectProductNameInMessages(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505728 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
Michael Giuffridad3bc8672018-10-25 22:48:025729
Sam Maiera6e76d72022-02-11 21:43:505730 This assumes we won't intentionally reference one product from the other
5731 product.
5732 """
5733 all_problems = []
5734 test_cases = [{
5735 "filename_postfix": "google_chrome_strings.grd",
5736 "correct_name": "Chrome",
5737 "incorrect_name": "Chromium",
5738 }, {
Thiago Perrotta099034f2023-06-05 18:10:205739 "filename_postfix": "google_chrome_strings.grd",
5740 "correct_name": "Chrome",
5741 "incorrect_name": "Chrome for Testing",
5742 }, {
Sam Maiera6e76d72022-02-11 21:43:505743 "filename_postfix": "chromium_strings.grd",
5744 "correct_name": "Chromium",
5745 "incorrect_name": "Chrome",
5746 }]
Michael Giuffridad3bc8672018-10-25 22:48:025747
Sam Maiera6e76d72022-02-11 21:43:505748 for test_case in test_cases:
5749 problems = []
5750 filename_filter = lambda x: x.LocalPath().endswith(test_case[
5751 "filename_postfix"])
Michael Giuffridad3bc8672018-10-25 22:48:025752
Sam Maiera6e76d72022-02-11 21:43:505753 # Check each new line. Can yield false positives in multiline comments, but
5754 # easier than trying to parse the XML because messages can have nested
5755 # children, and associating message elements with affected lines is hard.
5756 for f in input_api.AffectedSourceFiles(filename_filter):
5757 for line_num, line in f.ChangedContents():
5758 if "<message" in line or "<!--" in line or "-->" in line:
5759 continue
5760 if test_case["incorrect_name"] in line:
Thiago Perrotta099034f2023-06-05 18:10:205761 # Chrome for Testing is a special edge case: https://goo.gle/chrome-for-testing#bookmark=id.n1rat320av91
Daniel Cheng6303eed2025-05-03 00:12:335762 if (test_case["correct_name"] == "Chromium"
5763 and line.count("Chrome")
5764 == line.count("Chrome for Testing")):
Thiago Perrotta099034f2023-06-05 18:10:205765 continue
Sam Maiera6e76d72022-02-11 21:43:505766 problems.append("Incorrect product name in %s:%d" %
5767 (f.LocalPath(), line_num))
Michael Giuffridad3bc8672018-10-25 22:48:025768
Sam Maiera6e76d72022-02-11 21:43:505769 if problems:
5770 message = (
5771 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
5772 % (test_case["correct_name"], test_case["correct_name"],
5773 test_case["incorrect_name"]))
5774 all_problems.append(
5775 output_api.PresubmitPromptWarning(message, items=problems))
Michael Giuffridad3bc8672018-10-25 22:48:025776
Sam Maiera6e76d72022-02-11 21:43:505777 return all_problems
Michael Giuffridad3bc8672018-10-25 22:48:025778
5779
Saagar Sanghavifceeaae2020-08-12 16:40:365780def CheckForTooLargeFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505781 """Avoid large files, especially binary files, in the repository since
5782 git doesn't scale well for those. They will be in everyone's repo
5783 clones forever, forever making Chromium slower to clone and work
5784 with."""
Daniel Bratell93eb6c62019-04-29 20:13:365785
Sam Maiera6e76d72022-02-11 21:43:505786 # Uploading files to cloud storage is not trivial so we don't want
5787 # to set the limit too low, but the upper limit for "normal" large
5788 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
5789 # anything over 20 MB is exceptional.
Bruce Dawsonbb414db2022-12-27 20:21:255790 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024
Daniel Bratell93eb6c62019-04-29 20:13:365791
Sam Maiera6e76d72022-02-11 21:43:505792 too_large_files = []
5793 for f in input_api.AffectedFiles():
5794 # Check both added and modified files (but not deleted files).
5795 if f.Action() in ('A', 'M'):
5796 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Joe DeBlasio10a832f2023-04-21 20:20:185797 if size > TOO_LARGE_FILE_SIZE_LIMIT:
Sam Maiera6e76d72022-02-11 21:43:505798 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
Daniel Bratell93eb6c62019-04-29 20:13:365799
Sam Maiera6e76d72022-02-11 21:43:505800 if too_large_files:
5801 message = (
5802 'Do not commit large files to git since git scales badly for those.\n'
5803 +
5804 'Instead put the large files in cloud storage and use DEPS to\n' +
5805 'fetch them.\n' + '\n'.join(too_large_files))
5806 return [
5807 output_api.PresubmitError('Too large files found in commit',
5808 long_text=message + '\n')
5809 ]
5810 else:
5811 return []
Daniel Bratell93eb6c62019-04-29 20:13:365812
Max Morozb47503b2019-08-08 21:03:275813
Saagar Sanghavifceeaae2020-08-12 16:40:365814def CheckFuzzTargetsOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505815 """Checks specific for fuzz target sources."""
5816 EXPORTED_SYMBOLS = [
5817 'LLVMFuzzerInitialize',
5818 'LLVMFuzzerCustomMutator',
5819 'LLVMFuzzerCustomCrossOver',
5820 'LLVMFuzzerMutate',
5821 ]
Max Morozb47503b2019-08-08 21:03:275822
Sam Maiera6e76d72022-02-11 21:43:505823 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
Max Morozb47503b2019-08-08 21:03:275824
Sam Maiera6e76d72022-02-11 21:43:505825 def FilterFile(affected_file):
5826 """Ignore libFuzzer source code."""
5827 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
Bruce Dawson40fece62022-09-16 19:58:315828 files_to_skip = r"^third_party/libFuzzer"
Max Morozb47503b2019-08-08 21:03:275829
Sam Maiera6e76d72022-02-11 21:43:505830 return input_api.FilterSourceFile(affected_file,
5831 files_to_check=[files_to_check],
5832 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:275833
Sam Maiera6e76d72022-02-11 21:43:505834 files_with_missing_header = []
5835 for f in input_api.AffectedSourceFiles(FilterFile):
5836 contents = input_api.ReadFile(f, 'r')
5837 if REQUIRED_HEADER in contents:
5838 continue
Max Morozb47503b2019-08-08 21:03:275839
Sam Maiera6e76d72022-02-11 21:43:505840 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
5841 files_with_missing_header.append(f.LocalPath())
Max Morozb47503b2019-08-08 21:03:275842
Sam Maiera6e76d72022-02-11 21:43:505843 if not files_with_missing_header:
5844 return []
Max Morozb47503b2019-08-08 21:03:275845
Sam Maiera6e76d72022-02-11 21:43:505846 long_text = (
5847 'If you define any of the libFuzzer optional functions (%s), it is '
5848 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
5849 'work incorrectly on Mac (crbug.com/687076).\nNote that '
5850 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
5851 'to access command line arguments passed to the fuzzer. Instead, prefer '
5852 'static initialization and shared resources as documented in '
5853 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
5854 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n'
5855 % (', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER))
Max Morozb47503b2019-08-08 21:03:275856
Sam Maiera6e76d72022-02-11 21:43:505857 return [
5858 output_api.PresubmitPromptWarning(message="Missing '%s' in:" %
5859 REQUIRED_HEADER,
5860 items=files_with_missing_header,
5861 long_text=long_text)
5862 ]
Max Morozb47503b2019-08-08 21:03:275863
5864
Mohamed Heikald048240a2019-11-12 16:57:375865def _CheckNewImagesWarning(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505866 """
5867 Warns authors who add images into the repo to make sure their images are
5868 optimized before committing.
5869 """
5870 images_added = False
5871 image_paths = []
5872 errors = []
5873 filter_lambda = lambda x: input_api.FilterSourceFile(
5874 x,
Daniel Cheng6303eed2025-05-03 00:12:335875 files_to_skip=(
5876 ('(?i).*test', r'.*\/junit\/') + input_api.DEFAULT_FILES_TO_SKIP),
Sam Maiera6e76d72022-02-11 21:43:505877 files_to_check=[r'.*\/(drawable|mipmap)'])
5878 for f in input_api.AffectedFiles(include_deletes=False,
5879 file_filter=filter_lambda):
5880 local_path = f.LocalPath().lower()
5881 if any(
5882 local_path.endswith(extension)
5883 for extension in _IMAGE_EXTENSIONS):
5884 images_added = True
5885 image_paths.append(f)
5886 if images_added:
5887 errors.append(
5888 output_api.PresubmitPromptWarning(
5889 'It looks like you are trying to commit some images. If these are '
5890 'non-test-only images, please make sure to read and apply the tips in '
5891 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
5892 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
5893 'FYI only and will not block your CL on the CQ.', image_paths))
5894 return errors
Mohamed Heikald048240a2019-11-12 16:57:375895
5896
Saagar Sanghavifceeaae2020-08-12 16:40:365897def ChecksAndroidSpecificOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505898 """Groups upload checks that target android code."""
5899 results = []
5900 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
5901 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
5902 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
5903 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505904 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
5905 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
5906 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
5907 results.extend(_CheckNewImagesWarning(input_api, output_api))
5908 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
5909 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
Daniel Cheng6303eed2025-05-03 00:12:335910 results.extend(_CheckAndroidNullAwayAnnotatedClasses(
5911 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505912 return results
5913
Becky Zhou7c69b50992018-12-10 19:37:575914
Saagar Sanghavifceeaae2020-08-12 16:40:365915def ChecksAndroidSpecificOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505916 """Groups commit checks that target android code."""
5917 results = []
5918 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
Daniel Cheng6303eed2025-05-03 00:12:335919 results.extend(_CheckAndroidNullAwayAnnotatedClasses(
5920 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505921 return results
dgnaa68d5e2015-06-10 10:08:225922
Daniel Cheng6303eed2025-05-03 00:12:335923
Chris Hall59f8d0c72020-05-01 07:31:195924# TODO(chrishall): could we additionally match on any path owned by
5925# ui/accessibility/OWNERS ?
5926_ACCESSIBILITY_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:315927 r"^chrome/browser.*/accessibility/",
5928 r"^chrome/browser/extensions/api/automation.*/",
5929 r"^chrome/renderer/extensions/accessibility_.*",
5930 r"^chrome/tests/data/accessibility/",
5931 r"^content/browser/accessibility/",
5932 r"^content/renderer/accessibility/",
5933 r"^content/tests/data/accessibility/",
5934 r"^extensions/renderer/api/automation/",
Katie Dektar58ef07b2022-09-27 13:19:175935 r"^services/accessibility/",
Abigail Klein7a63c572024-02-28 20:45:095936 r"^services/screen_ai/",
Bruce Dawson40fece62022-09-16 19:58:315937 r"^ui/accessibility/",
5938 r"^ui/views/accessibility/",
Chris Hall59f8d0c72020-05-01 07:31:195939)
5940
Daniel Cheng6303eed2025-05-03 00:12:335941
Saagar Sanghavifceeaae2020-08-12 16:40:365942def CheckAccessibilityRelnotesField(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505943 """Checks that commits to accessibility code contain an AX-Relnotes field in
5944 their commit message."""
Chris Hall59f8d0c72020-05-01 07:31:195945
Sam Maiera6e76d72022-02-11 21:43:505946 def FileFilter(affected_file):
5947 paths = _ACCESSIBILITY_PATHS
5948 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:195949
Sam Maiera6e76d72022-02-11 21:43:505950 # Only consider changes affecting accessibility paths.
5951 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
5952 return []
Akihiro Ota08108e542020-05-20 15:30:535953
Sam Maiera6e76d72022-02-11 21:43:505954 # AX-Relnotes can appear in either the description or the footer.
5955 # When searching the description, require 'AX-Relnotes:' to appear at the
5956 # beginning of a line.
5957 ax_regex = input_api.re.compile('ax-relnotes[:=]')
5958 description_has_relnotes = any(
5959 ax_regex.match(line)
5960 for line in input_api.change.DescriptionText().lower().splitlines())
Chris Hall59f8d0c72020-05-01 07:31:195961
Sam Maiera6e76d72022-02-11 21:43:505962 footer_relnotes = input_api.change.GitFootersFromDescription().get(
5963 'AX-Relnotes', [])
5964 if description_has_relnotes or footer_relnotes:
5965 return []
Chris Hall59f8d0c72020-05-01 07:31:195966
Sam Maiera6e76d72022-02-11 21:43:505967 # TODO(chrishall): link to Relnotes documentation in message.
5968 message = (
5969 "Missing 'AX-Relnotes:' field required for accessibility changes"
5970 "\n please add 'AX-Relnotes: [release notes].' to describe any "
5971 "user-facing changes"
5972 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
5973 "user-facing effects"
5974 "\n if this is confusing or annoying then please contact members "
5975 "of ui/accessibility/OWNERS.")
5976
5977 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:225978
Mark Schillaci44c90b42024-11-22 20:44:385979
5980_ACCESSIBILITY_ARIA_METHOD_CANDIDATES_PATTERNS = r'(\-\>|\.)(get|has|FastGet|FastHas)Attribute\('
5981
Daniel Cheng6303eed2025-05-03 00:12:335982_ACCESSIBILITY_ARIA_BAD_PARAMS_PATTERNS = (r"\(html_names::kAria(.*)Attr\)",
5983 r"\(html_names::kRoleAttr\)")
Mark Schillaci44c90b42024-11-22 20:44:385984
Daniel Cheng6303eed2025-05-03 00:12:335985_ACCESSIBILITY_ARIA_FILE_CANDIDATES_PATTERNS = (r".*/accessibility/.*.(cc|h)",
5986 r".*/ax_.*.(cc|h)")
5987
Mark Schillaci44c90b42024-11-22 20:44:385988
5989def CheckAccessibilityAriaElementAttributeGetters(input_api, output_api):
5990 """Checks that the blink accessibility code follows the defined patterns
5991 for checking aria attributes, so that ElementInternals is not bypassed."""
5992
5993 # Limit to accessibility-related files.
5994 def FileFilter(affected_file):
5995 paths = _ACCESSIBILITY_ARIA_FILE_CANDIDATES_PATTERNS
5996 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
5997
Daniel Cheng6303eed2025-05-03 00:12:335998 aria_method_regex = input_api.re.compile(
5999 _ACCESSIBILITY_ARIA_METHOD_CANDIDATES_PATTERNS)
Mark Schillaci44c90b42024-11-22 20:44:386000 aria_bad_params_regex = input_api.re.compile(
Daniel Cheng6303eed2025-05-03 00:12:336001 "|".join(_ACCESSIBILITY_ARIA_BAD_PARAMS_PATTERNS))
Mark Schillaci44c90b42024-11-22 20:44:386002 problems = []
6003
6004 for f in input_api.AffectedSourceFiles(FileFilter):
6005 for line_num, line in f.ChangedContents():
Daniel Cheng6303eed2025-05-03 00:12:336006 if aria_method_regex.search(line) and aria_bad_params_regex.search(
6007 line):
6008 problems.append(
6009 f"{f.LocalPath()}:{line_num}\n {line.strip()}")
Mark Schillaci44c90b42024-11-22 20:44:386010
6011 if problems:
6012 return [
6013 output_api.PresubmitPromptWarning(
6014 "Accessibility code should not use element methods to get or check"
6015 "\nthe presence of aria attributes"
6016 "\nPlease use ARIA-specific attribute access, e.g. HasAriaAttribute(),"
6017 "\nAriaTokenAttribute(), AriaBoolAttribute(), AriaBooleanAttribute(),"
6018 "\nAriaFloatAttribute().",
6019 problems,
6020 )
6021 ]
6022 return []
6023
Daniel Cheng6303eed2025-05-03 00:12:336024
seanmccullough4a9356252021-04-08 19:54:096025# string pattern, sequence of strings to show when pattern matches,
6026# error flag. True if match is a presubmit error, otherwise it's a warning.
6027_NON_INCLUSIVE_TERMS = (
6028 (
6029 # Note that \b pattern in python re is pretty particular. In this
6030 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
6031 # ...' will not. This may require some tweaking to catch these cases
6032 # without triggering a lot of false positives. Leaving it naive and
6033 # less matchy for now.
Josip Sokcevic9d2806a02023-12-13 03:04:026034 r'/(?i)\b((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:096035 (
6036 'Please don\'t use blacklist, whitelist, ' # nocheck
6037 'or slave in your', # nocheck
6038 'code and make every effort to use other terms. Using "// nocheck"',
6039 '"# nocheck" or "<!-- nocheck -->"',
6040 'at the end of the offending line will bypass this PRESUBMIT error',
6041 'but avoid using this whenever possible. Reach out to',
6042 '[email protected] if you have questions'),
Daniel Cheng6303eed2025-05-03 00:12:336043 True), )
6044
seanmccullough4a9356252021-04-08 19:54:096045
Saagar Sanghavifceeaae2020-08-12 16:40:366046def ChecksCommon(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506047 """Checks common to both upload and commit."""
6048 results = []
Eric Boren6fd2b932018-01-25 15:05:086049 results.extend(
Sam Maiera6e76d72022-02-11 21:43:506050 input_api.canned_checks.PanProjectChecks(
6051 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:086052
Sam Maiera6e76d72022-02-11 21:43:506053 author = input_api.change.author_email
6054 if author and author not in _KNOWN_ROBOTS:
6055 results.extend(
6056 input_api.canned_checks.CheckAuthorizedAuthor(
6057 input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:246058
Sam Maiera6e76d72022-02-11 21:43:506059 results.extend(
6060 input_api.canned_checks.CheckChangeHasNoTabs(
6061 input_api,
6062 output_api,
6063 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
6064 results.extend(
6065 input_api.RunTests(
6066 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Edward Lesmesce51df52020-08-04 22:10:176067
Ben Pastene30dc57082025-06-02 22:19:206068 dirmd = 'dirmd.bat' if input_api.is_windows else 'dirmd'
6069 dirmd_bin = input_api.os_path.join(input_api.PresubmitLocalPath(),
6070 'third_party', 'depot_tools', dirmd)
Sam Maiera6e76d72022-02-11 21:43:506071 results.extend(
6072 input_api.RunTests(
6073 input_api.canned_checks.CheckDirMetadataFormat(
Ben Pastene30dc57082025-06-02 22:19:206074 input_api, output_api, dirmd_bin)))
Sam Maiera6e76d72022-02-11 21:43:506075 results.extend(
6076 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
6077 input_api, output_api))
6078 results.extend(
6079 input_api.canned_checks.CheckNoNewMetadataInOwners(
6080 input_api, output_api))
6081 results.extend(
6082 input_api.canned_checks.CheckInclusiveLanguage(
6083 input_api,
6084 output_api,
6085 excluded_directories_relative_path=[
6086 'infra', 'inclusive_language_presubmit_exempt_dirs.txt'
6087 ],
6088 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Yiwei Zhang5341bf02025-03-20 16:34:136089 results.extend(
6090 input_api.canned_checks.CheckNewDEPSHooksHasRequiredReviewers(
6091 input_api, output_api))
Jie Shengb0c86f02025-06-12 21:36:146092 results.extend(
6093 input_api.canned_checks.CheckValidHostsInDEPSOnUpload(
6094 input_api, output_api))
Dirk Prankee3c9c62d2021-05-18 18:35:596095
Aleksey Khoroshilov2978c942022-06-13 16:14:126096 presubmit_py_filter = lambda f: input_api.FilterSourceFile(
Daniel Cheng6f3d1ae12025-04-07 17:11:276097 f, files_to_check=[r'.*PRESUBMIT(?:_test)?\.py$'])
6098 potential_paths = set(
6099 map(
6100 lambda f: input_api.os_path.dirname(f.AbsoluteLocalPath()),
6101 input_api.AffectedFiles(include_deletes=False,
6102 file_filter=presubmit_py_filter)))
6103 for full_path in potential_paths:
Aleksey Khoroshilov2978c942022-06-13 16:14:126104 test_file = input_api.os_path.join(full_path, 'PRESUBMIT_test.py')
6105 # The PRESUBMIT.py file (and the directory containing it) might have
6106 # been affected by being moved or removed, so only try to run the tests
6107 # if they still exist.
6108 if not input_api.os_path.exists(test_file):
6109 continue
Sam Maiera6e76d72022-02-11 21:43:506110
Aleksey Khoroshilov2978c942022-06-13 16:14:126111 results.extend(
6112 input_api.canned_checks.RunUnitTestsInDirectory(
6113 input_api,
6114 output_api,
6115 full_path,
Takuto Ikuta40def482023-06-02 02:23:496116 files_to_check=[r'^PRESUBMIT_test\.py$']))
Sam Maiera6e76d72022-02-11 21:43:506117 return results
[email protected]1f7b4172010-01-28 01:17:346118
[email protected]b337cb5b2011-01-23 21:24:056119
Saagar Sanghavifceeaae2020-08-12 16:40:366120def CheckPatchFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506121 problems = [
6122 f.LocalPath() for f in input_api.AffectedFiles()
6123 if f.LocalPath().endswith(('.orig', '.rej'))
6124 ]
6125 # Cargo.toml.orig files are part of third-party crates downloaded from
6126 # crates.io and should be included.
6127 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
6128 if problems:
6129 return [
6130 output_api.PresubmitError("Don't commit .rej and .orig files.",
6131 problems)
6132 ]
6133 else:
6134 return []
[email protected]b8079ae4a2012-12-05 19:56:496135
6136
Saagar Sanghavifceeaae2020-08-12 16:40:366137def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506138 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
6139 macro_re = input_api.re.compile(
6140 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
6141 include_re = input_api.re.compile(r'^#include\s+"build/build_config.h"',
6142 input_api.re.MULTILINE)
6143 extension_re = input_api.re.compile(r'\.[a-z]+$')
6144 errors = []
Bruce Dawsonf7679202022-08-09 20:24:006145 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:506146 for f in input_api.AffectedFiles(include_deletes=False):
Bruce Dawsonf7679202022-08-09 20:24:006147 # The build-config macros are allowed to be used in build_config.h
6148 # without including itself.
6149 if f.LocalPath() == config_h_file:
6150 continue
Sam Maiera6e76d72022-02-11 21:43:506151 if not f.LocalPath().endswith(
6152 ('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
6153 continue
Arthur Sonzognia3dec412024-04-29 12:05:376154
Sam Maiera6e76d72022-02-11 21:43:506155 found_line_number = None
6156 found_macro = None
6157 all_lines = input_api.ReadFile(f, 'r').splitlines()
6158 for line_num, line in enumerate(all_lines):
6159 match = macro_re.search(line)
6160 if match:
6161 found_line_number = line_num
6162 found_macro = match.group(2)
6163 break
6164 if not found_line_number:
6165 continue
Kent Tamura5a8755d2017-06-29 23:37:076166
Sam Maiera6e76d72022-02-11 21:43:506167 found_include_line = -1
6168 for line_num, line in enumerate(all_lines):
6169 if include_re.search(line):
6170 found_include_line = line_num
6171 break
6172 if found_include_line >= 0 and found_include_line < found_line_number:
6173 continue
Kent Tamura5a8755d2017-06-29 23:37:076174
Sam Maiera6e76d72022-02-11 21:43:506175 if not f.LocalPath().endswith('.h'):
6176 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
6177 try:
6178 content = input_api.ReadFile(primary_header_path, 'r')
6179 if include_re.search(content):
6180 continue
6181 except IOError:
6182 pass
6183 errors.append('%s:%d %s macro is used without first including build/'
6184 'build_config.h.' %
6185 (f.LocalPath(), found_line_number, found_macro))
6186 if errors:
6187 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
6188 return []
Kent Tamura5a8755d2017-06-29 23:37:076189
6190
Lei Zhang1c12a22f2021-05-12 11:28:456191def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506192 stl_include_re = input_api.re.compile(r'^#include\s+<('
6193 r'algorithm|'
6194 r'array|'
6195 r'limits|'
6196 r'list|'
6197 r'map|'
6198 r'memory|'
6199 r'queue|'
6200 r'set|'
6201 r'string|'
6202 r'unordered_map|'
6203 r'unordered_set|'
6204 r'utility|'
6205 r'vector)>')
6206 std_namespace_re = input_api.re.compile(r'std::')
6207 errors = []
6208 for f in input_api.AffectedFiles():
6209 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
6210 continue
Lei Zhang1c12a22f2021-05-12 11:28:456211
Sam Maiera6e76d72022-02-11 21:43:506212 uses_std_namespace = False
6213 has_stl_include = False
6214 for line in f.NewContents():
6215 if has_stl_include and uses_std_namespace:
6216 break
Lei Zhang1c12a22f2021-05-12 11:28:456217
Sam Maiera6e76d72022-02-11 21:43:506218 if not has_stl_include and stl_include_re.search(line):
6219 has_stl_include = True
6220 continue
Lei Zhang1c12a22f2021-05-12 11:28:456221
Bruce Dawson4a5579a2022-04-08 17:11:366222 if not uses_std_namespace and (std_namespace_re.search(line)
Daniel Cheng6303eed2025-05-03 00:12:336223 or 'no-std-usage-because-pch-file'
6224 in line):
Sam Maiera6e76d72022-02-11 21:43:506225 uses_std_namespace = True
6226 continue
Lei Zhang1c12a22f2021-05-12 11:28:456227
Sam Maiera6e76d72022-02-11 21:43:506228 if has_stl_include and not uses_std_namespace:
6229 errors.append(
6230 '%s: Includes STL header(s) but does not reference std::' %
6231 f.LocalPath())
6232 if errors:
6233 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
6234 return []
Lei Zhang1c12a22f2021-05-12 11:28:456235
6236
Xiaohan Wang42d96c22022-01-20 17:23:116237def _CheckForDeprecatedOSMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:506238 """Check for sensible looking, totally invalid OS macros."""
6239 preprocessor_statement = input_api.re.compile(r'^\s*#')
6240 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
6241 results = []
6242 for lnum, line in f.ChangedContents():
6243 if preprocessor_statement.search(line):
6244 for match in os_macro.finditer(line):
6245 results.append(
6246 ' %s:%d: %s' %
6247 (f.LocalPath(), lnum, 'defined(OS_' + match.group(1) +
6248 ') -> BUILDFLAG(IS_' + match.group(1) + ')'))
6249 return results
[email protected]b00342e7f2013-03-26 16:21:546250
6251
Xiaohan Wang42d96c22022-01-20 17:23:116252def CheckForDeprecatedOSMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506253 """Check all affected files for invalid OS macros."""
6254 bad_macros = []
Bruce Dawsonf7679202022-08-09 20:24:006255 # The OS_ macros are allowed to be used in build/build_config.h.
6256 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:506257 for f in input_api.AffectedSourceFiles(None):
Bruce Dawsonf7679202022-08-09 20:24:006258 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')) \
6259 and f.LocalPath() != config_h_file:
Sam Maiera6e76d72022-02-11 21:43:506260 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
[email protected]b00342e7f2013-03-26 16:21:546261
Sam Maiera6e76d72022-02-11 21:43:506262 if not bad_macros:
6263 return []
[email protected]b00342e7f2013-03-26 16:21:546264
Sam Maiera6e76d72022-02-11 21:43:506265 return [
6266 output_api.PresubmitError(
6267 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
6268 'defined in build_config.h):', bad_macros)
6269 ]
[email protected]b00342e7f2013-03-26 16:21:546270
lliabraa35bab3932014-10-01 12:16:446271
6272def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:506273 """Check all affected files for invalid "if defined" macros."""
6274 ALWAYS_DEFINED_MACROS = (
6275 "TARGET_CPU_PPC",
6276 "TARGET_CPU_PPC64",
6277 "TARGET_CPU_68K",
6278 "TARGET_CPU_X86",
6279 "TARGET_CPU_ARM",
6280 "TARGET_CPU_MIPS",
6281 "TARGET_CPU_SPARC",
6282 "TARGET_CPU_ALPHA",
6283 "TARGET_IPHONE_SIMULATOR",
6284 "TARGET_OS_EMBEDDED",
6285 "TARGET_OS_IPHONE",
6286 "TARGET_OS_MAC",
6287 "TARGET_OS_UNIX",
6288 "TARGET_OS_WIN32",
6289 )
6290 ifdef_macro = input_api.re.compile(
6291 r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
6292 results = []
6293 for lnum, line in f.ChangedContents():
6294 for match in ifdef_macro.finditer(line):
6295 if match.group(1) in ALWAYS_DEFINED_MACROS:
6296 always_defined = ' %s is always defined. ' % match.group(1)
6297 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
6298 results.append(
6299 ' %s:%d %s\n\t%s' %
6300 (f.LocalPath(), lnum, always_defined, did_you_mean))
6301 return results
lliabraa35bab3932014-10-01 12:16:446302
6303
Saagar Sanghavifceeaae2020-08-12 16:40:366304def CheckForInvalidIfDefinedMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506305 """Check all affected files for invalid "if defined" macros."""
Arthur Sonzogni4fd14fd2024-06-02 18:42:526306 SKIPPED_PATHS = [
6307 'base/allocator/partition_allocator/src/partition_alloc/build_config.h',
6308 'build/build_config.h',
6309 'third_party/abseil-cpp/',
6310 'third_party/sqlite/',
6311 ]
Daniel Cheng6303eed2025-05-03 00:12:336312
Arthur Sonzogni4fd14fd2024-06-02 18:42:526313 def affected_files_filter(f):
6314 # Normalize the local path to Linux-style path separators so that the
6315 # path comparisons work on Windows as well.
Anton Bershanskyi4253349482025-02-11 21:01:276316 path = f.UnixLocalPath()
Arthur Sonzogni4fd14fd2024-06-02 18:42:526317
6318 for skipped_path in SKIPPED_PATHS:
6319 if path.startswith(skipped_path):
6320 return False
6321
6322 return path.endswith(('.h', '.c', '.cc', '.m', '.mm'))
6323
Sam Maiera6e76d72022-02-11 21:43:506324 bad_macros = []
Arthur Sonzogni4fd14fd2024-06-02 18:42:526325 for f in input_api.AffectedSourceFiles(affected_files_filter):
6326 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
lliabraa35bab3932014-10-01 12:16:446327
Sam Maiera6e76d72022-02-11 21:43:506328 if not bad_macros:
6329 return []
lliabraa35bab3932014-10-01 12:16:446330
Sam Maiera6e76d72022-02-11 21:43:506331 return [
6332 output_api.PresubmitError(
6333 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
6334 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
6335 bad_macros)
6336 ]
lliabraa35bab3932014-10-01 12:16:446337
Daniel Cheng6303eed2025-05-03 00:12:336338
Saagar Sanghavifceeaae2020-08-12 16:40:366339def CheckForIPCRules(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506340 """Check for same IPC rules described in
6341 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
6342 """
6343 base_pattern = r'IPC_ENUM_TRAITS\('
6344 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
6345 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
mlamouria82272622014-09-16 18:45:046346
Sam Maiera6e76d72022-02-11 21:43:506347 problems = []
6348 for f in input_api.AffectedSourceFiles(None):
6349 local_path = f.LocalPath()
6350 if not local_path.endswith('.h'):
6351 continue
6352 for line_number, line in f.ChangedContents():
6353 if inclusion_pattern.search(
6354 line) and not comment_pattern.search(line):
6355 problems.append('%s:%d\n %s' %
6356 (local_path, line_number, line.strip()))
mlamouria82272622014-09-16 18:45:046357
Sam Maiera6e76d72022-02-11 21:43:506358 if problems:
6359 return [
6360 output_api.PresubmitPromptWarning(_IPC_ENUM_TRAITS_DEPRECATED,
6361 problems)
6362 ]
6363 else:
6364 return []
mlamouria82272622014-09-16 18:45:046365
[email protected]b00342e7f2013-03-26 16:21:546366
Saagar Sanghavifceeaae2020-08-12 16:40:366367def CheckForLongPathnames(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506368 """Check to make sure no files being submitted have long paths.
6369 This causes issues on Windows.
6370 """
6371 problems = []
6372 for f in input_api.AffectedTestableFiles():
6373 local_path = f.LocalPath()
6374 # Windows has a path limit of 260 characters. Limit path length to 200 so
6375 # that we have some extra for the prefix on dev machines and the bots.
Daniel Cheng6303eed2025-05-03 00:12:336376 if (local_path.startswith('third_party/blink/web_tests/platform/')
6377 and not local_path.startswith(
6378 'third_party/blink/web_tests/platform/win')):
Weizhong Xia8b461f12024-06-21 21:46:336379 # Do not check length of the path for files not used by Windows
6380 continue
Sam Maiera6e76d72022-02-11 21:43:506381 if len(local_path) > 200:
6382 problems.append(local_path)
Stephen Martinis97a394142018-06-07 23:06:056383
Sam Maiera6e76d72022-02-11 21:43:506384 if problems:
6385 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
6386 else:
6387 return []
Stephen Martinis97a394142018-06-07 23:06:056388
6389
Saagar Sanghavifceeaae2020-08-12 16:40:366390def CheckForIncludeGuards(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506391 """Check that header files have proper guards against multiple inclusion.
6392 If a file should not have such guards (and it probably should) then it
Bruce Dawson4a5579a2022-04-08 17:11:366393 should include the string "no-include-guard-because-multiply-included" or
6394 "no-include-guard-because-pch-file".
Sam Maiera6e76d72022-02-11 21:43:506395 """
Daniel Bratell8ba52722018-03-02 16:06:146396
Sam Maiera6e76d72022-02-11 21:43:506397 def is_chromium_header_file(f):
6398 # We only check header files under the control of the Chromium
mikt84d6c712024-03-27 13:29:036399 # project. This excludes:
6400 # - third_party/*, except blink.
6401 # - base/allocator/partition_allocator/: PartitionAlloc is a standalone
6402 # library used outside of Chrome. Includes are referenced from its
6403 # own base directory. It has its own `CheckForIncludeGuards`
6404 # PRESUBMIT.py check.
6405 # - *_message_generator.h: They use include guards in a special,
6406 # non-typical way.
Sam Maiera6e76d72022-02-11 21:43:506407 file_with_path = input_api.os_path.normpath(f.LocalPath())
6408 return (file_with_path.endswith('.h')
6409 and not file_with_path.endswith('_message_generator.h')
Bruce Dawson4c4c2922022-05-02 18:07:336410 and not file_with_path.endswith('com_imported_mstscax.h')
Peter Kasting66c1f752024-12-02 15:28:376411 and not file_with_path.startswith(
6412 input_api.os_path.join('base', 'allocator',
6413 'partition_allocator'))
Sam Maiera6e76d72022-02-11 21:43:506414 and (not file_with_path.startswith('third_party')
6415 or file_with_path.startswith(
6416 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:146417
Sam Maiera6e76d72022-02-11 21:43:506418 def replace_special_with_underscore(string):
6419 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:146420
Sam Maiera6e76d72022-02-11 21:43:506421 errors = []
Daniel Bratell8ba52722018-03-02 16:06:146422
Sam Maiera6e76d72022-02-11 21:43:506423 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
6424 guard_name = None
6425 guard_line_number = None
6426 seen_guard_end = False
Lei Zhangd84f9512024-05-28 19:43:306427 bypass_checks_at_end_of_file = False
Daniel Bratell8ba52722018-03-02 16:06:146428
Sam Maiera6e76d72022-02-11 21:43:506429 file_with_path = input_api.os_path.normpath(f.LocalPath())
6430 base_file_name = input_api.os_path.splitext(
6431 input_api.os_path.basename(file_with_path))[0]
6432 upper_base_file_name = base_file_name.upper()
Daniel Bratell8ba52722018-03-02 16:06:146433
Sam Maiera6e76d72022-02-11 21:43:506434 expected_guard = replace_special_with_underscore(
6435 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:146436
Sam Maiera6e76d72022-02-11 21:43:506437 # For "path/elem/file_name.h" we should really only accept
6438 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
6439 # are too many (1000+) files with slight deviations from the
6440 # coding style. The most important part is that the include guard
6441 # is there, and that it's unique, not the name so this check is
6442 # forgiving for existing files.
6443 #
6444 # As code becomes more uniform, this could be made stricter.
Daniel Bratell8ba52722018-03-02 16:06:146445
Sam Maiera6e76d72022-02-11 21:43:506446 guard_name_pattern_list = [
6447 # Anything with the right suffix (maybe with an extra _).
6448 r'\w+_H__?',
Daniel Bratell8ba52722018-03-02 16:06:146449
Sam Maiera6e76d72022-02-11 21:43:506450 # To cover include guards with old Blink style.
6451 r'\w+_h',
Daniel Bratell8ba52722018-03-02 16:06:146452
Sam Maiera6e76d72022-02-11 21:43:506453 # Anything including the uppercase name of the file.
6454 r'\w*' + input_api.re.escape(
6455 replace_special_with_underscore(upper_base_file_name)) +
6456 r'\w*',
6457 ]
6458 guard_name_pattern = '|'.join(guard_name_pattern_list)
6459 guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
6460 guard_name_pattern + ')')
Daniel Bratell8ba52722018-03-02 16:06:146461
Sam Maiera6e76d72022-02-11 21:43:506462 for line_number, line in enumerate(f.NewContents()):
Bruce Dawson4a5579a2022-04-08 17:11:366463 if ('no-include-guard-because-multiply-included' in line
6464 or 'no-include-guard-because-pch-file' in line):
Lei Zhangd84f9512024-05-28 19:43:306465 bypass_checks_at_end_of_file = True
Sam Maiera6e76d72022-02-11 21:43:506466 break
Daniel Bratell8ba52722018-03-02 16:06:146467
Sam Maiera6e76d72022-02-11 21:43:506468 if guard_name is None:
6469 match = guard_pattern.match(line)
6470 if match:
6471 guard_name = match.group(1)
6472 guard_line_number = line_number
Daniel Bratell8ba52722018-03-02 16:06:146473
Sam Maiera6e76d72022-02-11 21:43:506474 # We allow existing files to use include guards whose names
6475 # don't match the chromium style guide, but new files should
6476 # get it right.
Bruce Dawson6cc154e2022-04-12 20:39:496477 if guard_name != expected_guard:
Bruce Dawson95eb7562022-09-14 15:27:166478 if f.Action() == 'A': # If file was just 'A'dded
Sam Maiera6e76d72022-02-11 21:43:506479 errors.append(
6480 output_api.PresubmitPromptWarning(
6481 'Header using the wrong include guard name %s'
6482 % guard_name, [
6483 '%s:%d' %
6484 (f.LocalPath(), line_number + 1)
6485 ], 'Expected: %r\nFound: %r' %
6486 (expected_guard, guard_name)))
6487 else:
6488 # The line after #ifndef should have a #define of the same name.
6489 if line_number == guard_line_number + 1:
6490 expected_line = '#define %s' % guard_name
6491 if line != expected_line:
6492 errors.append(
6493 output_api.PresubmitPromptWarning(
6494 'Missing "%s" for include guard' %
6495 expected_line,
6496 ['%s:%d' % (f.LocalPath(), line_number + 1)],
6497 'Expected: %r\nGot: %r' %
6498 (expected_line, line)))
Daniel Bratell8ba52722018-03-02 16:06:146499
Sam Maiera6e76d72022-02-11 21:43:506500 if not seen_guard_end and line == '#endif // %s' % guard_name:
6501 seen_guard_end = True
6502 elif seen_guard_end:
6503 if line.strip() != '':
6504 errors.append(
6505 output_api.PresubmitPromptWarning(
6506 'Include guard %s not covering the whole file'
6507 % (guard_name), [f.LocalPath()]))
6508 break # Nothing else to check and enough to warn once.
Daniel Bratell8ba52722018-03-02 16:06:146509
Lei Zhangd84f9512024-05-28 19:43:306510 if bypass_checks_at_end_of_file:
6511 continue
6512
Sam Maiera6e76d72022-02-11 21:43:506513 if guard_name is None:
6514 errors.append(
6515 output_api.PresubmitPromptWarning(
Bruce Dawson32114b62022-04-11 16:45:496516 'Missing include guard in %s\n'
Sam Maiera6e76d72022-02-11 21:43:506517 'Recommended name: %s\n'
6518 'This check can be disabled by having the string\n'
Bruce Dawson4a5579a2022-04-08 17:11:366519 '"no-include-guard-because-multiply-included" or\n'
Daniel Cheng6303eed2025-05-03 00:12:336520 '"no-include-guard-because-pch-file" in the header.' %
6521 (f.LocalPath(), expected_guard)))
Lei Zhangd84f9512024-05-28 19:43:306522 elif not seen_guard_end:
6523 errors.append(
6524 output_api.PresubmitPromptWarning(
6525 'Incorrect or missing include guard #endif in %s\n'
Daniel Cheng6303eed2025-05-03 00:12:336526 'Recommended #endif comment: // %s' %
6527 (f.LocalPath(), expected_guard)))
Sam Maiera6e76d72022-02-11 21:43:506528
6529 return errors
Daniel Bratell8ba52722018-03-02 16:06:146530
6531
Saagar Sanghavifceeaae2020-08-12 16:40:366532def CheckForWindowsLineEndings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506533 """Check source code and known ascii text files for Windows style line
6534 endings.
6535 """
Bruce Dawson5efbdc652022-04-11 19:29:516536 known_text_files = r'.*\.(txt|html|htm|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:236537
dpapadfd421fb2025-02-13 00:47:326538 _WEBUI_FILES_EXTENSIONS = r'\.(css|html|js|ts|svg)$'
6539
Sam Maiera6e76d72022-02-11 21:43:506540 file_inclusion_pattern = (known_text_files,
6541 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
dpapadfd421fb2025-02-13 00:47:326542 r'.+%s' % _HEADER_EXTENSIONS,
6543 r'.+%s' % _WEBUI_FILES_EXTENSIONS)
6544
6545 # Exclude folder that contains .ts files that are actually binary video
6546 # format and not TypeScript.
6547 file_exclusion_pattern = (r'media/test/data/')
mostynbb639aca52015-01-07 20:31:236548
Sam Maiera6e76d72022-02-11 21:43:506549 problems = []
6550 source_file_filter = lambda f: input_api.FilterSourceFile(
Daniel Cheng6303eed2025-05-03 00:12:336551 f,
6552 files_to_check=file_inclusion_pattern,
dpapadfd421fb2025-02-13 00:47:326553 files_to_skip=file_exclusion_pattern)
Sam Maiera6e76d72022-02-11 21:43:506554 for f in input_api.AffectedSourceFiles(source_file_filter):
Bruce Dawson5efbdc652022-04-11 19:29:516555 # Ignore test files that contain crlf intentionally.
6556 if f.LocalPath().endswith('crlf.txt'):
Daniel Chenga37c03db2022-05-12 17:20:346557 continue
Sam Maiera6e76d72022-02-11 21:43:506558 include_file = False
6559 for line in input_api.ReadFile(f, 'r').splitlines(True):
6560 if line.endswith('\r\n'):
6561 include_file = True
6562 if include_file:
6563 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:236564
Sam Maiera6e76d72022-02-11 21:43:506565 if problems:
6566 return [
6567 output_api.PresubmitPromptWarning(
6568 'Are you sure that you want '
6569 'these files to contain Windows style line endings?\n' +
6570 '\n'.join(problems))
6571 ]
mostynbb639aca52015-01-07 20:31:236572
Sam Maiera6e76d72022-02-11 21:43:506573 return []
6574
mostynbb639aca52015-01-07 20:31:236575
Evan Stade6cfc964c12021-05-18 20:21:166576def CheckIconFilesForLicenseHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506577 """Check that .icon files (which are fragments of C++) have license headers.
6578 """
Evan Stade6cfc964c12021-05-18 20:21:166579
Sam Maiera6e76d72022-02-11 21:43:506580 icon_files = (r'.*\.icon$', )
Evan Stade6cfc964c12021-05-18 20:21:166581
Sam Maiera6e76d72022-02-11 21:43:506582 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
6583 return input_api.canned_checks.CheckLicense(input_api,
6584 output_api,
6585 source_file_filter=icons)
6586
Evan Stade6cfc964c12021-05-18 20:21:166587
Jose Magana2b456f22021-03-09 23:26:406588def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506589 """Check source code for use of Chrome App technologies being
6590 deprecated.
6591 """
Jose Magana2b456f22021-03-09 23:26:406592
Sam Maiera6e76d72022-02-11 21:43:506593 def _CheckForDeprecatedTech(input_api,
6594 output_api,
6595 detection_list,
6596 files_to_check=None,
6597 files_to_skip=None):
Jose Magana2b456f22021-03-09 23:26:406598
Sam Maiera6e76d72022-02-11 21:43:506599 if (files_to_check or files_to_skip):
6600 source_file_filter = lambda f: input_api.FilterSourceFile(
6601 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
6602 else:
6603 source_file_filter = None
6604
6605 problems = []
6606
6607 for f in input_api.AffectedSourceFiles(source_file_filter):
6608 if f.Action() == 'D':
6609 continue
6610 for _, line in f.ChangedContents():
6611 if any(detect in line for detect in detection_list):
6612 problems.append(f.LocalPath())
6613
6614 return problems
6615
6616 # to avoid this presubmit script triggering warnings
6617 files_to_skip = ['PRESUBMIT.py', 'PRESUBMIT_test.py']
Jose Magana2b456f22021-03-09 23:26:406618
6619 problems = []
6620
Sam Maiera6e76d72022-02-11 21:43:506621 # NMF: any files with extensions .nmf or NMF
6622 _NMF_FILES = r'\.(nmf|NMF)$'
6623 problems += _CheckForDeprecatedTech(
6624 input_api,
6625 output_api,
6626 detection_list=[''], # any change to the file will trigger warning
6627 files_to_check=[r'.+%s' % _NMF_FILES])
Jose Magana2b456f22021-03-09 23:26:406628
Sam Maiera6e76d72022-02-11 21:43:506629 # MANIFEST: any manifest.json that in its diff includes "app":
6630 _MANIFEST_FILES = r'(manifest\.json)$'
6631 problems += _CheckForDeprecatedTech(
6632 input_api,
6633 output_api,
6634 detection_list=['"app":'],
6635 files_to_check=[r'.*%s' % _MANIFEST_FILES])
Jose Magana2b456f22021-03-09 23:26:406636
Sam Maiera6e76d72022-02-11 21:43:506637 # NaCl / PNaCl: any file that in its diff contains the strings in the list
6638 problems += _CheckForDeprecatedTech(
6639 input_api,
6640 output_api,
6641 detection_list=['config=nacl', 'enable-nacl', 'cpu=pnacl', 'nacl_io'],
Bruce Dawson40fece62022-09-16 19:58:316642 files_to_skip=files_to_skip + [r"^native_client_sdk/"])
Jose Magana2b456f22021-03-09 23:26:406643
Gao Shenga79ebd42022-08-08 17:25:596644 # PPAPI: any C/C++ file that in its diff includes a ppapi library
Sam Maiera6e76d72022-02-11 21:43:506645 problems += _CheckForDeprecatedTech(
6646 input_api,
6647 output_api,
6648 detection_list=['#include "ppapi', '#include <ppapi'],
6649 files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,
6650 r'.+%s' % _IMPLEMENTATION_EXTENSIONS),
Bruce Dawson40fece62022-09-16 19:58:316651 files_to_skip=[r"^ppapi/"])
Jose Magana2b456f22021-03-09 23:26:406652
Sam Maiera6e76d72022-02-11 21:43:506653 if problems:
6654 return [
6655 output_api.PresubmitPromptWarning(
6656 'You are adding/modifying code'
6657 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
6658 ' PNaCl, PPAPI). See this blog post for more details:\n'
6659 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
6660 'and this documentation for options to replace these technologies:\n'
6661 'https://developer.chrome.com/docs/apps/migration/\n' +
6662 '\n'.join(problems))
6663 ]
Jose Magana2b456f22021-03-09 23:26:406664
Sam Maiera6e76d72022-02-11 21:43:506665 return []
Jose Magana2b456f22021-03-09 23:26:406666
mostynbb639aca52015-01-07 20:31:236667
Saagar Sanghavifceeaae2020-08-12 16:40:366668def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
Sam Maiera6e76d72022-02-11 21:43:506669 """Checks that all source files use SYSLOG properly."""
6670 syslog_files = []
6671 for f in input_api.AffectedSourceFiles(src_file_filter):
6672 for line_number, line in f.ChangedContents():
6673 if 'SYSLOG' in line:
6674 syslog_files.append(f.LocalPath() + ':' + str(line_number))
pastarmovj032ba5bc2017-01-12 10:41:566675
Sam Maiera6e76d72022-02-11 21:43:506676 if syslog_files:
6677 return [
6678 output_api.PresubmitPromptWarning(
6679 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
6680 ' calls.\nFiles to check:\n',
6681 items=syslog_files)
6682 ]
6683 return []
pastarmovj89f7ee12016-09-20 14:58:136684
6685
[email protected]1f7b4172010-01-28 01:17:346686def CheckChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506687 if input_api.version < [2, 0, 0]:
6688 return [
6689 output_api.PresubmitError(
6690 "Your depot_tools is out of date. "
6691 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
6692 "but your version is %d.%d.%d" % tuple(input_api.version))
6693 ]
6694 results = []
6695 results.extend(
6696 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
6697 return results
[email protected]ca8d19842009-02-19 16:33:126698
6699
6700def CheckChangeOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506701 if input_api.version < [2, 0, 0]:
6702 return [
6703 output_api.PresubmitError(
6704 "Your depot_tools is out of date. "
6705 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
6706 "but your version is %d.%d.%d" % tuple(input_api.version))
6707 ]
Saagar Sanghavifceeaae2020-08-12 16:40:366708
Sam Maiera6e76d72022-02-11 21:43:506709 results = []
6710 # Make sure the tree is 'open'.
6711 results.extend(
6712 input_api.canned_checks.CheckTreeIsOpen(
6713 input_api,
6714 output_api,
6715 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:276716
Sam Maiera6e76d72022-02-11 21:43:506717 results.extend(
6718 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
6719 results.extend(
6720 input_api.canned_checks.CheckChangeHasBugField(input_api, output_api))
6721 results.extend(
6722 input_api.canned_checks.CheckChangeHasNoUnwantedTags(
6723 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:506724 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146725
6726
Saagar Sanghavifceeaae2020-08-12 16:40:366727def CheckStrings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506728 """Check string ICU syntax validity and if translation screenshots exist."""
6729 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
6730 # footer is set to true.
6731 git_footers = input_api.change.GitFootersFromDescription()
6732 skip_screenshot_check_footer = [
6733 footer.lower() for footer in git_footers.get(
6734 u'Skip-Translation-Screenshots-Check', [])
6735 ]
6736 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:026737
Sam Maiera6e76d72022-02-11 21:43:506738 import os
6739 import re
6740 import sys
6741 from io import StringIO
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146742
Sam Maiera6e76d72022-02-11 21:43:506743 new_or_added_paths = set(f.LocalPath() for f in input_api.AffectedFiles()
6744 if (f.Action() == 'A' or f.Action() == 'M'))
6745 removed_paths = set(f.LocalPath()
6746 for f in input_api.AffectedFiles(include_deletes=True)
6747 if f.Action() == 'D')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146748
Sam Maiera6e76d72022-02-11 21:43:506749 affected_grds = [
6750 f for f in input_api.AffectedFiles()
6751 if f.LocalPath().endswith(('.grd', '.grdp'))
6752 ]
6753 affected_grds = [
6754 f for f in affected_grds if not 'testdata' in f.LocalPath()
6755 ]
6756 if not affected_grds:
6757 return []
meacer8c0d3832019-12-26 21:46:166758
Sam Maiera6e76d72022-02-11 21:43:506759 affected_png_paths = [
Andrew Grieve713b89b2024-10-15 20:20:086760 f.LocalPath() for f in input_api.AffectedFiles()
6761 if f.LocalPath().endswith('.png')
Sam Maiera6e76d72022-02-11 21:43:506762 ]
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146763
Sam Maiera6e76d72022-02-11 21:43:506764 # Check for screenshots. Developers can upload screenshots using
6765 # tools/translation/upload_screenshots.py which finds and uploads
6766 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
6767 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
6768 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
6769 #
6770 # The logic here is as follows:
6771 #
6772 # - If the CL has a .png file under the screenshots directory for a grd
6773 # file, warn the developer. Actual images should never be checked into the
6774 # Chrome repo.
6775 #
6776 # - If the CL contains modified or new messages in grd files and doesn't
6777 # contain the corresponding .sha1 files, warn the developer to add images
6778 # and upload them via tools/translation/upload_screenshots.py.
6779 #
6780 # - If the CL contains modified or new messages in grd files and the
6781 # corresponding .sha1 files, everything looks good.
6782 #
6783 # - If the CL contains removed messages in grd files but the corresponding
6784 # .sha1 files aren't removed, warn the developer to remove them.
6785 unnecessary_screenshots = []
Jens Mueller054652c2023-05-10 15:12:306786 invalid_sha1 = []
Sam Maiera6e76d72022-02-11 21:43:506787 missing_sha1 = []
Bruce Dawson55776c42022-12-09 17:23:476788 missing_sha1_modified = []
Sam Maiera6e76d72022-02-11 21:43:506789 unnecessary_sha1_files = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146790
Sam Maiera6e76d72022-02-11 21:43:506791 # This checks verifies that the ICU syntax of messages this CL touched is
6792 # valid, and reports any found syntax errors.
6793 # Without this presubmit check, ICU syntax errors in Chromium strings can land
6794 # without developers being aware of them. Later on, such ICU syntax errors
6795 # break message extraction for translation, hence would block Chromium
6796 # translations until they are fixed.
6797 icu_syntax_errors = []
Jens Mueller054652c2023-05-10 15:12:306798 sha1_pattern = input_api.re.compile(r'^[a-fA-F0-9]{40}$',
6799 input_api.re.MULTILINE)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146800
Sam Maiera6e76d72022-02-11 21:43:506801 def _CheckScreenshotAdded(screenshots_dir, message_id):
6802 sha1_path = input_api.os_path.join(screenshots_dir,
6803 message_id + '.png.sha1')
6804 if sha1_path not in new_or_added_paths:
6805 missing_sha1.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306806 elif not _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256807 invalid_sha1.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146808
Bruce Dawson55776c42022-12-09 17:23:476809 def _CheckScreenshotModified(screenshots_dir, message_id):
6810 sha1_path = input_api.os_path.join(screenshots_dir,
6811 message_id + '.png.sha1')
6812 if sha1_path not in new_or_added_paths:
6813 missing_sha1_modified.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306814 elif not _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256815 invalid_sha1.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306816
6817 def _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256818 return sha1_pattern.search(
6819 next("\n".join(f.NewContents()) for f in input_api.AffectedFiles()
6820 if f.LocalPath() == sha1_path))
Bruce Dawson55776c42022-12-09 17:23:476821
Sam Maiera6e76d72022-02-11 21:43:506822 def _CheckScreenshotRemoved(screenshots_dir, message_id):
6823 sha1_path = input_api.os_path.join(screenshots_dir,
6824 message_id + '.png.sha1')
6825 if input_api.os_path.exists(
6826 sha1_path) and sha1_path not in removed_paths:
6827 unnecessary_sha1_files.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146828
Sam Maiera6e76d72022-02-11 21:43:506829 def _ValidateIcuSyntax(text, level, signatures):
6830 """Validates ICU syntax of a text string.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146831
Sam Maiera6e76d72022-02-11 21:43:506832 Check if text looks similar to ICU and checks for ICU syntax correctness
6833 in this case. Reports various issues with ICU syntax and values of
6834 variants. Supports checking of nested messages. Accumulate information of
6835 each ICU messages found in the text for further checking.
Rainhard Findlingfc31844c52020-05-15 09:58:266836
Sam Maiera6e76d72022-02-11 21:43:506837 Args:
6838 text: a string to check.
6839 level: a number of current nesting level.
6840 signatures: an accumulator, a list of tuple of (level, variable,
6841 kind, variants).
Rainhard Findlingfc31844c52020-05-15 09:58:266842
Sam Maiera6e76d72022-02-11 21:43:506843 Returns:
6844 None if a string is not ICU or no issue detected.
6845 A tuple of (message, start index, end index) if an issue detected.
6846 """
6847 valid_types = {
Daniel Cheng6303eed2025-05-03 00:12:336848 'plural': (frozenset([
6849 '=0', '=1', '=2', '=3', 'zero', 'one', 'two', 'few', 'many',
6850 'other'
6851 ]), frozenset(['=1', 'other'])),
6852 'selectordinal': (frozenset([
6853 '=0', '=1', '=2', '=3', 'zero', 'one', 'two', 'few', 'many',
6854 'other'
6855 ]), frozenset(['one', 'other'])),
Sam Maiera6e76d72022-02-11 21:43:506856 'select': (frozenset(), frozenset(['other'])),
6857 }
Rainhard Findlingfc31844c52020-05-15 09:58:266858
Sam Maiera6e76d72022-02-11 21:43:506859 # Check if the message looks like an attempt to use ICU
6860 # plural. If yes - check if its syntax strictly matches ICU format.
6861 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b',
6862 text)
6863 if not like:
6864 signatures.append((level, None, None, None))
6865 return
Rainhard Findlingfc31844c52020-05-15 09:58:266866
Sam Maiera6e76d72022-02-11 21:43:506867 # Check for valid prefix and suffix
6868 m = re.match(
6869 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
6870 r'(plural|selectordinal|select),\s*'
6871 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
6872 if not m:
6873 return (('This message looks like an ICU plural, '
6874 'but does not follow ICU syntax.'), like.start(),
6875 like.end())
6876 starting, variable, kind, variant_pairs = m.groups()
6877 variants, depth, last_pos = _ParseIcuVariants(variant_pairs,
6878 m.start(4))
6879 if depth:
6880 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
6881 len(text))
6882 first = text[0]
6883 ending = text[last_pos:]
6884 if not starting:
6885 return ('Invalid ICU format. No initial opening bracket',
6886 last_pos - 1, last_pos)
6887 if not ending or '}' not in ending:
6888 return ('Invalid ICU format. No final closing bracket',
6889 last_pos - 1, last_pos)
6890 elif first != '{':
6891 return ((
6892 'Invalid ICU format. Extra characters at the start of a complex '
6893 'message (go/icu-message-migration): "%s"') % starting, 0,
6894 len(starting))
6895 elif ending != '}':
6896 return ((
6897 'Invalid ICU format. Extra characters at the end of a complex '
6898 'message (go/icu-message-migration): "%s"') % ending,
6899 last_pos - 1, len(text) - 1)
6900 if kind not in valid_types:
6901 return (('Unknown ICU message type %s. '
6902 'Valid types are: plural, select, selectordinal') % kind,
6903 0, 0)
6904 known, required = valid_types[kind]
6905 defined_variants = set()
6906 for variant, variant_range, value, value_range in variants:
6907 start, end = variant_range
6908 if variant in defined_variants:
6909 return ('Variant "%s" is defined more than once' % variant,
6910 start, end)
6911 elif known and variant not in known:
6912 return ('Variant "%s" is not valid for %s message' %
6913 (variant, kind), start, end)
6914 defined_variants.add(variant)
6915 # Check for nested structure
6916 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
6917 if res:
6918 return (res[0], res[1] + value_range[0] + 1,
6919 res[2] + value_range[0] + 1)
6920 missing = required - defined_variants
6921 if missing:
6922 return ('Required variants missing: %s' % ', '.join(missing), 0,
6923 len(text))
6924 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:266925
Sam Maiera6e76d72022-02-11 21:43:506926 def _ParseIcuVariants(text, offset=0):
6927 """Parse variants part of ICU complex message.
Rainhard Findlingfc31844c52020-05-15 09:58:266928
Sam Maiera6e76d72022-02-11 21:43:506929 Builds a tuple of variant names and values, as well as
6930 their offsets in the input string.
Rainhard Findlingfc31844c52020-05-15 09:58:266931
Sam Maiera6e76d72022-02-11 21:43:506932 Args:
6933 text: a string to parse
6934 offset: additional offset to add to positions in the text to get correct
6935 position in the complete ICU string.
Rainhard Findlingfc31844c52020-05-15 09:58:266936
Sam Maiera6e76d72022-02-11 21:43:506937 Returns:
6938 List of tuples, each tuple consist of four fields: variant name,
6939 variant name span (tuple of two integers), variant value, value
6940 span (tuple of two integers).
6941 """
6942 depth, start, end = 0, -1, -1
6943 variants = []
6944 key = None
6945 for idx, char in enumerate(text):
6946 if char == '{':
6947 if not depth:
6948 start = idx
6949 chunk = text[end + 1:start]
6950 key = chunk.strip()
6951 pos = offset + end + 1 + chunk.find(key)
6952 span = (pos, pos + len(key))
6953 depth += 1
6954 elif char == '}':
6955 if not depth:
6956 return variants, depth, offset + idx
6957 depth -= 1
6958 if not depth:
6959 end = idx
6960 variants.append((key, span, text[start:end + 1],
6961 (offset + start, offset + end + 1)))
6962 return variants, depth, offset + end + 1
Rainhard Findlingfc31844c52020-05-15 09:58:266963
Terrence Reilly313f44ff2025-01-22 15:10:146964 old_sys_path = sys.path
Sam Maiera6e76d72022-02-11 21:43:506965 try:
Sam Maiera6e76d72022-02-11 21:43:506966 sys.path = sys.path + [
6967 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
6968 'translation')
6969 ]
6970 from helper import grd_helper
6971 finally:
6972 sys.path = old_sys_path
Rainhard Findlingfc31844c52020-05-15 09:58:266973
Sam Maiera6e76d72022-02-11 21:43:506974 for f in affected_grds:
6975 file_path = f.LocalPath()
6976 old_id_to_msg_map = {}
6977 new_id_to_msg_map = {}
6978 # Note that this code doesn't check if the file has been deleted. This is
6979 # OK because it only uses the old and new file contents and doesn't load
6980 # the file via its path.
6981 # It's also possible that a file's content refers to a renamed or deleted
6982 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
6983 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
6984 # .grdp files.
6985 if file_path.endswith('.grdp'):
6986 if f.OldContents():
6987 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6988 '\n'.join(f.OldContents()))
6989 if f.NewContents():
6990 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6991 '\n'.join(f.NewContents()))
6992 else:
6993 file_dir = input_api.os_path.dirname(file_path) or '.'
6994 if f.OldContents():
6995 old_id_to_msg_map = grd_helper.GetGrdMessages(
6996 StringIO('\n'.join(f.OldContents())), file_dir)
6997 if f.NewContents():
6998 new_id_to_msg_map = grd_helper.GetGrdMessages(
6999 StringIO('\n'.join(f.NewContents())), file_dir)
Rainhard Findlingfc31844c52020-05-15 09:58:267000
Sam Maiera6e76d72022-02-11 21:43:507001 grd_name, ext = input_api.os_path.splitext(
7002 input_api.os_path.basename(file_path))
7003 screenshots_dir = input_api.os_path.join(
7004 input_api.os_path.dirname(file_path),
7005 grd_name + ext.replace('.', '_'))
Rainhard Findlingfc31844c52020-05-15 09:58:267006
Sam Maiera6e76d72022-02-11 21:43:507007 # Compute added, removed and modified message IDs.
7008 old_ids = set(old_id_to_msg_map)
7009 new_ids = set(new_id_to_msg_map)
7010 added_ids = new_ids - old_ids
7011 removed_ids = old_ids - new_ids
7012 modified_ids = set([])
7013 for key in old_ids.intersection(new_ids):
Daniel Cheng6303eed2025-05-03 00:12:337014 if (old_id_to_msg_map[key].ContentsAsXml('', True)
7015 != new_id_to_msg_map[key].ContentsAsXml('', True)):
Sam Maiera6e76d72022-02-11 21:43:507016 # The message content itself changed. Require an updated screenshot.
7017 modified_ids.add(key)
7018 elif old_id_to_msg_map[key].attrs['meaning'] != \
7019 new_id_to_msg_map[key].attrs['meaning']:
Jens Mueller054652c2023-05-10 15:12:307020 # The message meaning changed. We later check for a screenshot.
7021 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147022
Sam Maiera6e76d72022-02-11 21:43:507023 if run_screenshot_check:
7024 # Check the screenshot directory for .png files. Warn if there is any.
7025 for png_path in affected_png_paths:
7026 if png_path.startswith(screenshots_dir):
7027 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147028
Sam Maiera6e76d72022-02-11 21:43:507029 for added_id in added_ids:
7030 _CheckScreenshotAdded(screenshots_dir, added_id)
Rainhard Findlingd8d04372020-08-13 13:30:097031
Sam Maiera6e76d72022-02-11 21:43:507032 for modified_id in modified_ids:
Bruce Dawson55776c42022-12-09 17:23:477033 _CheckScreenshotModified(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147034
Sam Maiera6e76d72022-02-11 21:43:507035 for removed_id in removed_ids:
7036 _CheckScreenshotRemoved(screenshots_dir, removed_id)
7037
7038 # Check new and changed strings for ICU syntax errors.
7039 for key in added_ids.union(modified_ids):
7040 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
7041 err = _ValidateIcuSyntax(msg, 0, [])
7042 if err is not None:
7043 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
7044
7045 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:267046 if run_screenshot_check:
Sam Maiera6e76d72022-02-11 21:43:507047 if unnecessary_screenshots:
7048 results.append(
7049 output_api.PresubmitError(
7050 'Do not include actual screenshots in the changelist. Run '
7051 'tools/translate/upload_screenshots.py to upload them instead:',
7052 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147053
Sam Maiera6e76d72022-02-11 21:43:507054 if missing_sha1:
7055 results.append(
7056 output_api.PresubmitError(
Bruce Dawson55776c42022-12-09 17:23:477057 'You are adding UI strings.\n'
Sam Maiera6e76d72022-02-11 21:43:507058 'To ensure the best translations, take screenshots of the relevant UI '
7059 '(https://g.co/chrome/translation) and add these files to your '
7060 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147061
Jens Mueller054652c2023-05-10 15:12:307062 if invalid_sha1:
7063 results.append(
7064 output_api.PresubmitError(
7065 'The following files do not seem to contain valid sha1 hashes. '
7066 'Make sure they contain hashes created by '
Daniel Cheng6303eed2025-05-03 00:12:337067 'tools/translate/upload_screenshots.py:',
7068 sorted(invalid_sha1)))
Jens Mueller054652c2023-05-10 15:12:307069
Bruce Dawson55776c42022-12-09 17:23:477070 if missing_sha1_modified:
7071 results.append(
7072 output_api.PresubmitError(
7073 'You are modifying UI strings or their meanings.\n'
7074 'To ensure the best translations, take screenshots of the relevant UI '
7075 '(https://g.co/chrome/translation) and add these files to your '
7076 'changelist:', sorted(missing_sha1_modified)))
7077
Sam Maiera6e76d72022-02-11 21:43:507078 if unnecessary_sha1_files:
7079 results.append(
7080 output_api.PresubmitError(
7081 'You removed strings associated with these files. Remove:',
7082 sorted(unnecessary_sha1_files)))
7083 else:
7084 results.append(
7085 output_api.PresubmitPromptOrNotify('Skipping translation '
7086 'screenshots check.'))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147087
Sam Maiera6e76d72022-02-11 21:43:507088 if icu_syntax_errors:
7089 results.append(
7090 output_api.PresubmitPromptWarning(
7091 'ICU syntax errors were found in the following strings (problems or '
7092 'feedback? Contact [email protected]):',
7093 items=icu_syntax_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:267094
Sam Maiera6e76d72022-02-11 21:43:507095 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:127096
7097
Daniel Cheng6303eed2025-05-03 00:12:337098def CheckTranslationExpectations(input_api,
7099 output_api,
7100 repo_root=None,
7101 translation_expectations_path=None,
7102 grd_files=None):
Sam Maiera6e76d72022-02-11 21:43:507103 import sys
7104 affected_grds = [
7105 f for f in input_api.AffectedFiles()
7106 if (f.LocalPath().endswith('.grd') or f.LocalPath().endswith('.grdp'))
7107 ]
7108 if not affected_grds:
7109 return []
7110
Terrence Reilly313f44ff2025-01-22 15:10:147111 old_sys_path = sys.path
Sam Maiera6e76d72022-02-11 21:43:507112 try:
Sam Maiera6e76d72022-02-11 21:43:507113 sys.path = sys.path + [
7114 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
7115 'translation')
7116 ]
Terrence Reilly313f44ff2025-01-22 15:10:147117 sys.path = sys.path + [
7118 input_api.os_path.join(input_api.PresubmitLocalPath(),
7119 'third_party', 'depot_tools')
7120 ]
Sam Maiera6e76d72022-02-11 21:43:507121 from helper import git_helper
7122 from helper import translation_helper
Terrence Reilly313f44ff2025-01-22 15:10:147123 import gclient_utils
Sam Maiera6e76d72022-02-11 21:43:507124 finally:
7125 sys.path = old_sys_path
7126
7127 # Check that translation expectations can be parsed and we can get a list of
7128 # translatable grd files. |repo_root| and |translation_expectations_path| are
7129 # only passed by tests.
7130 if not repo_root:
7131 repo_root = input_api.PresubmitLocalPath()
7132 if not translation_expectations_path:
7133 translation_expectations_path = input_api.os_path.join(
7134 repo_root, 'tools', 'gritsettings', 'translation_expectations.pyl')
Terrence Reilly313f44ff2025-01-22 15:10:147135 is_cog = gclient_utils.IsEnvCog()
7136 # Git is not available in cog workspaces.
7137 if not grd_files and not is_cog:
Sam Maiera6e76d72022-02-11 21:43:507138 grd_files = git_helper.list_grds_in_repository(repo_root)
Terrence Reilly313f44ff2025-01-22 15:10:147139 if not grd_files:
7140 grd_files = []
Sam Maiera6e76d72022-02-11 21:43:507141
7142 # Ignore bogus grd files used only for testing
Gao Shenga79ebd42022-08-08 17:25:597143 # ui/webui/resources/tools/generate_grd.py.
Sam Maiera6e76d72022-02-11 21:43:507144 ignore_path = input_api.os_path.join('ui', 'webui', 'resources', 'tools',
7145 'tests')
7146 grd_files = [p for p in grd_files if ignore_path not in p]
7147
Ben Mason5d4c3242025-04-15 20:28:377148 # Ensure no duplicate basenames.
7149 basename_to_src_paths = {}
7150 for grd_path in grd_files:
7151 basename = input_api.os_path.basename(grd_path)
7152 basename_to_src_paths.setdefault(basename, [])
7153 basename_to_src_paths[basename].append(grd_path)
7154 for src_paths in basename_to_src_paths.values():
7155 if len(src_paths) > 1:
7156 return [
7157 output_api.PresubmitNotifyResult(
7158 'Multiple string files have the same basename. This will result in '
Daniel Cheng6303eed2025-05-03 00:12:337159 'missing translations. Files: %s' % ', '.join(src_paths))
Ben Mason5d4c3242025-04-15 20:28:377160 ]
7161
Sam Maiera6e76d72022-02-11 21:43:507162 try:
7163 translation_helper.get_translatable_grds(
Terrence Reilly313f44ff2025-01-22 15:10:147164 repo_root, grd_files, translation_expectations_path, is_cog)
Sam Maiera6e76d72022-02-11 21:43:507165 except Exception as e:
7166 return [
7167 output_api.PresubmitNotifyResult(
7168 'Failed to get a list of translatable grd files. This happens when:\n'
7169 ' - One of the modified grd or grdp files cannot be parsed or\n'
7170 ' - %s is not updated.\n'
7171 'Stack:\n%s' % (translation_expectations_path, str(e)))
7172 ]
Mustafa Emre Acer51f2f742020-03-09 19:41:127173 return []
7174
Ken Rockotc31f4832020-05-29 18:58:517175
Saagar Sanghavifceeaae2020-08-12 16:40:367176def CheckStableMojomChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507177 """Changes to [Stable] mojom types must preserve backward-compatibility."""
7178 changed_mojoms = input_api.AffectedFiles(
7179 include_deletes=True,
7180 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:527181
Bruce Dawson344ab262022-06-04 11:35:107182 if not changed_mojoms or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:507183 return []
7184
7185 delta = []
7186 for mojom in changed_mojoms:
Sam Maiera6e76d72022-02-11 21:43:507187 delta.append({
7188 'filename': mojom.LocalPath(),
7189 'old': '\n'.join(mojom.OldContents()) or None,
7190 'new': '\n'.join(mojom.NewContents()) or None,
7191 })
7192
7193 process = input_api.subprocess.Popen([
Takuto Ikutadca10222022-04-13 02:51:217194 input_api.python3_executable,
Sam Maiera6e76d72022-02-11 21:43:507195 input_api.os_path.join(
7196 input_api.PresubmitLocalPath(), 'mojo', 'public', 'tools', 'mojom',
7197 'check_stable_mojom_compatibility.py'), '--src-root',
7198 input_api.PresubmitLocalPath()
7199 ],
7200 stdin=input_api.subprocess.PIPE,
7201 stdout=input_api.subprocess.PIPE,
7202 stderr=input_api.subprocess.PIPE,
7203 universal_newlines=True)
7204 (x, error) = process.communicate(input=input_api.json.dumps(delta))
7205 if process.returncode:
7206 return [
7207 output_api.PresubmitError(
7208 'One or more [Stable] mojom definitions appears to have been changed '
Alex Goughc99921652024-02-15 22:59:127209 'in a way that is not backward-compatible. See '
7210 'https://chromium.googlesource.com/chromium/src/+/HEAD/mojo/public/tools/bindings/README.md#versioning'
7211 ' for details.',
Sam Maiera6e76d72022-02-11 21:43:507212 long_text=error)
7213 ]
Erik Staabc734cd7a2021-11-23 03:11:527214 return []
7215
Daniel Cheng6303eed2025-05-03 00:12:337216
Dominic Battre645d42342020-12-04 16:14:107217def CheckDeprecationOfPreferences(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507218 """Removing a preference should come with a deprecation."""
Dominic Battre645d42342020-12-04 16:14:107219
Sam Maiera6e76d72022-02-11 21:43:507220 def FilterFile(affected_file):
7221 """Accept only .cc files and the like."""
7222 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
7223 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
7224 input_api.DEFAULT_FILES_TO_SKIP)
7225 return input_api.FilterSourceFile(
7226 affected_file,
7227 files_to_check=file_inclusion_pattern,
7228 files_to_skip=files_to_skip)
Dominic Battre645d42342020-12-04 16:14:107229
Sam Maiera6e76d72022-02-11 21:43:507230 def ModifiedLines(affected_file):
7231 """Returns a list of tuples (line number, line text) of added and removed
7232 lines.
Dominic Battre645d42342020-12-04 16:14:107233
Sam Maiera6e76d72022-02-11 21:43:507234 Deleted lines share the same line number as the previous line.
Dominic Battre645d42342020-12-04 16:14:107235
Sam Maiera6e76d72022-02-11 21:43:507236 This relies on the scm diff output describing each changed code section
7237 with a line of the form
Dominic Battre645d42342020-12-04 16:14:107238
Sam Maiera6e76d72022-02-11 21:43:507239 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
7240 """
7241 line_num = 0
7242 modified_lines = []
7243 for line in affected_file.GenerateScmDiff().splitlines():
7244 # Extract <new line num> of the patch fragment (see format above).
7245 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@',
7246 line)
7247 if m:
7248 line_num = int(m.groups(1)[0])
7249 continue
7250 if ((line.startswith('+') and not line.startswith('++'))
7251 or (line.startswith('-') and not line.startswith('--'))):
7252 modified_lines.append((line_num, line))
Dominic Battre645d42342020-12-04 16:14:107253
Sam Maiera6e76d72022-02-11 21:43:507254 if not line.startswith('-'):
7255 line_num += 1
7256 return modified_lines
Dominic Battre645d42342020-12-04 16:14:107257
Sam Maiera6e76d72022-02-11 21:43:507258 def FindLineWith(lines, needle):
7259 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
Dominic Battre645d42342020-12-04 16:14:107260
Sam Maiera6e76d72022-02-11 21:43:507261 If 0 or >1 lines contain `needle`, -1 is returned.
7262 """
7263 matching_line_numbers = [
7264 # + 1 for 1-based counting of line numbers.
7265 i + 1 for i, line in enumerate(lines) if needle in line
7266 ]
7267 return matching_line_numbers[0] if len(
7268 matching_line_numbers) == 1 else -1
Dominic Battre645d42342020-12-04 16:14:107269
Sam Maiera6e76d72022-02-11 21:43:507270 def ModifiedPrefMigration(affected_file):
7271 """Returns whether the MigrateObsolete.*Pref functions were modified."""
7272 # Determine first and last lines of MigrateObsolete.*Pref functions.
7273 new_contents = affected_file.NewContents()
7274 range_1 = (FindLineWith(new_contents,
7275 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
7276 FindLineWith(new_contents,
7277 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
7278 range_2 = (FindLineWith(new_contents,
7279 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
7280 FindLineWith(new_contents,
7281 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
7282 if (-1 in range_1 + range_2):
7283 raise Exception(
7284 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.'
7285 )
Dominic Battre645d42342020-12-04 16:14:107286
Sam Maiera6e76d72022-02-11 21:43:507287 # Check whether any of the modified lines are part of the
7288 # MigrateObsolete.*Pref functions.
7289 for line_nr, line in ModifiedLines(affected_file):
7290 if (range_1[0] <= line_nr <= range_1[1]
7291 or range_2[0] <= line_nr <= range_2[1]):
7292 return True
7293 return False
Dominic Battre645d42342020-12-04 16:14:107294
Sam Maiera6e76d72022-02-11 21:43:507295 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
7296 browser_prefs_file_pattern = input_api.re.compile(
7297 r'chrome/browser/prefs/browser_prefs.cc')
Dominic Battre645d42342020-12-04 16:14:107298
Sam Maiera6e76d72022-02-11 21:43:507299 changes = input_api.AffectedFiles(include_deletes=True,
7300 file_filter=FilterFile)
7301 potential_problems = []
7302 for f in changes:
7303 for line in f.GenerateScmDiff().splitlines():
7304 # Check deleted lines for pref registrations.
7305 if (line.startswith('-') and not line.startswith('--')
7306 and register_pref_pattern.search(line)):
7307 potential_problems.append('%s: %s' % (f.LocalPath(), line))
Dominic Battre645d42342020-12-04 16:14:107308
Sam Maiera6e76d72022-02-11 21:43:507309 if browser_prefs_file_pattern.search(f.LocalPath()):
7310 # If the developer modified the MigrateObsolete.*Prefs() functions, we
7311 # assume that they knew that they have to deprecate preferences and don't
7312 # warn.
7313 try:
7314 if ModifiedPrefMigration(f):
7315 return []
7316 except Exception as e:
7317 return [output_api.PresubmitError(str(e))]
Dominic Battre645d42342020-12-04 16:14:107318
Sam Maiera6e76d72022-02-11 21:43:507319 if potential_problems:
7320 return [
7321 output_api.PresubmitPromptWarning(
7322 'Discovered possible removal of preference registrations.\n\n'
7323 'Please make sure to properly deprecate preferences by clearing their\n'
7324 'value for a couple of milestones before finally removing the code.\n'
7325 'Otherwise data may stay in the preferences files forever. See\n'
7326 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
7327 'chrome/browser/prefs/README.md for examples.\n'
7328 'This may be a false positive warning (e.g. if you move preference\n'
7329 'registrations to a different place).\n', potential_problems)
7330 ]
7331 return []
7332
Matt Stark6ef08872021-07-29 01:21:467333
7334def CheckConsistentGrdChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507335 """Changes to GRD files must be consistent for tools to read them."""
7336 changed_grds = input_api.AffectedFiles(
7337 include_deletes=False,
7338 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
7339 errors = []
7340 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
7341 for matcher, msg in _INVALID_GRD_FILE_LINE]
7342 for grd in changed_grds:
7343 for i, line in enumerate(grd.NewContents()):
7344 for matcher, msg in invalid_file_regexes:
7345 if matcher.search(line):
7346 errors.append(
7347 output_api.PresubmitError(
7348 'Problem on {grd}:{i} - {msg}'.format(
7349 grd=grd.LocalPath(), i=i + 1, msg=msg)))
7350 return errors
7351
Kevin McNee967dd2d22021-11-15 16:09:297352
Henrique Ferreiro2a4b55942021-11-29 23:45:367353def CheckAssertAshOnlyCode(input_api, output_api):
7354 """Errors if a BUILD.gn file in an ash/ directory doesn't include
Georg Neis94f87f02024-10-22 08:20:137355 assert(is_chromeos).
7356 For a transition period, assert(is_chromeos_ash) is also accepted.
Henrique Ferreiro2a4b55942021-11-29 23:45:367357 """
7358
7359 def FileFilter(affected_file):
7360 """Includes directories known to be Ash only."""
7361 return input_api.FilterSourceFile(
7362 affected_file,
7363 files_to_check=(
7364 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
7365 r'.*/ash/.*BUILD\.gn'), # Any path component.
7366 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
7367
7368 errors = []
Georg Neis94f87f02024-10-22 08:20:137369 pattern = input_api.re.compile(r'assert\(is_chromeos(_ash)?\b')
Jameson Thies0ce669f2021-12-09 15:56:567370 for f in input_api.AffectedFiles(include_deletes=False,
7371 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:367372 if (not pattern.search(input_api.ReadFile(f))):
7373 errors.append(
7374 output_api.PresubmitError(
Georg Neis94f87f02024-10-22 08:20:137375 'Please add assert(is_chromeos) to %s. If that\'s not '
7376 'possible, please create an issue and add a comment such '
Alison Galed6b25fe2024-04-17 13:59:047377 'as:\n # TODO(crbug.com/XXX): add '
Georg Neis94f87f02024-10-22 08:20:137378 'assert(is_chromeos) when ...' % f.LocalPath()))
Henrique Ferreiro2a4b55942021-11-29 23:45:367379 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:277380
7381
Kalvin Lee84ad17a2023-09-25 11:14:417382def _IsMiraclePtrDisallowed(input_api, affected_file):
Anton Bershanskyi4253349482025-02-11 21:01:277383 path = affected_file.UnixLocalPath()
Sam Maiera6e76d72022-02-11 21:43:507384 if not _IsCPlusPlusFile(input_api, path):
7385 return False
7386
Bartek Nowierski49b1a452024-06-08 00:24:357387 # Renderer-only code is generally allowed to use MiraclePtr. These
7388 # directories, however, are specifically disallowed, for perf reasons.
Kalvin Lee84ad17a2023-09-25 11:14:417389 if ("third_party/blink/renderer/core/" in path
7390 or "third_party/blink/renderer/platform/heap/" in path
Bartek Nowierski49b1a452024-06-08 00:24:357391 or "third_party/blink/renderer/platform/wtf/" in path
7392 or "third_party/blink/renderer/platform/fonts/" in path):
7393 return True
7394
7395 # The below paths are an explicitly listed subset of Renderer-only code,
7396 # because the plan is to Oilpanize it.
7397 # TODO(crbug.com/330759291): Remove once Oilpanization is completed or
7398 # abandoned.
Daniel Cheng6303eed2025-05-03 00:12:337399 if ("third_party/blink/renderer/core/paint/" in path or
7400 "third_party/blink/renderer/platform/graphics/compositing/" in path
Bartek Nowierski49b1a452024-06-08 00:24:357401 or "third_party/blink/renderer/platform/graphics/paint/" in path):
Sam Maiera6e76d72022-02-11 21:43:507402 return True
7403
Sam Maiera6e76d72022-02-11 21:43:507404 # We assume that everything else may be used outside of Renderer processes.
Lukasz Anforowicz7016d05e2021-11-30 03:56:277405 return False
7406
Daniel Cheng6303eed2025-05-03 00:12:337407
Alison Galed6b25fe2024-04-17 13:59:047408# TODO(crbug.com/40206238): Remove these checks, once they are replaced
Lukasz Anforowicz7016d05e2021-11-30 03:56:277409# by the Chromium Clang Plugin (which will be preferable because it will
7410# 1) report errors earlier - at compile-time and 2) cover more rules).
7411def CheckRawPtrUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507412 """Rough checks that raw_ptr<T> usage guidelines are followed."""
7413 errors = []
7414 # The regex below matches "raw_ptr<" following a word boundary, but not in a
7415 # C++ comment.
7416 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
Kalvin Lee84ad17a2023-09-25 11:14:417417 file_filter = lambda f: _IsMiraclePtrDisallowed(input_api, f)
Sam Maiera6e76d72022-02-11 21:43:507418 for f, line_num, line in input_api.RightHandSideLines(file_filter):
7419 if raw_ptr_matcher.search(line):
7420 errors.append(
7421 output_api.PresubmitError(
7422 'Problem on {path}:{line} - '\
Kalvin Lee84ad17a2023-09-25 11:14:417423 'raw_ptr<T> should not be used in this renderer code '\
Sam Maiera6e76d72022-02-11 21:43:507424 '(as documented in the "Pointers to unprotected memory" '\
7425 'section in //base/memory/raw_ptr.md)'.format(
7426 path=f.LocalPath(), line=line_num)))
7427 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:567428
Daniel Cheng6303eed2025-05-03 00:12:337429
mikt9337567c2023-09-08 18:38:177430def CheckAdvancedMemorySafetyChecksUsage(input_api, output_api):
7431 """Checks that ADVANCED_MEMORY_SAFETY_CHECKS() macro is neither added nor
7432 removed as it is managed by the memory safety team internally.
7433 Do not add / remove it manually."""
7434 paths = set([])
7435 # The regex below matches "ADVANCED_MEMORY_SAFETY_CHECKS(" following a word
7436 # boundary, but not in a C++ comment.
7437 macro_matcher = input_api.re.compile(
Daniel Cheng6303eed2025-05-03 00:12:337438 r'^((?!//).)*\bADVANCED_MEMORY_SAFETY_CHECKS\(',
7439 input_api.re.MULTILINE)
mikt9337567c2023-09-08 18:38:177440 for f in input_api.AffectedFiles():
7441 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
7442 continue
7443 if macro_matcher.search(f.GenerateScmDiff()):
7444 paths.add(f.LocalPath())
7445 if not paths:
7446 return []
7447 return [output_api.PresubmitPromptWarning(
7448 'ADVANCED_MEMORY_SAFETY_CHECKS() macro is managed by ' \
7449 'the memory safety team (chrome-memory-safety@). ' \
7450 'Please contact us to add/delete the uses of the macro.',
7451 paths)]
Henrique Ferreirof9819f2e32021-11-30 13:31:567452
Daniel Cheng6303eed2025-05-03 00:12:337453
Henrique Ferreirof9819f2e32021-11-30 13:31:567454def CheckPythonShebang(input_api, output_api):
7455 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
7456 system-wide python.
7457 """
7458 errors = []
7459 sources = lambda affected_file: input_api.FilterSourceFile(
7460 affected_file,
7461 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
7462 r'third_party/blink/web_tests/external/') + input_api.
7463 DEFAULT_FILES_TO_SKIP),
7464 files_to_check=[r'.*\.py$'])
7465 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:277466 for line_num, line in f.ChangedContents():
7467 if line_num == 1 and line.startswith('#!/usr/bin/python'):
7468 errors.append(f.LocalPath())
7469 break
Henrique Ferreirof9819f2e32021-11-30 13:31:567470
7471 result = []
7472 for file in errors:
7473 result.append(
7474 output_api.PresubmitError(
7475 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
7476 file))
7477 return result
James Shen81cc0e22022-06-15 21:10:457478
7479
Andrew Grieve5a66ae72024-12-13 15:21:537480def CheckAndroidTestAnnotations(input_api, output_api):
James Shen81cc0e22022-06-15 21:10:457481 """Checks that tests have either @Batch or @DoNotBatch annotation. If this
7482 is not an instrumentation test, disregard."""
7483
7484 batch_annotation = input_api.re.compile(r'^\s*@Batch')
7485 do_not_batch_annotation = input_api.re.compile(r'^\s*@DoNotBatch')
Daniel Cheng6303eed2025-05-03 00:12:337486 robolectric_test = input_api.re.compile(
7487 r'@RunWith\((.*?)RobolectricTestRunner')
James Shen81cc0e22022-06-15 21:10:457488 test_class_declaration = input_api.re.compile(r'^\s*public\sclass.*Test')
7489 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
Daniel Cheng6303eed2025-05-03 00:12:337490 test_annotation_declaration = input_api.re.compile(
7491 r'^\s*public\s@interface\s.*{')
James Shen81cc0e22022-06-15 21:10:457492
ckitagawae8fd23b2022-06-17 15:29:387493 missing_annotation_errors = []
7494 extra_annotation_errors = []
Andrew Grieve5a66ae72024-12-13 15:21:537495 wrong_robolectric_test_runner_errors = []
James Shen81cc0e22022-06-15 21:10:457496
7497 def _FilterFile(affected_file):
7498 return input_api.FilterSourceFile(
7499 affected_file,
7500 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
7501 files_to_check=[r'.*Test\.java$'])
7502
7503 for f in input_api.AffectedSourceFiles(_FilterFile):
7504 batch_matched = None
7505 do_not_batch_matched = None
7506 is_instrumentation_test = True
Mark Schillaci8ef0d872023-07-18 22:07:597507 test_annotation_declaration_matched = None
Andrew Grieve5a66ae72024-12-13 15:21:537508 has_base_robolectric_rule = False
James Shen81cc0e22022-06-15 21:10:457509 for line in f.NewContents():
Andrew Grieve5a66ae72024-12-13 15:21:537510 if 'BaseRobolectricTestRule' in line:
7511 has_base_robolectric_rule = True
7512 continue
7513 if m := robolectric_test.search(line):
7514 is_instrumentation_test = False
7515 if m.group(1) == '' and not has_base_robolectric_rule:
Yiwei Zhang5341bf02025-03-20 16:34:137516 path = str(f.LocalPath())
7517 # These two spots cannot use it.
7518 if 'webapk' not in path and 'build' not in path:
7519 wrong_robolectric_test_runner_errors.append(path)
Andrew Grieve5a66ae72024-12-13 15:21:537520 break
7521 if uiautomator_test.search(line):
James Shen81cc0e22022-06-15 21:10:457522 is_instrumentation_test = False
7523 break
7524 if not batch_matched:
7525 batch_matched = batch_annotation.search(line)
7526 if not do_not_batch_matched:
7527 do_not_batch_matched = do_not_batch_annotation.search(line)
7528 test_class_declaration_matched = test_class_declaration.search(
7529 line)
Daniel Cheng6303eed2025-05-03 00:12:337530 test_annotation_declaration_matched = test_annotation_declaration.search(
7531 line)
Mark Schillaci8ef0d872023-07-18 22:07:597532 if test_class_declaration_matched or test_annotation_declaration_matched:
James Shen81cc0e22022-06-15 21:10:457533 break
Mark Schillaci8ef0d872023-07-18 22:07:597534 if test_annotation_declaration_matched:
7535 continue
Daniel Cheng6303eed2025-05-03 00:12:337536 if (is_instrumentation_test and not batch_matched
7537 and not do_not_batch_matched):
Sam Maier4cef9242022-10-03 14:21:247538 missing_annotation_errors.append(str(f.LocalPath()))
Daniel Cheng6303eed2025-05-03 00:12:337539 if (not is_instrumentation_test
7540 and (batch_matched or do_not_batch_matched)):
Sam Maier4cef9242022-10-03 14:21:247541 extra_annotation_errors.append(str(f.LocalPath()))
James Shen81cc0e22022-06-15 21:10:457542
7543 results = []
7544
ckitagawae8fd23b2022-06-17 15:29:387545 if missing_annotation_errors:
James Shen81cc0e22022-06-15 21:10:457546 results.append(
7547 output_api.PresubmitPromptWarning(
7548 """
Andrew Grieve43a5cf82023-09-08 15:09:467549A change was made to an on-device test that has neither been annotated with
7550@Batch nor @DoNotBatch. If this is a new test, please add the annotation. If
7551this is an existing test, please consider adding it if you are sufficiently
7552familiar with the test (but do so as a separate change).
7553
Jens Mueller2085ff82023-02-27 11:54:497554See https://source.chromium.org/chromium/chromium/src/+/main:docs/testing/batching_instrumentation_tests.md
ckitagawae8fd23b2022-06-17 15:29:387555""", missing_annotation_errors))
7556 if extra_annotation_errors:
7557 results.append(
7558 output_api.PresubmitPromptWarning(
7559 """
7560Robolectric tests do not need a @Batch or @DoNotBatch annotations.
7561""", extra_annotation_errors))
Andrew Grieve5a66ae72024-12-13 15:21:537562 if wrong_robolectric_test_runner_errors:
7563 results.append(
7564 output_api.PresubmitPromptWarning(
7565 """
Wenyu Fu0005ab82025-01-03 18:13:267566Robolectric tests should use either @RunWith(BaseRobolectricTestRunner.class) (or
Andrew Grieve5a66ae72024-12-13 15:21:537567a subclass of it), or use "@Rule BaseRobolectricTestRule".
7568""", wrong_robolectric_test_runner_errors))
James Shen81cc0e22022-06-15 21:10:457569
7570 return results
Sam Maier4cef9242022-10-03 14:21:247571
7572
Henrique Nakashima224ee2482025-03-21 18:35:027573def _CheckAndroidNullAwayAnnotatedClasses(input_api, output_api):
7574 """Checks that Java classes/interfaces/annotations are null-annotated."""
7575
Henrique Nakashima2bdd8ad2025-04-08 18:24:577576 # Temporary, crbug.com/389129271
7577 if input_api.change.RepositoryRoot().endswith('clank'):
7578 return []
7579
Daniel Cheng6303eed2025-05-03 00:12:337580 nullmarked_annotation = input_api.re.compile(
7581 r'^\s*@(NullMarked|NullUnmarked)')
Henrique Nakashima224ee2482025-03-21 18:35:027582
7583 missing_annotation_errors = []
7584
7585 def _FilterFile(affected_file):
7586 return input_api.FilterSourceFile(
7587 affected_file,
Daniel Cheng6303eed2025-05-03 00:12:337588 files_to_skip=(
7589 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
7590 input_api.DEFAULT_FILES_TO_SKIP + (
7591 r'.*Test.*\.java',
7592 r'^android_webview/.*', # Temporary, crbug.com/389129271
7593 r'^build/.*',
Daniel Cheng6303eed2025-05-03 00:12:337594 r'^chromecast/.*',
7595 r'^components/cronet/.*',
7596 r'^tools/.*',
7597 )),
7598 files_to_check=[r'.*\.java$'])
Henrique Nakashima224ee2482025-03-21 18:35:027599
7600 for f in input_api.AffectedSourceFiles(_FilterFile):
Henrique Nakashimac6605432025-04-24 18:11:597601 if f.Action() != 'A':
7602 continue
Henrique Nakashima224ee2482025-03-21 18:35:027603 for line in f.NewContents():
7604 if nullmarked_annotation.search(line):
7605 break
7606 else:
7607 missing_annotation_errors.append(str(f.LocalPath()))
7608
7609 results = []
7610
7611 if missing_annotation_errors:
7612 results.append(
Henrique Nakashima8bafbc52025-04-22 19:38:427613 output_api.PresubmitError(
Henrique Nakashima224ee2482025-03-21 18:35:027614 """
7615Please add @NullMarked and fix the NullAway warnings in the following files
7616(see https://chromium.googlesource.com/chromium/src/+/main/styleguide/java/nullaway.md):
7617""", missing_annotation_errors))
7618
7619 return results
7620
7621
Mike Dougherty1b8be712022-10-20 00:15:137622def CheckNoJsInIos(input_api, output_api):
7623 """Checks to make sure that JavaScript files are not used on iOS."""
7624
7625 def _FilterFile(affected_file):
7626 return input_api.FilterSourceFile(
7627 affected_file,
7628 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP +
Daniel Cheng6303eed2025-05-03 00:12:337629 (r'^ios/third_party/*', r'^ios/tools/*', r'^third_party/*',
7630 r'^components/autofill/ios/form_util/resources/*'),
Mike Dougherty1b8be712022-10-20 00:15:137631 files_to_check=[r'^ios/.*\.js$', r'.*/ios/.*\.js$'])
7632
Mike Dougherty4d1050b2023-03-14 15:59:537633 deleted_files = []
7634
7635 # Collect filenames of all removed JS files.
Arthur Sonzognic66e9c82024-04-23 07:53:047636 for f in input_api.AffectedFiles(file_filter=_FilterFile):
Mike Dougherty4d1050b2023-03-14 15:59:537637 local_path = f.LocalPath()
7638
Daniel Cheng6303eed2025-05-03 00:12:337639 if input_api.os_path.splitext(
7640 local_path)[1] == '.js' and f.Action() == 'D':
Mike Dougherty4d1050b2023-03-14 15:59:537641 deleted_files.append(input_api.os_path.basename(local_path))
7642
Mike Dougherty1b8be712022-10-20 00:15:137643 error_paths = []
Mike Dougherty4d1050b2023-03-14 15:59:537644 moved_paths = []
Mike Dougherty1b8be712022-10-20 00:15:137645 warning_paths = []
7646
7647 for f in input_api.AffectedSourceFiles(_FilterFile):
7648 local_path = f.LocalPath()
7649
7650 if input_api.os_path.splitext(local_path)[1] == '.js':
7651 if f.Action() == 'A':
Mike Dougherty4d1050b2023-03-14 15:59:537652 if input_api.os_path.basename(local_path) in deleted_files:
7653 # This script was probably moved rather than newly created.
7654 # Present a warning instead of an error for these cases.
7655 moved_paths.append(local_path)
7656 else:
7657 error_paths.append(local_path)
Mike Dougherty1b8be712022-10-20 00:15:137658 elif f.Action() != 'D':
7659 warning_paths.append(local_path)
7660
7661 results = []
7662
7663 if warning_paths:
Daniel Cheng6303eed2025-05-03 00:12:337664 results.append(
7665 output_api.PresubmitPromptWarning(
7666 'TypeScript is now fully supported for iOS feature scripts. '
7667 'Consider converting JavaScript files to TypeScript. See '
7668 '//ios/web/public/js_messaging/README.md for more details.',
7669 warning_paths))
Mike Dougherty1b8be712022-10-20 00:15:137670
Mike Dougherty4d1050b2023-03-14 15:59:537671 if moved_paths:
Daniel Cheng6303eed2025-05-03 00:12:337672 results.append(
7673 output_api.PresubmitPromptWarning(
7674 'Do not use JavaScript on iOS for new files as TypeScript is '
7675 'fully supported. (If this is a moved file, you may leave the '
7676 'script unconverted.) See //ios/web/public/js_messaging/README.md '
7677 'for help using scripts on iOS.', moved_paths))
Mike Dougherty4d1050b2023-03-14 15:59:537678
Mike Dougherty1b8be712022-10-20 00:15:137679 if error_paths:
Daniel Cheng6303eed2025-05-03 00:12:337680 results.append(
7681 output_api.PresubmitError(
7682 'Do not use JavaScript on iOS as TypeScript is fully supported. '
7683 'See //ios/web/public/js_messaging/README.md for help using '
7684 'scripts on iOS.', error_paths))
Mike Dougherty1b8be712022-10-20 00:15:137685
7686 return results
Hans Wennborg23a81d52023-03-24 16:38:137687
Daniel Cheng6303eed2025-05-03 00:12:337688
Hans Wennborg23a81d52023-03-24 16:38:137689def CheckLibcxxRevisionsMatch(input_api, output_api):
7690 """Check to make sure the libc++ version matches across deps files."""
Andrew Grieve21bb6792023-03-27 19:06:487691 # Disable check for changes to sub-repositories.
7692 if input_api.PresubmitLocalPath() != input_api.change.RepositoryRoot():
Sam Maierb926c58c2023-08-08 19:58:257693 return []
Hans Wennborg23a81d52023-03-24 16:38:137694
Daniel Cheng6303eed2025-05-03 00:12:337695 DEPS_FILES = ['DEPS', 'buildtools/deps_revisions.gni']
Hans Wennborg23a81d52023-03-24 16:38:137696
Anton Bershanskyi4253349482025-02-11 21:01:277697 file_filter = lambda f: f.UnixLocalPath() in DEPS_FILES
Hans Wennborg23a81d52023-03-24 16:38:137698 changed_deps_files = input_api.AffectedFiles(file_filter=file_filter)
7699 if not changed_deps_files:
7700 return []
7701
7702 def LibcxxRevision(file):
7703 file = input_api.os_path.join(input_api.PresubmitLocalPath(),
7704 *file.split('/'))
Daniel Cheng6303eed2025-05-03 00:12:337705 return input_api.re.search(r'libcxx_revision.*[:=].*[\'"](\w+)[\'"]',
7706 input_api.ReadFile(file)).group(1)
Hans Wennborg23a81d52023-03-24 16:38:137707
7708 if len(set([LibcxxRevision(f) for f in DEPS_FILES])) == 1:
7709 return []
7710
Daniel Cheng6303eed2025-05-03 00:12:337711 return [
7712 output_api.PresubmitError(
7713 'libcxx_revision not equal across %s' % ', '.join(DEPS_FILES),
7714 changed_deps_files)
7715 ]
Arthur Sonzogni7109bd32023-10-03 10:34:427716
7717
7718def CheckDanglingUntriaged(input_api, output_api):
7719 """Warn developers adding DanglingUntriaged raw_ptr."""
7720
7721 # Ignore during git presubmit --all.
7722 #
7723 # This would be too costly, because this would check every lines of every
7724 # C++ files. Check from _BANNED_CPP_FUNCTIONS are also reading the whole
7725 # source code, but only once to apply every checks. It seems the bots like
7726 # `win-presubmit` are particularly sensitive to reading the files. Adding
7727 # this check caused the bot to run 2x longer. See https://crbug.com/1486612.
7728 if input_api.no_diffs:
Arthur Sonzogni9eafd222023-11-10 08:50:397729 return []
Arthur Sonzogni7109bd32023-10-03 10:34:427730
7731 def FilterFile(file):
7732 return input_api.FilterSourceFile(
7733 file,
7734 files_to_check=[r".*\.(h|cc|cpp|cxx|m|mm)$"],
7735 files_to_skip=[r"^base/allocator.*"],
7736 )
7737
7738 count = 0
Arthur Sonzognic66e9c82024-04-23 07:53:047739 for f in input_api.AffectedFiles(file_filter=FilterFile):
Arthur Sonzogni9eafd222023-11-10 08:50:397740 count -= sum([l.count("DanglingUntriaged") for l in f.OldContents()])
7741 count += sum([l.count("DanglingUntriaged") for l in f.NewContents()])
Arthur Sonzogni7109bd32023-10-03 10:34:427742
7743 # Most likely, nothing changed:
7744 if count == 0:
7745 return []
7746
7747 # Congrats developers for improving it:
7748 if count < 0:
Arthur Sonzogni9eafd222023-11-10 08:50:397749 message = f"DanglingUntriaged pointers removed: {-count}\nThank you!"
Arthur Sonzogni7109bd32023-10-03 10:34:427750 return [output_api.PresubmitNotifyResult(message)]
7751
7752 # Check for 'DanglingUntriaged-notes' in the description:
7753 notes_regex = input_api.re.compile("DanglingUntriaged-notes[:=]")
7754 if any(
7755 notes_regex.match(line)
7756 for line in input_api.change.DescriptionText().splitlines()):
7757 return []
7758
7759 # Check for DanglingUntriaged-notes in the git footer:
7760 if input_api.change.GitFootersFromDescription().get(
7761 "DanglingUntriaged-notes", []):
7762 return []
7763
7764 message = (
Daniel Cheng6303eed2025-05-03 00:12:337765 "Unexpected new occurrences of `DanglingUntriaged` detected. Please\n"
7766 + "avoid adding new ones\n" + "\n" + "See documentation:\n" +
7767 "https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr.md\n"
7768 + "\n" + "See also the guide to fix dangling pointers:\n" +
7769 "https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr_guide.md\n"
7770 + "\n" +
Arthur Sonzogni9eafd222023-11-10 08:50:397771 "To disable this warning, please add in the commit description:\n" +
Alex Gough26dcd852023-12-22 16:47:197772 "DanglingUntriaged-notes: <rationale for new untriaged dangling " +
Daniel Cheng6303eed2025-05-03 00:12:337773 "pointers>")
Arthur Sonzogni7109bd32023-10-03 10:34:427774 return [output_api.PresubmitPromptWarning(message)]
Jan Keitel77be7522023-10-12 20:40:497775
Daniel Cheng6303eed2025-05-03 00:12:337776
Jan Keitel77be7522023-10-12 20:40:497777def CheckInlineConstexprDefinitionsInHeaders(input_api, output_api):
7778 """Checks that non-static constexpr definitions in headers are inline."""
7779 # In a properly formatted file, constexpr definitions inside classes or
7780 # structs will have additional whitespace at the beginning of the line.
7781 # The pattern looks for variables initialized as constexpr kVar = ...; or
7782 # constexpr kVar{...};
7783 # The pattern does not match expressions that have braces in kVar to avoid
7784 # matching constexpr functions.
7785 pattern = input_api.re.compile(r'^constexpr (?!inline )[^\(\)]*[={]')
Daniel Cheng6303eed2025-05-03 00:12:337786 attribute_pattern = input_api.re.compile(
7787 r'(\[\[[a-zA-Z_:]+\]\]|[A-Z]+[A-Z_]+) ')
Jan Keitel77be7522023-10-12 20:40:497788 problems = []
7789 for f in input_api.AffectedFiles():
7790 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
7791 continue
7792
7793 for line_number, line in f.ChangedContents():
7794 line = attribute_pattern.sub('', line)
7795 if pattern.search(line):
Daniel Cheng6303eed2025-05-03 00:12:337796 problems.append(f"{f.LocalPath()}: {line_number}\n {line}")
Jan Keitel77be7522023-10-12 20:40:497797
7798 if problems:
7799 return [
7800 output_api.PresubmitPromptWarning(
7801 'Consider inlining constexpr variable definitions in headers '
7802 'outside of classes to avoid unnecessary copies of the '
7803 'constant. See https://abseil.io/tips/168 for more details.',
7804 problems)
7805 ]
7806 else:
7807 return []
Alison Galed6b25fe2024-04-17 13:59:047808
Daniel Cheng6303eed2025-05-03 00:12:337809
Alison Galed6b25fe2024-04-17 13:59:047810def CheckTodoBugReferences(input_api, output_api):
7811 """Checks that bugs in TODOs use updated issue tracker IDs."""
7812
Daniel Cheng6303eed2025-05-03 00:12:337813 files_to_skip = [
7814 'PRESUBMIT_test.py', r"^third_party/rust/chromium_crates_io/vendor/.*"
7815 ]
Alison Galed6b25fe2024-04-17 13:59:047816
7817 def _FilterFile(affected_file):
Daniel Cheng6303eed2025-05-03 00:12:337818 return input_api.FilterSourceFile(affected_file,
7819 files_to_skip=files_to_skip)
Alison Galed6b25fe2024-04-17 13:59:047820
7821 # Monorail bug IDs are all less than or equal to 1524553 so check that all
7822 # bugs in TODOs are greater than that value.
Tom Sepez8e628582025-02-14 02:18:557823 pattern = input_api.re.compile(r'.*\bTODO\([^\)0-9]*([0-9]+)\).*')
Alison Galed6b25fe2024-04-17 13:59:047824 problems = []
7825 for f in input_api.AffectedSourceFiles(_FilterFile):
7826 for line_number, line in f.ChangedContents():
7827 match = pattern.match(line)
7828 if match and int(match.group(1)) <= 1524553:
Daniel Cheng6303eed2025-05-03 00:12:337829 problems.append(f"{f.LocalPath()}: {line_number}\n {line}")
Alison Galed6b25fe2024-04-17 13:59:047830
7831 if problems:
7832 return [
7833 output_api.PresubmitPromptWarning(
Alison Galecb598de52024-04-26 17:03:257834 'TODOs should use the new Chromium Issue Tracker IDs which can '
7835 'be found by navigating to the bug. See '
Daniel Cheng6303eed2025-05-03 00:12:337836 'https://crbug.com/336778624 for more details.', problems)
Alison Galed6b25fe2024-04-17 13:59:047837 ]
7838 else:
7839 return []
Mikita Kuchyne9cd0e29f2025-05-26 11:47:257840
7841def CheckNoBrowserStarInUnittests(input_api, output_api):
7842 """Checks that unit-tests don't contain Browser* variables.
7843 """
7844 problems = []
7845
7846 def FileFilter(affected_file):
7847 """Check unit-tests only"""
7848 return input_api.FilterSourceFile(
7849 affected_file,
7850 files_to_check=(
7851 r'.*unittest\.cc$',
7852 r'.*unittest\.h$'
7853 ),
7854 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
7855 )
7856
7857 browser_star_pattern = input_api.re.compile(r'\bBrowser\s*\*')
7858
7859 for f in input_api.AffectedFiles(include_deletes=False,
7860 file_filter=FileFilter):
7861 for line_num, line in f.ChangedContents():
7862 match = browser_star_pattern.search(line)
7863 if match:
7864 problems.append(' %s:%d:%s' %
7865 (f.LocalPath(), line_num, match.group(0)))
7866
7867 if not problems:
7868 return []
7869
7870 WARNING_MSG="""Do not use "Browser*" type in unittest files (e.g.,
7871 "*unittest.cc" or "*unittest.h"). Unit tests should generally
7872 not depend on the full Browser class or related components. Consider
7873 refactoring to mock dependencies, use test-specific fakes,
7874 or determine if a browser_test is more appropriate.
7875 """
7876 return [output_api.PresubmitPromptWarning(WARNING_MSG, items=problems)]