blob: 570a0b199ef9573ac1d5e27c38d946babd056792 [file] [log] [blame]
Avi Drissman24976592022-09-12 15:24:311# Copyright 2012 The Chromium Authors
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
[email protected]ca8d1982009-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]ca8d1982009-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]ca8d1982009-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]ca8d1982009-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/.*',
1554 # TODO(https://crbug.com/695592): Remove once WebSQL is deprecated.
1555 r'third_party/blink/web_tests/storage/websql/.*'
1556 # Various performance tools that do not build as part of Chrome.
1557 r'^tools/perf.*',
1558 r'.*perfetto.*',
1559 ),
Austin Sullivand661ab52022-11-16 08:55:151560 ),
1561 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531562 'std::random_shuffle',
1563 ('std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
1564 'base::RandomShuffle instead.'),
1565 True,
1566 (),
tzik5de2157f2018-05-08 03:42:471567 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151568 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531569 'ios/web/public/test/http_server',
1570 ('web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
1571 ),
1572 False,
1573 (),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:241574 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151575 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531576 'GetAddressOf',
1577 ('Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
1578 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
1579 'operator& is generally recommended. So always use operator& instead. ',
1580 'See http://crbug.com/914910 for more conversion guidance.'),
1581 True,
1582 (),
Robert Liao764c9492019-01-24 18:46:281583 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151584 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531585 'SHFileOperation',
1586 ('SHFileOperation was deprecated in Windows Vista, and there are less ',
1587 'complex functions to achieve the same goals. Use IFileOperation for ',
1588 'any esoteric actions instead.'),
1589 True,
1590 (),
Ben Lewisa9514602019-04-29 17:53:051591 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151592 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531593 'StringFromGUID2',
1594 ('StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
1595 'Use base::win::WStringFromGUID instead.'),
1596 True,
1597 (r'/base/win/win_util_unittest.cc', ),
Cliff Smolinsky81951642019-04-30 21:39:511598 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151599 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531600 'StringFromCLSID',
1601 ('StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
1602 'Use base::win::WStringFromGUID instead.'),
1603 True,
1604 (r'/base/win/win_util_unittest.cc', ),
Cliff Smolinsky81951642019-04-30 21:39:511605 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151606 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531607 'kCFAllocatorNull',
1608 (
1609 'The use of kCFAllocatorNull with the NoCopy creation of ',
1610 'CoreFoundation types is prohibited.',
1611 ),
1612 True,
1613 (),
Avi Drissman7382afa02019-04-29 23:27:131614 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151615 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531616 'mojo::ConvertTo',
1617 ('mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1618 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1619 'StringTraits if you would like to convert between custom types and',
1620 'the wire format of mojom types.'),
1621 False,
1622 (
1623 r'^fuchsia_web/webengine/browser/url_request_rewrite_rules_manager\.cc$',
1624 r'^fuchsia_web/webengine/url_request_rewrite_type_converters\.cc$',
1625 r'^third_party/blink/.*\.(cc|h)$',
1626 r'^content/renderer/.*\.(cc|h)$',
1627 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291628 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151629 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531630 'GetInterfaceProvider',
1631 ('InterfaceProvider is deprecated.',
1632 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1633 'or Platform::GetBrowserInterfaceBroker.'),
1634 False,
1635 (),
Oksana Zhuravlovac8222d22019-12-19 19:21:161636 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151637 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531638 'CComPtr',
1639 ('New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1640 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1641 'details.'),
1642 False,
1643 (),
Robert Liao1d78df52019-11-11 20:02:011644 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151645 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531646 r'/\b(IFACE|STD)METHOD_?\(',
1647 ('IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1648 'Instead, always use IFACEMETHODIMP in the declaration.'),
1649 False,
1650 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Xiaohan Wang72bd2ba2020-02-18 21:38:201651 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151652 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531653 'RemoveAllChildViewsWithoutDeleting',
1654 ('RemoveAllChildViewsWithoutDeleting is deprecated.',
1655 'This method is deemed dangerous as, unless raw pointers are re-added,',
1656 'calls to this method introduce memory leaks.'),
1657 False,
1658 (),
Peter Boström7ff41522021-07-29 03:43:271659 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151660 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531661 r'/\bTRACE_EVENT_ASYNC_',
1662 (
1663 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1664 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1665 ),
1666 False,
1667 (
1668 r'^base/trace_event/.*',
1669 r'^base/tracing/.*',
1670 ),
Eric Secklerbe6f48d2020-05-06 18:09:121671 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151672 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531673 'RoInitialize',
1674 ('Improper use of [base::win]::RoInitialize() has been implicated in a ',
1675 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
1676 'instead. See http://crbug.com/1197722 for more information.'),
1677 True,
1678 (
1679 r'^base/win/scoped_winrt_initializer\.cc$',
1680 r'^third_party/abseil-cpp/absl/.*',
1681 ),
Robert Liao22f66a52021-04-10 00:57:521682 ),
Patrick Monettec343bb982022-06-01 17:18:451683 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531684 r'base::Watchdog',
1685 (
1686 'base::Watchdog is deprecated because it creates its own thread.',
1687 'Instead, manually start a timer on a SequencedTaskRunner.',
1688 ),
1689 False,
1690 (),
Patrick Monettec343bb982022-06-01 17:18:451691 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091692 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531693 'base::Passed',
1694 ('Do not use base::Passed. It is a legacy helper for capturing ',
1695 'move-only types with base::BindRepeating, but invoking the ',
1696 'resulting RepeatingCallback moves the captured value out of ',
1697 'the callback storage, and subsequent invocations may pass the ',
1698 'value in a valid but undefined state. Prefer base::BindOnce().',
1699 'See http://crbug.com/1326449 for context.'),
1700 False,
1701 (
1702 # False positive, but it is also fine to let bind internals reference
1703 # base::Passed.
1704 r'^base[\\/]functional[\\/]bind\.h',
1705 r'^base[\\/]functional[\\/]bind_internal\.h',
1706 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091707 ),
Daniel Cheng2248b332022-07-27 06:16:591708 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531709 r'base::Feature k',
1710 ('Please use BASE_DECLARE_FEATURE() or BASE_FEATURE() instead of ',
1711 'directly declaring/defining features.'),
1712 True,
1713 [
1714 # Implements BASE_DECLARE_FEATURE().
1715 r'^base/feature_list\.h',
1716 ],
Daniel Chengba3bc2e2022-10-03 02:45:431717 ),
Robert Ogden92101dcb2022-10-19 23:49:361718 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531719 r'/\bchartorune\b',
1720 ('chartorune is not memory-safe, unless you can guarantee the input ',
1721 'string is always null-terminated. Otherwise, please use charntorune ',
1722 'from libphonenumber instead.'),
1723 True,
1724 [
1725 _THIRD_PARTY_EXCEPT_BLINK,
1726 # Exceptions to this rule should have a fuzzer.
1727 ],
Robert Ogden92101dcb2022-10-19 23:49:361728 ),
Arthur Sonzogni1da65fa2023-03-27 16:01:521729 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531730 r'/\b#include "base/atomicops\.h"\b',
1731 ('Do not use base::subtle atomics, but std::atomic, which are simpler '
1732 'to use, have better understood, clearer and richer semantics, and are '
1733 'harder to mis-use. See details in base/atomicops.h.', ),
1734 False,
1735 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Benoit Lize79cf0592023-01-27 10:01:571736 ),
Daniel Cheng566634ff2024-06-29 14:56:531737 BanRule(r'CrossThreadPersistent<', (
Arthur Sonzogni60348572e2023-04-07 10:22:521738 'Do not use blink::CrossThreadPersistent, but '
Daniel Cheng566634ff2024-06-29 14:56:531739 'blink::CrossThreadHandle. It is harder to mis-use.', 'More info: '
Arthur Sonzogni60348572e2023-04-07 10:22:521740 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1741 'Please contact platform-architecture-dev@ before adding new instances.'
Daniel Cheng566634ff2024-06-29 14:56:531742 ), False, []),
1743 BanRule(r'CrossThreadWeakPersistent<', (
Arthur Sonzogni60348572e2023-04-07 10:22:521744 'Do not use blink::CrossThreadWeakPersistent, but '
Daniel Cheng566634ff2024-06-29 14:56:531745 'blink::CrossThreadWeakHandle. It is harder to mis-use.', 'More info: '
Arthur Sonzogni60348572e2023-04-07 10:22:521746 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1747 'Please contact platform-architecture-dev@ before adding new instances.'
Daniel Cheng566634ff2024-06-29 14:56:531748 ), False, []),
1749 BanRule(r'objc/objc.h', (
Avi Drissman491617c2023-04-13 17:33:151750 'Do not include <objc/objc.h>. It defines away ARC lifetime '
1751 'annotations, and is thus dangerous.',
1752 'Please use the pimpl pattern; search for `ObjCStorage` for examples.',
1753 'For further reading on how to safely mix C++ and Obj-C, see',
1754 'https://chromium.googlesource.com/chromium/src/+/main/docs/mac/mixing_cpp_and_objc.md'
Daniel Cheng566634ff2024-06-29 14:56:531755 ), True, []),
1756 BanRule(
1757 r'/#include <filesystem>',
1758 ('libc++ <filesystem> is banned per the Google C++ styleguide.', ),
1759 True,
1760 # This fuzzing framework is a standalone open source project and
1761 # cannot rely on Chromium base.
1762 (r'third_party/centipede'),
Avi Drissman491617c2023-04-13 17:33:151763 ),
Grace Park8d59b54b2023-04-26 17:53:351764 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531765 r'TopDocument()',
1766 ('TopDocument() does not work correctly with out-of-process iframes. '
1767 'Please do not introduce new uses.', ),
1768 True,
1769 (
1770 # TODO(crbug.com/617677): Remove all remaining uses.
1771 r'^third_party/blink/renderer/core/dom/document\.cc',
1772 r'^third_party/blink/renderer/core/dom/document\.h',
1773 r'^third_party/blink/renderer/core/dom/element\.cc',
1774 r'^third_party/blink/renderer/core/exported/web_disallow_transition_scope_test\.cc',
1775 r'^third_party/blink/renderer/core/exported/web_document_test\.cc',
1776 r'^third_party/blink/renderer/core/html/html_anchor_element\.cc',
1777 r'^third_party/blink/renderer/core/html/html_dialog_element\.cc',
1778 r'^third_party/blink/renderer/core/html/html_element\.cc',
1779 r'^third_party/blink/renderer/core/html/html_frame_owner_element\.cc',
1780 r'^third_party/blink/renderer/core/html/media/video_wake_lock\.cc',
1781 r'^third_party/blink/renderer/core/loader/anchor_element_interaction_tracker\.cc',
1782 r'^third_party/blink/renderer/core/page/scrolling/root_scroller_controller\.cc',
1783 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.cc',
1784 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.h',
1785 r'^third_party/blink/renderer/core/script/classic_pending_script\.cc',
1786 r'^third_party/blink/renderer/core/script/script_loader\.cc',
1787 ),
Grace Park8d59b54b2023-04-26 17:53:351788 ),
Daniel Cheng72153e02023-05-18 21:18:141789 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531790 pattern=r'base::raw_ptr<',
1791 explanation=('Do not use base::raw_ptr, use raw_ptr.', ),
1792 treat_as_error=True,
1793 excluded_paths=(
1794 '^base/',
1795 '^tools/',
1796 ),
Daniel Cheng72153e02023-05-18 21:18:141797 ),
Arthur Sonzognif0eea302023-08-18 19:20:311798 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531799 pattern=r'base:raw_ref<',
1800 explanation=('Do not use base::raw_ref, use raw_ref.', ),
1801 treat_as_error=True,
1802 excluded_paths=(
1803 '^base/',
1804 '^tools/',
1805 ),
Arthur Sonzognif0eea302023-08-18 19:20:311806 ),
1807 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531808 pattern=r'/raw_ptr<[^;}]*\w{};',
1809 explanation=(
1810 'Do not use {} for raw_ptr initialization, use = nullptr instead.',
1811 ),
1812 treat_as_error=True,
1813 excluded_paths=(
1814 '^base/',
1815 '^tools/',
1816 ),
Arthur Sonzognif0eea302023-08-18 19:20:311817 ),
Anton Maliev66751812023-08-24 16:28:131818 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531819 pattern=r'/#include "base/allocator/.*/raw_'
1820 r'(ptr|ptr_cast|ptr_exclusion|ref).h"',
1821 explanation=(
1822 'Please include the corresponding facade headers:',
1823 '- #include "base/memory/raw_ptr.h"',
1824 '- #include "base/memory/raw_ptr_cast.h"',
1825 '- #include "base/memory/raw_ptr_exclusion.h"',
1826 '- #include "base/memory/raw_ref.h"',
1827 ),
1828 treat_as_error=True,
1829 excluded_paths=(
1830 '^base/',
1831 '^tools/',
1832 ),
Tom Sepez41eb158d2023-09-12 16:16:221833 ),
1834 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531835 pattern=r'ContentSettingsType::COOKIES',
1836 explanation=
1837 ('Do not use ContentSettingsType::COOKIES to check whether cookies are '
1838 'supported in the provided context. Instead rely on the '
1839 'content_settings::CookieSettings API. If you are using '
1840 'ContentSettingsType::COOKIES to check the user preference setting '
1841 'specifically, disregard this warning.', ),
1842 treat_as_error=False,
1843 excluded_paths=(
1844 '^chrome/browser/ui/content_settings/',
1845 '^components/content_settings/',
1846 '^services/network/cookie_settings.cc',
1847 '.*test.cc',
1848 ),
Arthur Sonzogni48c6aea22023-09-04 22:25:201849 ),
1850 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531851 pattern=r'ContentSettingsType::TRACKING_PROTECTION',
1852 explanation=
1853 ('Do not directly use ContentSettingsType::TRACKING_PROTECTION to check '
1854 'for tracking protection exceptions. Instead rely on the '
1855 'privacy_sandbox::TrackingProtectionSettings API.', ),
1856 treat_as_error=False,
1857 excluded_paths=(
1858 '^chrome/browser/ui/content_settings/',
1859 '^components/content_settings/',
1860 '^components/privacy_sandbox/tracking_protection_settings.cc',
1861 '.*test.cc',
1862 ),
Anton Maliev66751812023-08-24 16:28:131863 ),
Tom Andersoncd522072023-10-03 00:52:351864 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531865 pattern=r'/\bg_signal_connect',
1866 explanation=('Use ScopedGSignal instead of g_signal_connect*()', ),
1867 treat_as_error=True,
1868 excluded_paths=('^ui/base/glib/scoped_gsignal.h', ),
Michelle Abreo6b7437822024-04-26 17:29:041869 ),
1870 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531871 pattern=r'features::kIsolatedWebApps',
1872 explanation=(
1873 'Do not use `features::kIsolatedWebApps` directly to guard Isolated ',
1874 'Web App code. ',
Andrew Rayskiy7ae2b5d2025-02-28 16:59:381875 'Use `content::AreIsolatedWebAppsEnabled()` in the browser process '
1876 'or check the `kEnableIsolatedWebAppsInRenderer` command line flag '
1877 'in the renderer process.',
Daniel Cheng566634ff2024-06-29 14:56:531878 ),
1879 treat_as_error=True,
Andrew Rayskiy7ae2b5d2025-02-28 16:59:381880 excluded_paths=_TEST_CODE_EXCLUDED_PATHS + (
1881 '^chrome/browser/about_flags.cc',
1882 '^chrome/browser/component_updater/iwa_key_distribution_component_installer.cc',
1883 '^chrome/browser/web_applications/isolated_web_apps/chrome_content_browser_client_isolated_web_apps_part.cc',
1884 '^chrome/browser/ui/startup/bad_flags_prompt.cc',
1885 '^content/shell/browser/shell_content_browser_client.cc',
1886 )),
Daniel Cheng566634ff2024-06-29 14:56:531887 BanRule(
1888 pattern=r'features::kIsolatedWebAppDevMode',
1889 explanation=(
1890 'Do not use `features::kIsolatedWebAppDevMode` directly to guard code ',
1891 'related to Isolated Web App Developer Mode. ',
1892 'Use `web_app::IsIwaDevModeEnabled()` instead.',
1893 ),
1894 treat_as_error=True,
1895 excluded_paths=_TEST_CODE_EXCLUDED_PATHS + (
1896 '^chrome/browser/about_flags.cc',
1897 '^chrome/browser/web_applications/isolated_web_apps/isolated_web_app_features.cc',
1898 '^chrome/browser/ui/startup/bad_flags_prompt.cc',
1899 )),
1900 BanRule(
1901 pattern=r'features::kIsolatedWebAppUnmanagedInstall',
1902 explanation=(
1903 'Do not use `features::kIsolatedWebAppUnmanagedInstall` directly to ',
1904 'guard code related to unmanaged install flow for Isolated Web Apps. ',
1905 'Use `web_app::IsIwaUnmanagedInstallEnabled()` instead.',
1906 ),
1907 treat_as_error=True,
1908 excluded_paths=_TEST_CODE_EXCLUDED_PATHS + (
1909 '^chrome/browser/about_flags.cc',
1910 '^chrome/browser/web_applications/isolated_web_apps/isolated_web_app_features.cc',
1911 )),
1912 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531913 pattern='/(CUIAutomation|AccessibleObjectFromWindow)',
1914 explanation=
1915 ('Direct usage of UIAutomation or IAccessible2 in client code is '
1916 'discouraged in Chromium, as it is not an assistive technology and '
1917 'should not rely on accessibility APIs directly. These APIs can '
1918 'introduce significant performance overhead. However, if you believe '
1919 'your use case warrants an exception, please discuss it with an '
1920 'accessibility owner before proceeding. For more information on the '
1921 'performance implications, see https://docs.google.com/document/d/1jN4itpCe_bDXF0BhFaYwv4xVLsCWkL9eULdzjmLzkuk/edit#heading=h.pwth3nbwdub0.',
1922 ),
1923 treat_as_error=False,
Andrew Rayskiycdd45e732024-03-20 14:32:391924 ),
1925 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531926 pattern=r'/WIDGET_OWNS_NATIVE_WIDGET|'
1927 r'NATIVE_WIDGET_OWNS_WIDGET',
1928 explanation=
1929 ('WIDGET_OWNS_NATIVE_WIDGET and NATIVE_WIDGET_OWNS_WIDGET are in the '
1930 'process of being deprecated. Consider using the new '
1931 'CLIENT_OWNS_WIDGET ownership model. Eventually, this will be the only '
1932 'available ownership model available and the associated enumeration'
1933 'will be removed.', ),
1934 treat_as_error=False,
Andrew Rayskiycdd45e732024-03-20 14:32:391935 ),
1936 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531937 pattern='ProfileManager::GetLastUsedProfile',
1938 explanation=
1939 ('Most code should already be scoped to a Profile. Pass in a Profile* '
1940 'or retreive from an existing entity with a reference to the Profile '
1941 '(e.g. WebContents).', ),
1942 treat_as_error=False,
Arthur Sonzogni5cbd3e32024-02-08 17:51:321943 ),
Helmut Januschkab3f71ab52024-03-12 02:48:051944 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531945 pattern=(r'/FindBrowserWithUiElementContext|'
1946 r'FindBrowserWithTab|'
1947 r'FindBrowserWithGroup|'
1948 r'FindTabbedBrowser|'
1949 r'FindAnyBrowser|'
1950 r'FindBrowserWithProfile|'
Erik Chen5f02eb4c2024-08-23 06:30:441951 r'FindLastActive|'
Daniel Cheng566634ff2024-06-29 14:56:531952 r'FindBrowserWithActiveWindow'),
1953 explanation=
1954 ('Most code should already be scoped to a Browser. Pass in a Browser* '
1955 'or retreive from an existing entity with a reference to the Browser.',
1956 ),
1957 treat_as_error=False,
Helmut Januschkab3f71ab52024-03-12 02:48:051958 ),
1959 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531960 pattern='BrowserUserData',
1961 explanation=
1962 ('Do not use BrowserUserData to store state on a Browser instance. '
1963 'Instead use BrowserWindowFeatures. BrowserWindowFeatures is '
1964 'functionally identical but has two benefits: it does not force a '
1965 'dependency onto class Browser, and lifetime semantics are explicit '
1966 'rather than implicit. See BrowserUserData header file for more '
1967 'details.', ),
1968 treat_as_error=False,
Mike Doughertyab1bdec2024-08-06 16:39:011969 excluded_paths=(
Daniel Cheng6303eed2025-05-03 00:12:331970 # Exclude iOS as the iOS implementation of BrowserUserData is separate
1971 # and still in use.
1972 '^ios/', ),
Erik Chen87358e82024-06-04 02:13:121973 ),
Tom Sepezea67b6e2024-08-08 18:17:271974 BanRule(
Tom Sepezd3272cd2025-02-21 19:11:311975 pattern=r'subspan(0u,',
Daniel Cheng6303eed2025-05-03 00:12:331976 explanation=(
1977 'Prefer first(n) over subspan(0u, n) as it is shorter, and the '
1978 'compiler may have to emit a branch for the n == dynamic_extent '
1979 'case of subspan().', ),
Tom Sepezd3272cd2025-02-21 19:11:311980 treat_as_error=False,
1981 ),
1982 BanRule(
Tom Sepezea67b6e2024-08-08 18:17:271983 pattern=r'UNSAFE_TODO(',
Daniel Cheng6303eed2025-05-03 00:12:331984 explanation=(
1985 'Do not use UNSAFE_TODO() to write new unsafe code. Use only when '
1986 'removing a pre-existing file-wide allow_unsafe_buffers pragma, or '
1987 'when incrementally converting code off of unsafe interfaces', ),
Tom Sepezea67b6e2024-08-08 18:17:271988 treat_as_error=False,
1989 ),
1990 BanRule(
Claudio DeSouzaad1d1f252025-04-22 23:38:581991 pattern='#pragma allow_unsafe_buffers',
1992 explanation=
1993 ('Do not use allow_unsafe_buffers to write new unsafe code. Use only '
Daniel Cheng6303eed2025-05-03 00:12:331994 'when enabling unsafe buffers checks under a new uncovered path.', ),
Claudio DeSouzaad1d1f252025-04-22 23:38:581995 treat_as_error=False,
1996 ),
1997 BanRule(
Tom Sepezea67b6e2024-08-08 18:17:271998 pattern=r'UNSAFE_BUFFERS(',
1999 explanation=
Tom Sepeza90f92b2024-08-15 16:01:352000 ('Try to avoid using UNSAFE_BUFFERS() if at all possible. Otherwise, '
2001 'be sure to justify in a // SAFETY comment why other options are not '
Daniel Cheng6303eed2025-05-03 00:12:332002 'available, and why the code is safe.', ),
Tom Sepezea67b6e2024-08-08 18:17:272003 treat_as_error=False,
2004 ),
Erik Chend086ae02024-08-20 22:53:332005 BanRule(
2006 pattern='BrowserWithTestWindowTest',
2007 explanation=
2008 ('Do not use BrowserWithTestWindowTest. By instantiating an instance '
2009 'of class Browser, the test is no longer a unit test but is instead a '
2010 'browser test. The class BrowserWithTestWindowTest forces production '
2011 'logic to take on test-only conditionals, which is an anti-pattern. '
2012 'Features should be performing dependency injection rather than '
2013 'directly using class Browser. See '
Daniel Cheng6303eed2025-05-03 00:12:332014 'docs/chrome_browser_design_principles.md for more details.', ),
Erik Chend086ae02024-08-20 22:53:332015 treat_as_error=False,
2016 ),
Erik Chen8cf3a652024-08-23 17:13:302017 BanRule(
Erik Chen959cdd72024-08-29 02:11:212018 pattern='TestWithBrowserView',
2019 explanation=
Daniel Cheng6303eed2025-05-03 00:12:332020 ('Do not use TestWithBrowserView. See '
2021 'docs/chrome_browser_design_principles.md for details. If you want '
2022 'to write a test that has both a Browser and a BrowserView, create '
2023 'a browser_test. If you want to write a unit_test, your code must '
2024 'not reference Browser*.', ),
Erik Chen959cdd72024-08-29 02:11:212025 treat_as_error=False,
2026 ),
2027 BanRule(
Erik Chene89ebe32025-02-22 02:46:492028 pattern='CreateBrowserWithTestWindow',
2029 explanation=
Daniel Cheng6303eed2025-05-03 00:12:332030 ('Do not use CreateBrowserWithTestWindow. See '
2031 'docs/chrome_browser_design_principles.md for details. If you want '
2032 'to write a test that has a Browser, create a browser_test. If you '
2033 'want to write a unit_test, your code must not reference Browser*.',
Erik Chene89ebe32025-02-22 02:46:492034 ),
2035 treat_as_error=False,
2036 ),
2037 BanRule(
Erik Chenf12a06642025-03-13 23:30:342038 pattern='CreateBrowserWithTestWindowForParams',
2039 explanation=
Daniel Cheng6303eed2025-05-03 00:12:332040 ('Do not use CreateBrowserWithTestWindowForParams. See '
2041 'docs/chrome_browser_design_principles.md for details. If you want '
2042 'to write a test that has a Browser, create a browser_test and use '
2043 'Browser::Browser. If you want to write a unit_test, your code must '
2044 'not reference Browser*.', ),
Erik Chenf12a06642025-03-13 23:30:342045 treat_as_error=False,
2046 ),
2047 BanRule(
Erik Chen8cf3a652024-08-23 17:13:302048 pattern='RunUntilIdle',
2049 explanation=
2050 ('Do not RunUntilIdle. If possible, explicitly quit the run loop using '
2051 'run_loop.Quit() or run_loop.QuitClosure() if completion can be '
2052 'observed using a lambda or callback. Otherwise, wait for the '
Daniel Cheng6303eed2025-05-03 00:12:332053 'condition to be true via base::test::RunUntil().', ),
Erik Chen8cf3a652024-08-23 17:13:302054 treat_as_error=False,
2055 ),
Daniel Chengddde13a2024-09-05 21:39:282056 BanRule(
2057 pattern=r'/\bstd::(literals|string_literals|string_view_literals)\b',
Daniel Cheng6303eed2025-05-03 00:12:332058 explanation=(
Daniel Chengddde13a2024-09-05 21:39:282059 'User-defined literals are banned by the Google C++ style guide. '
2060 'Exceptions are provided in Chrome for string and string_view '
Daniel Cheng6303eed2025-05-03 00:12:332061 'literals that embed \\0.', ),
Daniel Chengddde13a2024-09-05 21:39:282062 treat_as_error=True,
2063 excluded_paths=(
2064 # Various tests or test helpers that embed NUL in strings or
2065 # string_views.
Daniel Chengddde13a2024-09-05 21:39:282066 r'^base/strings/string_util_unittest\.cc',
2067 r'^base/strings/utf_string_conversions_unittest\.cc',
2068 r'^chrome/browser/ash/crosapi/browser_data_back_migrator_unittest\.cc',
2069 r'^chrome/browser/ash/crosapi/browser_data_migrator_util_unittest\.cc',
2070 r'^chrome/browser/ash/crosapi/move_migrator_unittest\.cc',
Hidehiko Abe51601812025-01-12 16:17:352071 r'^chromeos/ash/experiences/arc/session/serial_number_util_unittest\.cc',
Daniel Chengddde13a2024-09-05 21:39:282072 r'^components/history/core/browser/visit_annotations_database\.cc',
2073 r'^components/history/core/browser/visit_annotations_database_unittest\.cc',
2074 r'^components/os_crypt/sync/os_crypt_unittest\.cc',
2075 r'^components/password_manager/core/browser/credentials_cleaner_unittest\.cc',
2076 r'^content/browser/file_system_access/file_system_access_file_writer_impl_unittest\.cc',
2077 r'^net/cookies/parsed_cookie_unittest\.cc',
2078 r'^third_party/blink/renderer/modules/webcodecs/test_helpers\.cc',
2079 r'^third_party/blink/renderer/modules/websockets/websocket_channel_impl_test\.cc',
2080 ),
Erik Chenba8b0cd32024-10-01 08:36:362081 ),
2082 BanRule(
2083 pattern='BUILDFLAG(GOOGLE_CHROME_BRANDING)',
2084 explanation=
2085 ('Code gated by GOOGLE_CHROME_BRANDING is effectively untested. This '
2086 'is typically wrong. Valid use cases are glue for private modules '
Daniel Cheng6303eed2025-05-03 00:12:332087 'shipped alongside Chrome, and installation-related logic.', ),
Erik Chenba8b0cd32024-10-01 08:36:362088 treat_as_error=False,
2089 ),
2090 BanRule(
2091 pattern='defined(OFFICIAL_BUILD)',
2092 explanation=
2093 ('Code gated by OFFICIAL_BUILD is effectively untested. This '
2094 'is typically wrong. One valid use case is low-level code that '
2095 'handles subtleties related to high-levels of optimizations that come '
Daniel Cheng6303eed2025-05-03 00:12:332096 'with OFFICIAL_BUILD.', ),
Erik Chenba8b0cd32024-10-01 08:36:362097 treat_as_error=False,
2098 ),
Erik Chen95b9c782024-11-08 03:26:272099 BanRule(
2100 pattern='WebContentsDestroyed',
2101 explanation=
2102 ('Do not use this method. It is invoked half-way through the '
2103 'destructor of WebContentsImpl and using it often results in crashes '
2104 'or surprising behavior. Conceptually, this is only necessary by '
2105 'objects that depend on, but outlive the WebContents. These objects '
2106 'should instead coordinate with the owner of the WebContents which is '
Daniel Cheng6303eed2025-05-03 00:12:332107 'responsible for destroying the WebContents.', ),
Erik Chen95b9c782024-11-08 03:26:272108 treat_as_error=False,
2109 ),
Maksim Sisovc98fdfa2024-11-16 20:12:272110 BanRule(
Georg Neisa7f94e62025-02-28 07:01:482111 pattern='IS_CHROMEOS_ASH',
Maksim Sisovc98fdfa2024-11-16 20:12:272112 explanation=
Georg Neisa7f94e62025-02-28 07:01:482113 ('IS_CHROMEOS_ASH is deprecated. Please use the equivalent IS_CHROMEOS '
Daniel Cheng6303eed2025-05-03 00:12:332114 'instead (Lacros is gone).', ),
Maksim Sisovc98fdfa2024-11-16 20:12:272115 treat_as_error=False,
2116 ),
Erik Chen1396bbe2025-01-27 23:39:362117 BanRule(
2118 pattern=(r'namespace {'),
2119 explanation=
2120 ('Anonymous namespaces are disallowed in C++ header files. See '
2121 'https://google.github.io/styleguide/cppguide.html#Internal_Linkage '
Daniel Cheng6303eed2025-05-03 00:12:332122 ' for details.', ),
Erik Chen1396bbe2025-01-27 23:39:362123 treat_as_error=False,
2124 excluded_paths=[
Daniel Cheng6303eed2025-05-03 00:12:332125 _THIRD_PARTY_EXCEPT_BLINK, # Don't warn in third_party folders.
2126 r'^(?!.*\.h$).*$', # Exclude all files except those that end in .h
Erik Chen1396bbe2025-01-27 23:39:362127 ],
2128 ),
Keren Zhuf06d757d2025-03-04 05:32:362129 BanRule(
2130 pattern=('AddChildViewRaw'),
2131 explanation=(
2132 'Do not use AddChildViewRaw. It is prone to memory leaks and '
2133 'use-after-free bugs. Instead, use AddChildView(std::unique_ptr). '
2134 'See https://crbug.com/40485510 for more details.', ),
2135 treat_as_error=False,
2136 ),
Nate Fischerd541ff82025-03-11 21:34:192137 BanRule(
2138 pattern=(r'IS_DESKTOP_ANDROID'),
2139 explanation=(
Eric Lokc26a46662025-05-02 01:04:032140 'Do not add new uses of IS_DESKTOP_ANDROID build flag until you '
2141 'have the approval of tedchoc@ or twellington@. '
2142 'Background: it is highly important to reduce the divergence of '
2143 'features across platforms. '
2144 'Allowances may be granted to only the directories below: '
2145 '[build/, chrome/, components/, extensions/, infra/, tools/] ',
2146 'Note: in particular we need to avoid components shared with '
2147 'WebView.',
2148 ),
Nate Fischerd541ff82025-03-11 21:34:192149 treat_as_error=False,
Ben Pastenee79d66112025-04-23 19:46:152150 surface_as_gerrit_lint=True,
Nate Fischerd541ff82025-03-11 21:34:192151 ),
[email protected]127f18ec2012-06-16 05:05:592152)
2153
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152154_DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING = (
Daniel Cheng6303eed2025-05-03 00:12:332155 'Used a predicate related to signin::ConsentLevel::kSync which will always '
2156 'return false in the future (crbug.com/40066949). Prefer using a predicate '
2157 'that also supports signin::ConsentLevel::kSignin when appropriate. It is '
2158 'safe to ignore this warning if you are just moving an existing call, or if '
2159 'you want special handling for users in the legacy state. In doubt, reach '
2160 'out to //components/sync/OWNERS.', )
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152161
2162# C++ functions related to signin::ConsentLevel::kSync which are deprecated.
Daniel Cheng6303eed2025-05-03 00:12:332163_DEPRECATED_SYNC_CONSENT_CPP_FUNCTIONS: Sequence[BanRule] = (
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152164 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:332165 'HasSyncConsent',
2166 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2167 False,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152168 ),
2169 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:332170 'CanSyncFeatureStart',
2171 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2172 False,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152173 ),
2174 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:332175 'IsSyncFeatureEnabled',
2176 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2177 False,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152178 ),
2179 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:332180 'IsSyncFeatureActive',
2181 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2182 False,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152183 ),
2184)
2185
2186# Java functions related to signin::ConsentLevel::kSync which are deprecated.
Daniel Cheng6303eed2025-05-03 00:12:332187_DEPRECATED_SYNC_CONSENT_JAVA_FUNCTIONS: Sequence[BanRule] = (
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152188 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:332189 'hasSyncConsent',
2190 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2191 False,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152192 ),
2193 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:332194 'canSyncFeatureStart',
2195 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2196 False,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152197 ),
2198 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:332199 'isSyncFeatureEnabled',
2200 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2201 False,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152202 ),
2203 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:332204 'isSyncFeatureActive',
2205 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2206 False,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152207 ),
2208)
2209
Justin Lulejian09fd06872025-04-01 22:03:282210_BANNED_MOJOM_PATTERNS: Sequence[BanRule] = (
Daniel Cheng92c15e32022-03-16 17:48:222211 BanRule(
2212 'handle<shared_buffer>',
2213 (
Justin Lulejian09fd06872025-04-01 22:03:282214 'Please use one of the more specific shared memory types instead:',
2215 ' mojo_base.mojom.ReadOnlySharedMemoryRegion',
2216 ' mojo_base.mojom.WritableSharedMemoryRegion',
2217 ' mojo_base.mojom.UnsafeSharedMemoryRegion',
Daniel Cheng92c15e32022-03-16 17:48:222218 ),
2219 True,
2220 ),
Justin Lulejian09fd06872025-04-01 22:03:282221 BanRule(
2222 'string extension_id',
2223 (
2224 'Please use the extensions::mojom::ExtensionId struct when '
2225 'passing extensions::ExtensionIds as mojom messages in order to ',
2226 'provide message validation.',
2227 ),
2228 True,
2229 # Only apply this to (mojom) files in a subdirectory of extensions.
2230 excluded_paths=(r'^((?!extensions/).)*$', ),
2231 ),
Daniel Cheng92c15e32022-03-16 17:48:222232)
2233
mlamouria82272622014-09-16 18:45:042234_IPC_ENUM_TRAITS_DEPRECATED = (
2235 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:502236 'See http://www.chromium.org/Home/chromium-security/education/'
2237 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:042238
Stephen Martinis97a394142018-06-07 23:06:052239_LONG_PATH_ERROR = (
2240 'Some files included in this CL have file names that are too long (> 200'
2241 ' characters). If committed, these files will cause issues on Windows. See'
Daniel Cheng6303eed2025-05-03 00:12:332242 ' https://crbug.com/612667 for more details.')
Stephen Martinis97a394142018-06-07 23:06:052243
Shenghua Zhangbfaa38b82017-11-16 21:58:022244_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Bruce Dawson40fece62022-09-16 19:58:312245 r".*/BuildHooksAndroidImpl\.java",
2246 r".*/LicenseContentProvider\.java",
2247 r".*/PlatformServiceBridgeImpl.java",
2248 r".*chrome/android/feed/dummy/.*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:022249]
[email protected]127f18ec2012-06-16 05:05:592250
Mohamed Heikald048240a2019-11-12 16:57:372251# List of image extensions that are used as resources in chromium.
2252_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
2253
Sean Kau46e29bc2017-08-28 16:31:162254# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:402255_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Bruce Dawson40fece62022-09-16 19:58:312256 r'test/data/',
2257 r'testing/buildbot/',
2258 r'^components/policy/resources/policy_templates\.json$',
2259 r'^third_party/protobuf/',
Camillo Bruni1411a352023-05-24 12:39:032260 r'^third_party/blink/perf_tests/speedometer.*/resources/todomvc/learn\.json',
Bruce Dawson40fece62022-09-16 19:58:312261 r'^third_party/blink/renderer/devtools/protocol\.json$',
2262 r'^third_party/blink/web_tests/external/wpt/',
2263 r'^tools/perf/',
2264 r'^tools/traceline/svgui/startup-release.json',
Daniel Cheng2d4c2d192022-07-01 01:38:312265 # vscode configuration files allow comments
Bruce Dawson40fece62022-09-16 19:58:312266 r'^tools/vscode/',
Sean Kau46e29bc2017-08-28 16:31:162267]
2268
Andrew Grieveb773bad2020-06-05 18:00:382269# These are not checked on the public chromium-presubmit trybot.
2270# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:042271# checkouts.
agrievef32bcc72016-04-04 14:57:402272_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:382273 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382274]
2275
Andrew Grieveb773bad2020-06-05 18:00:382276_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:042277 'android_webview/tools/run_cts.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:362278 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042279 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362280 'build/android/gyp/aar.pydeps',
2281 'build/android/gyp/aidl.pydeps',
2282 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:382283 'build/android/gyp/assert_static_initializers.pydeps',
Mohamed Heikal133e1f22023-04-18 20:04:372284 'build/android/gyp/binary_baseline_profile.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:022285 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:222286 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieveacac4242024-12-20 19:39:422287 'build/android/gyp/check_for_missing_direct_deps.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:112288 'build/android/gyp/compile_java.pydeps',
Peter Weneaa963f2023-01-20 19:40:302289 'build/android/gyp/compile_kt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362290 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362291 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362292 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:112293 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042294 'build/android/gyp/create_app_bundle_apks.pydeps',
2295 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362296 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:122297 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:092298 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:222299 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve2d972e5f2025-01-28 18:28:142300 'build/android/gyp/create_stub_manifest.pydeps',
Peter Wene6e017e2022-07-27 21:40:402301 'build/android/gyp/create_test_apk_wrapper_script.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002302 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362303 'build/android/gyp/dex.pydeps',
2304 'build/android/gyp/dist_aar.pydeps',
Andrew Grieve651ddb32025-01-23 03:27:342305 'build/android/gyp/errorprone.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362306 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:212307 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362308 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:362309 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362310 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:582311 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362312 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:142313 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:262314 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:472315 'build/android/gyp/java_google_api_keys.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042316 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362317 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362318 'build/android/gyp/merge_manifest.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:102319 'build/android/gyp/optimize_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362320 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:222321 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362322 'build/android/gyp/proguard.pydeps',
Mohamed Heikaldd52b452024-09-10 17:10:502323 'build/android/gyp/rename_java_classes.pydeps',
Andrew Grievee3a775ab2022-05-16 15:59:222324 'build/android/gyp/system_image_apks.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:102325 'build/android/gyp/trace_event_bytecode_rewriter.pydeps',
Andrew Grieve170b9782025-02-03 15:54:532326 'build/android/gyp/tracereferences.pydeps',
Peter Wen578730b2020-03-19 19:55:462327 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:302328 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:242329 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362330 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:462331 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:562332 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362333 'build/android/incremental_install/generate_android_manifest.pydeps',
2334 'build/android/incremental_install/write_installer_json.pydeps',
Stephanie Kim392913b452022-06-15 17:25:322335 'build/android/pylib/results/presentation/test_results_presentation.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042336 'build/android/resource_sizes.pydeps',
2337 'build/android/test_runner.pydeps',
2338 'build/android/test_wrapper/logdog_wrapper.pydeps',
zijiehe-google-com356980f2025-05-08 20:58:152339 'build/fuchsia/test/component_storage_test.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362340 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:322341 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:272342 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
2343 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Bailey Myers-Morganbd122132025-03-26 23:09:162344 'chrome/test/media_router/performance/performance_test.pydeps',
Junbo Kedcd3a452021-03-19 17:55:042345 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Mohannad Farrag19102742023-12-01 01:16:302346 'components/cronet/tools/check_combined_proguard_file.pydeps',
2347 'components/cronet/tools/generate_proguard_file.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002348 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382349 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002350 'content/public/android/generate_child_service.pydeps',
Hzj_jie77bdb802024-07-22 18:14:512351 'fuchsia_web/av_testing/av_sync_tests.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382352 'net/tools/testserver/testserver.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:182353 'testing/scripts/run_isolated_script_test.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:412354 'testing/merge_scripts/standard_isolated_script_merge.pydeps',
2355 'testing/merge_scripts/standard_gtest_merge.pydeps',
2356 'testing/merge_scripts/code_coverage/merge_results.pydeps',
2357 'testing/merge_scripts/code_coverage/merge_steps.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042358 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:422359 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
Yuki Shiino38eeaad12022-08-11 06:40:252360 'third_party/blink/renderer/bindings/scripts/check_generated_file_list.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:422361 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:132362 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Yuki Shiinoea477d32023-08-21 06:24:342363 'third_party/blink/renderer/bindings/scripts/generate_event_interface_names.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:502364 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:412365 'third_party/blink/tools/blinkpy/web_tests/merge_results.pydeps',
2366 'third_party/blink/tools/merge_web_test_results.pydeps',
John Budorickbc3571aa2019-04-25 02:20:062367 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:222368 'tools/binary_size/supersize.pydeps',
Peter Wen2dcfa6e2025-03-04 22:42:522369 'tools/cygprofile/generate_orderfile.pydeps',
Ben Pastene028104a2022-08-10 19:17:452370 'tools/perf/process_perf_results.pydeps',
Peter Wence103e12024-10-09 19:23:512371 'tools/pgo/generate_profile.pydeps',
agrievef32bcc72016-04-04 14:57:402372]
2373
2374_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
2375
Eric Boren6fd2b932018-01-25 15:05:082376# Bypass the AUTHORS check for these accounts.
Daniel Cheng6303eed2025-05-03 00:12:332377_KNOWN_ROBOTS = set() | set('%[email protected]' % s for s in (
2378 'findit-for-me', 'luci-bisection', 'predator-for-me-staging',
2379 'predator-for-me')) | set(
2380 '%[email protected]' % s
2381 for s in ('3su6n15k.default', )) | set(
2382 '%[email protected]' % s
2383 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
2384 'wpt-autoroller', 'chrome-weblayer-builder',
2385 'skylab-test-cros-roller', 'infra-try-recipes-tester',
2386 'chrome-automated-expectation',
2387 'chromium-automated-expectation', 'chrome-branch-day',
2388 'chrome-cherry-picker', 'chromium-autosharder')
2389 ) | set(
2390 '%[email protected]' % s
2391 for s in ('chromium-autoroll', 'chromium-release-autoroll')) | set(
2392 '%[email protected]' % s
2393 for s in ('chromium-internal-autoroll', )
2394 ) | set(
2395 '%[email protected]' %
2396 s for s in ('chrome-screen-ai-releaser', 'crash-eng', 'crash')
2397 ) | set(
2398 '%[email protected]' % s
2399 for s in ('swarming-tasks', )) | set(
2400 '%[email protected]' % s
2401 for s in ('global-integration-try-builder',
Rachael Newitte5664ef92025-05-08 14:00:232402 'global-integration-ci-builder')
2403 ) | set('%[email protected]' % s for s in (
2404 'chops-security-borg',
2405 'chops-security-cronjobs-cpesuggest')) | set(
2406 '%[email protected]' % s
2407 for s in ('chromeos-ci-release', ))
Eric Boren6fd2b932018-01-25 15:05:082408
Daniel Cheng6303eed2025-05-03 00:12:332409_INVALID_GRD_FILE_LINE = [(r'<file lang=.* path=.*',
2410 'Path should come before lang in GRD files.')]
2411
Eric Boren6fd2b932018-01-25 15:05:082412
Daniel Bratell65b033262019-04-23 08:17:062413def _IsCPlusPlusFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502414 """Returns True if this file contains C++-like code (and not Python,
2415 Go, Java, MarkDown, ...)"""
Daniel Bratell65b033262019-04-23 08:17:062416
Sam Maiera6e76d72022-02-11 21:43:502417 ext = input_api.os_path.splitext(file_path)[1]
2418 # This list is compatible with CppChecker.IsCppFile but we should
2419 # consider adding ".c" to it. If we do that we can use this function
2420 # at more places in the code.
2421 return ext in (
2422 '.h',
2423 '.cc',
2424 '.cpp',
2425 '.m',
2426 '.mm',
2427 )
2428
Daniel Bratell65b033262019-04-23 08:17:062429
2430def _IsCPlusPlusHeaderFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502431 return input_api.os_path.splitext(file_path)[1] == ".h"
Daniel Bratell65b033262019-04-23 08:17:062432
2433
2434def _IsJavaFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502435 return input_api.os_path.splitext(file_path)[1] == ".java"
Daniel Bratell65b033262019-04-23 08:17:062436
2437
2438def _IsProtoFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502439 return input_api.os_path.splitext(file_path)[1] == ".proto"
Daniel Bratell65b033262019-04-23 08:17:062440
Mohamed Heikal5e5b7922020-10-29 18:57:592441
Erik Staabc734cd7a2021-11-23 03:11:522442def _IsXmlOrGrdFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502443 ext = input_api.os_path.splitext(file_path)[1]
2444 return ext in ('.grd', '.xml')
Erik Staabc734cd7a2021-11-23 03:11:522445
2446
Sven Zheng76a79ea2022-12-21 21:25:242447def _IsMojomFile(input_api, file_path):
2448 return input_api.os_path.splitext(file_path)[1] == ".mojom"
2449
2450
Mohamed Heikal5e5b7922020-10-29 18:57:592451def CheckNoUpstreamDepsOnClank(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502452 """Prevent additions of dependencies from the upstream repo on //clank."""
2453 # clank can depend on clank
2454 if input_api.change.RepositoryRoot().endswith('clank'):
2455 return []
2456 build_file_patterns = [
2457 r'(.+/)?BUILD\.gn',
2458 r'.+\.gni',
2459 ]
2460 excluded_files = [r'build[/\\]config[/\\]android[/\\]config\.gni']
2461 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
Mohamed Heikal5e5b7922020-10-29 18:57:592462
Sam Maiera6e76d72022-02-11 21:43:502463 error_message = 'Disallowed import on //clank in an upstream build file:'
Mohamed Heikal5e5b7922020-10-29 18:57:592464
Sam Maiera6e76d72022-02-11 21:43:502465 def FilterFile(affected_file):
2466 return input_api.FilterSourceFile(affected_file,
2467 files_to_check=build_file_patterns,
2468 files_to_skip=excluded_files)
Mohamed Heikal5e5b7922020-10-29 18:57:592469
Sam Maiera6e76d72022-02-11 21:43:502470 problems = []
2471 for f in input_api.AffectedSourceFiles(FilterFile):
2472 local_path = f.LocalPath()
2473 for line_number, line in f.ChangedContents():
2474 if (bad_pattern.search(line)):
2475 problems.append('%s:%d\n %s' %
2476 (local_path, line_number, line.strip()))
2477 if problems:
2478 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
2479 else:
2480 return []
Mohamed Heikal5e5b7922020-10-29 18:57:592481
2482
Saagar Sanghavifceeaae2020-08-12 16:40:362483def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502484 """Attempts to prevent use of functions intended only for testing in
2485 non-testing code. For now this is just a best-effort implementation
2486 that ignores header files and may have some false positives. A
2487 better implementation would probably need a proper C++ parser.
2488 """
2489 # We only scan .cc files and the like, as the declaration of
2490 # for-testing functions in header files are hard to distinguish from
2491 # calls to such functions without a proper C++ parser.
2492 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:192493
Sam Maiera6e76d72022-02-11 21:43:502494 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
2495 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' %
2496 base_function_pattern)
2497 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
2498 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
2499 exclusion_pattern = input_api.re.compile(
2500 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' %
2501 (base_function_pattern, base_function_pattern))
2502 # Avoid a false positive in this case, where the method name, the ::, and
2503 # the closing { are all on different lines due to line wrapping.
2504 # HelperClassForTesting::
2505 # HelperClassForTesting(
2506 # args)
2507 # : member(0) {}
2508 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:192509
Sam Maiera6e76d72022-02-11 21:43:502510 def FilterFile(affected_file):
2511 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2512 input_api.DEFAULT_FILES_TO_SKIP)
2513 return input_api.FilterSourceFile(
2514 affected_file,
2515 files_to_check=file_inclusion_pattern,
2516 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:192517
Sam Maiera6e76d72022-02-11 21:43:502518 problems = []
2519 for f in input_api.AffectedSourceFiles(FilterFile):
2520 local_path = f.LocalPath()
2521 in_method_defn = False
2522 for line_number, line in f.ChangedContents():
2523 if (inclusion_pattern.search(line)
2524 and not comment_pattern.search(line)
2525 and not exclusion_pattern.search(line)
2526 and not allowlist_pattern.search(line)
2527 and not in_method_defn):
2528 problems.append('%s:%d\n %s' %
2529 (local_path, line_number, line.strip()))
2530 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:192531
Sam Maiera6e76d72022-02-11 21:43:502532 if problems:
2533 return [
2534 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
2535 ]
2536 else:
2537 return []
[email protected]55459852011-08-10 15:17:192538
2539
Saagar Sanghavifceeaae2020-08-12 16:40:362540def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502541 """This is a simplified version of
2542 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
2543 """
2544 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
2545 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
2546 name_pattern = r'ForTest(s|ing)?'
2547 # Describes an occurrence of "ForTest*" inside a // comment.
2548 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
2549 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
2550 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
2551 # Catch calls.
2552 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
2553 # Ignore definitions. (Comments are ignored separately.)
2554 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
Andrew Grieve40f451d2023-07-06 19:46:512555 allowlist_re = input_api.re.compile(r'// IN-TEST$')
Vaclav Brozek7dbc28c2018-03-27 08:35:232556
Sam Maiera6e76d72022-02-11 21:43:502557 problems = []
2558 sources = lambda x: input_api.FilterSourceFile(
2559 x,
Daniel Cheng6303eed2025-05-03 00:12:332560 files_to_skip=(
2561 ('(?i).*test', r'.*\/junit\/') + input_api.DEFAULT_FILES_TO_SKIP),
Sam Maiera6e76d72022-02-11 21:43:502562 files_to_check=[r'.*\.java$'])
2563 for f in input_api.AffectedFiles(include_deletes=False,
2564 file_filter=sources):
2565 local_path = f.LocalPath()
Vaclav Brozek7dbc28c2018-03-27 08:35:232566 is_inside_javadoc = False
Sam Maiera6e76d72022-02-11 21:43:502567 for line_number, line in f.ChangedContents():
2568 if is_inside_javadoc and javadoc_end_re.search(line):
2569 is_inside_javadoc = False
2570 if not is_inside_javadoc and javadoc_start_re.search(line):
2571 is_inside_javadoc = True
2572 if is_inside_javadoc:
2573 continue
2574 if (inclusion_re.search(line) and not comment_re.search(line)
2575 and not annotation_re.search(line)
Andrew Grieve40f451d2023-07-06 19:46:512576 and not allowlist_re.search(line)
Sam Maiera6e76d72022-02-11 21:43:502577 and not exclusion_re.search(line)):
2578 problems.append('%s:%d\n %s' %
2579 (local_path, line_number, line.strip()))
Vaclav Brozek7dbc28c2018-03-27 08:35:232580
Sam Maiera6e76d72022-02-11 21:43:502581 if problems:
2582 return [
2583 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
2584 ]
2585 else:
2586 return []
Vaclav Brozek7dbc28c2018-03-27 08:35:232587
2588
Saagar Sanghavifceeaae2020-08-12 16:40:362589def CheckNoIOStreamInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502590 """Checks to make sure no .h files include <iostream>."""
2591 files = []
2592 pattern = input_api.re.compile(r'^#include\s*<iostream>',
2593 input_api.re.MULTILINE)
2594 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2595 if not f.LocalPath().endswith('.h'):
2596 continue
2597 contents = input_api.ReadFile(f)
2598 if pattern.search(contents):
2599 files.append(f)
[email protected]10689ca2011-09-02 02:31:542600
Sam Maiera6e76d72022-02-11 21:43:502601 if len(files):
2602 return [
2603 output_api.PresubmitError(
2604 'Do not #include <iostream> in header files, since it inserts static '
2605 'initialization into every file including the header. Instead, '
2606 '#include <ostream>. See http://crbug.com/94794', files)
2607 ]
2608 return []
2609
[email protected]10689ca2011-09-02 02:31:542610
Aleksey Khoroshilov9b28c032022-06-03 16:35:322611def CheckNoStrCatRedefines(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502612 """Checks no windows headers with StrCat redefined are included directly."""
2613 files = []
Aleksey Khoroshilov9b28c032022-06-03 16:35:322614 files_to_check = (r'.+%s' % _HEADER_EXTENSIONS,
2615 r'.+%s' % _IMPLEMENTATION_EXTENSIONS)
2616 files_to_skip = (input_api.DEFAULT_FILES_TO_SKIP +
2617 _NON_BASE_DEPENDENT_PATHS)
2618 sources_filter = lambda f: input_api.FilterSourceFile(
2619 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
2620
Sam Maiera6e76d72022-02-11 21:43:502621 pattern_deny = input_api.re.compile(
2622 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
2623 input_api.re.MULTILINE)
2624 pattern_allow = input_api.re.compile(
2625 r'^#include\s"base/win/windows_defines.inc"', input_api.re.MULTILINE)
Aleksey Khoroshilov9b28c032022-06-03 16:35:322626 for f in input_api.AffectedSourceFiles(sources_filter):
Sam Maiera6e76d72022-02-11 21:43:502627 contents = input_api.ReadFile(f)
2628 if pattern_deny.search(
2629 contents) and not pattern_allow.search(contents):
2630 files.append(f.LocalPath())
Danil Chapovalov3518f362018-08-11 16:13:432631
Sam Maiera6e76d72022-02-11 21:43:502632 if len(files):
2633 return [
2634 output_api.PresubmitError(
2635 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
2636 'directly since they pollute code with StrCat macro. Instead, '
2637 'include matching header from base/win. See http://crbug.com/856536',
2638 files)
2639 ]
2640 return []
Danil Chapovalov3518f362018-08-11 16:13:432641
[email protected]10689ca2011-09-02 02:31:542642
Andrew Williamsc9f69b482023-07-10 16:07:362643def _CheckNoUNIT_TESTInSourceFiles(input_api, f):
2644 problems = []
2645
2646 unit_test_macro = input_api.re.compile(
Daniel Cheng6303eed2025-05-03 00:12:332647 r'^\s*#.*(?:ifn?def\s+UNIT_TEST|defined\s*\(?\s*UNIT_TEST\s*\)?)(?:$|\s+)'
2648 )
Andrew Williamsc9f69b482023-07-10 16:07:362649 for line_num, line in f.ChangedContents():
2650 if unit_test_macro.match(line):
2651 problems.append(' %s:%d' % (f.LocalPath(), line_num))
2652
2653 return problems
2654
2655
Saagar Sanghavifceeaae2020-08-12 16:40:362656def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502657 """Checks to make sure no source files use UNIT_TEST."""
2658 problems = []
2659 for f in input_api.AffectedFiles():
2660 if (not f.LocalPath().endswith(('.cc', '.mm'))):
2661 continue
Daniel Cheng6303eed2025-05-03 00:12:332662 problems.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, f))
[email protected]72df4e782012-06-21 16:28:182663
Sam Maiera6e76d72022-02-11 21:43:502664 if not problems:
2665 return []
2666 return [
2667 output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
2668 '\n'.join(problems))
2669 ]
2670
[email protected]72df4e782012-06-21 16:28:182671
Saagar Sanghavifceeaae2020-08-12 16:40:362672def CheckNoDISABLETypoInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502673 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
Dominic Battre033531052018-09-24 15:45:342674
Sam Maiera6e76d72022-02-11 21:43:502675 This test warns if somebody tries to disable a test with the DISABLE_ prefix
2676 instead of DISABLED_. To filter false positives, reports are only generated
2677 if a corresponding MAYBE_ line exists.
2678 """
2679 problems = []
Dominic Battre033531052018-09-24 15:45:342680
Sam Maiera6e76d72022-02-11 21:43:502681 # The following two patterns are looked for in tandem - is a test labeled
2682 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
2683 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
2684 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
Dominic Battre033531052018-09-24 15:45:342685
Sam Maiera6e76d72022-02-11 21:43:502686 # This is for the case that a test is disabled on all platforms.
2687 full_disable_pattern = input_api.re.compile(
2688 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
2689 input_api.re.MULTILINE)
Dominic Battre033531052018-09-24 15:45:342690
Arthur Sonzognic66e9c82024-04-23 07:53:042691 for f in input_api.AffectedFiles(include_deletes=False):
Sam Maiera6e76d72022-02-11 21:43:502692 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2693 continue
Dominic Battre033531052018-09-24 15:45:342694
Arthur Sonzognic66e9c82024-04-23 07:53:042695 # Search for MAYBE_, DISABLE_ pairs.
Sam Maiera6e76d72022-02-11 21:43:502696 disable_lines = {} # Maps of test name to line number.
2697 maybe_lines = {}
2698 for line_num, line in f.ChangedContents():
2699 disable_match = disable_pattern.search(line)
2700 if disable_match:
2701 disable_lines[disable_match.group(1)] = line_num
2702 maybe_match = maybe_pattern.search(line)
2703 if maybe_match:
2704 maybe_lines[maybe_match.group(1)] = line_num
Dominic Battre033531052018-09-24 15:45:342705
Sam Maiera6e76d72022-02-11 21:43:502706 # Search for DISABLE_ occurrences within a TEST() macro.
2707 disable_tests = set(disable_lines.keys())
2708 maybe_tests = set(maybe_lines.keys())
2709 for test in disable_tests.intersection(maybe_tests):
2710 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
Dominic Battre033531052018-09-24 15:45:342711
Sam Maiera6e76d72022-02-11 21:43:502712 contents = input_api.ReadFile(f)
2713 full_disable_match = full_disable_pattern.search(contents)
2714 if full_disable_match:
2715 problems.append(' %s' % f.LocalPath())
Dominic Battre033531052018-09-24 15:45:342716
Sam Maiera6e76d72022-02-11 21:43:502717 if not problems:
2718 return []
2719 return [
2720 output_api.PresubmitPromptWarning(
2721 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
2722 '\n'.join(problems))
2723 ]
2724
Dominic Battre033531052018-09-24 15:45:342725
Nina Satragnof7660532021-09-20 18:03:352726def CheckForgettingMAYBEInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502727 """Checks to make sure tests disabled conditionally are not missing a
2728 corresponding MAYBE_ prefix.
2729 """
2730 # Expect at least a lowercase character in the test name. This helps rule out
2731 # false positives with macros wrapping the actual tests name.
2732 define_maybe_pattern = input_api.re.compile(
2733 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
Bruce Dawsonffc55292022-04-20 04:18:192734 # The test_maybe_pattern needs to handle all of these forms. The standard:
2735 # IN_PROC_TEST_F(SyncTest, MAYBE_Start) {
2736 # With a wrapper macro around the test name:
2737 # IN_PROC_TEST_F(SyncTest, E2E_ENABLED(MAYBE_Start)) {
2738 # And the odd-ball NACL_BROWSER_TEST_f format:
2739 # NACL_BROWSER_TEST_F(NaClBrowserTest, SimpleLoad, {
2740 # The optional E2E_ENABLED-style is handled with (\w*\()?
2741 # The NACL_BROWSER_TEST_F pattern is handled by allowing a trailing comma or
2742 # trailing ')'.
2743 test_maybe_pattern = (
2744 r'^\s*\w*TEST[^(]*\(\s*\w+,\s*(\w*\()?MAYBE_{test_name}[\),]')
Sam Maiera6e76d72022-02-11 21:43:502745 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
2746 warnings = []
Nina Satragnof7660532021-09-20 18:03:352747
Sam Maiera6e76d72022-02-11 21:43:502748 # Read the entire files. We can't just read the affected lines, forgetting to
2749 # add MAYBE_ on a change would not show up otherwise.
Arthur Sonzognic66e9c82024-04-23 07:53:042750 for f in input_api.AffectedFiles(include_deletes=False):
Sam Maiera6e76d72022-02-11 21:43:502751 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2752 continue
2753 contents = input_api.ReadFile(f)
2754 lines = contents.splitlines(True)
2755 current_position = 0
2756 warning_test_names = set()
2757 for line_num, line in enumerate(lines, start=1):
2758 current_position += len(line)
2759 maybe_match = define_maybe_pattern.search(line)
2760 if maybe_match:
2761 test_name = maybe_match.group('test_name')
2762 # Do not warn twice for the same test.
2763 if (test_name in warning_test_names):
2764 continue
2765 warning_test_names.add(test_name)
Nina Satragnof7660532021-09-20 18:03:352766
Sam Maiera6e76d72022-02-11 21:43:502767 # Attempt to find the corresponding MAYBE_ test or suite, starting from
2768 # the current position.
2769 test_match = input_api.re.compile(
2770 test_maybe_pattern.format(test_name=test_name),
2771 input_api.re.MULTILINE).search(contents, current_position)
2772 suite_match = input_api.re.compile(
2773 suite_maybe_pattern.format(test_name=test_name),
2774 input_api.re.MULTILINE).search(contents, current_position)
2775 if not test_match and not suite_match:
2776 warnings.append(
2777 output_api.PresubmitPromptWarning(
2778 '%s:%d found MAYBE_ defined without corresponding test %s'
2779 % (f.LocalPath(), line_num, test_name)))
2780 return warnings
2781
[email protected]72df4e782012-06-21 16:28:182782
Saagar Sanghavifceeaae2020-08-12 16:40:362783def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502784 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
2785 errors = []
Kalvin Lee4a3b79de2022-05-26 16:00:162786 pattern = input_api.re.compile(r'\bDCHECK_IS_ON\b(?!\(\))',
Sam Maiera6e76d72022-02-11 21:43:502787 input_api.re.MULTILINE)
2788 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2789 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
2790 continue
2791 for lnum, line in f.ChangedContents():
2792 if input_api.re.search(pattern, line):
2793 errors.append(
2794 output_api.PresubmitError((
2795 '%s:%d: Use of DCHECK_IS_ON() must be written as "#if '
2796 + 'DCHECK_IS_ON()", not forgetting the parentheses.') %
2797 (f.LocalPath(), lnum)))
2798 return errors
danakj61c1aa22015-10-26 19:55:522799
2800
Weilun Shia487fad2020-10-28 00:10:342801# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
2802# more reliable way. See
2803# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:192804
wnwenbdc444e2016-05-25 13:44:152805
Saagar Sanghavifceeaae2020-08-12 16:40:362806def CheckFlakyTestUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502807 """Check that FlakyTest annotation is our own instead of the android one"""
2808 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
2809 files = []
2810 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2811 if f.LocalPath().endswith('Test.java'):
2812 if pattern.search(input_api.ReadFile(f)):
2813 files.append(f)
2814 if len(files):
2815 return [
2816 output_api.PresubmitError(
2817 'Use org.chromium.base.test.util.FlakyTest instead of '
2818 'android.test.FlakyTest', files)
2819 ]
2820 return []
mcasasb7440c282015-02-04 14:52:192821
wnwenbdc444e2016-05-25 13:44:152822
Saagar Sanghavifceeaae2020-08-12 16:40:362823def CheckNoDEPSGIT(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502824 """Make sure .DEPS.git is never modified manually."""
2825 if any(f.LocalPath().endswith('.DEPS.git')
2826 for f in input_api.AffectedFiles()):
2827 return [
2828 output_api.PresubmitError(
2829 'Never commit changes to .DEPS.git. This file is maintained by an\n'
2830 'automated system based on what\'s in DEPS and your changes will be\n'
2831 'overwritten.\n'
2832 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
2833 'get-the-code#Rolling_DEPS\n'
2834 'for more information')
2835 ]
2836 return []
[email protected]2a8ac9c2011-10-19 17:20:442837
2838
Sven Zheng76a79ea2022-12-21 21:25:242839def CheckCrosApiNeedBrowserTest(input_api, output_api):
2840 """Check new crosapi should add browser test."""
2841 has_new_crosapi = False
2842 has_browser_test = False
2843 for f in input_api.AffectedFiles():
Anton Bershanskyi4253349482025-02-11 21:01:272844 path = f.UnixLocalPath()
Daniel Cheng6303eed2025-05-03 00:12:332845 if (path.startswith('chromeos/crosapi/mojom')
2846 and _IsMojomFile(input_api, path) and f.Action() == 'A'):
Sven Zheng76a79ea2022-12-21 21:25:242847 has_new_crosapi = True
2848 if path.endswith('browsertest.cc') or path.endswith('browser_test.cc'):
2849 has_browser_test = True
2850 if has_new_crosapi and not has_browser_test:
2851 return [
2852 output_api.PresubmitPromptWarning(
2853 'You are adding a new crosapi, but there is no file ends with '
2854 'browsertest.cc file being added or modified. It is important '
2855 'to add crosapi browser test coverage to avoid version '
2856 ' skew issues.\n'
2857 'Check //docs/lacros/test_instructions.md for more information.'
Daniel Cheng6303eed2025-05-03 00:12:332858 )
Sven Zheng76a79ea2022-12-21 21:25:242859 ]
2860 return []
2861
2862
Saagar Sanghavifceeaae2020-08-12 16:40:362863def CheckValidHostsInDEPSOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502864 """Checks that DEPS file deps are from allowed_hosts."""
2865 # Run only if DEPS file has been modified to annoy fewer bystanders.
2866 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
2867 return []
2868 # Outsource work to gclient verify
2869 try:
2870 gclient_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
2871 'third_party', 'depot_tools',
2872 'gclient.py')
2873 input_api.subprocess.check_output(
Bruce Dawson8a43cf72022-05-13 17:10:322874 [input_api.python3_executable, gclient_path, 'verify'],
Sam Maiera6e76d72022-02-11 21:43:502875 stderr=input_api.subprocess.STDOUT)
2876 return []
2877 except input_api.subprocess.CalledProcessError as error:
2878 return [
2879 output_api.PresubmitError(
2880 'DEPS file must have only git dependencies.',
2881 long_text=error.output)
2882 ]
tandriief664692014-09-23 14:51:472883
2884
Mario Sanchez Prada2472cab2019-09-18 10:58:312885def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152886 ban_rule):
Allen Bauer84778682022-09-22 16:28:562887 """Helper method for checking for banned constructs.
Mario Sanchez Prada2472cab2019-09-18 10:58:312888
Sam Maiera6e76d72022-02-11 21:43:502889 Returns an string composed of the name of the file, the line number where the
2890 match has been found and the additional text passed as |message| in case the
2891 target type name matches the text inside the line passed as parameter.
2892 """
2893 result = []
Peng Huang9c5949a02020-06-11 19:20:542894
Daniel Chenga44a1bcd2022-03-15 20:00:152895 # Ignore comments about banned types.
2896 if input_api.re.search(r"^ *//", line):
Sam Maiera6e76d72022-02-11 21:43:502897 return result
Daniel Chenga44a1bcd2022-03-15 20:00:152898 # A // nocheck comment will bypass this error.
2899 if line.endswith(" nocheck"):
Sam Maiera6e76d72022-02-11 21:43:502900 return result
2901
2902 matched = False
Daniel Chenga44a1bcd2022-03-15 20:00:152903 if ban_rule.pattern[0:1] == '/':
2904 regex = ban_rule.pattern[1:]
Sam Maiera6e76d72022-02-11 21:43:502905 if input_api.re.search(regex, line):
2906 matched = True
Daniel Chenga44a1bcd2022-03-15 20:00:152907 elif ban_rule.pattern in line:
Sam Maiera6e76d72022-02-11 21:43:502908 matched = True
2909
2910 if matched:
2911 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
Daniel Chenga44a1bcd2022-03-15 20:00:152912 for line in ban_rule.explanation:
2913 result.append(' %s' % line)
Sam Maiera6e76d72022-02-11 21:43:502914
danakjd18e8892020-12-17 17:42:012915 return result
Mario Sanchez Prada2472cab2019-09-18 10:58:312916
2917
Saagar Sanghavifceeaae2020-08-12 16:40:362918def CheckNoBannedFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502919 """Make sure that banned functions are not used."""
Daniel Cheng6303eed2025-05-03 00:12:332920 results = []
[email protected]127f18ec2012-06-16 05:05:592921
Sam Maiera6e76d72022-02-11 21:43:502922 def IsExcludedFile(affected_file, excluded_paths):
Daniel Chenga44a1bcd2022-03-15 20:00:152923 if not excluded_paths:
2924 return False
2925
Anton Bershanskyi4253349482025-02-11 21:01:272926 local_path = affected_file.UnixLocalPath()
Sam Maiera6e76d72022-02-11 21:43:502927 for item in excluded_paths:
2928 if input_api.re.match(item, local_path):
2929 return True
2930 return False
wnwenbdc444e2016-05-25 13:44:152931
Sam Maiera6e76d72022-02-11 21:43:502932 def IsIosObjcFile(affected_file):
2933 local_path = affected_file.LocalPath()
2934 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m',
2935 '.h'):
2936 return False
2937 basename = input_api.os_path.basename(local_path)
2938 if 'ios' in basename.split('_'):
2939 return True
2940 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
2941 if sep and 'ios' in local_path.split(sep):
2942 return True
2943 return False
Sylvain Defresnea8b73d252018-02-28 15:45:542944
Daniel Chenga44a1bcd2022-03-15 20:00:152945 def CheckForMatch(affected_file, line_num: int, line: str,
2946 ban_rule: BanRule):
2947 if IsExcludedFile(affected_file, ban_rule.excluded_paths):
2948 return
2949
Ben Pastenee79d66112025-04-23 19:46:152950 message = _GetMessageForMatchingType(input_api, f, line_num, line,
2951 ban_rule)
2952 if message:
2953 result_loc = []
2954 if ban_rule.surface_as_gerrit_lint:
Daniel Cheng6303eed2025-05-03 00:12:332955 result_loc.append(
2956 output_api.PresubmitResultLocation(
2957 file_path=affected_file.LocalPath(),
2958 start_line=line_num,
2959 end_line=line_num,
2960 ))
Daniel Chenga44a1bcd2022-03-15 20:00:152961 if ban_rule.treat_as_error is not None and ban_rule.treat_as_error:
Ben Pastenee79d66112025-04-23 19:46:152962 results.append(
2963 output_api.PresubmitError('A banned function was used.\n' +
2964 '\n'.join(message),
2965 locations=result_loc))
2966
Sam Maiera6e76d72022-02-11 21:43:502967 else:
Ben Pastenee79d66112025-04-23 19:46:152968 results.append(
Daniel Cheng6303eed2025-05-03 00:12:332969 output_api.PresubmitPromptWarning(
2970 'A banned function was used.\n' + '\n'.join(message),
2971 locations=result_loc))
wnwenbdc444e2016-05-25 13:44:152972
Sam Maiera6e76d72022-02-11 21:43:502973 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2974 for f in input_api.AffectedFiles(file_filter=file_filter):
2975 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152976 for ban_rule in _BANNED_JAVA_FUNCTIONS:
2977 CheckForMatch(f, line_num, line, ban_rule)
Eric Stevensona9a980972017-09-23 00:04:412978
Clement Yan9b330cb2022-11-17 05:25:292979 file_filter = lambda f: f.LocalPath().endswith(('.js', '.ts'))
2980 for f in input_api.AffectedFiles(file_filter=file_filter):
2981 for line_num, line in f.ChangedContents():
2982 for ban_rule in _BANNED_JAVASCRIPT_FUNCTIONS:
2983 CheckForMatch(f, line_num, line, ban_rule)
2984
Sam Maiera6e76d72022-02-11 21:43:502985 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
2986 for f in input_api.AffectedFiles(file_filter=file_filter):
2987 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152988 for ban_rule in _BANNED_OBJC_FUNCTIONS:
2989 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:592990
Sam Maiera6e76d72022-02-11 21:43:502991 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
2992 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152993 for ban_rule in _BANNED_IOS_OBJC_FUNCTIONS:
2994 CheckForMatch(f, line_num, line, ban_rule)
Sylvain Defresnea8b73d252018-02-28 15:45:542995
Sam Maiera6e76d72022-02-11 21:43:502996 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
2997 for f in input_api.AffectedFiles(file_filter=egtest_filter):
2998 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152999 for ban_rule in _BANNED_IOS_EGTEST_FUNCTIONS:
3000 CheckForMatch(f, line_num, line, ban_rule)
Peter K. Lee6c03ccff2019-07-15 14:40:053001
Sam Maiera6e76d72022-02-11 21:43:503002 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
3003 for f in input_api.AffectedFiles(file_filter=file_filter):
3004 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:153005 for ban_rule in _BANNED_CPP_FUNCTIONS:
3006 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:593007
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:153008 # As of 05/2024, iOS fully migrated ConsentLevel::kSync to kSignin, and
3009 # Android is in the process of preventing new users from entering kSync.
3010 # So the warning is restricted to those platforms.
Riley Wong49be8a882025-02-27 00:38:233011 ios_pattern = input_api.re.compile(r'(^|[\W_])ios[\W_]')
Daniel Cheng6303eed2025-05-03 00:12:333012 file_filter = lambda f: (
3013 f.LocalPath().endswith(('.cc', '.mm', '.h')) and
3014 ('android' in f.LocalPath() or
3015 # Simply checking for an 'ios' substring would
3016 # catch unrelated cases, use a regex.
3017 ios_pattern.search(f.LocalPath())))
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:153018 for f in input_api.AffectedFiles(file_filter=file_filter):
3019 for line_num, line in f.ChangedContents():
3020 for ban_rule in _DEPRECATED_SYNC_CONSENT_CPP_FUNCTIONS:
3021 CheckForMatch(f, line_num, line, ban_rule)
3022
3023 file_filter = lambda f: f.LocalPath().endswith(('.java'))
3024 for f in input_api.AffectedFiles(file_filter=file_filter):
3025 for line_num, line in f.ChangedContents():
3026 for ban_rule in _DEPRECATED_SYNC_CONSENT_JAVA_FUNCTIONS:
3027 CheckForMatch(f, line_num, line, ban_rule)
3028
Daniel Cheng92c15e32022-03-16 17:48:223029 file_filter = lambda f: f.LocalPath().endswith(('.mojom'))
3030 for f in input_api.AffectedFiles(file_filter=file_filter):
3031 for line_num, line in f.ChangedContents():
3032 for ban_rule in _BANNED_MOJOM_PATTERNS:
3033 CheckForMatch(f, line_num, line, ban_rule)
3034
Ben Pastenee79d66112025-04-23 19:46:153035 return results
Daniel Cheng92c15e32022-03-16 17:48:223036
[email protected]127f18ec2012-06-16 05:05:593037
Michael Thiessen44457642020-02-06 00:24:153038def _CheckAndroidNoBannedImports(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503039 """Make sure that banned java imports are not used."""
3040 errors = []
Michael Thiessen44457642020-02-06 00:24:153041
Sam Maiera6e76d72022-02-11 21:43:503042 file_filter = lambda f: f.LocalPath().endswith(('.java'))
3043 for f in input_api.AffectedFiles(file_filter=file_filter):
3044 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:153045 for ban_rule in _BANNED_JAVA_IMPORTS:
3046 # Consider merging this into the above function. There is no
3047 # real difference anymore other than helping with a little
3048 # bit of boilerplate text. Doing so means things like
3049 # `treat_as_error` will also be uniformly handled.
Sam Maiera6e76d72022-02-11 21:43:503050 problems = _GetMessageForMatchingType(input_api, f, line_num,
Daniel Chenga44a1bcd2022-03-15 20:00:153051 line, ban_rule)
Sam Maiera6e76d72022-02-11 21:43:503052 if problems:
3053 errors.extend(problems)
3054 result = []
3055 if (errors):
3056 result.append(
3057 output_api.PresubmitError('Banned imports were used.\n' +
3058 '\n'.join(errors)))
3059 return result
Michael Thiessen44457642020-02-06 00:24:153060
3061
Saagar Sanghavifceeaae2020-08-12 16:40:363062def CheckNoPragmaOnce(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503063 """Make sure that banned functions are not used."""
3064 files = []
3065 pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
3066 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
3067 if not f.LocalPath().endswith('.h'):
3068 continue
Bruce Dawson4c4c2922022-05-02 18:07:333069 if f.LocalPath().endswith('com_imported_mstscax.h'):
3070 continue
Sam Maiera6e76d72022-02-11 21:43:503071 contents = input_api.ReadFile(f)
3072 if pattern.search(contents):
3073 files.append(f)
[email protected]6c063c62012-07-11 19:11:063074
Sam Maiera6e76d72022-02-11 21:43:503075 if files:
3076 return [
3077 output_api.PresubmitError(
3078 'Do not use #pragma once in header files.\n'
3079 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
3080 files)
3081 ]
3082 return []
[email protected]6c063c62012-07-11 19:11:063083
[email protected]127f18ec2012-06-16 05:05:593084
Saagar Sanghavifceeaae2020-08-12 16:40:363085def CheckNoTrinaryTrueFalse(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503086 """Checks to make sure we don't introduce use of foo ? true : false."""
3087 problems = []
3088 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
3089 for f in input_api.AffectedFiles():
3090 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
3091 continue
[email protected]e7479052012-09-19 00:26:123092
Sam Maiera6e76d72022-02-11 21:43:503093 for line_num, line in f.ChangedContents():
3094 if pattern.match(line):
3095 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]e7479052012-09-19 00:26:123096
Sam Maiera6e76d72022-02-11 21:43:503097 if not problems:
3098 return []
3099 return [
3100 output_api.PresubmitPromptWarning(
3101 'Please consider avoiding the "? true : false" pattern if possible.\n'
3102 + '\n'.join(problems))
3103 ]
[email protected]e7479052012-09-19 00:26:123104
3105
Saagar Sanghavifceeaae2020-08-12 16:40:363106def CheckUnwantedDependencies(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503107 """Runs checkdeps on #include and import statements added in this
3108 change. Breaking - rules is an error, breaking ! rules is a
3109 warning.
3110 """
3111 # Return early if no relevant file types were modified.
3112 for f in input_api.AffectedFiles():
3113 path = f.LocalPath()
3114 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path)
3115 or _IsJavaFile(input_api, path)):
3116 break
[email protected]55f9f382012-07-31 11:02:183117 else:
Sam Maiera6e76d72022-02-11 21:43:503118 return []
rhalavati08acd232017-04-03 07:23:283119
Sam Maiera6e76d72022-02-11 21:43:503120 import sys
3121 # We need to wait until we have an input_api object and use this
3122 # roundabout construct to import checkdeps because this file is
3123 # eval-ed and thus doesn't have __file__.
3124 original_sys_path = sys.path
3125 try:
3126 sys.path = sys.path + [
3127 input_api.os_path.join(input_api.PresubmitLocalPath(),
3128 'buildtools', 'checkdeps')
3129 ]
3130 import checkdeps
3131 from rules import Rule
3132 finally:
3133 # Restore sys.path to what it was before.
3134 sys.path = original_sys_path
[email protected]55f9f382012-07-31 11:02:183135
Sam Maiera6e76d72022-02-11 21:43:503136 added_includes = []
3137 added_imports = []
3138 added_java_imports = []
3139 for f in input_api.AffectedFiles():
3140 if _IsCPlusPlusFile(input_api, f.LocalPath()):
3141 changed_lines = [line for _, line in f.ChangedContents()]
3142 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
3143 elif _IsProtoFile(input_api, f.LocalPath()):
3144 changed_lines = [line for _, line in f.ChangedContents()]
3145 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
3146 elif _IsJavaFile(input_api, f.LocalPath()):
3147 changed_lines = [line for _, line in f.ChangedContents()]
3148 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:243149
Sam Maiera6e76d72022-02-11 21:43:503150 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
3151
3152 error_descriptions = []
3153 warning_descriptions = []
3154 error_subjects = set()
3155 warning_subjects = set()
3156
3157 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
3158 added_includes):
3159 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3160 description_with_path = '%s\n %s' % (path, rule_description)
3161 if rule_type == Rule.DISALLOW:
3162 error_descriptions.append(description_with_path)
3163 error_subjects.add("#includes")
3164 else:
3165 warning_descriptions.append(description_with_path)
3166 warning_subjects.add("#includes")
3167
3168 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
3169 added_imports):
3170 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3171 description_with_path = '%s\n %s' % (path, rule_description)
3172 if rule_type == Rule.DISALLOW:
3173 error_descriptions.append(description_with_path)
3174 error_subjects.add("imports")
3175 else:
3176 warning_descriptions.append(description_with_path)
3177 warning_subjects.add("imports")
3178
3179 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
3180 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
3181 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3182 description_with_path = '%s\n %s' % (path, rule_description)
3183 if rule_type == Rule.DISALLOW:
3184 error_descriptions.append(description_with_path)
3185 error_subjects.add("imports")
3186 else:
3187 warning_descriptions.append(description_with_path)
3188 warning_subjects.add("imports")
3189
3190 results = []
3191 if error_descriptions:
3192 results.append(
3193 output_api.PresubmitError(
3194 'You added one or more %s that violate checkdeps rules.' %
3195 " and ".join(error_subjects), error_descriptions))
3196 if warning_descriptions:
3197 results.append(
3198 output_api.PresubmitPromptOrNotify(
3199 'You added one or more %s of files that are temporarily\n'
3200 'allowed but being removed. Can you avoid introducing the\n'
3201 '%s? See relevant DEPS file(s) for details and contacts.' %
3202 (" and ".join(warning_subjects), "/".join(warning_subjects)),
3203 warning_descriptions))
3204 return results
[email protected]55f9f382012-07-31 11:02:183205
3206
Saagar Sanghavifceeaae2020-08-12 16:40:363207def CheckFilePermissions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503208 """Check that all files have their permissions properly set."""
3209 if input_api.platform == 'win32':
3210 return []
3211 checkperms_tool = input_api.os_path.join(input_api.PresubmitLocalPath(),
3212 'tools', 'checkperms',
3213 'checkperms.py')
3214 args = [
Bruce Dawson8a43cf72022-05-13 17:10:323215 input_api.python3_executable, checkperms_tool, '--root',
Sam Maiera6e76d72022-02-11 21:43:503216 input_api.change.RepositoryRoot()
3217 ]
3218 with input_api.CreateTemporaryFile() as file_list:
3219 for f in input_api.AffectedFiles():
3220 # checkperms.py file/directory arguments must be relative to the
3221 # repository.
3222 file_list.write((f.LocalPath() + '\n').encode('utf8'))
3223 file_list.close()
3224 args += ['--file-list', file_list.name]
3225 try:
3226 input_api.subprocess.check_output(args)
3227 return []
3228 except input_api.subprocess.CalledProcessError as error:
3229 return [
3230 output_api.PresubmitError('checkperms.py failed:',
3231 long_text=error.output.decode(
3232 'utf-8', 'ignore'))
3233 ]
[email protected]fbcafe5a2012-08-08 15:31:223234
3235
Saagar Sanghavifceeaae2020-08-12 16:40:363236def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503237 """Makes sure we don't include ui/aura/window_property.h
3238 in header files.
3239 """
3240 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
3241 errors = []
3242 for f in input_api.AffectedFiles():
3243 if not f.LocalPath().endswith('.h'):
3244 continue
3245 for line_num, line in f.ChangedContents():
3246 if pattern.match(line):
3247 errors.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]c8278b32012-10-30 20:35:493248
Sam Maiera6e76d72022-02-11 21:43:503249 results = []
3250 if errors:
3251 results.append(
3252 output_api.PresubmitError(
3253 'Header files should not include ui/aura/window_property.h',
3254 errors))
3255 return results
[email protected]c8278b32012-10-30 20:35:493256
3257
Omer Katzcc77ea92021-04-26 10:23:283258def CheckNoInternalHeapIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503259 """Makes sure we don't include any headers from
3260 third_party/blink/renderer/platform/heap/impl or
3261 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
3262 third_party/blink/renderer/platform/heap
3263 """
3264 impl_pattern = input_api.re.compile(
3265 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
3266 v8_wrapper_pattern = input_api.re.compile(
3267 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"'
3268 )
3269 file_filter = lambda f: not input_api.re.match(
Daniel Cheng6303eed2025-05-03 00:12:333270 r"^third_party/blink/renderer/platform/heap/.*", f.UnixLocalPath())
Sam Maiera6e76d72022-02-11 21:43:503271 errors = []
Omer Katzcc77ea92021-04-26 10:23:283272
Sam Maiera6e76d72022-02-11 21:43:503273 for f in input_api.AffectedFiles(file_filter=file_filter):
3274 for line_num, line in f.ChangedContents():
3275 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
3276 errors.append(' %s:%d' % (f.LocalPath(), line_num))
Omer Katzcc77ea92021-04-26 10:23:283277
Sam Maiera6e76d72022-02-11 21:43:503278 results = []
3279 if errors:
3280 results.append(
3281 output_api.PresubmitError(
3282 'Do not include files from third_party/blink/renderer/platform/heap/impl'
3283 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
3284 'relevant counterparts from third_party/blink/renderer/platform/heap',
3285 errors))
3286 return results
Omer Katzcc77ea92021-04-26 10:23:283287
3288
[email protected]70ca77752012-11-20 03:45:033289def _CheckForVersionControlConflictsInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:503290 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
3291 errors = []
3292 for line_num, line in f.ChangedContents():
3293 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
3294 # First-level headers in markdown look a lot like version control
3295 # conflict markers. http://daringfireball.net/projects/markdown/basics
3296 continue
3297 if pattern.match(line):
3298 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
3299 return errors
[email protected]70ca77752012-11-20 03:45:033300
3301
Saagar Sanghavifceeaae2020-08-12 16:40:363302def CheckForVersionControlConflicts(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503303 """Usually this is not intentional and will cause a compile failure."""
3304 errors = []
3305 for f in input_api.AffectedFiles():
3306 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
[email protected]70ca77752012-11-20 03:45:033307
Sam Maiera6e76d72022-02-11 21:43:503308 results = []
3309 if errors:
3310 results.append(
3311 output_api.PresubmitError(
3312 'Version control conflict markers found, please resolve.',
3313 errors))
3314 return results
[email protected]70ca77752012-11-20 03:45:033315
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203316
Saagar Sanghavifceeaae2020-08-12 16:40:363317def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
Dirk Prankee4df27972025-02-26 18:39:353318 pattern = input_api.re.compile(r'support\.google\.com\/chrome.*/answer')
Sam Maiera6e76d72022-02-11 21:43:503319 errors = []
3320 for f in input_api.AffectedFiles():
3321 for line_num, line in f.ChangedContents():
3322 if pattern.search(line):
3323 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
estadee17314a02017-01-12 16:22:163324
Sam Maiera6e76d72022-02-11 21:43:503325 results = []
3326 if errors:
3327 results.append(
3328 output_api.PresubmitPromptWarning(
3329 'Found Google support URL addressed by answer number. Please replace '
3330 'with a p= identifier instead. See crbug.com/679462\n',
3331 errors))
3332 return results
estadee17314a02017-01-12 16:22:163333
[email protected]70ca77752012-11-20 03:45:033334
Saagar Sanghavifceeaae2020-08-12 16:40:363335def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
Daniel Cheng6303eed2025-05-03 00:12:333336
Sam Maiera6e76d72022-02-11 21:43:503337 def FilterFile(affected_file):
3338 """Filter function for use with input_api.AffectedSourceFiles,
3339 below. This filters out everything except non-test files from
3340 top-level directories that generally speaking should not hard-code
3341 service URLs (e.g. src/android_webview/, src/content/ and others).
3342 """
3343 return input_api.FilterSourceFile(
3344 affected_file,
Bruce Dawson40fece62022-09-16 19:58:313345 files_to_check=[r'^(android_webview|base|content|net)/.*'],
Sam Maiera6e76d72022-02-11 21:43:503346 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3347 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:443348
Dirk Prankee4df27972025-02-26 18:39:353349 base_pattern = (r'"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
3350 r'\.(com|net)[^"]*"')
Sam Maiera6e76d72022-02-11 21:43:503351 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
3352 pattern = input_api.re.compile(base_pattern)
3353 problems = [] # items are (filename, line_number, line)
3354 for f in input_api.AffectedSourceFiles(FilterFile):
3355 for line_num, line in f.ChangedContents():
3356 if not comment_pattern.search(line) and pattern.search(line):
3357 problems.append((f.LocalPath(), line_num, line))
[email protected]06e6d0ff2012-12-11 01:36:443358
Sam Maiera6e76d72022-02-11 21:43:503359 if problems:
3360 return [
3361 output_api.PresubmitPromptOrNotify(
3362 'Most layers below src/chrome/ should not hardcode service URLs.\n'
3363 'Are you sure this is correct?', [
3364 ' %s:%d: %s' % (problem[0], problem[1], problem[2])
3365 for problem in problems
3366 ])
3367 ]
3368 else:
3369 return []
[email protected]06e6d0ff2012-12-11 01:36:443370
3371
Saagar Sanghavifceeaae2020-08-12 16:40:363372def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503373 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
James Cook6b6597c2019-11-06 22:05:293374
Sam Maiera6e76d72022-02-11 21:43:503375 def FileFilter(affected_file):
3376 """Includes directories known to be Chrome OS only."""
3377 return input_api.FilterSourceFile(
3378 affected_file,
3379 files_to_check=(
3380 '^ash/',
3381 '^chromeos/', # Top-level src/chromeos.
3382 '.*/chromeos/', # Any path component.
3383 '^components/arc',
3384 '^components/exo'),
3385 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:293386
Sam Maiera6e76d72022-02-11 21:43:503387 prefs = []
3388 priority_prefs = []
3389 for f in input_api.AffectedFiles(file_filter=FileFilter):
3390 for line_num, line in f.ChangedContents():
3391 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF',
3392 line):
3393 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
3394 prefs.append(' %s' % line)
3395 if input_api.re.search(
3396 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
3397 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
3398 priority_prefs.append(' %s' % line)
3399
3400 results = []
3401 if (prefs):
3402 results.append(
3403 output_api.PresubmitPromptWarning(
3404 'Preferences were registered as SYNCABLE_PREF and will be controlled '
3405 'by browser sync settings. If these prefs should be controlled by OS '
3406 'sync settings use SYNCABLE_OS_PREF instead.\n' +
3407 '\n'.join(prefs)))
3408 if (priority_prefs):
3409 results.append(
3410 output_api.PresubmitPromptWarning(
3411 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
3412 'controlled by browser sync settings. If these prefs should be '
3413 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
3414 'instead.\n' + '\n'.join(prefs)))
3415 return results
James Cook6b6597c2019-11-06 22:05:293416
3417
Saagar Sanghavifceeaae2020-08-12 16:40:363418def CheckNoAbbreviationInPngFileName(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503419 """Makes sure there are no abbreviations in the name of PNG files.
3420 The native_client_sdk directory is excluded because it has auto-generated PNG
3421 files for documentation.
3422 """
3423 errors = []
Yuanqing Zhu9eef02832022-12-04 14:42:173424 files_to_check = [r'.*\.png$']
Daniel Cheng6303eed2025-05-03 00:12:333425 files_to_skip = [
3426 r'^native_client_sdk/',
3427 r'^services/test/',
3428 r'^third_party/blink/web_tests/',
3429 ]
Sam Maiera6e76d72022-02-11 21:43:503430 file_filter = lambda f: input_api.FilterSourceFile(
3431 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Dirk Prankee4df27972025-02-26 18:39:353432 abbreviation = input_api.re.compile(r'.+_[a-z]\.png|.+_[a-z]_.*\.png')
Sam Maiera6e76d72022-02-11 21:43:503433 for f in input_api.AffectedFiles(include_deletes=False,
3434 file_filter=file_filter):
Yuanqing Zhu9eef02832022-12-04 14:42:173435 file_name = input_api.os_path.split(f.LocalPath())[1]
3436 if abbreviation.search(file_name):
3437 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:273438
Sam Maiera6e76d72022-02-11 21:43:503439 results = []
3440 if errors:
3441 results.append(
3442 output_api.PresubmitError(
3443 'The name of PNG files should not have abbreviations. \n'
3444 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
3445 'Contact [email protected] if you have questions.', errors))
3446 return results
[email protected]d2530012013-01-25 16:39:273447
Daniel Cheng6303eed2025-05-03 00:12:333448
Evan Stade7cd4a2c2022-08-04 23:37:253449def CheckNoProductIconsAddedToPublicRepo(input_api, output_api):
3450 """Heuristically identifies product icons based on their file name and reminds
3451 contributors not to add them to the Chromium repository.
3452 """
Peter Kotwiczf634d072025-04-28 22:48:153453
3454 if input_api.change.RepositoryRoot().endswith('clank'):
Daniel Cheng6303eed2025-05-03 00:12:333455 # TODO(crbug.com/414435241): Change check to compute whether change
3456 # belongs to internal repository instead of relying on string matching.
3457 return []
Peter Kotwiczf634d072025-04-28 22:48:153458
Evan Stade7cd4a2c2022-08-04 23:37:253459 errors = []
3460 files_to_check = [r'.*google.*\.png$|.*google.*\.svg$|.*google.*\.icon$']
3461 file_filter = lambda f: input_api.FilterSourceFile(
3462 f, files_to_check=files_to_check)
3463 for f in input_api.AffectedFiles(include_deletes=False,
3464 file_filter=file_filter):
3465 errors.append(' %s' % f.LocalPath())
3466
3467 results = []
3468 if errors:
Bruce Dawson3bcf0c92022-08-12 00:03:083469 # Give warnings instead of errors on presubmit --all and presubmit
3470 # --files.
Daniel Cheng6303eed2025-05-03 00:12:333471 message_type = (output_api.PresubmitNotifyResult
3472 if input_api.no_diffs else output_api.PresubmitError)
Evan Stade7cd4a2c2022-08-04 23:37:253473 results.append(
Bruce Dawson3bcf0c92022-08-12 00:03:083474 message_type(
Evan Stade7cd4a2c2022-08-04 23:37:253475 'Trademarked images should not be added to the public repo. '
3476 'See crbug.com/944754', errors))
3477 return results
3478
[email protected]d2530012013-01-25 16:39:273479
Daniel Cheng4dcdb6b2017-04-13 08:30:173480def _ExtractAddRulesFromParsedDeps(parsed_deps):
Sam Maiera6e76d72022-02-11 21:43:503481 """Extract the rules that add dependencies from a parsed DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:173482
Sam Maiera6e76d72022-02-11 21:43:503483 Args:
3484 parsed_deps: the locals dictionary from evaluating the DEPS file."""
3485 add_rules = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:173486 add_rules.update([
Sam Maiera6e76d72022-02-11 21:43:503487 rule[1:] for rule in parsed_deps.get('include_rules', [])
Daniel Cheng4dcdb6b2017-04-13 08:30:173488 if rule.startswith('+') or rule.startswith('!')
3489 ])
Sam Maiera6e76d72022-02-11 21:43:503490 for _, rules in parsed_deps.get('specific_include_rules', {}).items():
3491 add_rules.update([
3492 rule[1:] for rule in rules
3493 if rule.startswith('+') or rule.startswith('!')
3494 ])
3495 return add_rules
Daniel Cheng4dcdb6b2017-04-13 08:30:173496
3497
3498def _ParseDeps(contents):
Sam Maiera6e76d72022-02-11 21:43:503499 """Simple helper for parsing DEPS files."""
Daniel Cheng4dcdb6b2017-04-13 08:30:173500
Sam Maiera6e76d72022-02-11 21:43:503501 # Stubs for handling special syntax in the root DEPS file.
3502 class _VarImpl:
Daniel Cheng6303eed2025-05-03 00:12:333503
Sam Maiera6e76d72022-02-11 21:43:503504 def __init__(self, local_scope):
3505 self._local_scope = local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:173506
Sam Maiera6e76d72022-02-11 21:43:503507 def Lookup(self, var_name):
3508 """Implements the Var syntax."""
3509 try:
3510 return self._local_scope['vars'][var_name]
3511 except KeyError:
3512 raise Exception('Var is not defined: %s' % var_name)
Daniel Cheng4dcdb6b2017-04-13 08:30:173513
Sam Maiera6e76d72022-02-11 21:43:503514 local_scope = {}
3515 global_scope = {
3516 'Var': _VarImpl(local_scope).Lookup,
3517 'Str': str,
3518 }
Dirk Pranke1b9e06382021-05-14 01:16:223519
Sam Maiera6e76d72022-02-11 21:43:503520 exec(contents, global_scope, local_scope)
3521 return local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:173522
3523
Andrew Grieveb77ac762024-11-29 15:01:483524def _FindAllDepsFilesForSubpath(input_api, subpath):
3525 ret = []
3526 while subpath:
Daniel Cheng6303eed2025-05-03 00:12:333527 cur = input_api.os_path.join(input_api.change.RepositoryRoot(),
3528 subpath, 'DEPS')
Joanna Wang130e7bdd2024-12-10 17:39:033529 if input_api.os_path.isfile(cur):
Andrew Grieveb77ac762024-11-29 15:01:483530 ret.append(cur)
3531 subpath = input_api.os_path.dirname(subpath)
3532 return ret
3533
3534
3535def _FindAddedDepsThatRequireReview(input_api, depended_on_paths):
3536 """Filters to those whose DEPS set new_usages_require_review=True"""
3537 ret = set()
3538 cache = {}
3539 for target_path in depended_on_paths:
3540 for subpath in _FindAllDepsFilesForSubpath(input_api, target_path):
3541 config = cache.get(subpath)
3542 if config is None:
3543 config = _ParseDeps(input_api.ReadFile(subpath))
3544 cache[subpath] = config
3545 if config.get('new_usages_require_review'):
3546 ret.add(target_path)
3547 break
3548 return ret
3549
3550
Daniel Cheng4dcdb6b2017-04-13 08:30:173551def _CalculateAddedDeps(os_path, old_contents, new_contents):
Sam Maiera6e76d72022-02-11 21:43:503552 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
3553 a set of DEPS entries that we should look up.
[email protected]14a6131c2014-01-08 01:15:413554
Sam Maiera6e76d72022-02-11 21:43:503555 For a directory (rather than a specific filename) we fake a path to
3556 a specific filename by adding /DEPS. This is chosen as a file that
3557 will seldom or never be subject to per-file include_rules.
3558 """
3559 # We ignore deps entries on auto-generated directories.
3560 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:083561
Sam Maiera6e76d72022-02-11 21:43:503562 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
3563 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
Daniel Cheng4dcdb6b2017-04-13 08:30:173564
Sam Maiera6e76d72022-02-11 21:43:503565 added_deps = new_deps.difference(old_deps)
Daniel Cheng4dcdb6b2017-04-13 08:30:173566
Sam Maiera6e76d72022-02-11 21:43:503567 results = set()
3568 for added_dep in added_deps:
3569 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
3570 continue
3571 # Assume that a rule that ends in .h is a rule for a specific file.
3572 if added_dep.endswith('.h'):
3573 results.add(added_dep)
3574 else:
3575 results.add(os_path.join(added_dep, 'DEPS'))
3576 return results
[email protected]f32e2d1e2013-07-26 21:39:083577
Daniel Cheng6303eed2025-05-03 00:12:333578
Stephanie Kimec4f55a2024-04-24 16:54:023579def CheckForNewDEPSDownloadFromGoogleStorageHooks(input_api, output_api):
3580 """Checks that there are no new download_from_google_storage hooks"""
3581 for f in input_api.AffectedFiles(include_deletes=False):
3582 if f.LocalPath() == 'DEPS':
3583 old_hooks = _ParseDeps('\n'.join(f.OldContents()))['hooks']
3584 new_hooks = _ParseDeps('\n'.join(f.NewContents()))['hooks']
3585 old_name_to_hook = {hook['name']: hook for hook in old_hooks}
3586 new_name_to_hook = {hook['name']: hook for hook in new_hooks}
3587 added_hook_names = set(new_name_to_hook.keys()) - set(
3588 old_name_to_hook.keys())
3589 if not added_hook_names:
3590 return []
3591 new_download_from_google_storage_hooks = []
3592 for new_hook in added_hook_names:
3593 hook = new_name_to_hook[new_hook]
3594 action_cmd = hook['action']
3595 if any('download_from_google_storage' in arg
Daniel Cheng6303eed2025-05-03 00:12:333596 for arg in action_cmd):
Stephanie Kimec4f55a2024-04-24 16:54:023597 new_download_from_google_storage_hooks.append(new_hook)
3598 if new_download_from_google_storage_hooks:
3599 return [
3600 output_api.PresubmitError(
3601 'Please do not add new download_from_google_storage '
3602 'hooks. Instead, add a `gcs` dep_type entry to `deps`. '
3603 'See https://chromium.googlesource.com/chromium/src.git'
3604 '/+/refs/heads/main/docs/gcs_dependencies.md for more '
3605 'info. Added hooks:',
3606 items=new_download_from_google_storage_hooks)
3607 ]
3608 return []
3609
[email protected]f32e2d1e2013-07-26 21:39:083610
Rasika Navarangec2d33d22024-05-23 15:19:023611def CheckEachPerfettoTestDataFileHasDepsEntry(input_api, output_api):
3612 test_data_filter = lambda f: input_api.FilterSourceFile(
Rasika Navarange08e542162024-05-31 13:31:263613 f, files_to_check=[r'^base/tracing/test/data_sha256/.*\.sha256'])
Rasika Navarangec2d33d22024-05-23 15:19:023614 if not any(input_api.AffectedFiles(file_filter=test_data_filter)):
3615 return []
3616
3617 # Find DEPS entry
3618 deps_entry = []
Rasika Navarange277cd662024-06-04 10:14:593619 old_deps_entry = []
Rasika Navarangec2d33d22024-05-23 15:19:023620 for f in input_api.AffectedFiles(include_deletes=False):
3621 if f.LocalPath() == 'DEPS':
3622 new_deps = _ParseDeps('\n'.join(f.NewContents()))['deps']
3623 deps_entry = new_deps['src/base/tracing/test/data']
Rasika Navarange277cd662024-06-04 10:14:593624 old_deps = _ParseDeps('\n'.join(f.OldContents()))['deps']
3625 old_deps_entry = old_deps['src/base/tracing/test/data']
Rasika Navarangec2d33d22024-05-23 15:19:023626 if not deps_entry:
Rasika Navarange08e542162024-05-31 13:31:263627 # TODO(312895063):Add back error when .sha256 files have been moved.
Daniel Cheng6303eed2025-05-03 00:12:333628 return [
3629 output_api.PresubmitError(
3630 'You must update the DEPS file when you update a '
3631 '.sha256 file in base/tracing/test/data_sha256')
3632 ]
Rasika Navarangec2d33d22024-05-23 15:19:023633
3634 output = []
3635 for f in input_api.AffectedFiles(file_filter=test_data_filter):
3636 objects = deps_entry['objects']
3637 if not f.NewContents():
3638 # Deleted file so check that DEPS entry removed
3639 sha256_from_file = f.OldContents()[0]
3640 object_entry = next(
Daniel Cheng6303eed2025-05-03 00:12:333641 (item
3642 for item in objects if item["sha256sum"] == sha256_from_file),
Rasika Navarangec2d33d22024-05-23 15:19:023643 None)
Daniel Cheng6303eed2025-05-03 00:12:333644 old_entry = next((item for item in old_deps_entry['objects']
3645 if item["sha256sum"] == sha256_from_file), None)
Rasika Navarangec2d33d22024-05-23 15:19:023646 if object_entry:
Rasika Navarange277cd662024-06-04 10:14:593647 # Allow renaming of objects with the same hash
3648 if object_entry['object_name'] != old_entry['object_name']:
3649 continue
Daniel Cheng6303eed2025-05-03 00:12:333650 output.append(
3651 output_api.PresubmitError(
3652 'You deleted %s so you must also remove the corresponding DEPS entry.'
3653 % f.LocalPath()))
Rasika Navarangec2d33d22024-05-23 15:19:023654 continue
3655
3656 sha256_from_file = f.NewContents()[0]
3657 object_entry = next(
Daniel Cheng6303eed2025-05-03 00:12:333658 (item
3659 for item in objects if item["sha256sum"] == sha256_from_file),
Rasika Navarangec2d33d22024-05-23 15:19:023660 None)
3661 if not object_entry:
Daniel Cheng6303eed2025-05-03 00:12:333662 output.append(
3663 output_api.PresubmitError(
3664 'No corresponding DEPS entry found for %s. '
3665 'Run `base/tracing/test/test_data.py get_deps --filepath %s` '
3666 'to generate the DEPS entry.' %
3667 (f.LocalPath(), f.LocalPath())))
Rasika Navarangec2d33d22024-05-23 15:19:023668
3669 if output:
Daniel Cheng6303eed2025-05-03 00:12:333670 output.append(
3671 output_api.PresubmitError(
3672 'The DEPS entry for `src/base/tracing/test/data` in the DEPS file has not been '
3673 'updated properly. Run `base/tracing/test/test_data.py get_all_deps` to see what '
3674 'the DEPS entry should look like.'))
Rasika Navarangec2d33d22024-05-23 15:19:023675 return output
3676
3677
Saagar Sanghavifceeaae2020-08-12 16:40:363678def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503679 """When a dependency prefixed with + is added to a DEPS file, we
3680 want to make sure that the change is reviewed by an OWNER of the
3681 target file or directory, to avoid layering violations from being
3682 introduced. This check verifies that this happens.
3683 """
3684 # We rely on Gerrit's code-owners to check approvals.
3685 # input_api.gerrit is always set for Chromium, but other projects
3686 # might not use Gerrit.
Bruce Dawson344ab262022-06-04 11:35:103687 if not input_api.gerrit or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:503688 return []
Bruce Dawsonb357aeb2022-08-09 15:38:303689 if 'PRESUBMIT_SKIP_NETWORK' in input_api.environ:
Sam Maiera6e76d72022-02-11 21:43:503690 return []
Bruce Dawsonb357aeb2022-08-09 15:38:303691 try:
Daniel Cheng6303eed2025-05-03 00:12:333692 if (input_api.change.issue
3693 and input_api.gerrit.IsOwnersOverrideApproved(
3694 input_api.change.issue)):
Bruce Dawsonb357aeb2022-08-09 15:38:303695 # Skip OWNERS check when Owners-Override label is approved. This is
3696 # intended for global owners, trusted bots, and on-call sheriffs.
3697 # Review is still required for these changes.
3698 return []
3699 except Exception as e:
Daniel Cheng6303eed2025-05-03 00:12:333700 return [
3701 output_api.PresubmitPromptWarning(
3702 'Failed to retrieve owner override status - %s' % str(e))
3703 ]
Edward Lesmes6fba51082021-01-20 04:20:233704
Andrew Grieveb77ac762024-11-29 15:01:483705 # A set of paths (that might not exist) that are being added as DEPS
3706 # (via lines like "+foo/bar/baz").
3707 depended_on_paths = set()
jochen53efcdd2016-01-29 05:09:243708
Daniel Cheng6303eed2025-05-03 00:12:333709 file_filter = lambda f: not input_api.re.match(r"^third_party/blink/.*",
3710 f.UnixLocalPath())
Sam Maiera6e76d72022-02-11 21:43:503711 for f in input_api.AffectedFiles(include_deletes=False,
3712 file_filter=file_filter):
3713 filename = input_api.os_path.basename(f.LocalPath())
3714 if filename == 'DEPS':
Andrew Grieveb77ac762024-11-29 15:01:483715 depended_on_paths.update(
Sam Maiera6e76d72022-02-11 21:43:503716 _CalculateAddedDeps(input_api.os_path,
3717 '\n'.join(f.OldContents()),
3718 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:553719
Andrew Grieveb77ac762024-11-29 15:01:483720 # Requiring reviews is opt-in as of https://crbug.com/365797506
Daniel Cheng6303eed2025-05-03 00:12:333721 depended_on_paths = _FindAddedDepsThatRequireReview(
3722 input_api, depended_on_paths)
Andrew Grieveb77ac762024-11-29 15:01:483723 if not depended_on_paths:
Sam Maiera6e76d72022-02-11 21:43:503724 return []
[email protected]e871964c2013-05-13 14:14:553725
Sam Maiera6e76d72022-02-11 21:43:503726 if input_api.is_committing:
3727 if input_api.tbr:
3728 return [
3729 output_api.PresubmitNotifyResult(
3730 '--tbr was specified, skipping OWNERS check for DEPS additions'
3731 )
3732 ]
Daniel Cheng3008dc12022-05-13 04:02:113733 # TODO(dcheng): Make this generate an error on dry runs if the reviewer
3734 # is not added, to prevent review serialization.
Sam Maiera6e76d72022-02-11 21:43:503735 if input_api.dry_run:
3736 return [
3737 output_api.PresubmitNotifyResult(
3738 'This is a dry run, skipping OWNERS check for DEPS additions'
3739 )
3740 ]
3741 if not input_api.change.issue:
3742 return [
3743 output_api.PresubmitError(
3744 "DEPS approval by OWNERS check failed: this change has "
3745 "no change number, so we can't check it for approvals.")
3746 ]
3747 output = output_api.PresubmitError
[email protected]14a6131c2014-01-08 01:15:413748 else:
Sam Maiera6e76d72022-02-11 21:43:503749 output = output_api.PresubmitNotifyResult
[email protected]e871964c2013-05-13 14:14:553750
Sam Maiera6e76d72022-02-11 21:43:503751 owner_email, reviewers = (
3752 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3753 input_api, None, approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:553754
Sam Maiera6e76d72022-02-11 21:43:503755 owner_email = owner_email or input_api.change.author_email
3756
3757 approval_status = input_api.owners_client.GetFilesApprovalStatus(
Andrew Grieveb77ac762024-11-29 15:01:483758 depended_on_paths, reviewers.union([owner_email]), [])
Sam Maiera6e76d72022-02-11 21:43:503759 missing_files = [
Andrew Grieveb77ac762024-11-29 15:01:483760 p for p in depended_on_paths
3761 if approval_status[p] != input_api.owners_client.APPROVED
Sam Maiera6e76d72022-02-11 21:43:503762 ]
3763
3764 # We strip the /DEPS part that was added by
3765 # _FilesToCheckForIncomingDeps to fake a path to a file in a
3766 # directory.
3767 def StripDeps(path):
3768 start_deps = path.rfind('/DEPS')
3769 if start_deps != -1:
3770 return path[:start_deps]
3771 else:
3772 return path
3773
Scott Leebf6a0942024-06-26 22:59:393774 submodule_paths = set(input_api.ListSubmodules())
Daniel Cheng6303eed2025-05-03 00:12:333775
Scott Leebf6a0942024-06-26 22:59:393776 def is_from_submodules(path, submodule_paths):
3777 path = input_api.os_path.normpath(path)
3778 while path:
3779 if path in submodule_paths:
3780 return True
3781
3782 # All deps should be a relative path from the checkout.
3783 # i.e., shouldn't start with "/" or "c:\", for example.
3784 #
3785 # That said, this is to prevent an infinite loop, just in case
3786 # an input dep path starts with "/", because
3787 # os.path.dirname("/") => "/"
3788 parent = input_api.os_path.dirname(path)
3789 if parent == path:
3790 break
3791 path = parent
3792
3793 return False
3794
Sam Maiera6e76d72022-02-11 21:43:503795 unapproved_dependencies = [
3796 "'+%s'," % StripDeps(path) for path in missing_files
Scott Leebf6a0942024-06-26 22:59:393797 # if a newly added dep is from a submodule, it becomes trickier
3798 # to get suggested owners, especially it is from a different host.
3799 #
3800 # skip the review enforcement for cross-repo deps.
3801 if not is_from_submodules(path, submodule_paths)
Sam Maiera6e76d72022-02-11 21:43:503802 ]
3803
3804 if unapproved_dependencies:
3805 output_list = [
3806 output(
3807 'You need LGTM from owners of depends-on paths in DEPS that were '
3808 'modified in this CL:\n %s' %
3809 '\n '.join(sorted(unapproved_dependencies)))
3810 ]
3811 suggested_owners = input_api.owners_client.SuggestOwners(
3812 missing_files, exclude=[owner_email])
3813 output_list.append(
3814 output('Suggested missing target path OWNERS:\n %s' %
3815 '\n '.join(suggested_owners or [])))
3816 return output_list
3817
3818 return []
[email protected]e871964c2013-05-13 14:14:553819
3820
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493821# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:363822def CheckSpamLogging(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503823 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3824 files_to_skip = (
3825 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3826 input_api.DEFAULT_FILES_TO_SKIP + (
Jaewon Jung2f323bb2022-12-07 23:55:013827 r"^base/fuchsia/scoped_fx_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313828 r"^base/logging\.h$",
3829 r"^base/logging\.cc$",
3830 r"^base/task/thread_pool/task_tracker\.cc$",
3831 r"^chrome/app/chrome_main_delegate\.cc$",
Yao Li359937b2023-02-15 23:43:033832 r"^chrome/browser/ash/arc/enterprise/cert_store/arc_cert_installer\.cc$",
3833 r"^chrome/browser/ash/policy/remote_commands/user_command_arc_job\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313834 r"^chrome/browser/chrome_browser_main\.cc$",
3835 r"^chrome/browser/ui/startup/startup_browser_creator\.cc$",
3836 r"^chrome/browser/browser_switcher/bho/.*",
3837 r"^chrome/browser/diagnostics/diagnostics_writer\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313838 r"^chrome/chrome_elf/dll_hash/dll_hash_main\.cc$",
3839 r"^chrome/installer/setup/.*",
Daniel Ruberyad36eea2024-08-01 01:38:323840 # crdmg runs as a separate binary which intentionally does
3841 # not depend on base logging.
3842 r"^chrome/utility/safe_browsing/mac/crdmg\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313843 r"^chromecast/",
Vigen Issahhanjane2d93822023-06-30 15:57:203844 r"^components/cast",
Bruce Dawson40fece62022-09-16 19:58:313845 r"^components/media_control/renderer/media_playback_options\.cc$",
Salma Elmahallawy52976452023-01-27 17:04:493846 r"^components/policy/core/common/policy_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313847 r"^components/viz/service/display/"
Sam Maiera6e76d72022-02-11 21:43:503848 r"overlay_strategy_underlay_cast\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313849 r"^components/zucchini/.*",
Sam Maiera6e76d72022-02-11 21:43:503850 # TODO(peter): Remove exception. https://crbug.com/534537
Bruce Dawson40fece62022-09-16 19:58:313851 r"^content/browser/notifications/"
Sam Maiera6e76d72022-02-11 21:43:503852 r"notification_event_dispatcher_impl\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313853 r"^content/common/gpu/client/gl_helper_benchmark\.cc$",
3854 r"^courgette/courgette_minimal_tool\.cc$",
3855 r"^courgette/courgette_tool\.cc$",
3856 r"^extensions/renderer/logging_native_handler\.cc$",
3857 r"^fuchsia_web/common/init_logging\.cc$",
3858 r"^fuchsia_web/runners/common/web_component\.cc$",
Caroline Liua7050132023-02-13 22:23:153859 r"^fuchsia_web/shell/.*\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313860 r"^headless/app/headless_shell\.cc$",
3861 r"^ipc/ipc_logging\.cc$",
3862 r"^native_client_sdk/",
3863 r"^remoting/base/logging\.h$",
3864 r"^remoting/host/.*",
3865 r"^sandbox/linux/.*",
Austin Sullivana6054e02024-05-20 16:31:293866 r"^services/webnn/tflite/graph_impl_tflite\.cc$",
3867 r"^services/webnn/coreml/graph_impl_coreml\.mm$",
Bruce Dawson40fece62022-09-16 19:58:313868 r"^storage/browser/file_system/dump_file_system\.cc$",
Steinar H. Gundersone5689e42024-08-07 18:17:193869 r"^testing/perf/",
Bruce Dawson40fece62022-09-16 19:58:313870 r"^tools/",
3871 r"^ui/base/resource/data_pack\.cc$",
3872 r"^ui/aura/bench/bench_main\.cc$",
3873 r"^ui/ozone/platform/cast/",
3874 r"^ui/base/x/xwmstartupcheck/"
Sam Maiera6e76d72022-02-11 21:43:503875 r"xwmstartupcheck\.cc$"))
3876 source_file_filter = lambda x: input_api.FilterSourceFile(
3877 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:403878
Sam Maiera6e76d72022-02-11 21:43:503879 log_info = set([])
3880 printf = set([])
[email protected]85218562013-11-22 07:41:403881
Sam Maiera6e76d72022-02-11 21:43:503882 for f in input_api.AffectedSourceFiles(source_file_filter):
3883 for _, line in f.ChangedContents():
3884 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
3885 log_info.add(f.LocalPath())
3886 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
3887 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:373888
Sam Maiera6e76d72022-02-11 21:43:503889 if input_api.re.search(r"\bprintf\(", line):
3890 printf.add(f.LocalPath())
3891 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
3892 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:403893
Sam Maiera6e76d72022-02-11 21:43:503894 if log_info:
3895 return [
3896 output_api.PresubmitError(
3897 'These files spam the console log with LOG(INFO):',
3898 items=log_info)
3899 ]
3900 if printf:
3901 return [
3902 output_api.PresubmitError(
3903 'These files spam the console log with printf/fprintf:',
3904 items=printf)
3905 ]
3906 return []
[email protected]85218562013-11-22 07:41:403907
3908
Saagar Sanghavifceeaae2020-08-12 16:40:363909def CheckForAnonymousVariables(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503910 """These types are all expected to hold locks while in scope and
3911 so should never be anonymous (which causes them to be immediately
3912 destroyed)."""
3913 they_who_must_be_named = [
3914 'base::AutoLock',
3915 'base::AutoReset',
3916 'base::AutoUnlock',
3917 'SkAutoAlphaRestore',
3918 'SkAutoBitmapShaderInstall',
3919 'SkAutoBlitterChoose',
3920 'SkAutoBounderCommit',
3921 'SkAutoCallProc',
3922 'SkAutoCanvasRestore',
3923 'SkAutoCommentBlock',
3924 'SkAutoDescriptor',
3925 'SkAutoDisableDirectionCheck',
3926 'SkAutoDisableOvalCheck',
3927 'SkAutoFree',
3928 'SkAutoGlyphCache',
3929 'SkAutoHDC',
3930 'SkAutoLockColors',
3931 'SkAutoLockPixels',
3932 'SkAutoMalloc',
3933 'SkAutoMaskFreeImage',
3934 'SkAutoMutexAcquire',
3935 'SkAutoPathBoundsUpdate',
3936 'SkAutoPDFRelease',
3937 'SkAutoRasterClipValidate',
3938 'SkAutoRef',
3939 'SkAutoTime',
3940 'SkAutoTrace',
3941 'SkAutoUnref',
3942 ]
3943 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
3944 # bad: base::AutoLock(lock.get());
3945 # not bad: base::AutoLock lock(lock.get());
3946 bad_pattern = input_api.re.compile(anonymous)
3947 # good: new base::AutoLock(lock.get())
3948 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
3949 errors = []
[email protected]49aa76a2013-12-04 06:59:163950
Sam Maiera6e76d72022-02-11 21:43:503951 for f in input_api.AffectedFiles():
3952 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
3953 continue
3954 for linenum, line in f.ChangedContents():
3955 if bad_pattern.search(line) and not good_pattern.search(line):
3956 errors.append('%s:%d' % (f.LocalPath(), linenum))
[email protected]49aa76a2013-12-04 06:59:163957
Sam Maiera6e76d72022-02-11 21:43:503958 if errors:
3959 return [
3960 output_api.PresubmitError(
3961 'These lines create anonymous variables that need to be named:',
3962 items=errors)
3963 ]
3964 return []
[email protected]49aa76a2013-12-04 06:59:163965
3966
Saagar Sanghavifceeaae2020-08-12 16:40:363967def CheckUniquePtrOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503968 # Returns whether |template_str| is of the form <T, U...> for some types T
Glen Robertson9142ffd72024-05-16 01:37:473969 # and U, or is invalid due to mismatched angle bracket pairs. Assumes that
3970 # |template_str| is already in the form <...>.
3971 def HasMoreThanOneArgOrInvalid(template_str):
Sam Maiera6e76d72022-02-11 21:43:503972 # Level of <...> nesting.
3973 nesting = 0
3974 for c in template_str:
3975 if c == '<':
3976 nesting += 1
3977 elif c == '>':
3978 nesting -= 1
3979 elif c == ',' and nesting == 1:
3980 return True
Glen Robertson9142ffd72024-05-16 01:37:473981 if nesting != 0:
Daniel Cheng566634ff2024-06-29 14:56:533982 # Invalid.
3983 return True
Sam Maiera6e76d72022-02-11 21:43:503984 return False
Vaclav Brozekb7fadb692018-08-30 06:39:533985
Sam Maiera6e76d72022-02-11 21:43:503986 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3987 sources = lambda affected_file: input_api.FilterSourceFile(
3988 affected_file,
3989 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3990 DEFAULT_FILES_TO_SKIP),
3991 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:553992
Sam Maiera6e76d72022-02-11 21:43:503993 # Pattern to capture a single "<...>" block of template arguments. It can
3994 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
3995 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
3996 # latter would likely require counting that < and > match, which is not
3997 # expressible in regular languages. Should the need arise, one can introduce
3998 # limited counting (matching up to a total number of nesting depth), which
3999 # should cover all practical cases for already a low nesting limit.
4000 template_arg_pattern = (
4001 r'<[^>]*' # Opening block of <.
4002 r'>([^<]*>)?') # Closing block of >.
4003 # Prefix expressing that whatever follows is not already inside a <...>
4004 # block.
4005 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
4006 null_construct_pattern = input_api.re.compile(
4007 not_inside_template_arg_pattern + r'\bstd::unique_ptr' +
4008 template_arg_pattern + r'\(\)')
Vaclav Brozeka54c528b2018-04-06 19:23:554009
Sam Maiera6e76d72022-02-11 21:43:504010 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
4011 template_arg_no_array_pattern = (
4012 r'<[^>]*[^]]' # Opening block of <.
4013 r'>([^(<]*[^]]>)?') # Closing block of >.
4014 # Prefix saying that what follows is the start of an expression.
4015 start_of_expr_pattern = r'(=|\breturn|^)\s*'
4016 # Suffix saying that what follows are call parentheses with a non-empty list
4017 # of arguments.
4018 nonempty_arg_list_pattern = r'\(([^)]|$)'
4019 # Put the template argument into a capture group for deeper examination later.
4020 return_construct_pattern = input_api.re.compile(
4021 start_of_expr_pattern + r'std::unique_ptr' + '(?P<template_arg>' +
4022 template_arg_no_array_pattern + ')' + nonempty_arg_list_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:554023
Sam Maiera6e76d72022-02-11 21:43:504024 problems_constructor = []
4025 problems_nullptr = []
4026 for f in input_api.AffectedSourceFiles(sources):
4027 for line_number, line in f.ChangedContents():
4028 # Disallow:
4029 # return std::unique_ptr<T>(foo);
4030 # bar = std::unique_ptr<T>(foo);
4031 # But allow:
4032 # return std::unique_ptr<T[]>(foo);
4033 # bar = std::unique_ptr<T[]>(foo);
4034 # And also allow cases when the second template argument is present. Those
4035 # cases cannot be handled by std::make_unique:
4036 # return std::unique_ptr<T, U>(foo);
4037 # bar = std::unique_ptr<T, U>(foo);
4038 local_path = f.LocalPath()
4039 return_construct_result = return_construct_pattern.search(line)
Glen Robertson9142ffd72024-05-16 01:37:474040 if return_construct_result and not HasMoreThanOneArgOrInvalid(
Sam Maiera6e76d72022-02-11 21:43:504041 return_construct_result.group('template_arg')):
4042 problems_constructor.append(
4043 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4044 # Disallow:
4045 # std::unique_ptr<T>()
4046 if null_construct_pattern.search(line):
4047 problems_nullptr.append(
4048 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Vaclav Brozek851d9602018-04-04 16:13:054049
Sam Maiera6e76d72022-02-11 21:43:504050 errors = []
4051 if problems_nullptr:
4052 errors.append(
4053 output_api.PresubmitPromptWarning(
4054 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
4055 problems_nullptr))
4056 if problems_constructor:
4057 errors.append(
4058 output_api.PresubmitError(
4059 'The following files use explicit std::unique_ptr constructor. '
4060 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
4061 'std::make_unique is not an option.', problems_constructor))
4062 return errors
Peter Kasting4844e46e2018-02-23 07:27:104063
4064
Saagar Sanghavifceeaae2020-08-12 16:40:364065def CheckUserActionUpdate(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504066 """Checks if any new user action has been added."""
4067 if any('actions.xml' == input_api.os_path.basename(f)
4068 for f in input_api.LocalPaths()):
4069 # If actions.xml is already included in the changelist, the PRESUBMIT
4070 # for actions.xml will do a more complete presubmit check.
4071 return []
4072
4073 file_inclusion_pattern = [r'.*\.(cc|mm)$']
4074 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
4075 input_api.DEFAULT_FILES_TO_SKIP)
4076 file_filter = lambda f: input_api.FilterSourceFile(
4077 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
4078
4079 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
4080 current_actions = None
4081 for f in input_api.AffectedFiles(file_filter=file_filter):
4082 for line_num, line in f.ChangedContents():
4083 match = input_api.re.search(action_re, line)
4084 if match:
4085 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
4086 # loaded only once.
4087 if not current_actions:
Bruce Dawson6cb2d4d2023-03-01 21:35:094088 with open('tools/metrics/actions/actions.xml',
4089 encoding='utf-8') as actions_f:
Sam Maiera6e76d72022-02-11 21:43:504090 current_actions = actions_f.read()
4091 # Search for the matched user action name in |current_actions|.
4092 for action_name in match.groups():
4093 action = 'name="{0}"'.format(action_name)
4094 if action not in current_actions:
4095 return [
4096 output_api.PresubmitPromptWarning(
4097 'File %s line %d: %s is missing in '
4098 'tools/metrics/actions/actions.xml. Please run '
4099 'tools/metrics/actions/extract_actions.py to update.'
4100 % (f.LocalPath(), line_num, action_name))
4101 ]
[email protected]999261d2014-03-03 20:08:084102 return []
4103
[email protected]999261d2014-03-03 20:08:084104
Daniel Cheng13ca61a882017-08-25 15:11:254105def _ImportJSONCommentEater(input_api):
Sam Maiera6e76d72022-02-11 21:43:504106 import sys
4107 sys.path = sys.path + [
4108 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4109 'json_comment_eater')
4110 ]
4111 import json_comment_eater
4112 return json_comment_eater
Daniel Cheng13ca61a882017-08-25 15:11:254113
4114
[email protected]99171a92014-06-03 08:44:474115def _GetJSONParseError(input_api, filename, eat_comments=True):
dchenge07de812016-06-20 19:27:174116 try:
Sam Maiera6e76d72022-02-11 21:43:504117 contents = input_api.ReadFile(filename)
4118 if eat_comments:
4119 json_comment_eater = _ImportJSONCommentEater(input_api)
4120 contents = json_comment_eater.Nom(contents)
dchenge07de812016-06-20 19:27:174121
Sam Maiera6e76d72022-02-11 21:43:504122 input_api.json.loads(contents)
4123 except ValueError as e:
4124 return e
Andrew Grieve4deedb12022-02-03 21:34:504125 return None
4126
4127
Sam Maiera6e76d72022-02-11 21:43:504128def _GetIDLParseError(input_api, filename):
4129 try:
4130 contents = input_api.ReadFile(filename)
Devlin Croninf7582a12022-04-21 21:14:284131 for i, char in enumerate(contents):
Daniel Chenga37c03db2022-05-12 17:20:344132 if not char.isascii():
4133 return (
4134 'Non-ascii character "%s" (ord %d) found at offset %d.' %
4135 (char, ord(char), i))
Sam Maiera6e76d72022-02-11 21:43:504136 idl_schema = input_api.os_path.join(input_api.PresubmitLocalPath(),
4137 'tools', 'json_schema_compiler',
4138 'idl_schema.py')
4139 process = input_api.subprocess.Popen(
Bruce Dawson679fb082022-04-14 00:47:284140 [input_api.python3_executable, idl_schema],
Sam Maiera6e76d72022-02-11 21:43:504141 stdin=input_api.subprocess.PIPE,
4142 stdout=input_api.subprocess.PIPE,
4143 stderr=input_api.subprocess.PIPE,
4144 universal_newlines=True)
4145 (_, error) = process.communicate(input=contents)
4146 return error or None
4147 except ValueError as e:
4148 return e
agrievef32bcc72016-04-04 14:57:404149
agrievef32bcc72016-04-04 14:57:404150
Sam Maiera6e76d72022-02-11 21:43:504151def CheckParseErrors(input_api, output_api):
4152 """Check that IDL and JSON files do not contain syntax errors."""
4153 actions = {
4154 '.idl': _GetIDLParseError,
4155 '.json': _GetJSONParseError,
4156 }
4157 # Most JSON files are preprocessed and support comments, but these do not.
4158 json_no_comments_patterns = [
Bruce Dawson40fece62022-09-16 19:58:314159 r'^testing/',
Sam Maiera6e76d72022-02-11 21:43:504160 ]
4161 # Only run IDL checker on files in these directories.
4162 idl_included_patterns = [
Bruce Dawson40fece62022-09-16 19:58:314163 r'^chrome/common/extensions/api/',
4164 r'^extensions/common/api/',
Sam Maiera6e76d72022-02-11 21:43:504165 ]
agrievef32bcc72016-04-04 14:57:404166
Sam Maiera6e76d72022-02-11 21:43:504167 def get_action(affected_file):
4168 filename = affected_file.LocalPath()
4169 return actions.get(input_api.os_path.splitext(filename)[1])
agrievef32bcc72016-04-04 14:57:404170
Sam Maiera6e76d72022-02-11 21:43:504171 def FilterFile(affected_file):
4172 action = get_action(affected_file)
4173 if not action:
4174 return False
Anton Bershanskyi4253349482025-02-11 21:01:274175 path = affected_file.UnixLocalPath()
agrievef32bcc72016-04-04 14:57:404176
Sam Maiera6e76d72022-02-11 21:43:504177 if _MatchesFile(input_api,
4178 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS, path):
4179 return False
4180
4181 if (action == _GetIDLParseError
4182 and not _MatchesFile(input_api, idl_included_patterns, path)):
4183 return False
4184 return True
4185
4186 results = []
4187 for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
4188 include_deletes=False):
4189 action = get_action(affected_file)
4190 kwargs = {}
4191 if (action == _GetJSONParseError
4192 and _MatchesFile(input_api, json_no_comments_patterns,
Anton Bershanskyi4253349482025-02-11 21:01:274193 affected_file.UnixLocalPath())):
Sam Maiera6e76d72022-02-11 21:43:504194 kwargs['eat_comments'] = False
4195 parse_error = action(input_api, affected_file.AbsoluteLocalPath(),
4196 **kwargs)
4197 if parse_error:
4198 results.append(
4199 output_api.PresubmitError(
4200 '%s could not be parsed: %s' %
4201 (affected_file.LocalPath(), parse_error)))
4202 return results
4203
4204
4205def CheckJavaStyle(input_api, output_api):
4206 """Runs checkstyle on changed java files and returns errors if any exist."""
4207
4208 # Return early if no java files were modified.
4209 if not any(
4210 _IsJavaFile(input_api, f.LocalPath())
4211 for f in input_api.AffectedFiles()):
4212 return []
4213
4214 import sys
4215 original_sys_path = sys.path
4216 try:
4217 sys.path = sys.path + [
4218 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4219 'android', 'checkstyle')
4220 ]
4221 import checkstyle
4222 finally:
4223 # Restore sys.path to what it was before.
4224 sys.path = original_sys_path
4225
Daniel Cheng6303eed2025-05-03 00:12:334226 return checkstyle.run_presubmit(input_api,
4227 output_api,
4228 files_to_skip=_EXCLUDED_PATHS +
4229 input_api.DEFAULT_FILES_TO_SKIP)
Sam Maiera6e76d72022-02-11 21:43:504230
4231
4232def CheckPythonDevilInit(input_api, output_api):
4233 """Checks to make sure devil is initialized correctly in python scripts."""
4234 script_common_initialize_pattern = input_api.re.compile(
4235 r'script_common\.InitializeEnvironment\(')
4236 devil_env_config_initialize = input_api.re.compile(
4237 r'devil_env\.config\.Initialize\(')
4238
4239 errors = []
4240
4241 sources = lambda affected_file: input_api.FilterSourceFile(
4242 affected_file,
4243 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314244 r'^build/android/devil_chromium\.py',
Sven Zheng8e079562024-05-10 20:11:064245 r'^tools/bisect-builds\.py',
Bruce Dawson40fece62022-09-16 19:58:314246 r'^third_party/.*',
Sam Maiera6e76d72022-02-11 21:43:504247 )),
4248 files_to_check=[r'.*\.py$'])
4249
4250 for f in input_api.AffectedSourceFiles(sources):
4251 for line_num, line in f.ChangedContents():
4252 if (script_common_initialize_pattern.search(line)
4253 or devil_env_config_initialize.search(line)):
4254 errors.append("%s:%d" % (f.LocalPath(), line_num))
4255
4256 results = []
4257
4258 if errors:
4259 results.append(
4260 output_api.PresubmitError(
4261 'Devil initialization should always be done using '
4262 'devil_chromium.Initialize() in the chromium project, to use better '
4263 'defaults for dependencies (ex. up-to-date version of adb).',
4264 errors))
4265
4266 return results
4267
4268
4269def _MatchesFile(input_api, patterns, path):
4270 for pattern in patterns:
4271 if input_api.re.search(pattern, path):
4272 return True
4273 return False
4274
4275
Daniel Chenga37c03db2022-05-12 17:20:344276def _ChangeHasSecurityReviewer(input_api, owners_file):
4277 """Returns True iff the CL has a reviewer from SECURITY_OWNERS.
Sam Maiera6e76d72022-02-11 21:43:504278
Daniel Chenga37c03db2022-05-12 17:20:344279 Args:
4280 input_api: The presubmit input API.
4281 owners_file: OWNERS file with required reviewers. Typically, this is
4282 something like ipc/SECURITY_OWNERS.
4283
4284 Note: if the presubmit is running for commit rather than for upload, this
4285 only returns True if a security reviewer has also approved the CL.
Sam Maiera6e76d72022-02-11 21:43:504286 """
Daniel Chengd88244472022-05-16 09:08:474287 # Owners-Override should bypass all additional OWNERS enforcement checks.
4288 # A CR+1 vote will still be required to land this change.
4289 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
4290 input_api.change.issue)):
4291 return True
4292
Daniel Chenga37c03db2022-05-12 17:20:344293 owner_email, reviewers = (
4294 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
Daniel Cheng3008dc12022-05-13 04:02:114295 input_api,
4296 None,
4297 approval_needed=input_api.is_committing and not input_api.dry_run))
Sam Maiera6e76d72022-02-11 21:43:504298
Daniel Chenga37c03db2022-05-12 17:20:344299 security_owners = input_api.owners_client.ListOwners(owners_file)
4300 return any(owner in reviewers for owner in security_owners)
Sam Maiera6e76d72022-02-11 21:43:504301
Daniel Chenga37c03db2022-05-12 17:20:344302
4303@dataclass
Daniel Cheng171dad8d2022-05-21 00:40:254304class _SecurityProblemWithItems:
4305 problem: str
4306 items: Sequence[str]
4307
4308
4309@dataclass
Daniel Chenga37c03db2022-05-12 17:20:344310class _MissingSecurityOwnersResult:
Daniel Cheng171dad8d2022-05-21 00:40:254311 owners_file_problems: Sequence[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:344312 has_security_sensitive_files: bool
Daniel Cheng171dad8d2022-05-21 00:40:254313 missing_reviewer_problem: Optional[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:344314
4315
Daniel Cheng6303eed2025-05-03 00:12:334316def _FindMissingSecurityOwners(
4317 input_api,
4318 output_api,
4319 file_patterns: Sequence[str],
4320 excluded_patterns: Sequence[str],
4321 required_owners_file: str,
4322 custom_rule_function: Optional[Callable] = None
4323) -> _MissingSecurityOwnersResult:
Daniel Chenga37c03db2022-05-12 17:20:344324 """Find OWNERS files missing per-file rules for security-sensitive files.
4325
4326 Args:
4327 input_api: the PRESUBMIT input API object.
4328 output_api: the PRESUBMIT output API object.
4329 file_patterns: basename patterns that require a corresponding per-file
4330 security restriction.
4331 excluded_patterns: path patterns that should be exempted from
4332 requiring a security restriction.
4333 required_owners_file: path to the required OWNERS file, e.g.
4334 ipc/SECURITY_OWNERS
4335 cc_alias: If not None, email that will be CCed automatically if the
4336 change contains security-sensitive files, as determined by
4337 `file_patterns` and `excluded_patterns`.
4338 custom_rule_function: If not None, will be called with `input_api` and
4339 the current file under consideration. Returning True will add an
4340 exact match per-file rule check for the current file.
4341 """
4342
4343 # `to_check` is a mapping of an OWNERS file path to Patterns.
4344 #
4345 # Patterns is a dictionary mapping glob patterns (suitable for use in
4346 # per-file rules) to a PatternEntry.
4347 #
Sam Maiera6e76d72022-02-11 21:43:504348 # PatternEntry is a dictionary with two keys:
4349 # - 'files': the files that are matched by this pattern
4350 # - 'rules': the per-file rules needed for this pattern
Daniel Chenga37c03db2022-05-12 17:20:344351 #
Sam Maiera6e76d72022-02-11 21:43:504352 # For example, if we expect OWNERS file to contain rules for *.mojom and
4353 # *_struct_traits*.*, Patterns might look like this:
4354 # {
4355 # '*.mojom': {
4356 # 'files': ...,
4357 # 'rules': [
4358 # 'per-file *.mojom=set noparent',
4359 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
4360 # ],
4361 # },
4362 # '*_struct_traits*.*': {
4363 # 'files': ...,
4364 # 'rules': [
4365 # 'per-file *_struct_traits*.*=set noparent',
4366 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
4367 # ],
4368 # },
4369 # }
4370 to_check = {}
Daniel Chenga37c03db2022-05-12 17:20:344371 files_to_review = []
Sam Maiera6e76d72022-02-11 21:43:504372
Daniel Chenga37c03db2022-05-12 17:20:344373 def AddPatternToCheck(file, pattern):
Sam Maiera6e76d72022-02-11 21:43:504374 owners_file = input_api.os_path.join(
Daniel Chengd88244472022-05-16 09:08:474375 input_api.os_path.dirname(file.LocalPath()), 'OWNERS')
Sam Maiera6e76d72022-02-11 21:43:504376 if owners_file not in to_check:
4377 to_check[owners_file] = {}
4378 if pattern not in to_check[owners_file]:
4379 to_check[owners_file][pattern] = {
4380 'files': [],
4381 'rules': [
Daniel Chenga37c03db2022-05-12 17:20:344382 f'per-file {pattern}=set noparent',
4383 f'per-file {pattern}=file://{required_owners_file}',
Sam Maiera6e76d72022-02-11 21:43:504384 ]
4385 }
Daniel Chenged57a162022-05-25 02:56:344386 to_check[owners_file][pattern]['files'].append(file.LocalPath())
Daniel Chenga37c03db2022-05-12 17:20:344387 files_to_review.append(file.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:504388
Daniel Chenga37c03db2022-05-12 17:20:344389 # Only enforce security OWNERS rules for a directory if that directory has a
4390 # file that matches `file_patterns`. For example, if a directory only
4391 # contains *.mojom files and no *_messages*.h files, the check should only
4392 # ensure that rules for *.mojom files are present.
4393 for file in input_api.AffectedFiles(include_deletes=False):
4394 file_basename = input_api.os_path.basename(file.LocalPath())
4395 if custom_rule_function is not None and custom_rule_function(
4396 input_api, file):
4397 AddPatternToCheck(file, file_basename)
4398 continue
Sam Maiera6e76d72022-02-11 21:43:504399
Daniel Chenga37c03db2022-05-12 17:20:344400 if any(
4401 input_api.fnmatch.fnmatch(file.LocalPath(), pattern)
4402 for pattern in excluded_patterns):
Sam Maiera6e76d72022-02-11 21:43:504403 continue
4404
4405 for pattern in file_patterns:
Daniel Chenga37c03db2022-05-12 17:20:344406 # Unlike `excluded_patterns`, `file_patterns` is checked only against the
4407 # file's basename.
4408 if input_api.fnmatch.fnmatch(file_basename, pattern):
4409 AddPatternToCheck(file, pattern)
Sam Maiera6e76d72022-02-11 21:43:504410 break
4411
Daniel Chenga37c03db2022-05-12 17:20:344412 has_security_sensitive_files = bool(to_check)
Daniel Cheng171dad8d2022-05-21 00:40:254413
4414 # Check if any newly added lines in OWNERS files intersect with required
4415 # per-file OWNERS lines. If so, ensure that a security reviewer is included.
4416 # This is a hack, but is needed because the OWNERS check (by design) ignores
4417 # new OWNERS entries; otherwise, a non-owner could add someone as a new
4418 # OWNER and have that newly-added OWNER self-approve their own addition.
4419 newly_covered_files = []
4420 for file in input_api.AffectedFiles(include_deletes=False):
4421 if not file.LocalPath() in to_check:
4422 continue
4423 for _, line in file.ChangedContents():
4424 for _, entry in to_check[file.LocalPath()].items():
4425 if line in entry['rules']:
4426 newly_covered_files.extend(entry['files'])
4427
4428 missing_reviewer_problems = None
4429 if newly_covered_files and not _ChangeHasSecurityReviewer(
Daniel Chenga37c03db2022-05-12 17:20:344430 input_api, required_owners_file):
Daniel Cheng171dad8d2022-05-21 00:40:254431 missing_reviewer_problems = _SecurityProblemWithItems(
4432 f'Review from an owner in {required_owners_file} is required for '
4433 'the following newly-added files:',
4434 [f'{file}' for file in sorted(set(newly_covered_files))])
Sam Maiera6e76d72022-02-11 21:43:504435
4436 # Go through the OWNERS files to check, filtering out rules that are already
4437 # present in that OWNERS file.
4438 for owners_file, patterns in to_check.items():
4439 try:
Daniel Cheng171dad8d2022-05-21 00:40:254440 lines = set(
4441 input_api.ReadFile(
4442 input_api.os_path.join(input_api.change.RepositoryRoot(),
4443 owners_file)).splitlines())
4444 for entry in patterns.values():
4445 entry['rules'] = [
4446 rule for rule in entry['rules'] if rule not in lines
4447 ]
Sam Maiera6e76d72022-02-11 21:43:504448 except IOError:
4449 # No OWNERS file, so all the rules are definitely missing.
4450 continue
4451
4452 # All the remaining lines weren't found in OWNERS files, so emit an error.
Daniel Cheng171dad8d2022-05-21 00:40:254453 owners_file_problems = []
Daniel Chenga37c03db2022-05-12 17:20:344454
Sam Maiera6e76d72022-02-11 21:43:504455 for owners_file, patterns in to_check.items():
4456 missing_lines = []
4457 files = []
4458 for _, entry in patterns.items():
Daniel Chenged57a162022-05-25 02:56:344459 files.extend(entry['files'])
Sam Maiera6e76d72022-02-11 21:43:504460 missing_lines.extend(entry['rules'])
Sam Maiera6e76d72022-02-11 21:43:504461 if missing_lines:
Daniel Cheng171dad8d2022-05-21 00:40:254462 joined_missing_lines = '\n'.join(line for line in missing_lines)
4463 owners_file_problems.append(
4464 _SecurityProblemWithItems(
4465 'Found missing OWNERS lines for security-sensitive files. '
4466 f'Please add the following lines to {owners_file}:\n'
4467 f'{joined_missing_lines}\n\nTo ensure security review for:',
4468 files))
Daniel Chenga37c03db2022-05-12 17:20:344469
Daniel Cheng171dad8d2022-05-21 00:40:254470 return _MissingSecurityOwnersResult(owners_file_problems,
Daniel Chenga37c03db2022-05-12 17:20:344471 has_security_sensitive_files,
Daniel Cheng171dad8d2022-05-21 00:40:254472 missing_reviewer_problems)
Daniel Chenga37c03db2022-05-12 17:20:344473
4474
4475def _CheckChangeForIpcSecurityOwners(input_api, output_api):
4476 # Whether or not a file affects IPC is (mostly) determined by a simple list
4477 # of filename patterns.
4478 file_patterns = [
4479 # Legacy IPC:
4480 '*_messages.cc',
4481 '*_messages*.h',
4482 '*_param_traits*.*',
4483 # Mojo IPC:
4484 '*.mojom',
4485 '*_mojom_traits*.*',
4486 '*_type_converter*.*',
4487 # Android native IPC:
4488 '*.aidl',
4489 ]
4490
Daniel Chenga37c03db2022-05-12 17:20:344491 excluded_patterns = [
Daniel Cheng518943f2022-05-12 22:15:464492 # These third_party directories do not contain IPCs, but contain files
4493 # matching the above patterns, which trigger false positives.
Daniel Chenga37c03db2022-05-12 17:20:344494 'third_party/crashpad/*',
4495 'third_party/blink/renderer/platform/bindings/*',
Evan Stade23a77da2025-02-06 21:15:314496 'third_party/protobuf/*',
Daniel Chenga37c03db2022-05-12 17:20:344497 'third_party/win_build_output/*',
Daniel Chengd88244472022-05-16 09:08:474498 # Enum-only mojoms used for web metrics, so no security review needed.
4499 'third_party/blink/public/mojom/use_counter/metrics/*',
Daniel Chenga37c03db2022-05-12 17:20:344500 # These files are just used to communicate between class loaders running
4501 # in the same process.
4502 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
4503 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
4504 ]
4505
4506 def IsMojoServiceManifestFile(input_api, file):
Dirk Prankee4df27972025-02-26 18:39:354507 manifest_pattern = input_api.re.compile(r'manifests?\.(cc|h)$')
Daniel Cheng6303eed2025-05-03 00:12:334508 test_manifest_pattern = input_api.re.compile(
4509 r'test_manifests?\.(cc|h)')
Daniel Chenga37c03db2022-05-12 17:20:344510 if not manifest_pattern.search(file.LocalPath()):
4511 return False
4512
4513 if test_manifest_pattern.search(file.LocalPath()):
4514 return False
4515
4516 # All actual service manifest files should contain at least one
4517 # qualified reference to service_manager::Manifest.
4518 return any('service_manager::Manifest' in line
4519 for line in file.NewContents())
4520
4521 return _FindMissingSecurityOwners(
4522 input_api,
4523 output_api,
4524 file_patterns,
4525 excluded_patterns,
4526 'ipc/SECURITY_OWNERS',
4527 custom_rule_function=IsMojoServiceManifestFile)
4528
4529
4530def _CheckChangeForFuchsiaSecurityOwners(input_api, output_api):
4531 file_patterns = [
4532 # Component specifications.
4533 '*.cml', # Component Framework v2.
4534 '*.cmx', # Component Framework v1.
4535
4536 # Fuchsia IDL protocol specifications.
4537 '*.fidl',
4538 ]
4539
4540 # Don't check for owners files for changes in these directories.
4541 excluded_patterns = [
4542 'third_party/crashpad/*',
4543 ]
4544
4545 return _FindMissingSecurityOwners(input_api, output_api, file_patterns,
4546 excluded_patterns,
4547 'build/fuchsia/SECURITY_OWNERS')
4548
4549
4550def CheckSecurityOwners(input_api, output_api):
4551 """Checks that various security-sensitive files have an IPC OWNERS rule."""
4552 ipc_results = _CheckChangeForIpcSecurityOwners(input_api, output_api)
4553 fuchsia_results = _CheckChangeForFuchsiaSecurityOwners(
4554 input_api, output_api)
4555
4556 if ipc_results.has_security_sensitive_files:
4557 output_api.AppendCC('[email protected]')
Sam Maiera6e76d72022-02-11 21:43:504558
4559 results = []
Daniel Chenga37c03db2022-05-12 17:20:344560
Daniel Cheng171dad8d2022-05-21 00:40:254561 missing_reviewer_problems = []
4562 if ipc_results.missing_reviewer_problem:
4563 missing_reviewer_problems.append(ipc_results.missing_reviewer_problem)
4564 if fuchsia_results.missing_reviewer_problem:
4565 missing_reviewer_problems.append(
4566 fuchsia_results.missing_reviewer_problem)
Daniel Chenga37c03db2022-05-12 17:20:344567
Daniel Cheng171dad8d2022-05-21 00:40:254568 # Missing reviewers are an error unless there's no issue number
4569 # associated with this branch; in that case, the presubmit is being run
4570 # with --all or --files.
4571 #
4572 # Note that upload should never be an error; otherwise, it would be
4573 # impossible to upload changes at all.
4574 if input_api.is_committing and input_api.change.issue:
4575 make_presubmit_message = output_api.PresubmitError
4576 else:
4577 make_presubmit_message = output_api.PresubmitNotifyResult
4578 for problem in missing_reviewer_problems:
Sam Maiera6e76d72022-02-11 21:43:504579 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:254580 make_presubmit_message(problem.problem, items=problem.items))
Daniel Chenga37c03db2022-05-12 17:20:344581
Daniel Cheng171dad8d2022-05-21 00:40:254582 owners_file_problems = []
4583 owners_file_problems.extend(ipc_results.owners_file_problems)
4584 owners_file_problems.extend(fuchsia_results.owners_file_problems)
Daniel Chenga37c03db2022-05-12 17:20:344585
Daniel Cheng171dad8d2022-05-21 00:40:254586 for problem in owners_file_problems:
Daniel Cheng3008dc12022-05-13 04:02:114587 # Missing per-file rules are always an error. While swarming and caching
4588 # means that uploading a patchset with updated OWNERS files and sending
4589 # it to the CQ again should not have a large incremental cost, it is
4590 # still frustrating to discover the error only after the change has
4591 # already been uploaded.
Daniel Chenga37c03db2022-05-12 17:20:344592 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:254593 output_api.PresubmitError(problem.problem, items=problem.items))
Sam Maiera6e76d72022-02-11 21:43:504594
4595 return results
4596
4597
4598def _GetFilesUsingSecurityCriticalFunctions(input_api):
4599 """Checks affected files for changes to security-critical calls. This
4600 function checks the full change diff, to catch both additions/changes
4601 and removals.
4602
4603 Returns a dict keyed by file name, and the value is a set of detected
4604 functions.
4605 """
4606 # Map of function pretty name (displayed in an error) to the pattern to
4607 # match it with.
4608 _PATTERNS_TO_CHECK = {
4609 'content::GetServiceSandboxType<>()': 'GetServiceSandboxType\\<'
4610 }
4611 _PATTERNS_TO_CHECK = {
4612 k: input_api.re.compile(v)
4613 for k, v in _PATTERNS_TO_CHECK.items()
4614 }
4615
Sam Maiera6e76d72022-02-11 21:43:504616 # We don't want to trigger on strings within this file.
4617 def presubmit_file_filter(f):
Daniel Chenga37c03db2022-05-12 17:20:344618 return 'PRESUBMIT.py' != input_api.os_path.split(f.LocalPath())[1]
Sam Maiera6e76d72022-02-11 21:43:504619
4620 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
4621 files_to_functions = {}
4622 for f in input_api.AffectedFiles(file_filter=presubmit_file_filter):
4623 diff = f.GenerateScmDiff()
4624 for line in diff.split('\n'):
4625 # Not using just RightHandSideLines() because removing a
4626 # call to a security-critical function can be just as important
4627 # as adding or changing the arguments.
4628 if line.startswith('-') or (line.startswith('+')
4629 and not line.startswith('++')):
4630 for name, pattern in _PATTERNS_TO_CHECK.items():
4631 if pattern.search(line):
4632 path = f.LocalPath()
4633 if not path in files_to_functions:
4634 files_to_functions[path] = set()
4635 files_to_functions[path].add(name)
4636 return files_to_functions
4637
4638
4639def CheckSecurityChanges(input_api, output_api):
4640 """Checks that changes involving security-critical functions are reviewed
4641 by the security team.
4642 """
4643 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
4644 if not len(files_to_functions):
4645 return []
4646
Sam Maiera6e76d72022-02-11 21:43:504647 owners_file = 'ipc/SECURITY_OWNERS'
Daniel Chenga37c03db2022-05-12 17:20:344648 if _ChangeHasSecurityReviewer(input_api, owners_file):
Sam Maiera6e76d72022-02-11 21:43:504649 return []
4650
Daniel Chenga37c03db2022-05-12 17:20:344651 msg = 'The following files change calls to security-sensitive functions\n' \
Sam Maiera6e76d72022-02-11 21:43:504652 'that need to be reviewed by {}.\n'.format(owners_file)
4653 for path, names in files_to_functions.items():
4654 msg += ' {}\n'.format(path)
4655 for name in names:
4656 msg += ' {}\n'.format(name)
4657 msg += '\n'
4658
4659 if input_api.is_committing:
4660 output = output_api.PresubmitError
Mohamed Heikale217fc852020-07-06 19:44:034661 else:
Sam Maiera6e76d72022-02-11 21:43:504662 output = output_api.PresubmitNotifyResult
4663 return [output(msg)]
4664
4665
4666def CheckSetNoParent(input_api, output_api):
4667 """Checks that set noparent is only used together with an OWNERS file in
4668 //build/OWNERS.setnoparent (see also
4669 //docs/code_reviews.md#owners-files-details)
4670 """
4671 # Return early if no OWNERS files were modified.
4672 if not any(f.LocalPath().endswith('OWNERS')
4673 for f in input_api.AffectedFiles(include_deletes=False)):
4674 return []
4675
4676 errors = []
4677
4678 allowed_owners_files_file = 'build/OWNERS.setnoparent'
4679 allowed_owners_files = set()
Bruce Dawson58a45d22023-02-27 11:24:164680 with open(allowed_owners_files_file, 'r', encoding='utf-8') as f:
Sam Maiera6e76d72022-02-11 21:43:504681 for line in f:
4682 line = line.strip()
4683 if not line or line.startswith('#'):
4684 continue
4685 allowed_owners_files.add(line)
4686
4687 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
4688
4689 for f in input_api.AffectedFiles(include_deletes=False):
4690 if not f.LocalPath().endswith('OWNERS'):
4691 continue
4692
4693 found_owners_files = set()
4694 found_set_noparent_lines = dict()
4695
4696 # Parse the OWNERS file.
4697 for lineno, line in enumerate(f.NewContents(), 1):
4698 line = line.strip()
4699 if line.startswith('set noparent'):
4700 found_set_noparent_lines[''] = lineno
4701 if line.startswith('file://'):
4702 if line in allowed_owners_files:
4703 found_owners_files.add('')
4704 if line.startswith('per-file'):
4705 match = per_file_pattern.match(line)
4706 if match:
4707 glob = match.group(1).strip()
4708 directive = match.group(2).strip()
4709 if directive == 'set noparent':
4710 found_set_noparent_lines[glob] = lineno
4711 if directive.startswith('file://'):
4712 if directive in allowed_owners_files:
4713 found_owners_files.add(glob)
4714
4715 # Check that every set noparent line has a corresponding file:// line
4716 # listed in build/OWNERS.setnoparent. An exception is made for top level
4717 # directories since src/OWNERS shouldn't review them.
Anton Bershanskyi4253349482025-02-11 21:01:274718 linux_path = f.UnixLocalPath()
Bruce Dawson6bb0d672022-04-06 15:13:494719 if (linux_path.count('/') != 1
4720 and (not linux_path in _EXCLUDED_SET_NO_PARENT_PATHS)):
Sam Maiera6e76d72022-02-11 21:43:504721 for set_noparent_line in found_set_noparent_lines:
4722 if set_noparent_line in found_owners_files:
4723 continue
Daniel Cheng6303eed2025-05-03 00:12:334724 errors.append(
4725 ' %s:%d' %
4726 (linux_path, found_set_noparent_lines[set_noparent_line]))
Sam Maiera6e76d72022-02-11 21:43:504727
4728 results = []
4729 if errors:
4730 if input_api.is_committing:
4731 output = output_api.PresubmitError
4732 else:
4733 output = output_api.PresubmitPromptWarning
4734 results.append(
4735 output(
4736 'Found the following "set noparent" restrictions in OWNERS files that '
4737 'do not include owners from build/OWNERS.setnoparent:',
4738 long_text='\n\n'.join(errors)))
4739 return results
4740
4741
4742def CheckUselessForwardDeclarations(input_api, output_api):
4743 """Checks that added or removed lines in non third party affected
4744 header files do not lead to new useless class or struct forward
4745 declaration.
4746 """
4747 results = []
4748 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
4749 input_api.re.MULTILINE)
4750 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
4751 input_api.re.MULTILINE)
4752 for f in input_api.AffectedFiles(include_deletes=False):
Anton Bershanskyi4253349482025-02-11 21:01:274753 local_path = f.UnixLocalPath()
4754 if (local_path.startswith('third_party')
4755 and not local_path.startswith('third_party/blink')):
Sam Maiera6e76d72022-02-11 21:43:504756 continue
4757
Anton Bershanskyi4253349482025-02-11 21:01:274758 if not local_path.endswith('.h'):
Sam Maiera6e76d72022-02-11 21:43:504759 continue
4760
4761 contents = input_api.ReadFile(f)
4762 fwd_decls = input_api.re.findall(class_pattern, contents)
4763 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
4764
4765 useless_fwd_decls = []
4766 for decl in fwd_decls:
4767 count = sum(1 for _ in input_api.re.finditer(
4768 r'\b%s\b' % input_api.re.escape(decl), contents))
4769 if count == 1:
4770 useless_fwd_decls.append(decl)
4771
4772 if not useless_fwd_decls:
4773 continue
4774
4775 for line in f.GenerateScmDiff().splitlines():
4776 if (line.startswith('-') and not line.startswith('--')
4777 or line.startswith('+') and not line.startswith('++')):
4778 for decl in useless_fwd_decls:
4779 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
4780 results.append(
4781 output_api.PresubmitPromptWarning(
4782 '%s: %s forward declaration is no longer needed'
4783 % (f.LocalPath(), decl)))
4784 useless_fwd_decls.remove(decl)
4785
4786 return results
4787
4788
4789def _CheckAndroidDebuggableBuild(input_api, output_api):
4790 """Checks that code uses BuildInfo.isDebugAndroid() instead of
4791 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
4792 this is a debuggable build of Android.
4793 """
4794 build_type_check_pattern = input_api.re.compile(
4795 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
4796
4797 errors = []
4798
4799 sources = lambda affected_file: input_api.FilterSourceFile(
4800 affected_file,
4801 files_to_skip=(
4802 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4803 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314804 r"^android_webview/support_library/boundary_interfaces/",
4805 r"^chrome/android/webapk/.*",
4806 r'^third_party/.*',
4807 r"tools/android/customtabs_benchmark/.*",
4808 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504809 )),
4810 files_to_check=[r'.*\.java$'])
4811
4812 for f in input_api.AffectedSourceFiles(sources):
4813 for line_num, line in f.ChangedContents():
4814 if build_type_check_pattern.search(line):
4815 errors.append("%s:%d" % (f.LocalPath(), line_num))
4816
4817 results = []
4818
4819 if errors:
4820 results.append(
4821 output_api.PresubmitPromptWarning(
4822 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
4823 ' Please use BuildInfo.isDebugAndroid() instead.', errors))
4824
4825 return results
4826
Daniel Cheng6303eed2025-05-03 00:12:334827
Sam Maiera6e76d72022-02-11 21:43:504828# TODO: add unit tests
4829def _CheckAndroidToastUsage(input_api, output_api):
4830 """Checks that code uses org.chromium.ui.widget.Toast instead of
4831 android.widget.Toast (Chromium Toast doesn't force hardware
4832 acceleration on low-end devices, saving memory).
4833 """
4834 toast_import_pattern = input_api.re.compile(
4835 r'^import android\.widget\.Toast;$')
4836
4837 errors = []
4838
4839 sources = lambda affected_file: input_api.FilterSourceFile(
4840 affected_file,
4841 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
Daniel Cheng6303eed2025-05-03 00:12:334842 DEFAULT_FILES_TO_SKIP +
4843 (r'^chromecast/.*', r'^remoting/.*')),
Sam Maiera6e76d72022-02-11 21:43:504844 files_to_check=[r'.*\.java$'])
4845
4846 for f in input_api.AffectedSourceFiles(sources):
4847 for line_num, line in f.ChangedContents():
4848 if toast_import_pattern.search(line):
4849 errors.append("%s:%d" % (f.LocalPath(), line_num))
4850
4851 results = []
4852
4853 if errors:
4854 results.append(
4855 output_api.PresubmitError(
4856 'android.widget.Toast usage is detected. Android toasts use hardware'
4857 ' acceleration, and can be\ncostly on low-end devices. Please use'
4858 ' org.chromium.ui.widget.Toast instead.\n'
4859 'Contact [email protected] if you have any questions.',
4860 errors))
4861
4862 return results
4863
4864
4865def _CheckAndroidCrLogUsage(input_api, output_api):
4866 """Checks that new logs using org.chromium.base.Log:
4867 - Are using 'TAG' as variable name for the tags (warn)
4868 - Are using a tag that is shorter than 20 characters (error)
4869 """
4870
4871 # Do not check format of logs in the given files
4872 cr_log_check_excluded_paths = [
4873 # //chrome/android/webapk cannot depend on //base
Bruce Dawson40fece62022-09-16 19:58:314874 r"^chrome/android/webapk/.*",
Sam Maiera6e76d72022-02-11 21:43:504875 # WebView license viewer code cannot depend on //base; used in stub APK.
Bruce Dawson40fece62022-09-16 19:58:314876 r"^android_webview/glue/java/src/com/android/"
4877 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504878 # The customtabs_benchmark is a small app that does not depend on Chromium
4879 # java pieces.
Bruce Dawson40fece62022-09-16 19:58:314880 r"tools/android/customtabs_benchmark/.*",
Sam Maiera6e76d72022-02-11 21:43:504881 ]
4882
4883 cr_log_import_pattern = input_api.re.compile(
4884 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
4885 class_in_base_pattern = input_api.re.compile(
4886 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
4887 has_some_log_import_pattern = input_api.re.compile(r'^import .*\.Log;$',
4888 input_api.re.MULTILINE)
4889 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
4890 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
4891 log_decl_pattern = input_api.re.compile(
4892 r'static final String TAG = "(?P<name>(.*))"')
4893 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
4894
4895 REF_MSG = ('See docs/android_logging.md for more info.')
4896 sources = lambda x: input_api.FilterSourceFile(
4897 x,
4898 files_to_check=[r'.*\.java$'],
4899 files_to_skip=cr_log_check_excluded_paths)
4900
4901 tag_decl_errors = []
Andrew Grieved3a35d82024-01-02 21:24:384902 tag_length_errors = []
Sam Maiera6e76d72022-02-11 21:43:504903 tag_errors = []
4904 tag_with_dot_errors = []
4905 util_log_errors = []
4906
4907 for f in input_api.AffectedSourceFiles(sources):
4908 file_content = input_api.ReadFile(f)
4909 has_modified_logs = False
4910 # Per line checks
4911 if (cr_log_import_pattern.search(file_content)
4912 or (class_in_base_pattern.search(file_content)
4913 and not has_some_log_import_pattern.search(file_content))):
4914 # Checks to run for files using cr log
4915 for line_num, line in f.ChangedContents():
4916 if rough_log_decl_pattern.search(line):
4917 has_modified_logs = True
4918
4919 # Check if the new line is doing some logging
4920 match = log_call_pattern.search(line)
4921 if match:
4922 has_modified_logs = True
4923
4924 # Make sure it uses "TAG"
4925 if not match.group('tag') == 'TAG':
4926 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
4927 else:
4928 # Report non cr Log function calls in changed lines
4929 for line_num, line in f.ChangedContents():
4930 if log_call_pattern.search(line):
4931 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
4932
4933 # Per file checks
4934 if has_modified_logs:
4935 # Make sure the tag is using the "cr" prefix and is not too long
4936 match = log_decl_pattern.search(file_content)
4937 tag_name = match.group('name') if match else None
4938 if not tag_name:
4939 tag_decl_errors.append(f.LocalPath())
Andrew Grieved3a35d82024-01-02 21:24:384940 elif len(tag_name) > 20:
4941 tag_length_errors.append(f.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:504942 elif '.' in tag_name:
4943 tag_with_dot_errors.append(f.LocalPath())
4944
4945 results = []
4946 if tag_decl_errors:
4947 results.append(
4948 output_api.PresubmitPromptWarning(
4949 'Please define your tags using the suggested format: .\n'
4950 '"private static final String TAG = "<package tag>".\n'
4951 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
4952 tag_decl_errors))
4953
Andrew Grieved3a35d82024-01-02 21:24:384954 if tag_length_errors:
4955 results.append(
4956 output_api.PresubmitError(
4957 'The tag length is restricted by the system to be at most '
4958 '20 characters.\n' + REF_MSG, tag_length_errors))
4959
Sam Maiera6e76d72022-02-11 21:43:504960 if tag_errors:
4961 results.append(
4962 output_api.PresubmitPromptWarning(
4963 'Please use a variable named "TAG" for your log tags.\n' +
4964 REF_MSG, tag_errors))
4965
4966 if util_log_errors:
4967 results.append(
4968 output_api.PresubmitPromptWarning(
4969 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
4970 util_log_errors))
4971
4972 if tag_with_dot_errors:
4973 results.append(
4974 output_api.PresubmitPromptWarning(
4975 'Dot in log tags cause them to be elided in crash reports.\n' +
4976 REF_MSG, tag_with_dot_errors))
4977
4978 return results
4979
4980
Sam Maiera6e76d72022-02-11 21:43:504981def _CheckAndroidTestAnnotationUsage(input_api, output_api):
4982 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
4983 deprecated_annotation_import_pattern = input_api.re.compile(
4984 r'^import android\.test\.suitebuilder\.annotation\..*;',
4985 input_api.re.MULTILINE)
4986 sources = lambda x: input_api.FilterSourceFile(
4987 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
4988 errors = []
4989 for f in input_api.AffectedFiles(file_filter=sources):
4990 for line_num, line in f.ChangedContents():
4991 if deprecated_annotation_import_pattern.search(line):
4992 errors.append("%s:%d" % (f.LocalPath(), line_num))
4993
4994 results = []
4995 if errors:
4996 results.append(
4997 output_api.PresubmitError(
4998 'Annotations in android.test.suitebuilder.annotation have been'
Mohamed Heikal3d7a94c2023-03-28 16:55:244999 ' deprecated since API level 24. Please use androidx.test.filters'
5000 ' from //third_party/androidx:androidx_test_runner_java instead.'
Sam Maiera6e76d72022-02-11 21:43:505001 ' Contact [email protected] if you have any questions.',
5002 errors))
5003 return results
5004
5005
5006def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
5007 """Checks if MDPI assets are placed in a correct directory."""
Daniel Cheng6303eed2025-05-03 00:12:335008 file_filter = lambda f: (f.UnixLocalPath().endswith('.png') and
5009 ('/res/drawable/' in f.UnixLocalPath() or
5010 '/res/drawable-ldrtl/' in f.UnixLocalPath()))
Sam Maiera6e76d72022-02-11 21:43:505011 errors = []
5012 for f in input_api.AffectedFiles(include_deletes=False,
5013 file_filter=file_filter):
5014 errors.append(' %s' % f.LocalPath())
5015
5016 results = []
5017 if errors:
5018 results.append(
5019 output_api.PresubmitError(
5020 'MDPI assets should be placed in /res/drawable-mdpi/ or '
5021 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
5022 '/res/drawable-ldrtl/.\n'
5023 'Contact [email protected] if you have questions.', errors))
5024 return results
5025
5026
5027def _CheckAndroidWebkitImports(input_api, output_api):
5028 """Checks that code uses org.chromium.base.Callback instead of
5029 android.webview.ValueCallback except in the WebView glue layer
5030 and WebLayer.
5031 """
5032 valuecallback_import_pattern = input_api.re.compile(
5033 r'^import android\.webkit\.ValueCallback;$')
5034
5035 errors = []
5036
5037 sources = lambda affected_file: input_api.FilterSourceFile(
5038 affected_file,
5039 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
5040 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:315041 r'^android_webview/glue/.*',
elabadysayedcbbaea72024-08-01 16:10:425042 r'^android_webview/support_library/.*',
Bruce Dawson40fece62022-09-16 19:58:315043 r'^weblayer/.*',
Sam Maiera6e76d72022-02-11 21:43:505044 )),
5045 files_to_check=[r'.*\.java$'])
5046
5047 for f in input_api.AffectedSourceFiles(sources):
5048 for line_num, line in f.ChangedContents():
5049 if valuecallback_import_pattern.search(line):
5050 errors.append("%s:%d" % (f.LocalPath(), line_num))
5051
5052 results = []
5053
5054 if errors:
5055 results.append(
5056 output_api.PresubmitError(
5057 'android.webkit.ValueCallback usage is detected outside of the glue'
5058 ' layer. To stay compatible with the support library, android.webkit.*'
5059 ' classes should only be used inside the glue layer and'
5060 ' org.chromium.base.Callback should be used instead.', errors))
5061
5062 return results
5063
5064
5065def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
5066 """Checks Android XML styles """
5067
5068 # Return early if no relevant files were modified.
5069 if not any(
5070 _IsXmlOrGrdFile(input_api, f.LocalPath())
5071 for f in input_api.AffectedFiles(include_deletes=False)):
5072 return []
5073
5074 import sys
5075 original_sys_path = sys.path
5076 try:
5077 sys.path = sys.path + [
5078 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5079 'android', 'checkxmlstyle')
5080 ]
5081 import checkxmlstyle
5082 finally:
5083 # Restore sys.path to what it was before.
5084 sys.path = original_sys_path
5085
5086 if is_check_on_upload:
5087 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
5088 else:
5089 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
5090
5091
5092def _CheckAndroidInfoBarDeprecation(input_api, output_api):
5093 """Checks Android Infobar Deprecation """
5094
5095 import sys
5096 original_sys_path = sys.path
5097 try:
5098 sys.path = sys.path + [
5099 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5100 'android', 'infobar_deprecation')
5101 ]
5102 import infobar_deprecation
5103 finally:
5104 # Restore sys.path to what it was before.
5105 sys.path = original_sys_path
5106
5107 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
5108
5109
5110class _PydepsCheckerResult:
Daniel Cheng6303eed2025-05-03 00:12:335111
Sam Maiera6e76d72022-02-11 21:43:505112 def __init__(self, cmd, pydeps_path, process, old_contents):
5113 self._cmd = cmd
5114 self._pydeps_path = pydeps_path
5115 self._process = process
5116 self._old_contents = old_contents
5117
5118 def GetError(self):
5119 """Returns an error message, or None."""
5120 import difflib
Andrew Grieved27620b62023-07-13 16:35:075121 new_contents = self._process.stdout.read().splitlines()[2:]
Sam Maiera6e76d72022-02-11 21:43:505122 if self._process.wait() != 0:
5123 # STDERR should already be printed.
5124 return 'Command failed: ' + self._cmd
Sam Maiera6e76d72022-02-11 21:43:505125 if self._old_contents != new_contents:
5126 diff = '\n'.join(
5127 difflib.context_diff(self._old_contents, new_contents))
5128 return ('File is stale: {}\n'
5129 'Diff (apply to fix):\n'
5130 '{}\n'
5131 'To regenerate, run:\n\n'
5132 ' {}').format(self._pydeps_path, diff, self._cmd)
5133 return None
5134
5135
5136class PydepsChecker:
Daniel Cheng6303eed2025-05-03 00:12:335137
Sam Maiera6e76d72022-02-11 21:43:505138 def __init__(self, input_api, pydeps_files):
5139 self._file_cache = {}
5140 self._input_api = input_api
5141 self._pydeps_files = pydeps_files
5142
5143 def _LoadFile(self, path):
5144 """Returns the list of paths within a .pydeps file relative to //."""
5145 if path not in self._file_cache:
5146 with open(path, encoding='utf-8') as f:
5147 self._file_cache[path] = f.read()
5148 return self._file_cache[path]
5149
5150 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
Gao Shenga79ebd42022-08-08 17:25:595151 """Returns an iterable of paths within the .pydep, relativized to //."""
Sam Maiera6e76d72022-02-11 21:43:505152 pydeps_data = self._LoadFile(pydeps_path)
5153 uses_gn_paths = '--gn-paths' in pydeps_data
5154 entries = (l for l in pydeps_data.splitlines()
5155 if not l.startswith('#'))
5156 if uses_gn_paths:
5157 # Paths look like: //foo/bar/baz
5158 return (e[2:] for e in entries)
5159 else:
5160 # Paths look like: path/relative/to/file.pydeps
5161 os_path = self._input_api.os_path
5162 pydeps_dir = os_path.dirname(pydeps_path)
5163 return (os_path.normpath(os_path.join(pydeps_dir, e))
5164 for e in entries)
5165
5166 def _CreateFilesToPydepsMap(self):
5167 """Returns a map of local_path -> list_of_pydeps."""
5168 ret = {}
5169 for pydep_local_path in self._pydeps_files:
5170 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
5171 ret.setdefault(path, []).append(pydep_local_path)
5172 return ret
5173
5174 def ComputeAffectedPydeps(self):
5175 """Returns an iterable of .pydeps files that might need regenerating."""
5176 affected_pydeps = set()
5177 file_to_pydeps_map = None
5178 for f in self._input_api.AffectedFiles(include_deletes=True):
5179 local_path = f.LocalPath()
5180 # Changes to DEPS can lead to .pydeps changes if any .py files are in
5181 # subrepositories. We can't figure out which files change, so re-check
5182 # all files.
5183 # Changes to print_python_deps.py affect all .pydeps.
5184 if local_path in ('DEPS', 'PRESUBMIT.py'
5185 ) or local_path.endswith('print_python_deps.py'):
5186 return self._pydeps_files
5187 elif local_path.endswith('.pydeps'):
5188 if local_path in self._pydeps_files:
5189 affected_pydeps.add(local_path)
5190 elif local_path.endswith('.py'):
5191 if file_to_pydeps_map is None:
5192 file_to_pydeps_map = self._CreateFilesToPydepsMap()
5193 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
5194 return affected_pydeps
5195
5196 def DetermineIfStaleAsync(self, pydeps_path):
5197 """Runs print_python_deps.py to see if the files is stale."""
5198 import os
5199
5200 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
5201 if old_pydeps_data:
5202 cmd = old_pydeps_data[1][1:].strip()
5203 if '--output' not in cmd:
5204 cmd += ' --output ' + pydeps_path
5205 old_contents = old_pydeps_data[2:]
5206 else:
5207 # A default cmd that should work in most cases (as long as pydeps filename
5208 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
5209 # file is empty/new.
5210 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
5211 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
5212 old_contents = []
5213 env = dict(os.environ)
5214 env['PYTHONDONTWRITEBYTECODE'] = '1'
5215 process = self._input_api.subprocess.Popen(
5216 cmd + ' --output ""',
5217 shell=True,
5218 env=env,
5219 stdout=self._input_api.subprocess.PIPE,
5220 encoding='utf-8')
5221 return _PydepsCheckerResult(cmd, pydeps_path, process, old_contents)
agrievef32bcc72016-04-04 14:57:405222
5223
Tibor Goldschwendt360793f72019-06-25 18:23:495224def _ParseGclientArgs():
Sam Maiera6e76d72022-02-11 21:43:505225 args = {}
5226 with open('build/config/gclient_args.gni', 'r') as f:
5227 for line in f:
5228 line = line.strip()
5229 if not line or line.startswith('#'):
5230 continue
5231 attribute, value = line.split('=')
5232 args[attribute.strip()] = value.strip()
5233 return args
Tibor Goldschwendt360793f72019-06-25 18:23:495234
5235
Saagar Sanghavifceeaae2020-08-12 16:40:365236def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
Sam Maiera6e76d72022-02-11 21:43:505237 """Checks if a .pydeps file needs to be regenerated."""
5238 # This check is for Python dependency lists (.pydeps files), and involves
5239 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
5240 # doesn't work on Windows and Mac, so skip it on other platforms.
5241 if not input_api.platform.startswith('linux'):
5242 return []
Erik Staabc734cd7a2021-11-23 03:11:525243
Sam Maiera6e76d72022-02-11 21:43:505244 results = []
5245 # First, check for new / deleted .pydeps.
5246 for f in input_api.AffectedFiles(include_deletes=True):
5247 # Check whether we are running the presubmit check for a file in src.
Sam Maiera6e76d72022-02-11 21:43:505248 if f.LocalPath().endswith('.pydeps'):
Andrew Grieve713b89b2024-10-15 20:20:085249 # f.LocalPath is relative to repo (src, or internal repo).
5250 # os_path.exists is relative to src repo.
5251 # Therefore if os_path.exists is true, it means f.LocalPath is relative
5252 # to src and we can conclude that the pydeps is in src.
5253 exists = input_api.os_path.exists(f.LocalPath())
5254 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
5255 results.append(
5256 output_api.PresubmitError(
5257 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
5258 'remove %s' % f.LocalPath()))
5259 elif (f.Action() != 'D' and exists
5260 and f.LocalPath() not in _ALL_PYDEPS_FILES):
5261 results.append(
5262 output_api.PresubmitError(
5263 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
5264 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:405265
Sam Maiera6e76d72022-02-11 21:43:505266 if results:
5267 return results
5268
Gavin Mak23884402024-07-25 20:39:265269 try:
5270 parsed_args = _ParseGclientArgs()
5271 except FileNotFoundError:
5272 message = (
5273 'build/config/gclient_args.gni not found. Please make sure your '
Daniel Cheng6303eed2025-05-03 00:12:335274 'workspace has been initialized with gclient sync.')
Gavin Mak23884402024-07-25 20:39:265275 import sys
5276 original_sys_path = sys.path
5277 try:
5278 sys.path = sys.path + [
5279 input_api.os_path.join(input_api.PresubmitLocalPath(),
Daniel Cheng6303eed2025-05-03 00:12:335280 'third_party', 'depot_tools')
Gavin Mak23884402024-07-25 20:39:265281 ]
5282 import gclient_utils
5283 if gclient_utils.IsEnvCog():
5284 # Users will always hit this when they run presubmits before cog
5285 # workspace initialization finishes. The check shouldn't fail in
5286 # this case. This is an unavoidable workaround that's needed for
5287 # good presubmit UX for cog.
5288 results.append(output_api.PresubmitPromptWarning(message))
5289 else:
5290 results.append(output_api.PresubmitError(message))
5291 return results
5292 finally:
5293 # Restore sys.path to what it was before.
5294 sys.path = original_sys_path
5295
5296 is_android = parsed_args.get('checkout_android', 'false') == 'true'
Sam Maiera6e76d72022-02-11 21:43:505297 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
5298 affected_pydeps = set(checker.ComputeAffectedPydeps())
5299 affected_android_pydeps = affected_pydeps.intersection(
5300 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
5301 if affected_android_pydeps and not is_android:
5302 results.append(
5303 output_api.PresubmitPromptOrNotify(
5304 'You have changed python files that may affect pydeps for android\n'
Gao Shenga79ebd42022-08-08 17:25:595305 'specific scripts. However, the relevant presubmit check cannot be\n'
Sam Maiera6e76d72022-02-11 21:43:505306 'run because you are not using an Android checkout. To validate that\n'
5307 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
5308 'use the android-internal-presubmit optional trybot.\n'
5309 'Possibly stale pydeps files:\n{}'.format(
5310 '\n'.join(affected_android_pydeps))))
5311
5312 all_pydeps = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
5313 pydeps_to_check = affected_pydeps.intersection(all_pydeps)
5314 # Process these concurrently, as each one takes 1-2 seconds.
5315 pydep_results = [checker.DetermineIfStaleAsync(p) for p in pydeps_to_check]
5316 for result in pydep_results:
5317 error_msg = result.GetError()
5318 if error_msg:
5319 results.append(output_api.PresubmitError(error_msg))
5320
agrievef32bcc72016-04-04 14:57:405321 return results
5322
agrievef32bcc72016-04-04 14:57:405323
Saagar Sanghavifceeaae2020-08-12 16:40:365324def CheckSingletonInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505325 """Checks to make sure no header files have |Singleton<|."""
5326
5327 def FileFilter(affected_file):
5328 # It's ok for base/memory/singleton.h to have |Singleton<|.
5329 files_to_skip = (_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
Bruce Dawson40fece62022-09-16 19:58:315330 (r"^base/memory/singleton\.h$",
5331 r"^net/quic/platform/impl/quic_singleton_impl\.h$"))
Sam Maiera6e76d72022-02-11 21:43:505332 return input_api.FilterSourceFile(affected_file,
5333 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:435334
Sam Maiera6e76d72022-02-11 21:43:505335 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
5336 files = []
5337 for f in input_api.AffectedSourceFiles(FileFilter):
5338 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx')
5339 or f.LocalPath().endswith('.hpp')
5340 or f.LocalPath().endswith('.inl')):
5341 contents = input_api.ReadFile(f)
5342 for line in contents.splitlines(False):
5343 if (not line.lstrip().startswith('//')
5344 and # Strip C++ comment.
5345 pattern.search(line)):
5346 files.append(f)
5347 break
glidere61efad2015-02-18 17:39:435348
Sam Maiera6e76d72022-02-11 21:43:505349 if files:
5350 return [
5351 output_api.PresubmitError(
5352 'Found base::Singleton<T> in the following header files.\n' +
5353 'Please move them to an appropriate source file so that the ' +
5354 'template gets instantiated in a single compilation unit.',
5355 files)
5356 ]
5357 return []
glidere61efad2015-02-18 17:39:435358
5359
[email protected]fd20b902014-05-09 02:14:535360_DEPRECATED_CSS = [
Daniel Cheng6303eed2025-05-03 00:12:335361 # Values
5362 ("-webkit-box", "flex"),
5363 ("-webkit-inline-box", "inline-flex"),
5364 ("-webkit-flex", "flex"),
5365 ("-webkit-inline-flex", "inline-flex"),
5366 ("-webkit-min-content", "min-content"),
5367 ("-webkit-max-content", "max-content"),
[email protected]fd20b902014-05-09 02:14:535368
Daniel Cheng6303eed2025-05-03 00:12:335369 # Properties
5370 ("-webkit-background-clip", "background-clip"),
5371 ("-webkit-background-origin", "background-origin"),
5372 ("-webkit-background-size", "background-size"),
5373 ("-webkit-box-shadow", "box-shadow"),
5374 ("-webkit-user-select", "user-select"),
[email protected]fd20b902014-05-09 02:14:535375
Daniel Cheng6303eed2025-05-03 00:12:335376 # Functions
5377 ("-webkit-gradient", "gradient"),
5378 ("-webkit-repeating-gradient", "repeating-gradient"),
5379 ("-webkit-linear-gradient", "linear-gradient"),
5380 ("-webkit-repeating-linear-gradient", "repeating-linear-gradient"),
5381 ("-webkit-radial-gradient", "radial-gradient"),
5382 ("-webkit-repeating-radial-gradient", "repeating-radial-gradient"),
[email protected]fd20b902014-05-09 02:14:535383]
5384
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:205385
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:495386# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:365387def CheckNoDeprecatedCss(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505388 """ Make sure that we don't use deprecated CSS
5389 properties, functions or values. Our external
5390 documentation and iOS CSS for dom distiller
5391 (reader mode) are ignored by the hooks as it
5392 needs to be consumed by WebKit. """
5393 results = []
5394 file_inclusion_pattern = [r".+\.css$"]
Daniel Cheng6303eed2025-05-03 00:12:335395 files_to_skip = (
5396 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
5397 input_api.DEFAULT_FILES_TO_SKIP +
5398 ( # Legacy CSS file using deprecated CSS.
5399 r"^chrome/browser/resources/chromeos/arc_support/cr_overlay.css$",
5400 r"^chrome/common/extensions/docs",
5401 r"^chrome/docs",
5402 r"^native_client_sdk",
5403 # The NTP team prefers reserving -webkit-line-clamp for
5404 # ellipsis effect which can only be used with -webkit-box.
5405 r"ui/webui/resources/cr_components/most_visited/.*\.css$"))
Sam Maiera6e76d72022-02-11 21:43:505406 file_filter = lambda f: input_api.FilterSourceFile(
5407 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
5408 for fpath in input_api.AffectedFiles(file_filter=file_filter):
5409 for line_num, line in fpath.ChangedContents():
5410 for (deprecated_value, value) in _DEPRECATED_CSS:
5411 if deprecated_value in line:
5412 results.append(
5413 output_api.PresubmitError(
5414 "%s:%d: Use of deprecated CSS %s, use %s instead" %
5415 (fpath.LocalPath(), line_num, deprecated_value,
5416 value)))
5417 return results
[email protected]fd20b902014-05-09 02:14:535418
mohan.reddyf21db962014-10-16 12:26:475419
Saagar Sanghavifceeaae2020-08-12 16:40:365420def CheckForRelativeIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505421 bad_files = {}
5422 for f in input_api.AffectedFiles(include_deletes=False):
Anton Bershanskyi4253349482025-02-11 21:01:275423 if (f.UnixLocalPath().startswith('third_party')
5424 and not f.LocalPath().startswith('third_party/blink')):
Sam Maiera6e76d72022-02-11 21:43:505425 continue
rlanday6802cf632017-05-30 17:48:365426
Sam Maiera6e76d72022-02-11 21:43:505427 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
5428 continue
rlanday6802cf632017-05-30 17:48:365429
Sam Maiera6e76d72022-02-11 21:43:505430 relative_includes = [
5431 line for _, line in f.ChangedContents()
5432 if "#include" in line and "../" in line
5433 ]
5434 if not relative_includes:
5435 continue
5436 bad_files[f.LocalPath()] = relative_includes
rlanday6802cf632017-05-30 17:48:365437
Sam Maiera6e76d72022-02-11 21:43:505438 if not bad_files:
5439 return []
rlanday6802cf632017-05-30 17:48:365440
Sam Maiera6e76d72022-02-11 21:43:505441 error_descriptions = []
5442 for file_path, bad_lines in bad_files.items():
5443 error_description = file_path
5444 for line in bad_lines:
5445 error_description += '\n ' + line
5446 error_descriptions.append(error_description)
rlanday6802cf632017-05-30 17:48:365447
Sam Maiera6e76d72022-02-11 21:43:505448 results = []
5449 results.append(
5450 output_api.PresubmitError(
5451 'You added one or more relative #include paths (including "../").\n'
5452 'These shouldn\'t be used because they can be used to include headers\n'
5453 'from code that\'s not correctly specified as a dependency in the\n'
5454 'relevant BUILD.gn file(s).', error_descriptions))
rlanday6802cf632017-05-30 17:48:365455
Sam Maiera6e76d72022-02-11 21:43:505456 return results
rlanday6802cf632017-05-30 17:48:365457
Takeshi Yoshinoe387aa32017-08-02 13:16:135458
Saagar Sanghavifceeaae2020-08-12 16:40:365459def CheckForCcIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505460 """Check that nobody tries to include a cc file. It's a relatively
5461 common error which results in duplicate symbols in object
5462 files. This may not always break the build until someone later gets
5463 very confusing linking errors."""
5464 results = []
5465 for f in input_api.AffectedFiles(include_deletes=False):
5466 # We let third_party code do whatever it wants
Anton Bershanskyi4253349482025-02-11 21:01:275467 if (f.UnixLocalPath().startswith('third_party')
5468 and not f.LocalPath().startswith('third_party/blink')):
Sam Maiera6e76d72022-02-11 21:43:505469 continue
Daniel Bratell65b033262019-04-23 08:17:065470
Sam Maiera6e76d72022-02-11 21:43:505471 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
5472 continue
Daniel Bratell65b033262019-04-23 08:17:065473
Sam Maiera6e76d72022-02-11 21:43:505474 for _, line in f.ChangedContents():
5475 if line.startswith('#include "'):
5476 included_file = line.split('"')[1]
5477 if _IsCPlusPlusFile(input_api, included_file):
5478 # The most common naming for external files with C++ code,
5479 # apart from standard headers, is to call them foo.inc, but
5480 # Chromium sometimes uses foo-inc.cc so allow that as well.
5481 if not included_file.endswith(('.h', '-inc.cc')):
5482 results.append(
5483 output_api.PresubmitError(
5484 'Only header files or .inc files should be included in other\n'
5485 'C++ files. Compiling the contents of a cc file more than once\n'
5486 'will cause duplicate information in the build which may later\n'
5487 'result in strange link_errors.\n' +
5488 f.LocalPath() + ':\n ' + line))
Daniel Bratell65b033262019-04-23 08:17:065489
Sam Maiera6e76d72022-02-11 21:43:505490 return results
Daniel Bratell65b033262019-04-23 08:17:065491
5492
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205493def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
Sam Maiera6e76d72022-02-11 21:43:505494 if not isinstance(key, ast.Str):
5495 return 'Key at line %d must be a string literal' % key.lineno
5496 if not isinstance(value, ast.Dict):
5497 return 'Value at line %d must be a dict' % value.lineno
5498 if len(value.keys) != 1:
5499 return 'Dict at line %d must have single entry' % value.lineno
5500 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
5501 return (
5502 'Entry at line %d must have a string literal \'filepath\' as key' %
5503 value.lineno)
5504 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:135505
Takeshi Yoshinoe387aa32017-08-02 13:16:135506
Sergey Ulanov4af16052018-11-08 02:41:465507def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Sam Maiera6e76d72022-02-11 21:43:505508 if not isinstance(key, ast.Str):
5509 return 'Key at line %d must be a string literal' % key.lineno
5510 if not isinstance(value, ast.List):
5511 return 'Value at line %d must be a list' % value.lineno
5512 for element in value.elts:
5513 if not isinstance(element, ast.Str):
5514 return 'Watchlist elements on line %d is not a string' % key.lineno
5515 if not email_regex.match(element.s):
5516 return ('Watchlist element on line %d doesn\'t look like a valid '
5517 + 'email: %s') % (key.lineno, element.s)
5518 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:135519
Takeshi Yoshinoe387aa32017-08-02 13:16:135520
Sergey Ulanov4af16052018-11-08 02:41:465521def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Sam Maiera6e76d72022-02-11 21:43:505522 mismatch_template = (
5523 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
5524 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:135525
Sam Maiera6e76d72022-02-11 21:43:505526 email_regex = input_api.re.compile(
5527 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
Sergey Ulanov4af16052018-11-08 02:41:465528
Sam Maiera6e76d72022-02-11 21:43:505529 ast = input_api.ast
5530 i = 0
5531 last_key = ''
5532 while True:
5533 if i >= len(wd_dict.keys):
5534 if i >= len(w_dict.keys):
5535 return None
5536 return mismatch_template % ('missing',
5537 'line %d' % w_dict.keys[i].lineno)
5538 elif i >= len(w_dict.keys):
5539 return (mismatch_template %
5540 ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:135541
Sam Maiera6e76d72022-02-11 21:43:505542 wd_key = wd_dict.keys[i]
5543 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:135544
Sam Maiera6e76d72022-02-11 21:43:505545 result = _CheckWatchlistDefinitionsEntrySyntax(wd_key,
5546 wd_dict.values[i], ast)
5547 if result is not None:
5548 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:135549
Sam Maiera6e76d72022-02-11 21:43:505550 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast,
5551 email_regex)
5552 if result is not None:
5553 return 'Bad entry in WATCHLISTS dict: %s' % result
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205554
Sam Maiera6e76d72022-02-11 21:43:505555 if wd_key.s != w_key.s:
5556 return mismatch_template % ('%s at line %d' %
5557 (wd_key.s, wd_key.lineno),
5558 '%s at line %d' %
5559 (w_key.s, w_key.lineno))
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205560
Sam Maiera6e76d72022-02-11 21:43:505561 if wd_key.s < last_key:
5562 return (
5563 'WATCHLISTS dict is not sorted lexicographically at line %d and %d'
5564 % (wd_key.lineno, w_key.lineno))
5565 last_key = wd_key.s
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205566
Sam Maiera6e76d72022-02-11 21:43:505567 i = i + 1
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205568
5569
Sergey Ulanov4af16052018-11-08 02:41:465570def _CheckWATCHLISTSSyntax(expression, input_api):
Sam Maiera6e76d72022-02-11 21:43:505571 ast = input_api.ast
5572 if not isinstance(expression, ast.Expression):
5573 return 'WATCHLISTS file must contain a valid expression'
5574 dictionary = expression.body
5575 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
5576 return 'WATCHLISTS file must have single dict with exactly two entries'
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205577
Sam Maiera6e76d72022-02-11 21:43:505578 first_key = dictionary.keys[0]
5579 first_value = dictionary.values[0]
5580 second_key = dictionary.keys[1]
5581 second_value = dictionary.values[1]
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205582
Sam Maiera6e76d72022-02-11 21:43:505583 if (not isinstance(first_key, ast.Str)
5584 or first_key.s != 'WATCHLIST_DEFINITIONS'
5585 or not isinstance(first_value, ast.Dict)):
5586 return ('The first entry of the dict in WATCHLISTS file must be '
5587 'WATCHLIST_DEFINITIONS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205588
Sam Maiera6e76d72022-02-11 21:43:505589 if (not isinstance(second_key, ast.Str) or second_key.s != 'WATCHLISTS'
5590 or not isinstance(second_value, ast.Dict)):
5591 return ('The second entry of the dict in WATCHLISTS file must be '
5592 'WATCHLISTS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205593
Sam Maiera6e76d72022-02-11 21:43:505594 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:135595
5596
Saagar Sanghavifceeaae2020-08-12 16:40:365597def CheckWATCHLISTS(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505598 for f in input_api.AffectedFiles(include_deletes=False):
5599 if f.LocalPath() == 'WATCHLISTS':
5600 contents = input_api.ReadFile(f, 'r')
Takeshi Yoshinoe387aa32017-08-02 13:16:135601
Sam Maiera6e76d72022-02-11 21:43:505602 try:
5603 # First, make sure that it can be evaluated.
5604 input_api.ast.literal_eval(contents)
5605 # Get an AST tree for it and scan the tree for detailed style checking.
5606 expression = input_api.ast.parse(contents,
5607 filename='WATCHLISTS',
5608 mode='eval')
5609 except ValueError as e:
5610 return [
5611 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5612 long_text=repr(e))
5613 ]
5614 except SyntaxError as e:
5615 return [
5616 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5617 long_text=repr(e))
5618 ]
5619 except TypeError as e:
5620 return [
5621 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5622 long_text=repr(e))
5623 ]
Takeshi Yoshinoe387aa32017-08-02 13:16:135624
Sam Maiera6e76d72022-02-11 21:43:505625 result = _CheckWATCHLISTSSyntax(expression, input_api)
5626 if result is not None:
5627 return [output_api.PresubmitError(result)]
5628 break
Takeshi Yoshinoe387aa32017-08-02 13:16:135629
Sam Maiera6e76d72022-02-11 21:43:505630 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:135631
Daniel Cheng6303eed2025-05-03 00:12:335632
Sean Kaucb7c9b32022-10-25 21:25:525633def CheckGnRebasePath(input_api, output_api):
Terrence Reilly313f44ff2025-01-22 15:10:145634 """Checks that target_gen_dir is not used with "//" in rebase_path().
Sean Kaucb7c9b32022-10-25 21:25:525635
5636 Developers should use root_build_dir instead of "//" when using target_gen_dir because
5637 Chromium is sometimes built outside of the source tree.
5638 """
5639
5640 def gn_files(f):
5641 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
5642
Daniel Cheng6303eed2025-05-03 00:12:335643 rebase_path_regex = input_api.re.compile(
5644 r'rebase_path\(("\$target_gen_dir"|target_gen_dir), ("/"|"//")\)')
Sean Kaucb7c9b32022-10-25 21:25:525645 problems = []
5646 for f in input_api.AffectedSourceFiles(gn_files):
5647 for line_num, line in f.ChangedContents():
5648 if rebase_path_regex.search(line):
Daniel Cheng6303eed2025-05-03 00:12:335649 problems.append('Absolute path in rebase_path() in %s:%d' %
5650 (f.LocalPath(), line_num))
Sean Kaucb7c9b32022-10-25 21:25:525651
5652 if problems:
5653 return [
5654 output_api.PresubmitPromptWarning(
5655 'Using an absolute path in rebase_path()',
5656 items=sorted(problems),
5657 long_text=(
5658 'rebase_path() should use root_build_dir instead of "/" ',
5659 'since builds can be initiated from outside of the source ',
5660 'root.'))
5661 ]
5662 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:135663
Daniel Cheng6303eed2025-05-03 00:12:335664
Andrew Grieve1b290e4a22020-11-24 20:07:015665def CheckGnGlobForward(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505666 """Checks that forward_variables_from(invoker, "*") follows best practices.
Andrew Grieve1b290e4a22020-11-24 20:07:015667
Sam Maiera6e76d72022-02-11 21:43:505668 As documented at //build/docs/writing_gn_templates.md
5669 """
Andrew Grieve1b290e4a22020-11-24 20:07:015670
Sam Maiera6e76d72022-02-11 21:43:505671 def gn_files(f):
5672 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
Andrew Grieve1b290e4a22020-11-24 20:07:015673
Sam Maiera6e76d72022-02-11 21:43:505674 problems = []
5675 for f in input_api.AffectedSourceFiles(gn_files):
5676 for line_num, line in f.ChangedContents():
5677 if 'forward_variables_from(invoker, "*")' in line:
5678 problems.append(
5679 'Bare forward_variables_from(invoker, "*") in %s:%d' %
5680 (f.LocalPath(), line_num))
5681
5682 if problems:
5683 return [
5684 output_api.PresubmitPromptWarning(
5685 'forward_variables_from("*") without exclusions',
5686 items=sorted(problems),
5687 long_text=(
Gao Shenga79ebd42022-08-08 17:25:595688 'The variables "visibility" and "test_only" should be '
Sam Maiera6e76d72022-02-11 21:43:505689 'explicitly listed in forward_variables_from(). For more '
5690 'details, see:\n'
5691 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
5692 'build/docs/writing_gn_templates.md'
5693 '#Using-forward_variables_from'))
5694 ]
5695 return []
Andrew Grieve1b290e4a22020-11-24 20:07:015696
Daniel Cheng6303eed2025-05-03 00:12:335697
Saagar Sanghavifceeaae2020-08-12 16:40:365698def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505699 """Checks that newly added header files have corresponding GN changes.
5700 Note that this is only a heuristic. To be precise, run script:
5701 build/check_gn_headers.py.
5702 """
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195703
Sam Maiera6e76d72022-02-11 21:43:505704 def headers(f):
5705 return input_api.FilterSourceFile(
5706 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195707
Sam Maiera6e76d72022-02-11 21:43:505708 new_headers = []
5709 for f in input_api.AffectedSourceFiles(headers):
5710 if f.Action() != 'A':
5711 continue
5712 new_headers.append(f.LocalPath())
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195713
Sam Maiera6e76d72022-02-11 21:43:505714 def gn_files(f):
5715 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195716
Sam Maiera6e76d72022-02-11 21:43:505717 all_gn_changed_contents = ''
5718 for f in input_api.AffectedSourceFiles(gn_files):
5719 for _, line in f.ChangedContents():
5720 all_gn_changed_contents += line
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195721
Sam Maiera6e76d72022-02-11 21:43:505722 problems = []
5723 for header in new_headers:
5724 basename = input_api.os_path.basename(header)
5725 if basename not in all_gn_changed_contents:
5726 problems.append(header)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195727
Sam Maiera6e76d72022-02-11 21:43:505728 if problems:
5729 return [
5730 output_api.PresubmitPromptWarning(
5731 'Missing GN changes for new header files',
5732 items=sorted(problems),
5733 long_text=
5734 'Please double check whether newly added header files need '
5735 'corresponding changes in gn or gni files.\nThis checking is only a '
5736 'heuristic. Run build/check_gn_headers.py to be precise.\n'
5737 'Read https://crbug.com/661774 for more info.')
5738 ]
5739 return []
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195740
5741
Saagar Sanghavifceeaae2020-08-12 16:40:365742def CheckCorrectProductNameInMessages(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505743 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
Michael Giuffridad3bc8672018-10-25 22:48:025744
Sam Maiera6e76d72022-02-11 21:43:505745 This assumes we won't intentionally reference one product from the other
5746 product.
5747 """
5748 all_problems = []
5749 test_cases = [{
5750 "filename_postfix": "google_chrome_strings.grd",
5751 "correct_name": "Chrome",
5752 "incorrect_name": "Chromium",
5753 }, {
Thiago Perrotta099034f2023-06-05 18:10:205754 "filename_postfix": "google_chrome_strings.grd",
5755 "correct_name": "Chrome",
5756 "incorrect_name": "Chrome for Testing",
5757 }, {
Sam Maiera6e76d72022-02-11 21:43:505758 "filename_postfix": "chromium_strings.grd",
5759 "correct_name": "Chromium",
5760 "incorrect_name": "Chrome",
5761 }]
Michael Giuffridad3bc8672018-10-25 22:48:025762
Sam Maiera6e76d72022-02-11 21:43:505763 for test_case in test_cases:
5764 problems = []
5765 filename_filter = lambda x: x.LocalPath().endswith(test_case[
5766 "filename_postfix"])
Michael Giuffridad3bc8672018-10-25 22:48:025767
Sam Maiera6e76d72022-02-11 21:43:505768 # Check each new line. Can yield false positives in multiline comments, but
5769 # easier than trying to parse the XML because messages can have nested
5770 # children, and associating message elements with affected lines is hard.
5771 for f in input_api.AffectedSourceFiles(filename_filter):
5772 for line_num, line in f.ChangedContents():
5773 if "<message" in line or "<!--" in line or "-->" in line:
5774 continue
5775 if test_case["incorrect_name"] in line:
Thiago Perrotta099034f2023-06-05 18:10:205776 # Chrome for Testing is a special edge case: https://goo.gle/chrome-for-testing#bookmark=id.n1rat320av91
Daniel Cheng6303eed2025-05-03 00:12:335777 if (test_case["correct_name"] == "Chromium"
5778 and line.count("Chrome")
5779 == line.count("Chrome for Testing")):
Thiago Perrotta099034f2023-06-05 18:10:205780 continue
Sam Maiera6e76d72022-02-11 21:43:505781 problems.append("Incorrect product name in %s:%d" %
5782 (f.LocalPath(), line_num))
Michael Giuffridad3bc8672018-10-25 22:48:025783
Sam Maiera6e76d72022-02-11 21:43:505784 if problems:
5785 message = (
5786 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
5787 % (test_case["correct_name"], test_case["correct_name"],
5788 test_case["incorrect_name"]))
5789 all_problems.append(
5790 output_api.PresubmitPromptWarning(message, items=problems))
Michael Giuffridad3bc8672018-10-25 22:48:025791
Sam Maiera6e76d72022-02-11 21:43:505792 return all_problems
Michael Giuffridad3bc8672018-10-25 22:48:025793
5794
Saagar Sanghavifceeaae2020-08-12 16:40:365795def CheckForTooLargeFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505796 """Avoid large files, especially binary files, in the repository since
5797 git doesn't scale well for those. They will be in everyone's repo
5798 clones forever, forever making Chromium slower to clone and work
5799 with."""
Daniel Bratell93eb6c62019-04-29 20:13:365800
Sam Maiera6e76d72022-02-11 21:43:505801 # Uploading files to cloud storage is not trivial so we don't want
5802 # to set the limit too low, but the upper limit for "normal" large
5803 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
5804 # anything over 20 MB is exceptional.
Bruce Dawsonbb414db2022-12-27 20:21:255805 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024
Daniel Bratell93eb6c62019-04-29 20:13:365806
Sam Maiera6e76d72022-02-11 21:43:505807 too_large_files = []
5808 for f in input_api.AffectedFiles():
5809 # Check both added and modified files (but not deleted files).
5810 if f.Action() in ('A', 'M'):
5811 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Joe DeBlasio10a832f2023-04-21 20:20:185812 if size > TOO_LARGE_FILE_SIZE_LIMIT:
Sam Maiera6e76d72022-02-11 21:43:505813 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
Daniel Bratell93eb6c62019-04-29 20:13:365814
Sam Maiera6e76d72022-02-11 21:43:505815 if too_large_files:
5816 message = (
5817 'Do not commit large files to git since git scales badly for those.\n'
5818 +
5819 'Instead put the large files in cloud storage and use DEPS to\n' +
5820 'fetch them.\n' + '\n'.join(too_large_files))
5821 return [
5822 output_api.PresubmitError('Too large files found in commit',
5823 long_text=message + '\n')
5824 ]
5825 else:
5826 return []
Daniel Bratell93eb6c62019-04-29 20:13:365827
Max Morozb47503b2019-08-08 21:03:275828
Saagar Sanghavifceeaae2020-08-12 16:40:365829def CheckFuzzTargetsOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505830 """Checks specific for fuzz target sources."""
5831 EXPORTED_SYMBOLS = [
5832 'LLVMFuzzerInitialize',
5833 'LLVMFuzzerCustomMutator',
5834 'LLVMFuzzerCustomCrossOver',
5835 'LLVMFuzzerMutate',
5836 ]
Max Morozb47503b2019-08-08 21:03:275837
Sam Maiera6e76d72022-02-11 21:43:505838 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
Max Morozb47503b2019-08-08 21:03:275839
Sam Maiera6e76d72022-02-11 21:43:505840 def FilterFile(affected_file):
5841 """Ignore libFuzzer source code."""
5842 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
Bruce Dawson40fece62022-09-16 19:58:315843 files_to_skip = r"^third_party/libFuzzer"
Max Morozb47503b2019-08-08 21:03:275844
Sam Maiera6e76d72022-02-11 21:43:505845 return input_api.FilterSourceFile(affected_file,
5846 files_to_check=[files_to_check],
5847 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:275848
Sam Maiera6e76d72022-02-11 21:43:505849 files_with_missing_header = []
5850 for f in input_api.AffectedSourceFiles(FilterFile):
5851 contents = input_api.ReadFile(f, 'r')
5852 if REQUIRED_HEADER in contents:
5853 continue
Max Morozb47503b2019-08-08 21:03:275854
Sam Maiera6e76d72022-02-11 21:43:505855 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
5856 files_with_missing_header.append(f.LocalPath())
Max Morozb47503b2019-08-08 21:03:275857
Sam Maiera6e76d72022-02-11 21:43:505858 if not files_with_missing_header:
5859 return []
Max Morozb47503b2019-08-08 21:03:275860
Sam Maiera6e76d72022-02-11 21:43:505861 long_text = (
5862 'If you define any of the libFuzzer optional functions (%s), it is '
5863 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
5864 'work incorrectly on Mac (crbug.com/687076).\nNote that '
5865 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
5866 'to access command line arguments passed to the fuzzer. Instead, prefer '
5867 'static initialization and shared resources as documented in '
5868 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
5869 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n'
5870 % (', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER))
Max Morozb47503b2019-08-08 21:03:275871
Sam Maiera6e76d72022-02-11 21:43:505872 return [
5873 output_api.PresubmitPromptWarning(message="Missing '%s' in:" %
5874 REQUIRED_HEADER,
5875 items=files_with_missing_header,
5876 long_text=long_text)
5877 ]
Max Morozb47503b2019-08-08 21:03:275878
5879
Mohamed Heikald048240a2019-11-12 16:57:375880def _CheckNewImagesWarning(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505881 """
5882 Warns authors who add images into the repo to make sure their images are
5883 optimized before committing.
5884 """
5885 images_added = False
5886 image_paths = []
5887 errors = []
5888 filter_lambda = lambda x: input_api.FilterSourceFile(
5889 x,
Daniel Cheng6303eed2025-05-03 00:12:335890 files_to_skip=(
5891 ('(?i).*test', r'.*\/junit\/') + input_api.DEFAULT_FILES_TO_SKIP),
Sam Maiera6e76d72022-02-11 21:43:505892 files_to_check=[r'.*\/(drawable|mipmap)'])
5893 for f in input_api.AffectedFiles(include_deletes=False,
5894 file_filter=filter_lambda):
5895 local_path = f.LocalPath().lower()
5896 if any(
5897 local_path.endswith(extension)
5898 for extension in _IMAGE_EXTENSIONS):
5899 images_added = True
5900 image_paths.append(f)
5901 if images_added:
5902 errors.append(
5903 output_api.PresubmitPromptWarning(
5904 'It looks like you are trying to commit some images. If these are '
5905 'non-test-only images, please make sure to read and apply the tips in '
5906 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
5907 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
5908 'FYI only and will not block your CL on the CQ.', image_paths))
5909 return errors
Mohamed Heikald048240a2019-11-12 16:57:375910
5911
Saagar Sanghavifceeaae2020-08-12 16:40:365912def ChecksAndroidSpecificOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505913 """Groups upload checks that target android code."""
5914 results = []
5915 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
5916 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
5917 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
5918 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505919 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
5920 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
5921 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
5922 results.extend(_CheckNewImagesWarning(input_api, output_api))
5923 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
5924 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
Daniel Cheng6303eed2025-05-03 00:12:335925 results.extend(_CheckAndroidNullAwayAnnotatedClasses(
5926 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505927 return results
5928
Becky Zhou7c69b50992018-12-10 19:37:575929
Saagar Sanghavifceeaae2020-08-12 16:40:365930def ChecksAndroidSpecificOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505931 """Groups commit checks that target android code."""
5932 results = []
5933 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
Daniel Cheng6303eed2025-05-03 00:12:335934 results.extend(_CheckAndroidNullAwayAnnotatedClasses(
5935 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505936 return results
dgnaa68d5e2015-06-10 10:08:225937
Daniel Cheng6303eed2025-05-03 00:12:335938
Chris Hall59f8d0c72020-05-01 07:31:195939# TODO(chrishall): could we additionally match on any path owned by
5940# ui/accessibility/OWNERS ?
5941_ACCESSIBILITY_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:315942 r"^chrome/browser.*/accessibility/",
5943 r"^chrome/browser/extensions/api/automation.*/",
5944 r"^chrome/renderer/extensions/accessibility_.*",
5945 r"^chrome/tests/data/accessibility/",
5946 r"^content/browser/accessibility/",
5947 r"^content/renderer/accessibility/",
5948 r"^content/tests/data/accessibility/",
5949 r"^extensions/renderer/api/automation/",
Katie Dektar58ef07b2022-09-27 13:19:175950 r"^services/accessibility/",
Abigail Klein7a63c572024-02-28 20:45:095951 r"^services/screen_ai/",
Bruce Dawson40fece62022-09-16 19:58:315952 r"^ui/accessibility/",
5953 r"^ui/views/accessibility/",
Chris Hall59f8d0c72020-05-01 07:31:195954)
5955
Daniel Cheng6303eed2025-05-03 00:12:335956
Saagar Sanghavifceeaae2020-08-12 16:40:365957def CheckAccessibilityRelnotesField(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505958 """Checks that commits to accessibility code contain an AX-Relnotes field in
5959 their commit message."""
Chris Hall59f8d0c72020-05-01 07:31:195960
Sam Maiera6e76d72022-02-11 21:43:505961 def FileFilter(affected_file):
5962 paths = _ACCESSIBILITY_PATHS
5963 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:195964
Sam Maiera6e76d72022-02-11 21:43:505965 # Only consider changes affecting accessibility paths.
5966 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
5967 return []
Akihiro Ota08108e542020-05-20 15:30:535968
Sam Maiera6e76d72022-02-11 21:43:505969 # AX-Relnotes can appear in either the description or the footer.
5970 # When searching the description, require 'AX-Relnotes:' to appear at the
5971 # beginning of a line.
5972 ax_regex = input_api.re.compile('ax-relnotes[:=]')
5973 description_has_relnotes = any(
5974 ax_regex.match(line)
5975 for line in input_api.change.DescriptionText().lower().splitlines())
Chris Hall59f8d0c72020-05-01 07:31:195976
Sam Maiera6e76d72022-02-11 21:43:505977 footer_relnotes = input_api.change.GitFootersFromDescription().get(
5978 'AX-Relnotes', [])
5979 if description_has_relnotes or footer_relnotes:
5980 return []
Chris Hall59f8d0c72020-05-01 07:31:195981
Sam Maiera6e76d72022-02-11 21:43:505982 # TODO(chrishall): link to Relnotes documentation in message.
5983 message = (
5984 "Missing 'AX-Relnotes:' field required for accessibility changes"
5985 "\n please add 'AX-Relnotes: [release notes].' to describe any "
5986 "user-facing changes"
5987 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
5988 "user-facing effects"
5989 "\n if this is confusing or annoying then please contact members "
5990 "of ui/accessibility/OWNERS.")
5991
5992 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:225993
Mark Schillaci44c90b42024-11-22 20:44:385994
5995_ACCESSIBILITY_ARIA_METHOD_CANDIDATES_PATTERNS = r'(\-\>|\.)(get|has|FastGet|FastHas)Attribute\('
5996
Daniel Cheng6303eed2025-05-03 00:12:335997_ACCESSIBILITY_ARIA_BAD_PARAMS_PATTERNS = (r"\(html_names::kAria(.*)Attr\)",
5998 r"\(html_names::kRoleAttr\)")
Mark Schillaci44c90b42024-11-22 20:44:385999
Daniel Cheng6303eed2025-05-03 00:12:336000_ACCESSIBILITY_ARIA_FILE_CANDIDATES_PATTERNS = (r".*/accessibility/.*.(cc|h)",
6001 r".*/ax_.*.(cc|h)")
6002
Mark Schillaci44c90b42024-11-22 20:44:386003
6004def CheckAccessibilityAriaElementAttributeGetters(input_api, output_api):
6005 """Checks that the blink accessibility code follows the defined patterns
6006 for checking aria attributes, so that ElementInternals is not bypassed."""
6007
6008 # Limit to accessibility-related files.
6009 def FileFilter(affected_file):
6010 paths = _ACCESSIBILITY_ARIA_FILE_CANDIDATES_PATTERNS
6011 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
6012
Daniel Cheng6303eed2025-05-03 00:12:336013 aria_method_regex = input_api.re.compile(
6014 _ACCESSIBILITY_ARIA_METHOD_CANDIDATES_PATTERNS)
Mark Schillaci44c90b42024-11-22 20:44:386015 aria_bad_params_regex = input_api.re.compile(
Daniel Cheng6303eed2025-05-03 00:12:336016 "|".join(_ACCESSIBILITY_ARIA_BAD_PARAMS_PATTERNS))
Mark Schillaci44c90b42024-11-22 20:44:386017 problems = []
6018
6019 for f in input_api.AffectedSourceFiles(FileFilter):
6020 for line_num, line in f.ChangedContents():
Daniel Cheng6303eed2025-05-03 00:12:336021 if aria_method_regex.search(line) and aria_bad_params_regex.search(
6022 line):
6023 problems.append(
6024 f"{f.LocalPath()}:{line_num}\n {line.strip()}")
Mark Schillaci44c90b42024-11-22 20:44:386025
6026 if problems:
6027 return [
6028 output_api.PresubmitPromptWarning(
6029 "Accessibility code should not use element methods to get or check"
6030 "\nthe presence of aria attributes"
6031 "\nPlease use ARIA-specific attribute access, e.g. HasAriaAttribute(),"
6032 "\nAriaTokenAttribute(), AriaBoolAttribute(), AriaBooleanAttribute(),"
6033 "\nAriaFloatAttribute().",
6034 problems,
6035 )
6036 ]
6037 return []
6038
Daniel Cheng6303eed2025-05-03 00:12:336039
seanmccullough4a9356252021-04-08 19:54:096040# string pattern, sequence of strings to show when pattern matches,
6041# error flag. True if match is a presubmit error, otherwise it's a warning.
6042_NON_INCLUSIVE_TERMS = (
6043 (
6044 # Note that \b pattern in python re is pretty particular. In this
6045 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
6046 # ...' will not. This may require some tweaking to catch these cases
6047 # without triggering a lot of false positives. Leaving it naive and
6048 # less matchy for now.
Josip Sokcevic9d2806a02023-12-13 03:04:026049 r'/(?i)\b((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:096050 (
6051 'Please don\'t use blacklist, whitelist, ' # nocheck
6052 'or slave in your', # nocheck
6053 'code and make every effort to use other terms. Using "// nocheck"',
6054 '"# nocheck" or "<!-- nocheck -->"',
6055 'at the end of the offending line will bypass this PRESUBMIT error',
6056 'but avoid using this whenever possible. Reach out to',
6057 '[email protected] if you have questions'),
Daniel Cheng6303eed2025-05-03 00:12:336058 True), )
6059
seanmccullough4a9356252021-04-08 19:54:096060
Saagar Sanghavifceeaae2020-08-12 16:40:366061def ChecksCommon(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506062 """Checks common to both upload and commit."""
6063 results = []
Eric Boren6fd2b932018-01-25 15:05:086064 results.extend(
Sam Maiera6e76d72022-02-11 21:43:506065 input_api.canned_checks.PanProjectChecks(
6066 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:086067
Sam Maiera6e76d72022-02-11 21:43:506068 author = input_api.change.author_email
6069 if author and author not in _KNOWN_ROBOTS:
6070 results.extend(
6071 input_api.canned_checks.CheckAuthorizedAuthor(
6072 input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:246073
Sam Maiera6e76d72022-02-11 21:43:506074 results.extend(
6075 input_api.canned_checks.CheckChangeHasNoTabs(
6076 input_api,
6077 output_api,
6078 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
6079 results.extend(
6080 input_api.RunTests(
6081 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Edward Lesmesce51df52020-08-04 22:10:176082
Mohamed Amir Yosef0ca6efb2025-05-14 10:02:286083 dirmd = 'dirmd.bat' if input_api.is_windows else 'dirmd'
6084 dirmd_bin = input_api.os_path.join(input_api.PresubmitLocalPath(),
6085 'third_party', 'depot_tools', dirmd)
Sam Maiera6e76d72022-02-11 21:43:506086 results.extend(
6087 input_api.RunTests(
6088 input_api.canned_checks.CheckDirMetadataFormat(
Mohamed Amir Yosef0ca6efb2025-05-14 10:02:286089 input_api, output_api, dirmd_bin)))
Sam Maiera6e76d72022-02-11 21:43:506090 results.extend(
6091 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
6092 input_api, output_api))
6093 results.extend(
6094 input_api.canned_checks.CheckNoNewMetadataInOwners(
6095 input_api, output_api))
6096 results.extend(
6097 input_api.canned_checks.CheckInclusiveLanguage(
6098 input_api,
6099 output_api,
6100 excluded_directories_relative_path=[
6101 'infra', 'inclusive_language_presubmit_exempt_dirs.txt'
6102 ],
6103 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Yiwei Zhang5341bf02025-03-20 16:34:136104 results.extend(
6105 input_api.canned_checks.CheckNewDEPSHooksHasRequiredReviewers(
6106 input_api, output_api))
Dirk Prankee3c9c62d2021-05-18 18:35:596107
Aleksey Khoroshilov2978c942022-06-13 16:14:126108 presubmit_py_filter = lambda f: input_api.FilterSourceFile(
Daniel Cheng6f3d1ae12025-04-07 17:11:276109 f, files_to_check=[r'.*PRESUBMIT(?:_test)?\.py$'])
6110 potential_paths = set(
6111 map(
6112 lambda f: input_api.os_path.dirname(f.AbsoluteLocalPath()),
6113 input_api.AffectedFiles(include_deletes=False,
6114 file_filter=presubmit_py_filter)))
6115 for full_path in potential_paths:
Aleksey Khoroshilov2978c942022-06-13 16:14:126116 test_file = input_api.os_path.join(full_path, 'PRESUBMIT_test.py')
6117 # The PRESUBMIT.py file (and the directory containing it) might have
6118 # been affected by being moved or removed, so only try to run the tests
6119 # if they still exist.
6120 if not input_api.os_path.exists(test_file):
6121 continue
Sam Maiera6e76d72022-02-11 21:43:506122
Aleksey Khoroshilov2978c942022-06-13 16:14:126123 results.extend(
6124 input_api.canned_checks.RunUnitTestsInDirectory(
6125 input_api,
6126 output_api,
6127 full_path,
Takuto Ikuta40def482023-06-02 02:23:496128 files_to_check=[r'^PRESUBMIT_test\.py$']))
Sam Maiera6e76d72022-02-11 21:43:506129 return results
[email protected]1f7b4172010-01-28 01:17:346130
[email protected]b337cb5b2011-01-23 21:24:056131
Saagar Sanghavifceeaae2020-08-12 16:40:366132def CheckPatchFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506133 problems = [
6134 f.LocalPath() for f in input_api.AffectedFiles()
6135 if f.LocalPath().endswith(('.orig', '.rej'))
6136 ]
6137 # Cargo.toml.orig files are part of third-party crates downloaded from
6138 # crates.io and should be included.
6139 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
6140 if problems:
6141 return [
6142 output_api.PresubmitError("Don't commit .rej and .orig files.",
6143 problems)
6144 ]
6145 else:
6146 return []
[email protected]b8079ae4a2012-12-05 19:56:496147
6148
Saagar Sanghavifceeaae2020-08-12 16:40:366149def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506150 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
6151 macro_re = input_api.re.compile(
6152 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
6153 include_re = input_api.re.compile(r'^#include\s+"build/build_config.h"',
6154 input_api.re.MULTILINE)
6155 extension_re = input_api.re.compile(r'\.[a-z]+$')
6156 errors = []
Bruce Dawsonf7679202022-08-09 20:24:006157 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:506158 for f in input_api.AffectedFiles(include_deletes=False):
Bruce Dawsonf7679202022-08-09 20:24:006159 # The build-config macros are allowed to be used in build_config.h
6160 # without including itself.
6161 if f.LocalPath() == config_h_file:
6162 continue
Sam Maiera6e76d72022-02-11 21:43:506163 if not f.LocalPath().endswith(
6164 ('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
6165 continue
Arthur Sonzognia3dec412024-04-29 12:05:376166
Sam Maiera6e76d72022-02-11 21:43:506167 found_line_number = None
6168 found_macro = None
6169 all_lines = input_api.ReadFile(f, 'r').splitlines()
6170 for line_num, line in enumerate(all_lines):
6171 match = macro_re.search(line)
6172 if match:
6173 found_line_number = line_num
6174 found_macro = match.group(2)
6175 break
6176 if not found_line_number:
6177 continue
Kent Tamura5a8755d2017-06-29 23:37:076178
Sam Maiera6e76d72022-02-11 21:43:506179 found_include_line = -1
6180 for line_num, line in enumerate(all_lines):
6181 if include_re.search(line):
6182 found_include_line = line_num
6183 break
6184 if found_include_line >= 0 and found_include_line < found_line_number:
6185 continue
Kent Tamura5a8755d2017-06-29 23:37:076186
Sam Maiera6e76d72022-02-11 21:43:506187 if not f.LocalPath().endswith('.h'):
6188 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
6189 try:
6190 content = input_api.ReadFile(primary_header_path, 'r')
6191 if include_re.search(content):
6192 continue
6193 except IOError:
6194 pass
6195 errors.append('%s:%d %s macro is used without first including build/'
6196 'build_config.h.' %
6197 (f.LocalPath(), found_line_number, found_macro))
6198 if errors:
6199 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
6200 return []
Kent Tamura5a8755d2017-06-29 23:37:076201
6202
Lei Zhang1c12a22f2021-05-12 11:28:456203def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506204 stl_include_re = input_api.re.compile(r'^#include\s+<('
6205 r'algorithm|'
6206 r'array|'
6207 r'limits|'
6208 r'list|'
6209 r'map|'
6210 r'memory|'
6211 r'queue|'
6212 r'set|'
6213 r'string|'
6214 r'unordered_map|'
6215 r'unordered_set|'
6216 r'utility|'
6217 r'vector)>')
6218 std_namespace_re = input_api.re.compile(r'std::')
6219 errors = []
6220 for f in input_api.AffectedFiles():
6221 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
6222 continue
Lei Zhang1c12a22f2021-05-12 11:28:456223
Sam Maiera6e76d72022-02-11 21:43:506224 uses_std_namespace = False
6225 has_stl_include = False
6226 for line in f.NewContents():
6227 if has_stl_include and uses_std_namespace:
6228 break
Lei Zhang1c12a22f2021-05-12 11:28:456229
Sam Maiera6e76d72022-02-11 21:43:506230 if not has_stl_include and stl_include_re.search(line):
6231 has_stl_include = True
6232 continue
Lei Zhang1c12a22f2021-05-12 11:28:456233
Bruce Dawson4a5579a2022-04-08 17:11:366234 if not uses_std_namespace and (std_namespace_re.search(line)
Daniel Cheng6303eed2025-05-03 00:12:336235 or 'no-std-usage-because-pch-file'
6236 in line):
Sam Maiera6e76d72022-02-11 21:43:506237 uses_std_namespace = True
6238 continue
Lei Zhang1c12a22f2021-05-12 11:28:456239
Sam Maiera6e76d72022-02-11 21:43:506240 if has_stl_include and not uses_std_namespace:
6241 errors.append(
6242 '%s: Includes STL header(s) but does not reference std::' %
6243 f.LocalPath())
6244 if errors:
6245 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
6246 return []
Lei Zhang1c12a22f2021-05-12 11:28:456247
6248
Xiaohan Wang42d96c22022-01-20 17:23:116249def _CheckForDeprecatedOSMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:506250 """Check for sensible looking, totally invalid OS macros."""
6251 preprocessor_statement = input_api.re.compile(r'^\s*#')
6252 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
6253 results = []
6254 for lnum, line in f.ChangedContents():
6255 if preprocessor_statement.search(line):
6256 for match in os_macro.finditer(line):
6257 results.append(
6258 ' %s:%d: %s' %
6259 (f.LocalPath(), lnum, 'defined(OS_' + match.group(1) +
6260 ') -> BUILDFLAG(IS_' + match.group(1) + ')'))
6261 return results
[email protected]b00342e7f2013-03-26 16:21:546262
6263
Xiaohan Wang42d96c22022-01-20 17:23:116264def CheckForDeprecatedOSMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506265 """Check all affected files for invalid OS macros."""
6266 bad_macros = []
Bruce Dawsonf7679202022-08-09 20:24:006267 # The OS_ macros are allowed to be used in build/build_config.h.
6268 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:506269 for f in input_api.AffectedSourceFiles(None):
Bruce Dawsonf7679202022-08-09 20:24:006270 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')) \
6271 and f.LocalPath() != config_h_file:
Sam Maiera6e76d72022-02-11 21:43:506272 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
[email protected]b00342e7f2013-03-26 16:21:546273
Sam Maiera6e76d72022-02-11 21:43:506274 if not bad_macros:
6275 return []
[email protected]b00342e7f2013-03-26 16:21:546276
Sam Maiera6e76d72022-02-11 21:43:506277 return [
6278 output_api.PresubmitError(
6279 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
6280 'defined in build_config.h):', bad_macros)
6281 ]
[email protected]b00342e7f2013-03-26 16:21:546282
lliabraa35bab3932014-10-01 12:16:446283
6284def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:506285 """Check all affected files for invalid "if defined" macros."""
6286 ALWAYS_DEFINED_MACROS = (
6287 "TARGET_CPU_PPC",
6288 "TARGET_CPU_PPC64",
6289 "TARGET_CPU_68K",
6290 "TARGET_CPU_X86",
6291 "TARGET_CPU_ARM",
6292 "TARGET_CPU_MIPS",
6293 "TARGET_CPU_SPARC",
6294 "TARGET_CPU_ALPHA",
6295 "TARGET_IPHONE_SIMULATOR",
6296 "TARGET_OS_EMBEDDED",
6297 "TARGET_OS_IPHONE",
6298 "TARGET_OS_MAC",
6299 "TARGET_OS_UNIX",
6300 "TARGET_OS_WIN32",
6301 )
6302 ifdef_macro = input_api.re.compile(
6303 r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
6304 results = []
6305 for lnum, line in f.ChangedContents():
6306 for match in ifdef_macro.finditer(line):
6307 if match.group(1) in ALWAYS_DEFINED_MACROS:
6308 always_defined = ' %s is always defined. ' % match.group(1)
6309 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
6310 results.append(
6311 ' %s:%d %s\n\t%s' %
6312 (f.LocalPath(), lnum, always_defined, did_you_mean))
6313 return results
lliabraa35bab3932014-10-01 12:16:446314
6315
Saagar Sanghavifceeaae2020-08-12 16:40:366316def CheckForInvalidIfDefinedMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506317 """Check all affected files for invalid "if defined" macros."""
Arthur Sonzogni4fd14fd2024-06-02 18:42:526318 SKIPPED_PATHS = [
6319 'base/allocator/partition_allocator/src/partition_alloc/build_config.h',
6320 'build/build_config.h',
6321 'third_party/abseil-cpp/',
6322 'third_party/sqlite/',
6323 ]
Daniel Cheng6303eed2025-05-03 00:12:336324
Arthur Sonzogni4fd14fd2024-06-02 18:42:526325 def affected_files_filter(f):
6326 # Normalize the local path to Linux-style path separators so that the
6327 # path comparisons work on Windows as well.
Anton Bershanskyi4253349482025-02-11 21:01:276328 path = f.UnixLocalPath()
Arthur Sonzogni4fd14fd2024-06-02 18:42:526329
6330 for skipped_path in SKIPPED_PATHS:
6331 if path.startswith(skipped_path):
6332 return False
6333
6334 return path.endswith(('.h', '.c', '.cc', '.m', '.mm'))
6335
Sam Maiera6e76d72022-02-11 21:43:506336 bad_macros = []
Arthur Sonzogni4fd14fd2024-06-02 18:42:526337 for f in input_api.AffectedSourceFiles(affected_files_filter):
6338 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
lliabraa35bab3932014-10-01 12:16:446339
Sam Maiera6e76d72022-02-11 21:43:506340 if not bad_macros:
6341 return []
lliabraa35bab3932014-10-01 12:16:446342
Sam Maiera6e76d72022-02-11 21:43:506343 return [
6344 output_api.PresubmitError(
6345 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
6346 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
6347 bad_macros)
6348 ]
lliabraa35bab3932014-10-01 12:16:446349
Daniel Cheng6303eed2025-05-03 00:12:336350
Saagar Sanghavifceeaae2020-08-12 16:40:366351def CheckForIPCRules(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506352 """Check for same IPC rules described in
6353 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
6354 """
6355 base_pattern = r'IPC_ENUM_TRAITS\('
6356 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
6357 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
mlamouria82272622014-09-16 18:45:046358
Sam Maiera6e76d72022-02-11 21:43:506359 problems = []
6360 for f in input_api.AffectedSourceFiles(None):
6361 local_path = f.LocalPath()
6362 if not local_path.endswith('.h'):
6363 continue
6364 for line_number, line in f.ChangedContents():
6365 if inclusion_pattern.search(
6366 line) and not comment_pattern.search(line):
6367 problems.append('%s:%d\n %s' %
6368 (local_path, line_number, line.strip()))
mlamouria82272622014-09-16 18:45:046369
Sam Maiera6e76d72022-02-11 21:43:506370 if problems:
6371 return [
6372 output_api.PresubmitPromptWarning(_IPC_ENUM_TRAITS_DEPRECATED,
6373 problems)
6374 ]
6375 else:
6376 return []
mlamouria82272622014-09-16 18:45:046377
[email protected]b00342e7f2013-03-26 16:21:546378
Saagar Sanghavifceeaae2020-08-12 16:40:366379def CheckForLongPathnames(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506380 """Check to make sure no files being submitted have long paths.
6381 This causes issues on Windows.
6382 """
6383 problems = []
6384 for f in input_api.AffectedTestableFiles():
6385 local_path = f.LocalPath()
6386 # Windows has a path limit of 260 characters. Limit path length to 200 so
6387 # that we have some extra for the prefix on dev machines and the bots.
Daniel Cheng6303eed2025-05-03 00:12:336388 if (local_path.startswith('third_party/blink/web_tests/platform/')
6389 and not local_path.startswith(
6390 'third_party/blink/web_tests/platform/win')):
Weizhong Xia8b461f12024-06-21 21:46:336391 # Do not check length of the path for files not used by Windows
6392 continue
Sam Maiera6e76d72022-02-11 21:43:506393 if len(local_path) > 200:
6394 problems.append(local_path)
Stephen Martinis97a394142018-06-07 23:06:056395
Sam Maiera6e76d72022-02-11 21:43:506396 if problems:
6397 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
6398 else:
6399 return []
Stephen Martinis97a394142018-06-07 23:06:056400
6401
Saagar Sanghavifceeaae2020-08-12 16:40:366402def CheckForIncludeGuards(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506403 """Check that header files have proper guards against multiple inclusion.
6404 If a file should not have such guards (and it probably should) then it
Bruce Dawson4a5579a2022-04-08 17:11:366405 should include the string "no-include-guard-because-multiply-included" or
6406 "no-include-guard-because-pch-file".
Sam Maiera6e76d72022-02-11 21:43:506407 """
Daniel Bratell8ba52722018-03-02 16:06:146408
Sam Maiera6e76d72022-02-11 21:43:506409 def is_chromium_header_file(f):
6410 # We only check header files under the control of the Chromium
mikt84d6c712024-03-27 13:29:036411 # project. This excludes:
6412 # - third_party/*, except blink.
6413 # - base/allocator/partition_allocator/: PartitionAlloc is a standalone
6414 # library used outside of Chrome. Includes are referenced from its
6415 # own base directory. It has its own `CheckForIncludeGuards`
6416 # PRESUBMIT.py check.
6417 # - *_message_generator.h: They use include guards in a special,
6418 # non-typical way.
Sam Maiera6e76d72022-02-11 21:43:506419 file_with_path = input_api.os_path.normpath(f.LocalPath())
6420 return (file_with_path.endswith('.h')
6421 and not file_with_path.endswith('_message_generator.h')
Bruce Dawson4c4c2922022-05-02 18:07:336422 and not file_with_path.endswith('com_imported_mstscax.h')
Peter Kasting66c1f752024-12-02 15:28:376423 and not file_with_path.startswith(
6424 input_api.os_path.join('base', 'allocator',
6425 'partition_allocator'))
Sam Maiera6e76d72022-02-11 21:43:506426 and (not file_with_path.startswith('third_party')
6427 or file_with_path.startswith(
6428 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:146429
Sam Maiera6e76d72022-02-11 21:43:506430 def replace_special_with_underscore(string):
6431 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:146432
Sam Maiera6e76d72022-02-11 21:43:506433 errors = []
Daniel Bratell8ba52722018-03-02 16:06:146434
Sam Maiera6e76d72022-02-11 21:43:506435 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
6436 guard_name = None
6437 guard_line_number = None
6438 seen_guard_end = False
Lei Zhangd84f9512024-05-28 19:43:306439 bypass_checks_at_end_of_file = False
Daniel Bratell8ba52722018-03-02 16:06:146440
Sam Maiera6e76d72022-02-11 21:43:506441 file_with_path = input_api.os_path.normpath(f.LocalPath())
6442 base_file_name = input_api.os_path.splitext(
6443 input_api.os_path.basename(file_with_path))[0]
6444 upper_base_file_name = base_file_name.upper()
Daniel Bratell8ba52722018-03-02 16:06:146445
Sam Maiera6e76d72022-02-11 21:43:506446 expected_guard = replace_special_with_underscore(
6447 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:146448
Sam Maiera6e76d72022-02-11 21:43:506449 # For "path/elem/file_name.h" we should really only accept
6450 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
6451 # are too many (1000+) files with slight deviations from the
6452 # coding style. The most important part is that the include guard
6453 # is there, and that it's unique, not the name so this check is
6454 # forgiving for existing files.
6455 #
6456 # As code becomes more uniform, this could be made stricter.
Daniel Bratell8ba52722018-03-02 16:06:146457
Sam Maiera6e76d72022-02-11 21:43:506458 guard_name_pattern_list = [
6459 # Anything with the right suffix (maybe with an extra _).
6460 r'\w+_H__?',
Daniel Bratell8ba52722018-03-02 16:06:146461
Sam Maiera6e76d72022-02-11 21:43:506462 # To cover include guards with old Blink style.
6463 r'\w+_h',
Daniel Bratell8ba52722018-03-02 16:06:146464
Sam Maiera6e76d72022-02-11 21:43:506465 # Anything including the uppercase name of the file.
6466 r'\w*' + input_api.re.escape(
6467 replace_special_with_underscore(upper_base_file_name)) +
6468 r'\w*',
6469 ]
6470 guard_name_pattern = '|'.join(guard_name_pattern_list)
6471 guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
6472 guard_name_pattern + ')')
Daniel Bratell8ba52722018-03-02 16:06:146473
Sam Maiera6e76d72022-02-11 21:43:506474 for line_number, line in enumerate(f.NewContents()):
Bruce Dawson4a5579a2022-04-08 17:11:366475 if ('no-include-guard-because-multiply-included' in line
6476 or 'no-include-guard-because-pch-file' in line):
Lei Zhangd84f9512024-05-28 19:43:306477 bypass_checks_at_end_of_file = True
Sam Maiera6e76d72022-02-11 21:43:506478 break
Daniel Bratell8ba52722018-03-02 16:06:146479
Sam Maiera6e76d72022-02-11 21:43:506480 if guard_name is None:
6481 match = guard_pattern.match(line)
6482 if match:
6483 guard_name = match.group(1)
6484 guard_line_number = line_number
Daniel Bratell8ba52722018-03-02 16:06:146485
Sam Maiera6e76d72022-02-11 21:43:506486 # We allow existing files to use include guards whose names
6487 # don't match the chromium style guide, but new files should
6488 # get it right.
Bruce Dawson6cc154e2022-04-12 20:39:496489 if guard_name != expected_guard:
Bruce Dawson95eb7562022-09-14 15:27:166490 if f.Action() == 'A': # If file was just 'A'dded
Sam Maiera6e76d72022-02-11 21:43:506491 errors.append(
6492 output_api.PresubmitPromptWarning(
6493 'Header using the wrong include guard name %s'
6494 % guard_name, [
6495 '%s:%d' %
6496 (f.LocalPath(), line_number + 1)
6497 ], 'Expected: %r\nFound: %r' %
6498 (expected_guard, guard_name)))
6499 else:
6500 # The line after #ifndef should have a #define of the same name.
6501 if line_number == guard_line_number + 1:
6502 expected_line = '#define %s' % guard_name
6503 if line != expected_line:
6504 errors.append(
6505 output_api.PresubmitPromptWarning(
6506 'Missing "%s" for include guard' %
6507 expected_line,
6508 ['%s:%d' % (f.LocalPath(), line_number + 1)],
6509 'Expected: %r\nGot: %r' %
6510 (expected_line, line)))
Daniel Bratell8ba52722018-03-02 16:06:146511
Sam Maiera6e76d72022-02-11 21:43:506512 if not seen_guard_end and line == '#endif // %s' % guard_name:
6513 seen_guard_end = True
6514 elif seen_guard_end:
6515 if line.strip() != '':
6516 errors.append(
6517 output_api.PresubmitPromptWarning(
6518 'Include guard %s not covering the whole file'
6519 % (guard_name), [f.LocalPath()]))
6520 break # Nothing else to check and enough to warn once.
Daniel Bratell8ba52722018-03-02 16:06:146521
Lei Zhangd84f9512024-05-28 19:43:306522 if bypass_checks_at_end_of_file:
6523 continue
6524
Sam Maiera6e76d72022-02-11 21:43:506525 if guard_name is None:
6526 errors.append(
6527 output_api.PresubmitPromptWarning(
Bruce Dawson32114b62022-04-11 16:45:496528 'Missing include guard in %s\n'
Sam Maiera6e76d72022-02-11 21:43:506529 'Recommended name: %s\n'
6530 'This check can be disabled by having the string\n'
Bruce Dawson4a5579a2022-04-08 17:11:366531 '"no-include-guard-because-multiply-included" or\n'
Daniel Cheng6303eed2025-05-03 00:12:336532 '"no-include-guard-because-pch-file" in the header.' %
6533 (f.LocalPath(), expected_guard)))
Lei Zhangd84f9512024-05-28 19:43:306534 elif not seen_guard_end:
6535 errors.append(
6536 output_api.PresubmitPromptWarning(
6537 'Incorrect or missing include guard #endif in %s\n'
Daniel Cheng6303eed2025-05-03 00:12:336538 'Recommended #endif comment: // %s' %
6539 (f.LocalPath(), expected_guard)))
Sam Maiera6e76d72022-02-11 21:43:506540
6541 return errors
Daniel Bratell8ba52722018-03-02 16:06:146542
6543
Saagar Sanghavifceeaae2020-08-12 16:40:366544def CheckForWindowsLineEndings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506545 """Check source code and known ascii text files for Windows style line
6546 endings.
6547 """
Bruce Dawson5efbdc652022-04-11 19:29:516548 known_text_files = r'.*\.(txt|html|htm|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:236549
dpapadfd421fb2025-02-13 00:47:326550 _WEBUI_FILES_EXTENSIONS = r'\.(css|html|js|ts|svg)$'
6551
Sam Maiera6e76d72022-02-11 21:43:506552 file_inclusion_pattern = (known_text_files,
6553 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
dpapadfd421fb2025-02-13 00:47:326554 r'.+%s' % _HEADER_EXTENSIONS,
6555 r'.+%s' % _WEBUI_FILES_EXTENSIONS)
6556
6557 # Exclude folder that contains .ts files that are actually binary video
6558 # format and not TypeScript.
6559 file_exclusion_pattern = (r'media/test/data/')
mostynbb639aca52015-01-07 20:31:236560
Sam Maiera6e76d72022-02-11 21:43:506561 problems = []
6562 source_file_filter = lambda f: input_api.FilterSourceFile(
Daniel Cheng6303eed2025-05-03 00:12:336563 f,
6564 files_to_check=file_inclusion_pattern,
dpapadfd421fb2025-02-13 00:47:326565 files_to_skip=file_exclusion_pattern)
Sam Maiera6e76d72022-02-11 21:43:506566 for f in input_api.AffectedSourceFiles(source_file_filter):
Bruce Dawson5efbdc652022-04-11 19:29:516567 # Ignore test files that contain crlf intentionally.
6568 if f.LocalPath().endswith('crlf.txt'):
Daniel Chenga37c03db2022-05-12 17:20:346569 continue
Sam Maiera6e76d72022-02-11 21:43:506570 include_file = False
6571 for line in input_api.ReadFile(f, 'r').splitlines(True):
6572 if line.endswith('\r\n'):
6573 include_file = True
6574 if include_file:
6575 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:236576
Sam Maiera6e76d72022-02-11 21:43:506577 if problems:
6578 return [
6579 output_api.PresubmitPromptWarning(
6580 'Are you sure that you want '
6581 'these files to contain Windows style line endings?\n' +
6582 '\n'.join(problems))
6583 ]
mostynbb639aca52015-01-07 20:31:236584
Sam Maiera6e76d72022-02-11 21:43:506585 return []
6586
mostynbb639aca52015-01-07 20:31:236587
Evan Stade6cfc964c12021-05-18 20:21:166588def CheckIconFilesForLicenseHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506589 """Check that .icon files (which are fragments of C++) have license headers.
6590 """
Evan Stade6cfc964c12021-05-18 20:21:166591
Sam Maiera6e76d72022-02-11 21:43:506592 icon_files = (r'.*\.icon$', )
Evan Stade6cfc964c12021-05-18 20:21:166593
Sam Maiera6e76d72022-02-11 21:43:506594 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
6595 return input_api.canned_checks.CheckLicense(input_api,
6596 output_api,
6597 source_file_filter=icons)
6598
Evan Stade6cfc964c12021-05-18 20:21:166599
Jose Magana2b456f22021-03-09 23:26:406600def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506601 """Check source code for use of Chrome App technologies being
6602 deprecated.
6603 """
Jose Magana2b456f22021-03-09 23:26:406604
Sam Maiera6e76d72022-02-11 21:43:506605 def _CheckForDeprecatedTech(input_api,
6606 output_api,
6607 detection_list,
6608 files_to_check=None,
6609 files_to_skip=None):
Jose Magana2b456f22021-03-09 23:26:406610
Sam Maiera6e76d72022-02-11 21:43:506611 if (files_to_check or files_to_skip):
6612 source_file_filter = lambda f: input_api.FilterSourceFile(
6613 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
6614 else:
6615 source_file_filter = None
6616
6617 problems = []
6618
6619 for f in input_api.AffectedSourceFiles(source_file_filter):
6620 if f.Action() == 'D':
6621 continue
6622 for _, line in f.ChangedContents():
6623 if any(detect in line for detect in detection_list):
6624 problems.append(f.LocalPath())
6625
6626 return problems
6627
6628 # to avoid this presubmit script triggering warnings
6629 files_to_skip = ['PRESUBMIT.py', 'PRESUBMIT_test.py']
Jose Magana2b456f22021-03-09 23:26:406630
6631 problems = []
6632
Sam Maiera6e76d72022-02-11 21:43:506633 # NMF: any files with extensions .nmf or NMF
6634 _NMF_FILES = r'\.(nmf|NMF)$'
6635 problems += _CheckForDeprecatedTech(
6636 input_api,
6637 output_api,
6638 detection_list=[''], # any change to the file will trigger warning
6639 files_to_check=[r'.+%s' % _NMF_FILES])
Jose Magana2b456f22021-03-09 23:26:406640
Sam Maiera6e76d72022-02-11 21:43:506641 # MANIFEST: any manifest.json that in its diff includes "app":
6642 _MANIFEST_FILES = r'(manifest\.json)$'
6643 problems += _CheckForDeprecatedTech(
6644 input_api,
6645 output_api,
6646 detection_list=['"app":'],
6647 files_to_check=[r'.*%s' % _MANIFEST_FILES])
Jose Magana2b456f22021-03-09 23:26:406648
Sam Maiera6e76d72022-02-11 21:43:506649 # NaCl / PNaCl: any file that in its diff contains the strings in the list
6650 problems += _CheckForDeprecatedTech(
6651 input_api,
6652 output_api,
6653 detection_list=['config=nacl', 'enable-nacl', 'cpu=pnacl', 'nacl_io'],
Bruce Dawson40fece62022-09-16 19:58:316654 files_to_skip=files_to_skip + [r"^native_client_sdk/"])
Jose Magana2b456f22021-03-09 23:26:406655
Gao Shenga79ebd42022-08-08 17:25:596656 # PPAPI: any C/C++ file that in its diff includes a ppapi library
Sam Maiera6e76d72022-02-11 21:43:506657 problems += _CheckForDeprecatedTech(
6658 input_api,
6659 output_api,
6660 detection_list=['#include "ppapi', '#include <ppapi'],
6661 files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,
6662 r'.+%s' % _IMPLEMENTATION_EXTENSIONS),
Bruce Dawson40fece62022-09-16 19:58:316663 files_to_skip=[r"^ppapi/"])
Jose Magana2b456f22021-03-09 23:26:406664
Sam Maiera6e76d72022-02-11 21:43:506665 if problems:
6666 return [
6667 output_api.PresubmitPromptWarning(
6668 'You are adding/modifying code'
6669 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
6670 ' PNaCl, PPAPI). See this blog post for more details:\n'
6671 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
6672 'and this documentation for options to replace these technologies:\n'
6673 'https://developer.chrome.com/docs/apps/migration/\n' +
6674 '\n'.join(problems))
6675 ]
Jose Magana2b456f22021-03-09 23:26:406676
Sam Maiera6e76d72022-02-11 21:43:506677 return []
Jose Magana2b456f22021-03-09 23:26:406678
mostynbb639aca52015-01-07 20:31:236679
Saagar Sanghavifceeaae2020-08-12 16:40:366680def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
Sam Maiera6e76d72022-02-11 21:43:506681 """Checks that all source files use SYSLOG properly."""
6682 syslog_files = []
6683 for f in input_api.AffectedSourceFiles(src_file_filter):
6684 for line_number, line in f.ChangedContents():
6685 if 'SYSLOG' in line:
6686 syslog_files.append(f.LocalPath() + ':' + str(line_number))
pastarmovj032ba5bc2017-01-12 10:41:566687
Sam Maiera6e76d72022-02-11 21:43:506688 if syslog_files:
6689 return [
6690 output_api.PresubmitPromptWarning(
6691 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
6692 ' calls.\nFiles to check:\n',
6693 items=syslog_files)
6694 ]
6695 return []
pastarmovj89f7ee12016-09-20 14:58:136696
6697
[email protected]1f7b4172010-01-28 01:17:346698def CheckChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506699 if input_api.version < [2, 0, 0]:
6700 return [
6701 output_api.PresubmitError(
6702 "Your depot_tools is out of date. "
6703 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
6704 "but your version is %d.%d.%d" % tuple(input_api.version))
6705 ]
6706 results = []
6707 results.extend(
6708 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
6709 return results
[email protected]ca8d1982009-02-19 16:33:126710
6711
6712def CheckChangeOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506713 if input_api.version < [2, 0, 0]:
6714 return [
6715 output_api.PresubmitError(
6716 "Your depot_tools is out of date. "
6717 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
6718 "but your version is %d.%d.%d" % tuple(input_api.version))
6719 ]
Saagar Sanghavifceeaae2020-08-12 16:40:366720
Sam Maiera6e76d72022-02-11 21:43:506721 results = []
6722 # Make sure the tree is 'open'.
6723 results.extend(
6724 input_api.canned_checks.CheckTreeIsOpen(
6725 input_api,
6726 output_api,
6727 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:276728
Sam Maiera6e76d72022-02-11 21:43:506729 results.extend(
6730 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
6731 results.extend(
6732 input_api.canned_checks.CheckChangeHasBugField(input_api, output_api))
6733 results.extend(
6734 input_api.canned_checks.CheckChangeHasNoUnwantedTags(
6735 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:506736 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146737
6738
Saagar Sanghavifceeaae2020-08-12 16:40:366739def CheckStrings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506740 """Check string ICU syntax validity and if translation screenshots exist."""
6741 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
6742 # footer is set to true.
6743 git_footers = input_api.change.GitFootersFromDescription()
6744 skip_screenshot_check_footer = [
6745 footer.lower() for footer in git_footers.get(
6746 u'Skip-Translation-Screenshots-Check', [])
6747 ]
6748 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:026749
Sam Maiera6e76d72022-02-11 21:43:506750 import os
6751 import re
6752 import sys
6753 from io import StringIO
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146754
Sam Maiera6e76d72022-02-11 21:43:506755 new_or_added_paths = set(f.LocalPath() for f in input_api.AffectedFiles()
6756 if (f.Action() == 'A' or f.Action() == 'M'))
6757 removed_paths = set(f.LocalPath()
6758 for f in input_api.AffectedFiles(include_deletes=True)
6759 if f.Action() == 'D')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146760
Sam Maiera6e76d72022-02-11 21:43:506761 affected_grds = [
6762 f for f in input_api.AffectedFiles()
6763 if f.LocalPath().endswith(('.grd', '.grdp'))
6764 ]
6765 affected_grds = [
6766 f for f in affected_grds if not 'testdata' in f.LocalPath()
6767 ]
6768 if not affected_grds:
6769 return []
meacer8c0d3832019-12-26 21:46:166770
Sam Maiera6e76d72022-02-11 21:43:506771 affected_png_paths = [
Andrew Grieve713b89b2024-10-15 20:20:086772 f.LocalPath() for f in input_api.AffectedFiles()
6773 if f.LocalPath().endswith('.png')
Sam Maiera6e76d72022-02-11 21:43:506774 ]
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146775
Sam Maiera6e76d72022-02-11 21:43:506776 # Check for screenshots. Developers can upload screenshots using
6777 # tools/translation/upload_screenshots.py which finds and uploads
6778 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
6779 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
6780 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
6781 #
6782 # The logic here is as follows:
6783 #
6784 # - If the CL has a .png file under the screenshots directory for a grd
6785 # file, warn the developer. Actual images should never be checked into the
6786 # Chrome repo.
6787 #
6788 # - If the CL contains modified or new messages in grd files and doesn't
6789 # contain the corresponding .sha1 files, warn the developer to add images
6790 # and upload them via tools/translation/upload_screenshots.py.
6791 #
6792 # - If the CL contains modified or new messages in grd files and the
6793 # corresponding .sha1 files, everything looks good.
6794 #
6795 # - If the CL contains removed messages in grd files but the corresponding
6796 # .sha1 files aren't removed, warn the developer to remove them.
6797 unnecessary_screenshots = []
Jens Mueller054652c2023-05-10 15:12:306798 invalid_sha1 = []
Sam Maiera6e76d72022-02-11 21:43:506799 missing_sha1 = []
Bruce Dawson55776c42022-12-09 17:23:476800 missing_sha1_modified = []
Sam Maiera6e76d72022-02-11 21:43:506801 unnecessary_sha1_files = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146802
Sam Maiera6e76d72022-02-11 21:43:506803 # This checks verifies that the ICU syntax of messages this CL touched is
6804 # valid, and reports any found syntax errors.
6805 # Without this presubmit check, ICU syntax errors in Chromium strings can land
6806 # without developers being aware of them. Later on, such ICU syntax errors
6807 # break message extraction for translation, hence would block Chromium
6808 # translations until they are fixed.
6809 icu_syntax_errors = []
Jens Mueller054652c2023-05-10 15:12:306810 sha1_pattern = input_api.re.compile(r'^[a-fA-F0-9]{40}$',
6811 input_api.re.MULTILINE)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146812
Sam Maiera6e76d72022-02-11 21:43:506813 def _CheckScreenshotAdded(screenshots_dir, message_id):
6814 sha1_path = input_api.os_path.join(screenshots_dir,
6815 message_id + '.png.sha1')
6816 if sha1_path not in new_or_added_paths:
6817 missing_sha1.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306818 elif not _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256819 invalid_sha1.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146820
Bruce Dawson55776c42022-12-09 17:23:476821 def _CheckScreenshotModified(screenshots_dir, message_id):
6822 sha1_path = input_api.os_path.join(screenshots_dir,
6823 message_id + '.png.sha1')
6824 if sha1_path not in new_or_added_paths:
6825 missing_sha1_modified.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306826 elif not _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256827 invalid_sha1.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306828
6829 def _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256830 return sha1_pattern.search(
6831 next("\n".join(f.NewContents()) for f in input_api.AffectedFiles()
6832 if f.LocalPath() == sha1_path))
Bruce Dawson55776c42022-12-09 17:23:476833
Sam Maiera6e76d72022-02-11 21:43:506834 def _CheckScreenshotRemoved(screenshots_dir, message_id):
6835 sha1_path = input_api.os_path.join(screenshots_dir,
6836 message_id + '.png.sha1')
6837 if input_api.os_path.exists(
6838 sha1_path) and sha1_path not in removed_paths:
6839 unnecessary_sha1_files.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146840
Sam Maiera6e76d72022-02-11 21:43:506841 def _ValidateIcuSyntax(text, level, signatures):
6842 """Validates ICU syntax of a text string.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146843
Sam Maiera6e76d72022-02-11 21:43:506844 Check if text looks similar to ICU and checks for ICU syntax correctness
6845 in this case. Reports various issues with ICU syntax and values of
6846 variants. Supports checking of nested messages. Accumulate information of
6847 each ICU messages found in the text for further checking.
Rainhard Findlingfc31844c52020-05-15 09:58:266848
Sam Maiera6e76d72022-02-11 21:43:506849 Args:
6850 text: a string to check.
6851 level: a number of current nesting level.
6852 signatures: an accumulator, a list of tuple of (level, variable,
6853 kind, variants).
Rainhard Findlingfc31844c52020-05-15 09:58:266854
Sam Maiera6e76d72022-02-11 21:43:506855 Returns:
6856 None if a string is not ICU or no issue detected.
6857 A tuple of (message, start index, end index) if an issue detected.
6858 """
6859 valid_types = {
Daniel Cheng6303eed2025-05-03 00:12:336860 'plural': (frozenset([
6861 '=0', '=1', '=2', '=3', 'zero', 'one', 'two', 'few', 'many',
6862 'other'
6863 ]), frozenset(['=1', 'other'])),
6864 'selectordinal': (frozenset([
6865 '=0', '=1', '=2', '=3', 'zero', 'one', 'two', 'few', 'many',
6866 'other'
6867 ]), frozenset(['one', 'other'])),
Sam Maiera6e76d72022-02-11 21:43:506868 'select': (frozenset(), frozenset(['other'])),
6869 }
Rainhard Findlingfc31844c52020-05-15 09:58:266870
Sam Maiera6e76d72022-02-11 21:43:506871 # Check if the message looks like an attempt to use ICU
6872 # plural. If yes - check if its syntax strictly matches ICU format.
6873 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b',
6874 text)
6875 if not like:
6876 signatures.append((level, None, None, None))
6877 return
Rainhard Findlingfc31844c52020-05-15 09:58:266878
Sam Maiera6e76d72022-02-11 21:43:506879 # Check for valid prefix and suffix
6880 m = re.match(
6881 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
6882 r'(plural|selectordinal|select),\s*'
6883 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
6884 if not m:
6885 return (('This message looks like an ICU plural, '
6886 'but does not follow ICU syntax.'), like.start(),
6887 like.end())
6888 starting, variable, kind, variant_pairs = m.groups()
6889 variants, depth, last_pos = _ParseIcuVariants(variant_pairs,
6890 m.start(4))
6891 if depth:
6892 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
6893 len(text))
6894 first = text[0]
6895 ending = text[last_pos:]
6896 if not starting:
6897 return ('Invalid ICU format. No initial opening bracket',
6898 last_pos - 1, last_pos)
6899 if not ending or '}' not in ending:
6900 return ('Invalid ICU format. No final closing bracket',
6901 last_pos - 1, last_pos)
6902 elif first != '{':
6903 return ((
6904 'Invalid ICU format. Extra characters at the start of a complex '
6905 'message (go/icu-message-migration): "%s"') % starting, 0,
6906 len(starting))
6907 elif ending != '}':
6908 return ((
6909 'Invalid ICU format. Extra characters at the end of a complex '
6910 'message (go/icu-message-migration): "%s"') % ending,
6911 last_pos - 1, len(text) - 1)
6912 if kind not in valid_types:
6913 return (('Unknown ICU message type %s. '
6914 'Valid types are: plural, select, selectordinal') % kind,
6915 0, 0)
6916 known, required = valid_types[kind]
6917 defined_variants = set()
6918 for variant, variant_range, value, value_range in variants:
6919 start, end = variant_range
6920 if variant in defined_variants:
6921 return ('Variant "%s" is defined more than once' % variant,
6922 start, end)
6923 elif known and variant not in known:
6924 return ('Variant "%s" is not valid for %s message' %
6925 (variant, kind), start, end)
6926 defined_variants.add(variant)
6927 # Check for nested structure
6928 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
6929 if res:
6930 return (res[0], res[1] + value_range[0] + 1,
6931 res[2] + value_range[0] + 1)
6932 missing = required - defined_variants
6933 if missing:
6934 return ('Required variants missing: %s' % ', '.join(missing), 0,
6935 len(text))
6936 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:266937
Sam Maiera6e76d72022-02-11 21:43:506938 def _ParseIcuVariants(text, offset=0):
6939 """Parse variants part of ICU complex message.
Rainhard Findlingfc31844c52020-05-15 09:58:266940
Sam Maiera6e76d72022-02-11 21:43:506941 Builds a tuple of variant names and values, as well as
6942 their offsets in the input string.
Rainhard Findlingfc31844c52020-05-15 09:58:266943
Sam Maiera6e76d72022-02-11 21:43:506944 Args:
6945 text: a string to parse
6946 offset: additional offset to add to positions in the text to get correct
6947 position in the complete ICU string.
Rainhard Findlingfc31844c52020-05-15 09:58:266948
Sam Maiera6e76d72022-02-11 21:43:506949 Returns:
6950 List of tuples, each tuple consist of four fields: variant name,
6951 variant name span (tuple of two integers), variant value, value
6952 span (tuple of two integers).
6953 """
6954 depth, start, end = 0, -1, -1
6955 variants = []
6956 key = None
6957 for idx, char in enumerate(text):
6958 if char == '{':
6959 if not depth:
6960 start = idx
6961 chunk = text[end + 1:start]
6962 key = chunk.strip()
6963 pos = offset + end + 1 + chunk.find(key)
6964 span = (pos, pos + len(key))
6965 depth += 1
6966 elif char == '}':
6967 if not depth:
6968 return variants, depth, offset + idx
6969 depth -= 1
6970 if not depth:
6971 end = idx
6972 variants.append((key, span, text[start:end + 1],
6973 (offset + start, offset + end + 1)))
6974 return variants, depth, offset + end + 1
Rainhard Findlingfc31844c52020-05-15 09:58:266975
Terrence Reilly313f44ff2025-01-22 15:10:146976 old_sys_path = sys.path
Sam Maiera6e76d72022-02-11 21:43:506977 try:
Sam Maiera6e76d72022-02-11 21:43:506978 sys.path = sys.path + [
6979 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
6980 'translation')
6981 ]
6982 from helper import grd_helper
6983 finally:
6984 sys.path = old_sys_path
Rainhard Findlingfc31844c52020-05-15 09:58:266985
Sam Maiera6e76d72022-02-11 21:43:506986 for f in affected_grds:
6987 file_path = f.LocalPath()
6988 old_id_to_msg_map = {}
6989 new_id_to_msg_map = {}
6990 # Note that this code doesn't check if the file has been deleted. This is
6991 # OK because it only uses the old and new file contents and doesn't load
6992 # the file via its path.
6993 # It's also possible that a file's content refers to a renamed or deleted
6994 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
6995 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
6996 # .grdp files.
6997 if file_path.endswith('.grdp'):
6998 if f.OldContents():
6999 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
7000 '\n'.join(f.OldContents()))
7001 if f.NewContents():
7002 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
7003 '\n'.join(f.NewContents()))
7004 else:
7005 file_dir = input_api.os_path.dirname(file_path) or '.'
7006 if f.OldContents():
7007 old_id_to_msg_map = grd_helper.GetGrdMessages(
7008 StringIO('\n'.join(f.OldContents())), file_dir)
7009 if f.NewContents():
7010 new_id_to_msg_map = grd_helper.GetGrdMessages(
7011 StringIO('\n'.join(f.NewContents())), file_dir)
Rainhard Findlingfc31844c52020-05-15 09:58:267012
Sam Maiera6e76d72022-02-11 21:43:507013 grd_name, ext = input_api.os_path.splitext(
7014 input_api.os_path.basename(file_path))
7015 screenshots_dir = input_api.os_path.join(
7016 input_api.os_path.dirname(file_path),
7017 grd_name + ext.replace('.', '_'))
Rainhard Findlingfc31844c52020-05-15 09:58:267018
Sam Maiera6e76d72022-02-11 21:43:507019 # Compute added, removed and modified message IDs.
7020 old_ids = set(old_id_to_msg_map)
7021 new_ids = set(new_id_to_msg_map)
7022 added_ids = new_ids - old_ids
7023 removed_ids = old_ids - new_ids
7024 modified_ids = set([])
7025 for key in old_ids.intersection(new_ids):
Daniel Cheng6303eed2025-05-03 00:12:337026 if (old_id_to_msg_map[key].ContentsAsXml('', True)
7027 != new_id_to_msg_map[key].ContentsAsXml('', True)):
Sam Maiera6e76d72022-02-11 21:43:507028 # The message content itself changed. Require an updated screenshot.
7029 modified_ids.add(key)
7030 elif old_id_to_msg_map[key].attrs['meaning'] != \
7031 new_id_to_msg_map[key].attrs['meaning']:
Jens Mueller054652c2023-05-10 15:12:307032 # The message meaning changed. We later check for a screenshot.
7033 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147034
Sam Maiera6e76d72022-02-11 21:43:507035 if run_screenshot_check:
7036 # Check the screenshot directory for .png files. Warn if there is any.
7037 for png_path in affected_png_paths:
7038 if png_path.startswith(screenshots_dir):
7039 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147040
Sam Maiera6e76d72022-02-11 21:43:507041 for added_id in added_ids:
7042 _CheckScreenshotAdded(screenshots_dir, added_id)
Rainhard Findlingd8d04372020-08-13 13:30:097043
Sam Maiera6e76d72022-02-11 21:43:507044 for modified_id in modified_ids:
Bruce Dawson55776c42022-12-09 17:23:477045 _CheckScreenshotModified(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147046
Sam Maiera6e76d72022-02-11 21:43:507047 for removed_id in removed_ids:
7048 _CheckScreenshotRemoved(screenshots_dir, removed_id)
7049
7050 # Check new and changed strings for ICU syntax errors.
7051 for key in added_ids.union(modified_ids):
7052 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
7053 err = _ValidateIcuSyntax(msg, 0, [])
7054 if err is not None:
7055 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
7056
7057 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:267058 if run_screenshot_check:
Sam Maiera6e76d72022-02-11 21:43:507059 if unnecessary_screenshots:
7060 results.append(
7061 output_api.PresubmitError(
7062 'Do not include actual screenshots in the changelist. Run '
7063 'tools/translate/upload_screenshots.py to upload them instead:',
7064 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147065
Sam Maiera6e76d72022-02-11 21:43:507066 if missing_sha1:
7067 results.append(
7068 output_api.PresubmitError(
Bruce Dawson55776c42022-12-09 17:23:477069 'You are adding UI strings.\n'
Sam Maiera6e76d72022-02-11 21:43:507070 'To ensure the best translations, take screenshots of the relevant UI '
7071 '(https://g.co/chrome/translation) and add these files to your '
7072 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147073
Jens Mueller054652c2023-05-10 15:12:307074 if invalid_sha1:
7075 results.append(
7076 output_api.PresubmitError(
7077 'The following files do not seem to contain valid sha1 hashes. '
7078 'Make sure they contain hashes created by '
Daniel Cheng6303eed2025-05-03 00:12:337079 'tools/translate/upload_screenshots.py:',
7080 sorted(invalid_sha1)))
Jens Mueller054652c2023-05-10 15:12:307081
Bruce Dawson55776c42022-12-09 17:23:477082 if missing_sha1_modified:
7083 results.append(
7084 output_api.PresubmitError(
7085 'You are modifying UI strings or their meanings.\n'
7086 'To ensure the best translations, take screenshots of the relevant UI '
7087 '(https://g.co/chrome/translation) and add these files to your '
7088 'changelist:', sorted(missing_sha1_modified)))
7089
Sam Maiera6e76d72022-02-11 21:43:507090 if unnecessary_sha1_files:
7091 results.append(
7092 output_api.PresubmitError(
7093 'You removed strings associated with these files. Remove:',
7094 sorted(unnecessary_sha1_files)))
7095 else:
7096 results.append(
7097 output_api.PresubmitPromptOrNotify('Skipping translation '
7098 'screenshots check.'))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147099
Sam Maiera6e76d72022-02-11 21:43:507100 if icu_syntax_errors:
7101 results.append(
7102 output_api.PresubmitPromptWarning(
7103 'ICU syntax errors were found in the following strings (problems or '
7104 'feedback? Contact [email protected]):',
7105 items=icu_syntax_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:267106
Sam Maiera6e76d72022-02-11 21:43:507107 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:127108
7109
Daniel Cheng6303eed2025-05-03 00:12:337110def CheckTranslationExpectations(input_api,
7111 output_api,
7112 repo_root=None,
7113 translation_expectations_path=None,
7114 grd_files=None):
Sam Maiera6e76d72022-02-11 21:43:507115 import sys
7116 affected_grds = [
7117 f for f in input_api.AffectedFiles()
7118 if (f.LocalPath().endswith('.grd') or f.LocalPath().endswith('.grdp'))
7119 ]
7120 if not affected_grds:
7121 return []
7122
Terrence Reilly313f44ff2025-01-22 15:10:147123 old_sys_path = sys.path
Sam Maiera6e76d72022-02-11 21:43:507124 try:
Sam Maiera6e76d72022-02-11 21:43:507125 sys.path = sys.path + [
7126 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
7127 'translation')
7128 ]
Terrence Reilly313f44ff2025-01-22 15:10:147129 sys.path = sys.path + [
7130 input_api.os_path.join(input_api.PresubmitLocalPath(),
7131 'third_party', 'depot_tools')
7132 ]
Sam Maiera6e76d72022-02-11 21:43:507133 from helper import git_helper
7134 from helper import translation_helper
Terrence Reilly313f44ff2025-01-22 15:10:147135 import gclient_utils
Sam Maiera6e76d72022-02-11 21:43:507136 finally:
7137 sys.path = old_sys_path
7138
7139 # Check that translation expectations can be parsed and we can get a list of
7140 # translatable grd files. |repo_root| and |translation_expectations_path| are
7141 # only passed by tests.
7142 if not repo_root:
7143 repo_root = input_api.PresubmitLocalPath()
7144 if not translation_expectations_path:
7145 translation_expectations_path = input_api.os_path.join(
7146 repo_root, 'tools', 'gritsettings', 'translation_expectations.pyl')
Terrence Reilly313f44ff2025-01-22 15:10:147147 is_cog = gclient_utils.IsEnvCog()
7148 # Git is not available in cog workspaces.
7149 if not grd_files and not is_cog:
Sam Maiera6e76d72022-02-11 21:43:507150 grd_files = git_helper.list_grds_in_repository(repo_root)
Terrence Reilly313f44ff2025-01-22 15:10:147151 if not grd_files:
7152 grd_files = []
Sam Maiera6e76d72022-02-11 21:43:507153
7154 # Ignore bogus grd files used only for testing
Gao Shenga79ebd42022-08-08 17:25:597155 # ui/webui/resources/tools/generate_grd.py.
Sam Maiera6e76d72022-02-11 21:43:507156 ignore_path = input_api.os_path.join('ui', 'webui', 'resources', 'tools',
7157 'tests')
7158 grd_files = [p for p in grd_files if ignore_path not in p]
7159
Ben Mason5d4c3242025-04-15 20:28:377160 # Ensure no duplicate basenames.
7161 basename_to_src_paths = {}
7162 for grd_path in grd_files:
7163 basename = input_api.os_path.basename(grd_path)
7164 basename_to_src_paths.setdefault(basename, [])
7165 basename_to_src_paths[basename].append(grd_path)
7166 for src_paths in basename_to_src_paths.values():
7167 if len(src_paths) > 1:
7168 return [
7169 output_api.PresubmitNotifyResult(
7170 'Multiple string files have the same basename. This will result in '
Daniel Cheng6303eed2025-05-03 00:12:337171 'missing translations. Files: %s' % ', '.join(src_paths))
Ben Mason5d4c3242025-04-15 20:28:377172 ]
7173
Sam Maiera6e76d72022-02-11 21:43:507174 try:
7175 translation_helper.get_translatable_grds(
Terrence Reilly313f44ff2025-01-22 15:10:147176 repo_root, grd_files, translation_expectations_path, is_cog)
Sam Maiera6e76d72022-02-11 21:43:507177 except Exception as e:
7178 return [
7179 output_api.PresubmitNotifyResult(
7180 'Failed to get a list of translatable grd files. This happens when:\n'
7181 ' - One of the modified grd or grdp files cannot be parsed or\n'
7182 ' - %s is not updated.\n'
7183 'Stack:\n%s' % (translation_expectations_path, str(e)))
7184 ]
Mustafa Emre Acer51f2f742020-03-09 19:41:127185 return []
7186
Ken Rockotc31f4832020-05-29 18:58:517187
Saagar Sanghavifceeaae2020-08-12 16:40:367188def CheckStableMojomChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507189 """Changes to [Stable] mojom types must preserve backward-compatibility."""
7190 changed_mojoms = input_api.AffectedFiles(
7191 include_deletes=True,
7192 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:527193
Bruce Dawson344ab262022-06-04 11:35:107194 if not changed_mojoms or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:507195 return []
7196
7197 delta = []
7198 for mojom in changed_mojoms:
Sam Maiera6e76d72022-02-11 21:43:507199 delta.append({
7200 'filename': mojom.LocalPath(),
7201 'old': '\n'.join(mojom.OldContents()) or None,
7202 'new': '\n'.join(mojom.NewContents()) or None,
7203 })
7204
7205 process = input_api.subprocess.Popen([
Takuto Ikutadca10222022-04-13 02:51:217206 input_api.python3_executable,
Sam Maiera6e76d72022-02-11 21:43:507207 input_api.os_path.join(
7208 input_api.PresubmitLocalPath(), 'mojo', 'public', 'tools', 'mojom',
7209 'check_stable_mojom_compatibility.py'), '--src-root',
7210 input_api.PresubmitLocalPath()
7211 ],
7212 stdin=input_api.subprocess.PIPE,
7213 stdout=input_api.subprocess.PIPE,
7214 stderr=input_api.subprocess.PIPE,
7215 universal_newlines=True)
7216 (x, error) = process.communicate(input=input_api.json.dumps(delta))
7217 if process.returncode:
7218 return [
7219 output_api.PresubmitError(
7220 'One or more [Stable] mojom definitions appears to have been changed '
Alex Goughc99921652024-02-15 22:59:127221 'in a way that is not backward-compatible. See '
7222 'https://chromium.googlesource.com/chromium/src/+/HEAD/mojo/public/tools/bindings/README.md#versioning'
7223 ' for details.',
Sam Maiera6e76d72022-02-11 21:43:507224 long_text=error)
7225 ]
Erik Staabc734cd7a2021-11-23 03:11:527226 return []
7227
Daniel Cheng6303eed2025-05-03 00:12:337228
Dominic Battre645d42342020-12-04 16:14:107229def CheckDeprecationOfPreferences(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507230 """Removing a preference should come with a deprecation."""
Dominic Battre645d42342020-12-04 16:14:107231
Sam Maiera6e76d72022-02-11 21:43:507232 def FilterFile(affected_file):
7233 """Accept only .cc files and the like."""
7234 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
7235 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
7236 input_api.DEFAULT_FILES_TO_SKIP)
7237 return input_api.FilterSourceFile(
7238 affected_file,
7239 files_to_check=file_inclusion_pattern,
7240 files_to_skip=files_to_skip)
Dominic Battre645d42342020-12-04 16:14:107241
Sam Maiera6e76d72022-02-11 21:43:507242 def ModifiedLines(affected_file):
7243 """Returns a list of tuples (line number, line text) of added and removed
7244 lines.
Dominic Battre645d42342020-12-04 16:14:107245
Sam Maiera6e76d72022-02-11 21:43:507246 Deleted lines share the same line number as the previous line.
Dominic Battre645d42342020-12-04 16:14:107247
Sam Maiera6e76d72022-02-11 21:43:507248 This relies on the scm diff output describing each changed code section
7249 with a line of the form
Dominic Battre645d42342020-12-04 16:14:107250
Sam Maiera6e76d72022-02-11 21:43:507251 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
7252 """
7253 line_num = 0
7254 modified_lines = []
7255 for line in affected_file.GenerateScmDiff().splitlines():
7256 # Extract <new line num> of the patch fragment (see format above).
7257 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@',
7258 line)
7259 if m:
7260 line_num = int(m.groups(1)[0])
7261 continue
7262 if ((line.startswith('+') and not line.startswith('++'))
7263 or (line.startswith('-') and not line.startswith('--'))):
7264 modified_lines.append((line_num, line))
Dominic Battre645d42342020-12-04 16:14:107265
Sam Maiera6e76d72022-02-11 21:43:507266 if not line.startswith('-'):
7267 line_num += 1
7268 return modified_lines
Dominic Battre645d42342020-12-04 16:14:107269
Sam Maiera6e76d72022-02-11 21:43:507270 def FindLineWith(lines, needle):
7271 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
Dominic Battre645d42342020-12-04 16:14:107272
Sam Maiera6e76d72022-02-11 21:43:507273 If 0 or >1 lines contain `needle`, -1 is returned.
7274 """
7275 matching_line_numbers = [
7276 # + 1 for 1-based counting of line numbers.
7277 i + 1 for i, line in enumerate(lines) if needle in line
7278 ]
7279 return matching_line_numbers[0] if len(
7280 matching_line_numbers) == 1 else -1
Dominic Battre645d42342020-12-04 16:14:107281
Sam Maiera6e76d72022-02-11 21:43:507282 def ModifiedPrefMigration(affected_file):
7283 """Returns whether the MigrateObsolete.*Pref functions were modified."""
7284 # Determine first and last lines of MigrateObsolete.*Pref functions.
7285 new_contents = affected_file.NewContents()
7286 range_1 = (FindLineWith(new_contents,
7287 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
7288 FindLineWith(new_contents,
7289 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
7290 range_2 = (FindLineWith(new_contents,
7291 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
7292 FindLineWith(new_contents,
7293 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
7294 if (-1 in range_1 + range_2):
7295 raise Exception(
7296 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.'
7297 )
Dominic Battre645d42342020-12-04 16:14:107298
Sam Maiera6e76d72022-02-11 21:43:507299 # Check whether any of the modified lines are part of the
7300 # MigrateObsolete.*Pref functions.
7301 for line_nr, line in ModifiedLines(affected_file):
7302 if (range_1[0] <= line_nr <= range_1[1]
7303 or range_2[0] <= line_nr <= range_2[1]):
7304 return True
7305 return False
Dominic Battre645d42342020-12-04 16:14:107306
Sam Maiera6e76d72022-02-11 21:43:507307 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
7308 browser_prefs_file_pattern = input_api.re.compile(
7309 r'chrome/browser/prefs/browser_prefs.cc')
Dominic Battre645d42342020-12-04 16:14:107310
Sam Maiera6e76d72022-02-11 21:43:507311 changes = input_api.AffectedFiles(include_deletes=True,
7312 file_filter=FilterFile)
7313 potential_problems = []
7314 for f in changes:
7315 for line in f.GenerateScmDiff().splitlines():
7316 # Check deleted lines for pref registrations.
7317 if (line.startswith('-') and not line.startswith('--')
7318 and register_pref_pattern.search(line)):
7319 potential_problems.append('%s: %s' % (f.LocalPath(), line))
Dominic Battre645d42342020-12-04 16:14:107320
Sam Maiera6e76d72022-02-11 21:43:507321 if browser_prefs_file_pattern.search(f.LocalPath()):
7322 # If the developer modified the MigrateObsolete.*Prefs() functions, we
7323 # assume that they knew that they have to deprecate preferences and don't
7324 # warn.
7325 try:
7326 if ModifiedPrefMigration(f):
7327 return []
7328 except Exception as e:
7329 return [output_api.PresubmitError(str(e))]
Dominic Battre645d42342020-12-04 16:14:107330
Sam Maiera6e76d72022-02-11 21:43:507331 if potential_problems:
7332 return [
7333 output_api.PresubmitPromptWarning(
7334 'Discovered possible removal of preference registrations.\n\n'
7335 'Please make sure to properly deprecate preferences by clearing their\n'
7336 'value for a couple of milestones before finally removing the code.\n'
7337 'Otherwise data may stay in the preferences files forever. See\n'
7338 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
7339 'chrome/browser/prefs/README.md for examples.\n'
7340 'This may be a false positive warning (e.g. if you move preference\n'
7341 'registrations to a different place).\n', potential_problems)
7342 ]
7343 return []
7344
Matt Stark6ef08872021-07-29 01:21:467345
7346def CheckConsistentGrdChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507347 """Changes to GRD files must be consistent for tools to read them."""
7348 changed_grds = input_api.AffectedFiles(
7349 include_deletes=False,
7350 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
7351 errors = []
7352 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
7353 for matcher, msg in _INVALID_GRD_FILE_LINE]
7354 for grd in changed_grds:
7355 for i, line in enumerate(grd.NewContents()):
7356 for matcher, msg in invalid_file_regexes:
7357 if matcher.search(line):
7358 errors.append(
7359 output_api.PresubmitError(
7360 'Problem on {grd}:{i} - {msg}'.format(
7361 grd=grd.LocalPath(), i=i + 1, msg=msg)))
7362 return errors
7363
Kevin McNee967dd2d22021-11-15 16:09:297364
Henrique Ferreiro2a4b55942021-11-29 23:45:367365def CheckAssertAshOnlyCode(input_api, output_api):
7366 """Errors if a BUILD.gn file in an ash/ directory doesn't include
Georg Neis94f87f02024-10-22 08:20:137367 assert(is_chromeos).
7368 For a transition period, assert(is_chromeos_ash) is also accepted.
Henrique Ferreiro2a4b55942021-11-29 23:45:367369 """
7370
7371 def FileFilter(affected_file):
7372 """Includes directories known to be Ash only."""
7373 return input_api.FilterSourceFile(
7374 affected_file,
7375 files_to_check=(
7376 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
7377 r'.*/ash/.*BUILD\.gn'), # Any path component.
7378 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
7379
7380 errors = []
Georg Neis94f87f02024-10-22 08:20:137381 pattern = input_api.re.compile(r'assert\(is_chromeos(_ash)?\b')
Jameson Thies0ce669f2021-12-09 15:56:567382 for f in input_api.AffectedFiles(include_deletes=False,
7383 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:367384 if (not pattern.search(input_api.ReadFile(f))):
7385 errors.append(
7386 output_api.PresubmitError(
Georg Neis94f87f02024-10-22 08:20:137387 'Please add assert(is_chromeos) to %s. If that\'s not '
7388 'possible, please create an issue and add a comment such '
Alison Galed6b25fe2024-04-17 13:59:047389 'as:\n # TODO(crbug.com/XXX): add '
Georg Neis94f87f02024-10-22 08:20:137390 'assert(is_chromeos) when ...' % f.LocalPath()))
Henrique Ferreiro2a4b55942021-11-29 23:45:367391 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:277392
7393
Kalvin Lee84ad17a2023-09-25 11:14:417394def _IsMiraclePtrDisallowed(input_api, affected_file):
Anton Bershanskyi4253349482025-02-11 21:01:277395 path = affected_file.UnixLocalPath()
Sam Maiera6e76d72022-02-11 21:43:507396 if not _IsCPlusPlusFile(input_api, path):
7397 return False
7398
Bartek Nowierski49b1a452024-06-08 00:24:357399 # Renderer-only code is generally allowed to use MiraclePtr. These
7400 # directories, however, are specifically disallowed, for perf reasons.
Kalvin Lee84ad17a2023-09-25 11:14:417401 if ("third_party/blink/renderer/core/" in path
7402 or "third_party/blink/renderer/platform/heap/" in path
Bartek Nowierski49b1a452024-06-08 00:24:357403 or "third_party/blink/renderer/platform/wtf/" in path
7404 or "third_party/blink/renderer/platform/fonts/" in path):
7405 return True
7406
7407 # The below paths are an explicitly listed subset of Renderer-only code,
7408 # because the plan is to Oilpanize it.
7409 # TODO(crbug.com/330759291): Remove once Oilpanization is completed or
7410 # abandoned.
Daniel Cheng6303eed2025-05-03 00:12:337411 if ("third_party/blink/renderer/core/paint/" in path or
7412 "third_party/blink/renderer/platform/graphics/compositing/" in path
Bartek Nowierski49b1a452024-06-08 00:24:357413 or "third_party/blink/renderer/platform/graphics/paint/" in path):
Sam Maiera6e76d72022-02-11 21:43:507414 return True
7415
Sam Maiera6e76d72022-02-11 21:43:507416 # We assume that everything else may be used outside of Renderer processes.
Lukasz Anforowicz7016d05e2021-11-30 03:56:277417 return False
7418
Daniel Cheng6303eed2025-05-03 00:12:337419
Alison Galed6b25fe2024-04-17 13:59:047420# TODO(crbug.com/40206238): Remove these checks, once they are replaced
Lukasz Anforowicz7016d05e2021-11-30 03:56:277421# by the Chromium Clang Plugin (which will be preferable because it will
7422# 1) report errors earlier - at compile-time and 2) cover more rules).
7423def CheckRawPtrUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507424 """Rough checks that raw_ptr<T> usage guidelines are followed."""
7425 errors = []
7426 # The regex below matches "raw_ptr<" following a word boundary, but not in a
7427 # C++ comment.
7428 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
Kalvin Lee84ad17a2023-09-25 11:14:417429 file_filter = lambda f: _IsMiraclePtrDisallowed(input_api, f)
Sam Maiera6e76d72022-02-11 21:43:507430 for f, line_num, line in input_api.RightHandSideLines(file_filter):
7431 if raw_ptr_matcher.search(line):
7432 errors.append(
7433 output_api.PresubmitError(
7434 'Problem on {path}:{line} - '\
Kalvin Lee84ad17a2023-09-25 11:14:417435 'raw_ptr<T> should not be used in this renderer code '\
Sam Maiera6e76d72022-02-11 21:43:507436 '(as documented in the "Pointers to unprotected memory" '\
7437 'section in //base/memory/raw_ptr.md)'.format(
7438 path=f.LocalPath(), line=line_num)))
7439 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:567440
Daniel Cheng6303eed2025-05-03 00:12:337441
mikt9337567c2023-09-08 18:38:177442def CheckAdvancedMemorySafetyChecksUsage(input_api, output_api):
7443 """Checks that ADVANCED_MEMORY_SAFETY_CHECKS() macro is neither added nor
7444 removed as it is managed by the memory safety team internally.
7445 Do not add / remove it manually."""
7446 paths = set([])
7447 # The regex below matches "ADVANCED_MEMORY_SAFETY_CHECKS(" following a word
7448 # boundary, but not in a C++ comment.
7449 macro_matcher = input_api.re.compile(
Daniel Cheng6303eed2025-05-03 00:12:337450 r'^((?!//).)*\bADVANCED_MEMORY_SAFETY_CHECKS\(',
7451 input_api.re.MULTILINE)
mikt9337567c2023-09-08 18:38:177452 for f in input_api.AffectedFiles():
7453 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
7454 continue
7455 if macro_matcher.search(f.GenerateScmDiff()):
7456 paths.add(f.LocalPath())
7457 if not paths:
7458 return []
7459 return [output_api.PresubmitPromptWarning(
7460 'ADVANCED_MEMORY_SAFETY_CHECKS() macro is managed by ' \
7461 'the memory safety team (chrome-memory-safety@). ' \
7462 'Please contact us to add/delete the uses of the macro.',
7463 paths)]
Henrique Ferreirof9819f2e32021-11-30 13:31:567464
Daniel Cheng6303eed2025-05-03 00:12:337465
Henrique Ferreirof9819f2e32021-11-30 13:31:567466def CheckPythonShebang(input_api, output_api):
7467 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
7468 system-wide python.
7469 """
7470 errors = []
7471 sources = lambda affected_file: input_api.FilterSourceFile(
7472 affected_file,
7473 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
7474 r'third_party/blink/web_tests/external/') + input_api.
7475 DEFAULT_FILES_TO_SKIP),
7476 files_to_check=[r'.*\.py$'])
7477 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:277478 for line_num, line in f.ChangedContents():
7479 if line_num == 1 and line.startswith('#!/usr/bin/python'):
7480 errors.append(f.LocalPath())
7481 break
Henrique Ferreirof9819f2e32021-11-30 13:31:567482
7483 result = []
7484 for file in errors:
7485 result.append(
7486 output_api.PresubmitError(
7487 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
7488 file))
7489 return result
James Shen81cc0e22022-06-15 21:10:457490
7491
Andrew Grieve5a66ae72024-12-13 15:21:537492def CheckAndroidTestAnnotations(input_api, output_api):
James Shen81cc0e22022-06-15 21:10:457493 """Checks that tests have either @Batch or @DoNotBatch annotation. If this
7494 is not an instrumentation test, disregard."""
7495
7496 batch_annotation = input_api.re.compile(r'^\s*@Batch')
7497 do_not_batch_annotation = input_api.re.compile(r'^\s*@DoNotBatch')
Daniel Cheng6303eed2025-05-03 00:12:337498 robolectric_test = input_api.re.compile(
7499 r'@RunWith\((.*?)RobolectricTestRunner')
James Shen81cc0e22022-06-15 21:10:457500 test_class_declaration = input_api.re.compile(r'^\s*public\sclass.*Test')
7501 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
Daniel Cheng6303eed2025-05-03 00:12:337502 test_annotation_declaration = input_api.re.compile(
7503 r'^\s*public\s@interface\s.*{')
James Shen81cc0e22022-06-15 21:10:457504
ckitagawae8fd23b2022-06-17 15:29:387505 missing_annotation_errors = []
7506 extra_annotation_errors = []
Andrew Grieve5a66ae72024-12-13 15:21:537507 wrong_robolectric_test_runner_errors = []
James Shen81cc0e22022-06-15 21:10:457508
7509 def _FilterFile(affected_file):
7510 return input_api.FilterSourceFile(
7511 affected_file,
7512 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
7513 files_to_check=[r'.*Test\.java$'])
7514
7515 for f in input_api.AffectedSourceFiles(_FilterFile):
7516 batch_matched = None
7517 do_not_batch_matched = None
7518 is_instrumentation_test = True
Mark Schillaci8ef0d872023-07-18 22:07:597519 test_annotation_declaration_matched = None
Andrew Grieve5a66ae72024-12-13 15:21:537520 has_base_robolectric_rule = False
James Shen81cc0e22022-06-15 21:10:457521 for line in f.NewContents():
Andrew Grieve5a66ae72024-12-13 15:21:537522 if 'BaseRobolectricTestRule' in line:
7523 has_base_robolectric_rule = True
7524 continue
7525 if m := robolectric_test.search(line):
7526 is_instrumentation_test = False
7527 if m.group(1) == '' and not has_base_robolectric_rule:
Yiwei Zhang5341bf02025-03-20 16:34:137528 path = str(f.LocalPath())
7529 # These two spots cannot use it.
7530 if 'webapk' not in path and 'build' not in path:
7531 wrong_robolectric_test_runner_errors.append(path)
Andrew Grieve5a66ae72024-12-13 15:21:537532 break
7533 if uiautomator_test.search(line):
James Shen81cc0e22022-06-15 21:10:457534 is_instrumentation_test = False
7535 break
7536 if not batch_matched:
7537 batch_matched = batch_annotation.search(line)
7538 if not do_not_batch_matched:
7539 do_not_batch_matched = do_not_batch_annotation.search(line)
7540 test_class_declaration_matched = test_class_declaration.search(
7541 line)
Daniel Cheng6303eed2025-05-03 00:12:337542 test_annotation_declaration_matched = test_annotation_declaration.search(
7543 line)
Mark Schillaci8ef0d872023-07-18 22:07:597544 if test_class_declaration_matched or test_annotation_declaration_matched:
James Shen81cc0e22022-06-15 21:10:457545 break
Mark Schillaci8ef0d872023-07-18 22:07:597546 if test_annotation_declaration_matched:
7547 continue
Daniel Cheng6303eed2025-05-03 00:12:337548 if (is_instrumentation_test and not batch_matched
7549 and not do_not_batch_matched):
Sam Maier4cef9242022-10-03 14:21:247550 missing_annotation_errors.append(str(f.LocalPath()))
Daniel Cheng6303eed2025-05-03 00:12:337551 if (not is_instrumentation_test
7552 and (batch_matched or do_not_batch_matched)):
Sam Maier4cef9242022-10-03 14:21:247553 extra_annotation_errors.append(str(f.LocalPath()))
James Shen81cc0e22022-06-15 21:10:457554
7555 results = []
7556
ckitagawae8fd23b2022-06-17 15:29:387557 if missing_annotation_errors:
James Shen81cc0e22022-06-15 21:10:457558 results.append(
7559 output_api.PresubmitPromptWarning(
7560 """
Andrew Grieve43a5cf82023-09-08 15:09:467561A change was made to an on-device test that has neither been annotated with
7562@Batch nor @DoNotBatch. If this is a new test, please add the annotation. If
7563this is an existing test, please consider adding it if you are sufficiently
7564familiar with the test (but do so as a separate change).
7565
Jens Mueller2085ff82023-02-27 11:54:497566See https://source.chromium.org/chromium/chromium/src/+/main:docs/testing/batching_instrumentation_tests.md
ckitagawae8fd23b2022-06-17 15:29:387567""", missing_annotation_errors))
7568 if extra_annotation_errors:
7569 results.append(
7570 output_api.PresubmitPromptWarning(
7571 """
7572Robolectric tests do not need a @Batch or @DoNotBatch annotations.
7573""", extra_annotation_errors))
Andrew Grieve5a66ae72024-12-13 15:21:537574 if wrong_robolectric_test_runner_errors:
7575 results.append(
7576 output_api.PresubmitPromptWarning(
7577 """
Wenyu Fu0005ab82025-01-03 18:13:267578Robolectric tests should use either @RunWith(BaseRobolectricTestRunner.class) (or
Andrew Grieve5a66ae72024-12-13 15:21:537579a subclass of it), or use "@Rule BaseRobolectricTestRule".
7580""", wrong_robolectric_test_runner_errors))
James Shen81cc0e22022-06-15 21:10:457581
7582 return results
Sam Maier4cef9242022-10-03 14:21:247583
7584
Henrique Nakashima224ee2482025-03-21 18:35:027585def _CheckAndroidNullAwayAnnotatedClasses(input_api, output_api):
7586 """Checks that Java classes/interfaces/annotations are null-annotated."""
7587
Henrique Nakashima2bdd8ad2025-04-08 18:24:577588 # Temporary, crbug.com/389129271
7589 if input_api.change.RepositoryRoot().endswith('clank'):
7590 return []
7591
Daniel Cheng6303eed2025-05-03 00:12:337592 nullmarked_annotation = input_api.re.compile(
7593 r'^\s*@(NullMarked|NullUnmarked)')
Henrique Nakashima224ee2482025-03-21 18:35:027594
7595 missing_annotation_errors = []
7596
7597 def _FilterFile(affected_file):
7598 return input_api.FilterSourceFile(
7599 affected_file,
Daniel Cheng6303eed2025-05-03 00:12:337600 files_to_skip=(
7601 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
7602 input_api.DEFAULT_FILES_TO_SKIP + (
7603 r'.*Test.*\.java',
7604 r'^android_webview/.*', # Temporary, crbug.com/389129271
7605 r'^build/.*',
7606 r'^chrome/android/.*', # Temporary, crbug.com/389129271
7607 r'^chromecast/.*',
7608 r'^components/cronet/.*',
7609 r'^tools/.*',
7610 )),
7611 files_to_check=[r'.*\.java$'])
Henrique Nakashima224ee2482025-03-21 18:35:027612
7613 for f in input_api.AffectedSourceFiles(_FilterFile):
Henrique Nakashimac6605432025-04-24 18:11:597614 if f.Action() != 'A':
7615 continue
Henrique Nakashima224ee2482025-03-21 18:35:027616 for line in f.NewContents():
7617 if nullmarked_annotation.search(line):
7618 break
7619 else:
7620 missing_annotation_errors.append(str(f.LocalPath()))
7621
7622 results = []
7623
7624 if missing_annotation_errors:
7625 results.append(
Henrique Nakashima8bafbc52025-04-22 19:38:427626 output_api.PresubmitError(
Henrique Nakashima224ee2482025-03-21 18:35:027627 """
7628Please add @NullMarked and fix the NullAway warnings in the following files
7629(see https://chromium.googlesource.com/chromium/src/+/main/styleguide/java/nullaway.md):
7630""", missing_annotation_errors))
7631
7632 return results
7633
7634
Mike Dougherty1b8be712022-10-20 00:15:137635def CheckNoJsInIos(input_api, output_api):
7636 """Checks to make sure that JavaScript files are not used on iOS."""
7637
7638 def _FilterFile(affected_file):
7639 return input_api.FilterSourceFile(
7640 affected_file,
7641 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP +
Daniel Cheng6303eed2025-05-03 00:12:337642 (r'^ios/third_party/*', r'^ios/tools/*', r'^third_party/*',
7643 r'^components/autofill/ios/form_util/resources/*'),
Mike Dougherty1b8be712022-10-20 00:15:137644 files_to_check=[r'^ios/.*\.js$', r'.*/ios/.*\.js$'])
7645
Mike Dougherty4d1050b2023-03-14 15:59:537646 deleted_files = []
7647
7648 # Collect filenames of all removed JS files.
Arthur Sonzognic66e9c82024-04-23 07:53:047649 for f in input_api.AffectedFiles(file_filter=_FilterFile):
Mike Dougherty4d1050b2023-03-14 15:59:537650 local_path = f.LocalPath()
7651
Daniel Cheng6303eed2025-05-03 00:12:337652 if input_api.os_path.splitext(
7653 local_path)[1] == '.js' and f.Action() == 'D':
Mike Dougherty4d1050b2023-03-14 15:59:537654 deleted_files.append(input_api.os_path.basename(local_path))
7655
Mike Dougherty1b8be712022-10-20 00:15:137656 error_paths = []
Mike Dougherty4d1050b2023-03-14 15:59:537657 moved_paths = []
Mike Dougherty1b8be712022-10-20 00:15:137658 warning_paths = []
7659
7660 for f in input_api.AffectedSourceFiles(_FilterFile):
7661 local_path = f.LocalPath()
7662
7663 if input_api.os_path.splitext(local_path)[1] == '.js':
7664 if f.Action() == 'A':
Mike Dougherty4d1050b2023-03-14 15:59:537665 if input_api.os_path.basename(local_path) in deleted_files:
7666 # This script was probably moved rather than newly created.
7667 # Present a warning instead of an error for these cases.
7668 moved_paths.append(local_path)
7669 else:
7670 error_paths.append(local_path)
Mike Dougherty1b8be712022-10-20 00:15:137671 elif f.Action() != 'D':
7672 warning_paths.append(local_path)
7673
7674 results = []
7675
7676 if warning_paths:
Daniel Cheng6303eed2025-05-03 00:12:337677 results.append(
7678 output_api.PresubmitPromptWarning(
7679 'TypeScript is now fully supported for iOS feature scripts. '
7680 'Consider converting JavaScript files to TypeScript. See '
7681 '//ios/web/public/js_messaging/README.md for more details.',
7682 warning_paths))
Mike Dougherty1b8be712022-10-20 00:15:137683
Mike Dougherty4d1050b2023-03-14 15:59:537684 if moved_paths:
Daniel Cheng6303eed2025-05-03 00:12:337685 results.append(
7686 output_api.PresubmitPromptWarning(
7687 'Do not use JavaScript on iOS for new files as TypeScript is '
7688 'fully supported. (If this is a moved file, you may leave the '
7689 'script unconverted.) See //ios/web/public/js_messaging/README.md '
7690 'for help using scripts on iOS.', moved_paths))
Mike Dougherty4d1050b2023-03-14 15:59:537691
Mike Dougherty1b8be712022-10-20 00:15:137692 if error_paths:
Daniel Cheng6303eed2025-05-03 00:12:337693 results.append(
7694 output_api.PresubmitError(
7695 'Do not use JavaScript on iOS as TypeScript is fully supported. '
7696 'See //ios/web/public/js_messaging/README.md for help using '
7697 'scripts on iOS.', error_paths))
Mike Dougherty1b8be712022-10-20 00:15:137698
7699 return results
Hans Wennborg23a81d52023-03-24 16:38:137700
Daniel Cheng6303eed2025-05-03 00:12:337701
Hans Wennborg23a81d52023-03-24 16:38:137702def CheckLibcxxRevisionsMatch(input_api, output_api):
7703 """Check to make sure the libc++ version matches across deps files."""
Andrew Grieve21bb6792023-03-27 19:06:487704 # Disable check for changes to sub-repositories.
7705 if input_api.PresubmitLocalPath() != input_api.change.RepositoryRoot():
Sam Maierb926c58c2023-08-08 19:58:257706 return []
Hans Wennborg23a81d52023-03-24 16:38:137707
Daniel Cheng6303eed2025-05-03 00:12:337708 DEPS_FILES = ['DEPS', 'buildtools/deps_revisions.gni']
Hans Wennborg23a81d52023-03-24 16:38:137709
Anton Bershanskyi4253349482025-02-11 21:01:277710 file_filter = lambda f: f.UnixLocalPath() in DEPS_FILES
Hans Wennborg23a81d52023-03-24 16:38:137711 changed_deps_files = input_api.AffectedFiles(file_filter=file_filter)
7712 if not changed_deps_files:
7713 return []
7714
7715 def LibcxxRevision(file):
7716 file = input_api.os_path.join(input_api.PresubmitLocalPath(),
7717 *file.split('/'))
Daniel Cheng6303eed2025-05-03 00:12:337718 return input_api.re.search(r'libcxx_revision.*[:=].*[\'"](\w+)[\'"]',
7719 input_api.ReadFile(file)).group(1)
Hans Wennborg23a81d52023-03-24 16:38:137720
7721 if len(set([LibcxxRevision(f) for f in DEPS_FILES])) == 1:
7722 return []
7723
Daniel Cheng6303eed2025-05-03 00:12:337724 return [
7725 output_api.PresubmitError(
7726 'libcxx_revision not equal across %s' % ', '.join(DEPS_FILES),
7727 changed_deps_files)
7728 ]
Arthur Sonzogni7109bd32023-10-03 10:34:427729
7730
7731def CheckDanglingUntriaged(input_api, output_api):
7732 """Warn developers adding DanglingUntriaged raw_ptr."""
7733
7734 # Ignore during git presubmit --all.
7735 #
7736 # This would be too costly, because this would check every lines of every
7737 # C++ files. Check from _BANNED_CPP_FUNCTIONS are also reading the whole
7738 # source code, but only once to apply every checks. It seems the bots like
7739 # `win-presubmit` are particularly sensitive to reading the files. Adding
7740 # this check caused the bot to run 2x longer. See https://crbug.com/1486612.
7741 if input_api.no_diffs:
Arthur Sonzogni9eafd222023-11-10 08:50:397742 return []
Arthur Sonzogni7109bd32023-10-03 10:34:427743
7744 def FilterFile(file):
7745 return input_api.FilterSourceFile(
7746 file,
7747 files_to_check=[r".*\.(h|cc|cpp|cxx|m|mm)$"],
7748 files_to_skip=[r"^base/allocator.*"],
7749 )
7750
7751 count = 0
Arthur Sonzognic66e9c82024-04-23 07:53:047752 for f in input_api.AffectedFiles(file_filter=FilterFile):
Arthur Sonzogni9eafd222023-11-10 08:50:397753 count -= sum([l.count("DanglingUntriaged") for l in f.OldContents()])
7754 count += sum([l.count("DanglingUntriaged") for l in f.NewContents()])
Arthur Sonzogni7109bd32023-10-03 10:34:427755
7756 # Most likely, nothing changed:
7757 if count == 0:
7758 return []
7759
7760 # Congrats developers for improving it:
7761 if count < 0:
Arthur Sonzogni9eafd222023-11-10 08:50:397762 message = f"DanglingUntriaged pointers removed: {-count}\nThank you!"
Arthur Sonzogni7109bd32023-10-03 10:34:427763 return [output_api.PresubmitNotifyResult(message)]
7764
7765 # Check for 'DanglingUntriaged-notes' in the description:
7766 notes_regex = input_api.re.compile("DanglingUntriaged-notes[:=]")
7767 if any(
7768 notes_regex.match(line)
7769 for line in input_api.change.DescriptionText().splitlines()):
7770 return []
7771
7772 # Check for DanglingUntriaged-notes in the git footer:
7773 if input_api.change.GitFootersFromDescription().get(
7774 "DanglingUntriaged-notes", []):
7775 return []
7776
7777 message = (
Daniel Cheng6303eed2025-05-03 00:12:337778 "Unexpected new occurrences of `DanglingUntriaged` detected. Please\n"
7779 + "avoid adding new ones\n" + "\n" + "See documentation:\n" +
7780 "https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr.md\n"
7781 + "\n" + "See also the guide to fix dangling pointers:\n" +
7782 "https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr_guide.md\n"
7783 + "\n" +
Arthur Sonzogni9eafd222023-11-10 08:50:397784 "To disable this warning, please add in the commit description:\n" +
Alex Gough26dcd852023-12-22 16:47:197785 "DanglingUntriaged-notes: <rationale for new untriaged dangling " +
Daniel Cheng6303eed2025-05-03 00:12:337786 "pointers>")
Arthur Sonzogni7109bd32023-10-03 10:34:427787 return [output_api.PresubmitPromptWarning(message)]
Jan Keitel77be7522023-10-12 20:40:497788
Daniel Cheng6303eed2025-05-03 00:12:337789
Jan Keitel77be7522023-10-12 20:40:497790def CheckInlineConstexprDefinitionsInHeaders(input_api, output_api):
7791 """Checks that non-static constexpr definitions in headers are inline."""
7792 # In a properly formatted file, constexpr definitions inside classes or
7793 # structs will have additional whitespace at the beginning of the line.
7794 # The pattern looks for variables initialized as constexpr kVar = ...; or
7795 # constexpr kVar{...};
7796 # The pattern does not match expressions that have braces in kVar to avoid
7797 # matching constexpr functions.
7798 pattern = input_api.re.compile(r'^constexpr (?!inline )[^\(\)]*[={]')
Daniel Cheng6303eed2025-05-03 00:12:337799 attribute_pattern = input_api.re.compile(
7800 r'(\[\[[a-zA-Z_:]+\]\]|[A-Z]+[A-Z_]+) ')
Jan Keitel77be7522023-10-12 20:40:497801 problems = []
7802 for f in input_api.AffectedFiles():
7803 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
7804 continue
7805
7806 for line_number, line in f.ChangedContents():
7807 line = attribute_pattern.sub('', line)
7808 if pattern.search(line):
Daniel Cheng6303eed2025-05-03 00:12:337809 problems.append(f"{f.LocalPath()}: {line_number}\n {line}")
Jan Keitel77be7522023-10-12 20:40:497810
7811 if problems:
7812 return [
7813 output_api.PresubmitPromptWarning(
7814 'Consider inlining constexpr variable definitions in headers '
7815 'outside of classes to avoid unnecessary copies of the '
7816 'constant. See https://abseil.io/tips/168 for more details.',
7817 problems)
7818 ]
7819 else:
7820 return []
Alison Galed6b25fe2024-04-17 13:59:047821
Daniel Cheng6303eed2025-05-03 00:12:337822
Alison Galed6b25fe2024-04-17 13:59:047823def CheckTodoBugReferences(input_api, output_api):
7824 """Checks that bugs in TODOs use updated issue tracker IDs."""
7825
Daniel Cheng6303eed2025-05-03 00:12:337826 files_to_skip = [
7827 'PRESUBMIT_test.py', r"^third_party/rust/chromium_crates_io/vendor/.*"
7828 ]
Alison Galed6b25fe2024-04-17 13:59:047829
7830 def _FilterFile(affected_file):
Daniel Cheng6303eed2025-05-03 00:12:337831 return input_api.FilterSourceFile(affected_file,
7832 files_to_skip=files_to_skip)
Alison Galed6b25fe2024-04-17 13:59:047833
7834 # Monorail bug IDs are all less than or equal to 1524553 so check that all
7835 # bugs in TODOs are greater than that value.
Tom Sepez8e628582025-02-14 02:18:557836 pattern = input_api.re.compile(r'.*\bTODO\([^\)0-9]*([0-9]+)\).*')
Alison Galed6b25fe2024-04-17 13:59:047837 problems = []
7838 for f in input_api.AffectedSourceFiles(_FilterFile):
7839 for line_number, line in f.ChangedContents():
7840 match = pattern.match(line)
7841 if match and int(match.group(1)) <= 1524553:
Daniel Cheng6303eed2025-05-03 00:12:337842 problems.append(f"{f.LocalPath()}: {line_number}\n {line}")
Alison Galed6b25fe2024-04-17 13:59:047843
7844 if problems:
7845 return [
7846 output_api.PresubmitPromptWarning(
Alison Galecb598de52024-04-26 17:03:257847 'TODOs should use the new Chromium Issue Tracker IDs which can '
7848 'be found by navigating to the bug. See '
Daniel Cheng6303eed2025-05-03 00:12:337849 'https://crbug.com/336778624 for more details.', problems)
Alison Galed6b25fe2024-04-17 13:59:047850 ]
7851 else:
7852 return []