Thanks to visit codestin.com
Credit goes to chromium.googlesource.com

blob: d97cdb648749e26cb2a1ad77b2acf53068f27fd5 [file] [log] [blame]
Avi Drissman24976592022-09-12 15:24:311# Copyright 2012 The Chromium Authors
[email protected]ca8d19842009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
[email protected]ca8d19842009-02-19 16:33:124"""Top-level presubmit script for Chromium.
5
Daniel Chengd88244472022-05-16 09:08:476See https://www.chromium.org/developers/how-tos/depottools/presubmit-scripts/
tfarina78bb92f42015-01-31 00:20:487for more details about the presubmit API built into depot_tools.
[email protected]ca8d19842009-02-19 16:33:128"""
Daniel Chenga44a1bcd2022-03-15 20:00:159
Daniel Chenga37c03db2022-05-12 17:20:3410from typing import Callable
Daniel Chenga44a1bcd2022-03-15 20:00:1511from typing import Optional
12from typing import Sequence
mikt19226ff22024-08-27 05:28:2113from typing import Tuple
Daniel Chenga44a1bcd2022-03-15 20:00:1514from dataclasses import dataclass
15
Saagar Sanghavifceeaae2020-08-12 16:40:3616PRESUBMIT_VERSION = '2.0.0'
[email protected]eea609a2011-11-18 13:10:1217
[email protected]379e7dd2010-01-28 17:39:2118_EXCLUDED_PATHS = (
Bruce Dawson7f8566b2022-05-06 16:22:1819 # Generated file
Bruce Dawson40fece62022-09-16 19:58:3120 (r"chrome/android/webapk/shell_apk/src/org/chromium"
21 r"/webapk/lib/runtime_library/IWebApkApi.java"),
Mila Greene3aa7222021-09-07 16:34:0822 # File needs to write to stdout to emulate a tool it's replacing.
Bruce Dawson40fece62022-09-16 19:58:3123 r"chrome/updater/mac/keystone/ksadmin.mm",
Ilya Shermane8a7d2d2020-07-25 04:33:4724 # Generated file.
Bruce Dawson40fece62022-09-16 19:58:3125 (r"^components/variations/proto/devtools/"
Ilya Shermanc167a962020-08-18 18:40:2626 r"client_variations.js"),
Bruce Dawson3bd976c2022-05-06 22:47:5227 # These are video files, not typescript.
Bruce Dawson40fece62022-09-16 19:58:3128 r"^media/test/data/.*.ts",
29 r"^native_client_sdksrc/build_tools/make_rules.py",
30 r"^native_client_sdk/src/build_tools/make_simple.py",
31 r"^native_client_sdk/src/tools/.*.mk",
32 r"^net/tools/spdyshark/.*",
33 r"^skia/.*",
34 r"^third_party/blink/.*",
35 r"^third_party/breakpad/.*",
Darwin Huangd74a9d32019-07-17 17:58:4636 # sqlite is an imported third party dependency.
Bruce Dawson40fece62022-09-16 19:58:3137 r"^third_party/sqlite/.*",
38 r"^v8/.*",
[email protected]3e4eb112011-01-18 03:29:5439 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5340 r".+_autogen\.h$",
Yue Shecf1380552022-08-23 20:59:2041 r".+_pb2(_grpc)?\.py$",
Bruce Dawson40fece62022-09-16 19:58:3142 r"^gpu/config/.*_list_json\.cc$",
43 r"tools/md_browser/.*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1444 # Test pages for Maps telemetry tests.
Bruce Dawson40fece62022-09-16 19:58:3145 r"tools/perf/page_sets/maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5446 # Test pages for WebRTC telemetry tests.
Bruce Dawson40fece62022-09-16 19:58:3147 r"tools/perf/page_sets/webrtc_cases.*",
dpapad2efd4452023-04-06 01:43:4548 # Test file compared with generated output.
49 r"tools/polymer/tests/html_to_wrapper/.*.html.ts$",
dpapada45be36c2024-08-07 20:19:3550 # Third-party dependency frozen at a fixed version.
51 r"chrome/test/data/webui/chromeos/chai_v4.js$",
[email protected]4306417642009-06-11 00:33:4052)
[email protected]ca8d19842009-02-19 16:33:1253
John Abd-El-Malek759fea62021-03-13 03:41:1454_EXCLUDED_SET_NO_PARENT_PATHS = (
55 # It's for historical reasons that blink isn't a top level directory, where
56 # it would be allowed to have "set noparent" to avoid top level owners
57 # accidentally +1ing changes.
Daniel Cheng6303eed2025-05-03 00:12:3358 'third_party/blink/OWNERS', )
wnwenbdc444e2016-05-25 13:44:1559
[email protected]06e6d0ff2012-12-11 01:36:4460# Fragment of a regular expression that matches C++ and Objective-C++
61# implementation files.
62_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
63
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1964# Fragment of a regular expression that matches C++ and Objective-C++
65# header files.
66_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
67
Aleksey Khoroshilov9b28c032022-06-03 16:35:3268# Paths with sources that don't use //base.
69_NON_BASE_DEPENDENT_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:3170 r"^chrome/browser/browser_switcher/bho/",
71 r"^tools/win/",
Aleksey Khoroshilov9b28c032022-06-03 16:35:3272)
73
[email protected]06e6d0ff2012-12-11 01:36:4474# Regular expression that matches code only used for test binaries
75# (best effort).
76_TEST_CODE_EXCLUDED_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:3177 r'.*/(fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
Marijn Kruisselbrink2a2d5fc2024-05-15 15:23:4978 # Test support files, like:
79 # foo_test_support.cc
80 # bar_test_util_linux.cc (suffix)
81 # baz_test_base.cc
82 r'.+_test_(base|support|util)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
James Cook1b4dc132021-03-09 22:45:1383 # Test suite files, like:
84 # foo_browsertest.cc
85 # bar_unittest_mac.cc (suffix)
86 # baz_unittests.cc (plural)
87 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(s)?(_[a-z]+)?%s' %
Daniel Cheng6303eed2025-05-03 00:12:3388 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1889 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
Victor Hugo Vianna Silvac22e0202021-06-09 19:46:2190 r'.+sync_service_impl_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Bruce Dawson40fece62022-09-16 19:58:3191 r'.*/(test|tool(s)?)/.*',
danakj89f47082020-09-02 17:53:4392 # content_shell is used for running content_browsertests.
Bruce Dawson40fece62022-09-16 19:58:3193 r'content/shell/.*',
danakj89f47082020-09-02 17:53:4394 # Web test harness.
Bruce Dawson40fece62022-09-16 19:58:3195 r'content/web_test/.*',
[email protected]7b054982013-11-27 00:44:4796 # Non-production example code.
Bruce Dawson40fece62022-09-16 19:58:3197 r'mojo/examples/.*',
[email protected]8176de12014-06-20 19:07:0898 # Launcher for running iOS tests on the simulator.
Bruce Dawson40fece62022-09-16 19:58:3199 r'testing/iossim/iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:41100 # EarlGrey app side code for tests.
Bruce Dawson40fece62022-09-16 19:58:31101 r'ios/.*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:17102 # Views Examples code
Bruce Dawson40fece62022-09-16 19:58:31103 r'ui/views/examples/.*',
Austin Sullivan33da70a2020-10-07 15:39:41104 # Chromium Codelab
Daniel Cheng6303eed2025-05-03 00:12:33105 r'codelabs/*')
[email protected]ca8d19842009-02-19 16:33:12106
Daniel Bratell609102be2019-03-27 20:53:21107_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:15108
[email protected]eea609a2011-11-18 13:10:12109_TEST_ONLY_WARNING = (
110 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:55111 'production code. If you are doing this from inside another method\n'
112 'named as *ForTesting(), then consider exposing things to have tests\n'
113 'make that same call directly.\n'
114 'If that is not possible, you may put a comment on the same line with\n'
115 ' // IN-TEST \n'
116 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
117 'method and can be ignored. Do not do this inside production code.\n'
118 'The android-binary-size trybot will block if the method exists in the\n'
Yulun Zeng08d7d8c2024-02-01 18:46:54119 'release apk.\n'
120 'Note: this warning might be a false positive (crbug.com/1196548).')
[email protected]eea609a2011-11-18 13:10:12121
122
Daniel Chenga44a1bcd2022-03-15 20:00:15123@dataclass
124class BanRule:
Daniel Chenga37c03db2022-05-12 17:20:34125 # String pattern. If the pattern begins with a slash, the pattern will be
126 # treated as a regular expression instead.
127 pattern: str
128 # Explanation as a sequence of strings. Each string in the sequence will be
129 # printed on its own line.
mikt19226ff22024-08-27 05:28:21130 explanation: Tuple[str, ...]
Daniel Chenga37c03db2022-05-12 17:20:34131 # Whether or not to treat this ban as a fatal error. If unspecified,
132 # defaults to true.
133 treat_as_error: Optional[bool] = None
134 # Paths that should be excluded from the ban check. Each string is a regular
135 # expression that will be matched against the path of the file being checked
136 # relative to the root of the source tree.
137 excluded_paths: Optional[Sequence[str]] = None
Ben Pastenee79d66112025-04-23 19:46:15138 # If True, surfaces any violation as a Gerrit comment on the CL after
139 # running the CQ.
140 surface_as_gerrit_lint: Optional[bool] = None
[email protected]cf9b78f2012-11-14 11:40:28141
Daniel Chenga44a1bcd2022-03-15 20:00:15142
Daniel Cheng6303eed2025-05-03 00:12:33143_BANNED_JAVA_IMPORTS: Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15144 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33145 'import java.net.URI;',
146 ('Use org.chromium.url.GURL instead of java.net.URI, where possible.',
147 ),
148 excluded_paths=(
149 (r'net/android/javatests/src/org/chromium/net/'
150 r'AndroidProxySelectorTest\.java'),
151 r'components/cronet/',
152 r'third_party/robolectric/local/',
153 ),
Michael Thiessen44457642020-02-06 00:24:15154 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15155 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33156 'import android.annotation.TargetApi;',
157 ('Do not use TargetApi, use @androidx.annotation.RequiresApi instead. '
158 'RequiresApi ensures that any calls are guarded by the appropriate '
159 'SDK_INT check. See https://crbug.com/1116486.', ),
Daniel Chenga44a1bcd2022-03-15 20:00:15160 ),
161 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33162 'import androidx.test.rule.ActivityTestRule;',
163 ('Do not use ActivityTestRule, use '
164 'org.chromium.base.test.BaseActivityTestRule instead.', ),
165 excluded_paths=('components/cronet/', ),
Daniel Chenga44a1bcd2022-03-15 20:00:15166 ),
Min Qinbc44383c2023-02-22 17:25:26167 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33168 'import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;',
169 ('Do not use VectorDrawableCompat, use getResources().getDrawable() to '
170 'avoid extra indirections. Please also add trace event as the call '
171 'might take more than 20 ms to complete.', ),
Min Qinbc44383c2023-02-22 17:25:26172 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15173)
wnwenbdc444e2016-05-25 13:44:15174
Daniel Cheng6303eed2025-05-03 00:12:33175_BANNED_JAVA_FUNCTIONS: Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15176 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33177 'StrictMode.allowThreadDiskReads()',
178 ('Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
179 'directly.', ),
180 False,
Eric Stevensona9a980972017-09-23 00:04:41181 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15182 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33183 'StrictMode.allowThreadDiskWrites()',
184 ('Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
185 'directly.', ),
186 False,
Eric Stevensona9a980972017-09-23 00:04:41187 ),
Daniel Cheng917ce542022-03-15 20:46:57188 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33189 '.waitForIdleSync()',
190 ('Do not use waitForIdleSync as it masks underlying issues. There is '
191 'almost always something else you should wait on instead.', ),
192 False,
Michael Thiessen0f2547e32020-07-27 21:55:36193 ),
Ashley Newson09cbd602022-10-26 11:40:14194 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33195 r'/(?<!\bsuper\.)(?<!\bIntent )\bregisterReceiver\(',
196 ('Do not call android.content.Context.registerReceiver (or an override) '
197 'directly. Use one of the wrapper methods defined in '
198 'org.chromium.base.ContextUtils, such as '
199 'registerProtectedBroadcastReceiver, '
200 'registerExportedBroadcastReceiver, or '
201 'registerNonExportedBroadcastReceiver. See their documentation for '
202 'which one to use.', ),
203 True,
204 excluded_paths=(
205 r'.*Test[^a-z]',
206 r'third_party/',
207 'base/android/java/src/org/chromium/base/ContextUtils.java',
208 'chromecast/browser/android/apk/src/org/chromium/chromecast/shell/BroadcastReceiverScope.java',
209 ),
Ashley Newson09cbd602022-10-26 11:40:14210 ),
Ted Chocd5b327b12022-11-05 02:13:22211 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33212 r'/(?:extends|new)\s*(?:android.util.)?Property<[A-Za-z.]+,\s*(?:Integer|Float)>',
213 ('Do not use Property<..., Integer|Float>, but use FloatProperty or '
214 'IntProperty because it will avoid unnecessary autoboxing of '
215 'primitives.', ),
Ted Chocd5b327b12022-11-05 02:13:22216 ),
Peilin Wangbba4a8652022-11-10 16:33:57217 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33218 'requestLayout()',
219 ('Layouts can be expensive. Prefer using ViewUtils.requestLayout(), '
220 'which emits a trace event with additional information to help with '
221 'scroll jank investigations. See http://crbug.com/1354176.', ),
222 False,
223 excluded_paths=(
224 'ui/android/java/src/org/chromium/ui/base/ViewUtils.java', ),
Peilin Wangbba4a8652022-11-10 16:33:57225 ),
Ted Chocf40ea9152023-02-14 19:02:39226 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33227 'ProfileManager.getLastUsedRegularProfile()',
228 ('Prefer passing in the Profile reference instead of relying on the '
229 'static getLastUsedRegularProfile() call. Only top level entry points '
230 '(e.g. Activities) should call this method. Otherwise, the Profile '
Vikram Pasupathyb052c892025-07-08 18:10:00231 'should either be passed in explicitly or retrieved from an existing '
Daniel Cheng6303eed2025-05-03 00:12:33232 'entity with a reference to the Profile (e.g. WebContents).', ),
233 False,
234 excluded_paths=(r'.*Test[A-Z]?.*\.java', ),
Ted Chocf40ea9152023-02-14 19:02:39235 ),
Min Qinbc44383c2023-02-22 17:25:26236 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33237 r'/(ResourcesCompat|getResources\(\))\.getDrawable\(\)',
238 ('getDrawable() can be expensive. If you have a lot of calls to '
239 'GetDrawable() or your code may introduce janks, please put your calls '
240 'inside a trace().', ),
241 False,
242 excluded_paths=(r'.*Test[A-Z]?.*\.java', ),
Min Qinbc44383c2023-02-22 17:25:26243 ),
Henrique Nakashimabbf2b262023-03-10 17:21:39244 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33245 r'/RecordHistogram\.getHistogram(ValueCount|TotalCount|Samples)ForTesting\(',
246 ('Raw histogram counts are easy to misuse; for example they don\'t reset '
247 'between batched tests. Use HistogramWatcher to check histogram records '
248 'instead.', ),
249 False,
250 excluded_paths=(
251 'base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java',
252 'base/test/android/javatests/src/org/chromium/base/test/util/HistogramWatcher.java',
253 ),
Henrique Nakashimabbf2b262023-03-10 17:21:39254 ),
Jenna Himawan859865d2025-02-25 22:22:31255 BanRule(
256 r'/((announceForAccessibility\()|TYPE_ANNOUNCEMENT)',
257 ('Android 16 deprecates accessibility announcements, characterized by '
258 'the use of announceForAccessibility or the dispatch of '
259 'TYPE_ANNOUNCEMENT accessibility events. See '
260 'https://developer.android.com/about/versions/16/behavior-changes-all#disruptive-a11y'
261 ' for more details and suggested replacements.', ),
262 False,
263 ),
Nate Fischerd541ff82025-03-11 21:34:19264 BanRule(
Sirisha Kavuluru67f07b3d2025-07-28 19:16:01265 pattern=(r'/((DeviceInfo\.isDesktop\()|IS_DESKTOP_ANDROID|PackageManager\.FEATURE_PC)'),
Nate Fischerd541ff82025-03-11 21:34:19266 explanation=(
Sirisha Kavuluru7fbc3c12025-08-20 19:23:36267 'Usage of IS_DESKTOP_ANDROID build flag or DeviceInfo.isDesktop() '
268 'is discouraged. Use system affordances to determine feature '
269 'availablility. Refer to https://source.chromium.org/chromium/chromium/src/+/main:docs/ui/android/device_form_factor.md for guidelines.'
270 'To request an exception, file a bug at '
271 'https://b.corp.google.com/issues/new?component=1753515&template=2172655'
272 'Once approved, use centralized util DeviceInfo.isDesktop() '
273 'instead of direct build flag or PackageManager.FEATURE_PC checks.'
Eric Lokc26a46662025-05-02 01:04:03274 'Allowances may be granted to only the directories below: '
Sirisha Kavuluru7fbc3c12025-08-20 19:23:36275 '[build/, chrome/, components/, extensions/, infra/, tools/]'
Eric Lokc26a46662025-05-02 01:04:03276 'Note: in particular we need to avoid components shared with '
277 'WebView.',
278 ),
Nate Fischerd541ff82025-03-11 21:34:19279 treat_as_error=False,
Ben Pastenee79d66112025-04-23 19:46:15280 surface_as_gerrit_lint=True,
Nate Fischerd541ff82025-03-11 21:34:19281 ),
Eric Stevensona9a980972017-09-23 00:04:41282)
283
Daniel Cheng6303eed2025-05-03 00:12:33284_BANNED_JAVASCRIPT_FUNCTIONS: Sequence[BanRule] = (
Clement Yan9b330cb2022-11-17 05:25:29285 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33286 r'/\bchrome\.send\b',
287 (
288 '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).',
289 'Please use mojo instead for new webuis. https://docs.google.com/document/d/1RF-GSUoveYa37eoyZ9EhwMtaIwoW7Z88pIgNZ9YzQi4/edit#heading=h.gkk22wgk6wff',
290 ),
291 True,
292 (
293 r'^(?!ash\/webui).+',
294 # TODO(crbug.com/1385601): pre-existing violations still need to be
295 # cleaned up.
296 'ash/webui/common/resources/cr.m.js',
297 'ash/webui/common/resources/multidevice_setup/multidevice_setup_browser_proxy.js',
298 'ash/webui/common/resources/quick_unlock/lock_screen_constants.ts',
299 'ash/webui/common/resources/smb_shares/smb_browser_proxy.js',
300 'ash/webui/connectivity_diagnostics/resources/connectivity_diagnostics.ts',
301 'ash/webui/diagnostics_ui/resources/diagnostics_browser_proxy.ts',
302 'ash/webui/multidevice_debug/resources/logs.js',
303 'ash/webui/multidevice_debug/resources/webui.js',
304 'ash/webui/projector_app/resources/annotator/trusted/annotator_browser_proxy.js',
305 'ash/webui/projector_app/resources/app/trusted/projector_browser_proxy.js',
306 # TODO(b/301634378): Remove violation exception once Scanning App
307 # migrated off usage of `chrome.send`.
308 'ash/webui/scanning/resources/scanning_browser_proxy.ts',
309 ),
310 ), )
Clement Yan9b330cb2022-11-17 05:25:29311
Daniel Cheng6303eed2025-05-03 00:12:33312_BANNED_OBJC_FUNCTIONS: Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15313 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33314 'addTrackingRect:',
315 (
316 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
317 'prohibited. Please use CrTrackingArea instead.',
318 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
319 ),
320 False,
[email protected]127f18ec2012-06-16 05:05:59321 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15322 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33323 r'/NSTrackingArea\W',
324 (
325 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
326 'instead.',
327 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
328 ),
329 False,
[email protected]127f18ec2012-06-16 05:05:59330 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15331 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33332 'convertPointFromBase:',
333 (
334 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
335 'Please use |convertPoint:(point) fromView:nil| instead.',
336 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
337 ),
338 True,
[email protected]127f18ec2012-06-16 05:05:59339 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15340 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33341 'convertPointToBase:',
342 (
343 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
344 'Please use |convertPoint:(point) toView:nil| instead.',
345 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
346 ),
347 True,
[email protected]127f18ec2012-06-16 05:05:59348 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15349 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33350 'convertRectFromBase:',
351 (
352 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
353 'Please use |convertRect:(point) fromView:nil| instead.',
354 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
355 ),
356 True,
[email protected]127f18ec2012-06-16 05:05:59357 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15358 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33359 'convertRectToBase:',
360 (
361 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
362 'Please use |convertRect:(point) toView:nil| instead.',
363 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
364 ),
365 True,
[email protected]127f18ec2012-06-16 05:05:59366 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15367 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33368 'convertSizeFromBase:',
369 (
370 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
371 'Please use |convertSize:(point) fromView:nil| instead.',
372 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
373 ),
374 True,
[email protected]127f18ec2012-06-16 05:05:59375 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15376 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33377 'convertSizeToBase:',
378 (
379 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
380 'Please use |convertSize:(point) toView:nil| instead.',
381 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
382 ),
383 True,
[email protected]127f18ec2012-06-16 05:05:59384 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15385 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33386 r"/\s+UTF8String\s*]",
387 (
388 'The use of -[NSString UTF8String] is dangerous as it can return null',
389 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
390 'Please use |SysNSStringToUTF8| instead.',
391 ),
392 True,
393 excluded_paths=('^third_party/ocmock/OCMock/', ),
jif65398702016-10-27 10:19:48394 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15395 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33396 r'__unsafe_unretained',
397 (
398 'The use of __unsafe_unretained is almost certainly wrong, unless',
399 'when interacting with NSFastEnumeration or NSInvocation.',
400 'Please use __weak in files build with ARC, nothing otherwise.',
401 ),
402 False,
Sylvain Defresne4cf1d182017-09-18 14:16:34403 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15404 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33405 'freeWhenDone:NO',
406 (
407 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
408 'Foundation types is prohibited.',
409 ),
410 True,
Avi Drissman7382afa02019-04-29 23:27:13411 ),
Avi Drissman3d243a42023-08-01 16:53:59412 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33413 'This file requires ARC support.',
414 (
415 'ARC compilation is default in Chromium; do not add boilerplate to ',
416 'files that require ARC.',
417 ),
418 True,
Avi Drissman3d243a42023-08-01 16:53:59419 ),
[email protected]127f18ec2012-06-16 05:05:59420)
421
Sylvain Defresnea8b73d252018-02-28 15:45:54422_BANNED_IOS_OBJC_FUNCTIONS = (
Daniel Chenga44a1bcd2022-03-15 20:00:15423 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33424 r'/\bTEST[(]',
425 ('TEST() macro should not be used in Objective-C++ code as it does not ',
426 'drain the autorelease pool at the end of the test. Use TEST_F() ',
427 'macro instead with a fixture inheriting from PlatformTest (or a ',
428 'typedef).'),
429 True,
Sylvain Defresnea8b73d252018-02-28 15:45:54430 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15431 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33432 r'/\btesting::Test\b',
433 ('testing::Test should not be used in Objective-C++ code as it does ',
434 'not drain the autorelease pool at the end of the test. Use ',
435 'PlatformTest instead.'),
436 True,
Sylvain Defresnea8b73d252018-02-28 15:45:54437 ),
Ewann2ecc8d72022-07-18 07:41:23438 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33439 ' systemImageNamed:',
440 ('+[UIImage systemImageNamed:] should not be used to create symbols.',
441 'Instead use a wrapper defined in:',
442 'ios/chrome/browser/shared/ui/symbols/symbol_helpers.h'),
443 True,
444 excluded_paths=(
445 'ios/chrome/browser/shared/ui/symbols/symbol_helpers.mm',
446 'ios/chrome/common',
447 # App extensions have restricted dependencies and thus can't use the
448 # wrappers.
449 r'^ios/chrome/\w+_extension/',
450 ),
Ewann2ecc8d72022-07-18 07:41:23451 ),
Sylvain Defresne781b9f92024-12-11 09:36:18452 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33453 r'public (RefCounted)?BrowserStateKeyedServiceFactory',
454 ('KeyedService factories in //ios/chrome/browser should inherit from',
455 '(Refcounted)?ProfileKeyedServieFactoryIOS, not directory from',
456 '(Refcounted)?BrowserStateKeyedServiceFactory.'),
457 treat_as_error=True,
458 excluded_paths=(
459 'ios/components',
460 'ios/web_view',
461 ),
Sylvain Defresne781b9f92024-12-11 09:36:18462 ),
Sylvain Defresnea8b73d252018-02-28 15:45:54463)
464
Daniel Cheng6303eed2025-05-03 00:12:33465_BANNED_IOS_EGTEST_FUNCTIONS: Sequence[BanRule] = (BanRule(
466 r'/\bEXPECT_OCMOCK_VERIFY\b',
467 ('EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
468 'it is meant for GTests. Use [mock verify] instead.'),
469 True,
470), )
Peter K. Lee6c03ccff2019-07-15 14:40:05471
Daniel Cheng566634ff2024-06-29 14:56:53472_BANNED_CPP_FUNCTIONS: Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15473 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53474 '%#0',
475 (
476 'Zero-padded values that use "#" to add prefixes don\'t exhibit ',
477 'consistent behavior, since the prefix is not prepended for zero ',
478 'values. Use "0x%0..." instead.',
479 ),
480 False,
481 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting7c0d98a2023-10-06 15:42:39482 ),
483 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53484 r'/\busing namespace ',
485 (
486 'Using directives ("using namespace x") are banned by the Google Style',
487 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
488 'Explicitly qualify symbols or use using declarations ("using x::foo").',
489 ),
490 True,
491 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting94a56c42019-10-25 21:54:04492 ),
Antonio Gomes07300d02019-03-13 20:59:57493 # Make sure that gtest's FRIEND_TEST() macro is not used; the
494 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
495 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
Daniel Chenga44a1bcd2022-03-15 20:00:15496 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53497 'FRIEND_TEST(',
498 (
499 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
500 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
501 ),
502 False,
503 excluded_paths=(
504 "base/gtest_prod_util.h",
505 "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/gtest_prod_util.h",
506 ),
[email protected]23e6cbc2012-06-16 18:51:20507 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15508 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53509 'setMatrixClip',
510 (
511 'Overriding setMatrixClip() is prohibited; ',
512 'the base function is deprecated. ',
513 ),
514 True,
515 (),
tomhudsone2c14d552016-05-26 17:07:46516 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15517 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53518 'SkRefPtr',
519 ('The use of SkRefPtr is prohibited. ', 'Please use sk_sp<> instead.'),
520 True,
521 (),
[email protected]52657f62013-05-20 05:30:31522 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15523 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53524 'SkAutoRef',
525 ('The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
526 'Please use sk_sp<> instead.'),
527 True,
528 (),
[email protected]52657f62013-05-20 05:30:31529 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15530 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53531 'SkAutoTUnref',
532 ('The use of SkAutoTUnref is dangerous because it implicitly ',
533 'converts to a raw pointer. Please use sk_sp<> instead.'),
534 True,
535 (),
[email protected]52657f62013-05-20 05:30:31536 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15537 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53538 'SkAutoUnref',
539 ('The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
540 'because it implicitly converts to a raw pointer. ',
541 'Please use sk_sp<> instead.'),
542 True,
543 (),
[email protected]52657f62013-05-20 05:30:31544 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15545 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53546 r'/HANDLE_EINTR\(.*close',
547 ('HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
548 'descriptor will be closed, and it is incorrect to retry the close.',
549 'Either call close directly and ignore its return value, or wrap close',
550 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
551 ),
552 True,
553 (),
[email protected]d89eec82013-12-03 14:10:59554 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15555 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53556 r'/IGNORE_EINTR\((?!.*close)',
557 (
558 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
559 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
560 ),
561 True,
562 (
563 # Files that #define IGNORE_EINTR.
564 r'^base/posix/eintr_wrapper\.h$',
565 r'^ppapi/tests/test_broker\.cc$',
566 ),
[email protected]d89eec82013-12-03 14:10:59567 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15568 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53569 r'/v8::Extension\(',
570 (
571 'Do not introduce new v8::Extensions into the code base, use',
572 'gin::Wrappable instead. See http://crbug.com/334679',
573 ),
574 True,
575 (r'extensions/renderer/safe_builtins\.*', ),
[email protected]ec5b3f02014-04-04 18:43:43576 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15577 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53578 '#pragma comment(lib,',
579 ('Specify libraries to link with in build files and not in the source.',
580 ),
581 True,
582 (
583 r'^base/third_party/symbolize/.*',
584 r'^third_party/abseil-cpp/.*',
Victor Hugo Vianna Silvac86846c02025-03-07 06:56:37585 r'^third_party/grpc/source/.*',
Daniel Cheng566634ff2024-06-29 14:56:53586 ),
jame2d1a952016-04-02 00:27:10587 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15588 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53589 r'/base::SequenceChecker\b',
590 ('Consider using SEQUENCE_CHECKER macros instead of the class directly.',
591 ),
592 False,
593 (),
gabd52c912a2017-05-11 04:15:59594 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15595 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53596 r'/base::ThreadChecker\b',
597 ('Consider using THREAD_CHECKER macros instead of the class directly.',
598 ),
599 False,
600 (),
gabd52c912a2017-05-11 04:15:59601 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15602 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53603 r'/\b(?!(Sequenced|SingleThread))\w*TaskRunner::(GetCurrentDefault|CurrentDefaultHandle)',
604 (
605 'It is not allowed to call these methods from the subclasses ',
606 'of Sequenced or SingleThread task runners.',
607 ),
608 True,
609 (),
Sean Maher03efef12022-09-23 22:43:13610 ),
611 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53612 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
613 (
614 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
615 'deprecated (http://crbug.com/634507). Please avoid converting away',
616 'from the Time types in Chromium code, especially if any math is',
617 'being done on time values. For interfacing with platform/library',
618 'APIs, use base::Time::(From,To)DeltaSinceWindowsEpoch() or',
619 'base::{TimeDelta::In}Microseconds(), or one of the other type',
620 'converter methods instead. For faking TimeXXX values (for unit',
621 'testing only), use TimeXXX() + Microseconds(N). For',
622 'other use cases, please contact base/time/OWNERS.',
623 ),
624 False,
625 excluded_paths=(
626 "base/time/time.h",
627 "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/time/time.h",
628 ),
Yuri Wiitala2f8de5c2017-07-21 00:11:06629 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15630 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53631 'CallJavascriptFunctionUnsafe',
632 (
633 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
634 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
635 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
636 ),
637 False,
638 (
639 r'^content/browser/webui/web_ui_impl\.(cc|h)$',
640 r'^content/public/browser/web_ui\.h$',
641 r'^content/public/test/test_web_ui\.(cc|h)$',
642 ),
dbeamb6f4fde2017-06-15 04:03:06643 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15644 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53645 'leveldb::DB::Open',
646 (
647 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
648 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
649 "Chrome's tracing, making their memory usage visible.",
650 ),
651 True,
652 (r'^third_party/leveldatabase/.*\.(cc|h)$', ),
Gabriel Charette0592c3a2017-07-26 12:02:04653 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15654 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53655 'leveldb::NewMemEnv',
656 (
657 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
658 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
659 "to Chrome's tracing, making their memory usage visible.",
660 ),
661 True,
662 (r'^third_party/leveldatabase/.*\.(cc|h)$', ),
Chris Mumfordc38afb62017-10-09 17:55:08663 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15664 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53665 'base::ScopedMockTimeMessageLoopTaskRunner',
666 (
667 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
668 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
669 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
670 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
671 'with gab@ first if you think you need it)',
672 ),
673 False,
674 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57675 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15676 BanRule(
Peter Kasting5fdcd782025-01-13 14:57:07677 '\bstd::aligned_(storage|union)\b',
Daniel Cheng6303eed2025-05-03 00:12:33678 ('std::aligned_storage and std::aligned_union are deprecated in',
679 'C++23. Use an aligned char array instead.'),
Peter Kasting5fdcd782025-01-13 14:57:07680 True,
681 (),
682 ),
683 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53684 'std::regex',
685 (
686 'Using std::regex adds unnecessary binary size to Chrome. Please use',
687 're2::RE2 instead (crbug.com/755321)',
688 ),
689 True,
690 [
691 # Abseil's benchmarks never linked into chrome.
692 'third_party/abseil-cpp/.*_benchmark.cc',
693 ],
Francois Doray43670e32017-09-27 12:40:38694 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15695 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53696 r'/\bstd::sto(i|l|ul|ll|ull)\b',
697 (
698 'std::sto{i,l,ul,ll,ull}() use exceptions to communicate results. ',
699 'Use base::StringTo[U]Int[64]() instead.',
700 ),
701 True,
702 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting991618a62019-06-17 22:00:09703 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15704 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53705 r'/\bstd::sto(f|d|ld)\b',
706 (
707 'std::sto{f,d,ld}() use exceptions to communicate results. ',
708 'For locale-independent values, e.g. reading numbers from disk',
709 'profiles, use base::StringToDouble().',
710 'For user-visible values, parse using ICU.',
711 ),
712 True,
713 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting991618a62019-06-17 22:00:09714 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15715 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53716 r'/\bstd::to_string\b',
717 (
718 'std::to_string() is locale dependent and slower than alternatives.',
719 'For locale-independent strings, e.g. writing numbers to disk',
720 'profiles, use base::NumberToString().',
721 'For user-visible strings, use base::FormatNumber() and',
722 'the related functions in base/i18n/number_formatting.h.',
723 ),
724 True,
725 [
726 # TODO(crbug.com/335672557): Please do not add to this list. Existing
727 # uses should removed.
Daniel Cheng566634ff2024-06-29 14:56:53728 "third_party/blink/renderer/core/css/parser/css_proto_converter.cc",
729 "third_party/blink/renderer/core/editing/ime/edit_context.cc",
730 "third_party/blink/renderer/platform/graphics/bitmap_image_test.cc",
Daniel Cheng566634ff2024-06-29 14:56:53731 _THIRD_PARTY_EXCEPT_BLINK
732 ],
Daniel Bratell69334cc2019-03-26 11:07:45733 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15734 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53735 r'/#include <(cctype|ctype\.h|cwctype|wctype.h)>',
736 (
737 '<cctype>/<ctype.h>/<cwctype>/<wctype.h> are banned. Use',
738 '"third_party/abseil-cpp/absl/strings/ascii.h" instead.',
739 ),
740 True,
741 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting6f79b202023-08-09 21:25:41742 ),
743 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53744 r'/\bstd::shared_ptr\b',
745 ('std::shared_ptr is banned. Use scoped_refptr instead.', ),
746 True,
747 [
748 # Needed for interop with third-party library.
Dirk Prankee4df27972025-02-26 18:39:35749 r'^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
750 r'array_buffer_contents\.(cc|h)',
751 r'^third_party/blink/renderer/core/typed_arrays/dom_array_buffer\.cc',
Daniel Cheng566634ff2024-06-29 14:56:53752 '^third_party/blink/renderer/bindings/core/v8/' +
753 'v8_wasm_response_extensions.cc',
Dirk Prankee4df27972025-02-26 18:39:35754 r'^gin/array_buffer\.(cc|h)',
755 r'^gin/per_isolate_data\.(cc|h)',
Daniel Cheng566634ff2024-06-29 14:56:53756 '^chrome/services/sharing/nearby/',
757 # Needed for interop with third-party library libunwindstack.
Dirk Prankee4df27972025-02-26 18:39:35758 r'^base/profiler/libunwindstack_unwinder_android\.(cc|h)',
759 r'^base/profiler/native_unwinder_android_memory_regions_map_impl.(cc|h)',
Daniel Cheng566634ff2024-06-29 14:56:53760 # Needed for interop with third-party boringssl cert verifier
761 '^third_party/boringssl/',
762 '^net/cert/',
763 '^net/tools/cert_verify_tool/',
764 '^services/cert_verifier/',
765 '^components/certificate_transparency/',
766 '^components/media_router/common/providers/cast/certificate/',
Nina Satragnoe447f2d2025-05-08 16:32:19767 '^components/trusted_vault/',
Daniel Cheng566634ff2024-06-29 14:56:53768 # gRPC provides some C++ libraries that use std::shared_ptr<>.
769 '^chromeos/ash/services/libassistant/grpc/',
770 '^chromecast/cast_core/grpc',
771 '^chromecast/cast_core/runtime/browser',
Dirk Prankee4df27972025-02-26 18:39:35772 r'^ios/chrome/test/earl_grey/chrome_egtest_plugin_client\.(mm|h)',
Daniel Cheng566634ff2024-06-29 14:56:53773 # Fuchsia provides C++ libraries that use std::shared_ptr<>.
Dirk Prankee4df27972025-02-26 18:39:35774 r'^base/fuchsia/.*\.(cc|h)',
775 r'.*fuchsia.*test\.(cc|h)',
Daniel Cheng566634ff2024-06-29 14:56:53776 # Clang plugins have different build config.
777 '^tools/clang/plugins/',
Sam Maier808f0062025-07-23 15:48:22778 # Needed for interop with Android native-only services.
779 r'^content/app/android/javaless_child_process_service\.cc',
Daniel Cheng566634ff2024-06-29 14:56:53780 _THIRD_PARTY_EXCEPT_BLINK
781 ], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21782 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15783 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53784 r'/\bstd::weak_ptr\b',
785 ('std::weak_ptr is banned. Use base::WeakPtr instead.', ),
786 True,
787 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting991618a62019-06-17 22:00:09788 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15789 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53790 r'/\blong long\b',
791 ('long long is banned. Use [u]int64_t instead.', ),
792 False, # Only a warning since it is already used.
793 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21794 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15795 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53796 r'/\b(absl|std)::any\b',
797 (
798 '{absl,std}::any are banned due to incompatibility with the component ',
799 'build.',
800 ),
801 True,
802 # Not an error in third party folders, though it probably should be :)
803 [_THIRD_PARTY_EXCEPT_BLINK],
Daniel Chengc05fcc62022-01-12 16:54:29804 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15805 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53806 r'/\bstd::bind\b',
807 (
808 'std::bind() is banned because of lifetime risks. Use ',
809 'base::Bind{Once,Repeating}() instead.',
810 ),
811 True,
812 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21813 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15814 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53815 (r'/\bstd::(?:'
816 r'linear_congruential_engine|mersenne_twister_engine|'
817 r'subtract_with_carry_engine|discard_block_engine|'
818 r'independent_bits_engine|shuffle_order_engine|'
819 r'minstd_rand0?|mt19937(_64)?|ranlux(24|48)(_base)?|knuth_b|'
820 r'default_random_engine|'
821 r'random_device|'
822 r'seed_seq'
823 r')\b'),
824 (
825 'STL random number engines and generators are banned. Use the ',
826 'helpers in base/rand_util.h instead, e.g. base::RandBytes() or ',
827 'base::RandomBitGenerator.'
828 '',
829 'Please reach out to [email protected] if the base APIs are ',
830 'insufficient for your needs.',
831 ),
832 True,
833 [
834 # Not an error in third_party folders.
835 _THIRD_PARTY_EXCEPT_BLINK,
836 # Various tools which build outside of Chrome.
837 r'testing/libfuzzer',
Steinar H. Gundersone5689e42024-08-07 18:17:19838 r'testing/perf/confidence',
Daniel Cheng566634ff2024-06-29 14:56:53839 r'tools/android/io_benchmark/',
840 # Fuzzers are allowed to use standard library random number generators
841 # since fuzzing speed + reproducibility is important.
Daniel Cheng566634ff2024-06-29 14:56:53842 r'.+_fuzzer\.cc$',
843 r'.+_fuzzertest\.cc$',
844 # TODO(https://crbug.com/1380528): These are all unsanctioned uses of
845 # the standard library's random number generators, and should be
846 # migrated to the //base equivalent.
847 r'ash/ambient/model/ambient_topic_queue\.cc',
848 r'base/allocator/partition_allocator/src/partition_alloc/partition_alloc_unittest\.cc',
Daniel Cheng566634ff2024-06-29 14:56:53849 r'base/test/launcher/test_launcher\.cc',
850 r'cc/metrics/video_playback_roughness_reporter_unittest\.cc',
851 r'chrome/browser/apps/app_service/metrics/website_metrics\.cc',
852 r'chrome/browser/ash/power/auto_screen_brightness/monotone_cubic_spline_unittest\.cc',
853 r'chrome/browser/ash/printing/zeroconf_printer_detector_unittest\.cc',
854 r'chrome/browser/nearby_sharing/contacts/nearby_share_contact_manager_impl_unittest\.cc',
855 r'chrome/browser/nearby_sharing/contacts/nearby_share_contacts_sorter_unittest\.cc',
856 r'chrome/browser/privacy_budget/mesa_distribution_unittest\.cc',
857 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
858 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
859 r'chrome/browser/win/conflicts/module_blocklist_cache_util_unittest\.cc',
860 r'chromeos/ash/components/memory/userspace_swap/swap_storage_unittest\.cc',
861 r'chromeos/ash/components/memory/userspace_swap/userspace_swap\.cc',
862 r'components/metrics/metrics_state_manager\.cc',
863 r'components/omnibox/browser/history_quick_provider_performance_unittest\.cc',
864 r'components/zucchini/disassembler_elf_unittest\.cc',
865 r'content/browser/webid/federated_auth_request_impl\.cc',
866 r'content/browser/webid/federated_auth_request_impl\.cc',
867 r'media/cast/test/utility/udp_proxy\.h',
868 r'sql/recover_module/module_unittest\.cc',
Nicolas Dossou-Gbeteaf9023d2025-04-07 17:44:38869 r'components/regional_capabilities/regional_capabilities_utils.cc',
Daniel Cheng566634ff2024-06-29 14:56:53870 # Do not add new entries to this list. If you have a use case which is
871 # not satisfied by the current APIs (i.e. you need an explicitly-seeded
872 # sequence, or stability of some sort is required), please contact
873 # [email protected].
874 ],
Daniel Cheng192683f2022-11-01 20:52:44875 ),
876 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53877 r'/\b(absl,std)::bind_front\b',
878 ('{absl,std}::bind_front() are banned. Use base::Bind{Once,Repeating}() '
879 'instead.', ),
880 True,
881 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12882 ),
883 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53884 r'/\bABSL_FLAG\b',
885 ('ABSL_FLAG is banned. Use base::CommandLine instead.', ),
886 True,
887 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12888 ),
889 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53890 r'/\babsl::c_',
Daniel Cheng6303eed2025-05-03 00:12:33891 ('Abseil container utilities are banned. Use std::ranges:: instead.',
892 ),
Daniel Cheng566634ff2024-06-29 14:56:53893 True,
894 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12895 ),
896 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53897 r'/\babsl::FixedArray\b',
898 ('absl::FixedArray is banned. Use base::FixedArray instead.', ),
899 True,
900 [
901 # base::FixedArray provides canonical access.
902 r'^base/types/fixed_array.h',
903 # Not an error in third_party folders.
904 _THIRD_PARTY_EXCEPT_BLINK,
905 ],
Peter Kasting431239a2023-09-29 03:11:44906 ),
907 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53908 r'/\babsl::FunctionRef\b',
909 ('absl::FunctionRef is banned. Use base::FunctionRef instead.', ),
910 True,
911 [
912 # base::Bind{Once,Repeating} references absl::FunctionRef to disallow
913 # interoperability.
914 r'^base/functional/bind_internal\.h',
915 # base::FunctionRef is implemented on top of absl::FunctionRef.
916 r'^base/functional/function_ref.*\..+',
917 # Not an error in third_party folders.
918 _THIRD_PARTY_EXCEPT_BLINK,
919 ],
Peter Kasting4f35bfc2022-10-18 18:39:12920 ),
921 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53922 r'/\babsl::(Insecure)?BitGen\b',
923 ('absl random number generators are banned. Use the helpers in '
924 'base/rand_util.h instead, e.g. base::RandBytes() or ',
925 'base::RandomBitGenerator.'),
926 True,
927 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12928 ),
929 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:33930 pattern=r'/\babsl::(optional|nullopt|make_optional)\b',
Peter Kasting3b77a0c2024-08-22 00:22:26931 explanation=('absl::optional is banned. Use std::optional instead.', ),
932 treat_as_error=True,
933 excluded_paths=[
934 _THIRD_PARTY_EXCEPT_BLINK,
935 ]),
936 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53937 r'/(\babsl::Span\b|#include <span>|\bstd::span\b)',
Daniel Cheng6303eed2025-05-03 00:12:33938 ('absl::Span and std::span are banned. Use base::span instead.', ),
Daniel Cheng566634ff2024-06-29 14:56:53939 True,
940 [
941 # Included for conversions between base and std.
942 r'base/containers/span.h',
943 # Test base::span<> compatibility against std::span<>.
944 r'base/containers/span_unittest.cc',
945 # //base/numerics can't use base or absl. So it uses std.
946 r'base/numerics/.*'
Lei Zhang1f9d9ec42024-06-20 18:42:27947
Daniel Cheng566634ff2024-06-29 14:56:53948 # Needed to use QUICHE API.
Ciara McMullinc029c8e2024-08-21 14:22:32949 r'android_webview/browser/ip_protection/.*',
Daniel Cheng566634ff2024-06-29 14:56:53950 r'chrome/browser/ip_protection/.*',
951 r'components/ip_protection/.*',
952 r'net/third_party/quiche/overrides/quiche_platform_impl/quiche_stack_trace_impl\.*',
953 r'services/network/web_transport\.cc',
Lei Zhang1f9d9ec42024-06-20 18:42:27954
Daniel Cheng566634ff2024-06-29 14:56:53955 # Not an error in third_party folders.
956 _THIRD_PARTY_EXCEPT_BLINK,
957 ],
Peter Kasting4f35bfc2022-10-18 18:39:12958 ),
959 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53960 r'/\babsl::StatusOr\b',
961 ('absl::StatusOr is banned. Use base::expected instead.', ),
962 True,
963 [
964 # Needed to use liburlpattern API.
965 r'components/url_pattern/.*',
966 r'services/network/shared_dictionary/simple_url_pattern_matcher\.cc',
967 r'third_party/blink/renderer/core/url_pattern/.*',
968 r'third_party/blink/renderer/modules/manifest/manifest_parser\.cc',
Lei Zhang1f9d9ec42024-06-20 18:42:27969
Daniel Cheng566634ff2024-06-29 14:56:53970 # Needed to use QUICHE API.
Ciara McMullinc029c8e2024-08-21 14:22:32971 r'android_webview/browser/ip_protection/.*',
Daniel Cheng566634ff2024-06-29 14:56:53972 r'chrome/browser/ip_protection/.*',
973 r'components/ip_protection/.*',
Victor Vasiliev435ec102025-05-07 08:33:39974 r'net/quic/dedicated_web_transport_http3_client\.cc',
Lei Zhang1f9d9ec42024-06-20 18:42:27975
Daniel Cheng566634ff2024-06-29 14:56:53976 # Needed to use MediaPipe API.
977 r'components/media_effects/.*\.cc',
978 # Not an error in third_party folders.
979 _THIRD_PARTY_EXCEPT_BLINK
980 ],
Peter Kasting4f35bfc2022-10-18 18:39:12981 ),
982 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53983 r'/\babsl::(StrSplit|StrJoin|StrCat|StrAppend|Substitute|StrContains)\b',
984 ('Abseil string utilities are banned. Use base/strings instead.', ),
985 True,
986 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12987 ),
988 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53989 r'/\babsl::(Mutex|CondVar|Notification|Barrier|BlockingCounter)\b',
990 (
991 'Abseil synchronization primitives are banned. Use',
992 'base/synchronization instead.',
993 ),
994 True,
995 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12996 ),
997 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53998 r'/\babsl::(Duration|Time|TimeZone|CivilDay)\b',
999 ('Abseil\'s time library is banned. Use base/time instead.', ),
1000 True,
1001 [
1002 # Needed to use QUICHE API.
Ciara McMullinc029c8e2024-08-21 14:22:321003 r'android_webview/browser/ip_protection/.*',
Daniel Cheng566634ff2024-06-29 14:56:531004 r'chrome/browser/ip_protection/.*',
1005 r'components/ip_protection/.*',
Lei Zhang1f9d9ec42024-06-20 18:42:271006
Daniel Cheng566634ff2024-06-29 14:56:531007 # Needed to integrate with //third_party/nearby
Daniel Cheng566634ff2024-06-29 14:56:531008 r'components/cross_device/nearby/system_clock.cc',
1009 _THIRD_PARTY_EXCEPT_BLINK # Not an error in third_party folders.
1010 ],
1011 ),
1012 BanRule(
Victor Hugo Vianna Silva6e84e8d42025-03-19 00:32:001013 r'/absl::(bad_variant_access|get|holds_alternative|monostate|variant|'
1014 r'visit)',
1015 ('Abseil\'s variant library is banned, use std.', ),
Victor Hugo Vianna Silvad9139fbe2025-03-19 20:59:081016 True,
Daniel Cheng6303eed2025-05-03 00:12:331017 [_THIRD_PARTY_EXCEPT_BLINK],
Victor Hugo Vianna Silva6e84e8d42025-03-19 00:32:001018 ),
1019 BanRule(
1020 r'/absl::(apply|exchange|forward|in_place|index_sequence|'
1021 r'integer_sequence|make_from_tuple|make_index_sequence|'
1022 r'make_integer_sequence|move)',
1023 ('Abseil\'s util library is banned, use std.', ),
Victor Hugo Vianna Silvad9139fbe2025-03-19 20:59:081024 True,
Daniel Cheng6303eed2025-05-03 00:12:331025 [_THIRD_PARTY_EXCEPT_BLINK],
Victor Hugo Vianna Silva6e84e8d42025-03-19 00:32:001026 ),
1027 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531028 r'/#include <chrono>',
1029 ('<chrono> is banned. Use base/time instead.', ),
1030 True,
1031 [
1032 # Not an error in third_party folders:
1033 _THIRD_PARTY_EXCEPT_BLINK,
Daniel Cheng566634ff2024-06-29 14:56:531034 # This uses openscreen API depending on std::chrono.
1035 "components/openscreen_platform/task_runner.cc",
1036 ]),
1037 BanRule(
1038 r'/#include <exception>',
1039 ('Exceptions are banned and disabled in Chromium.', ),
1040 True,
1041 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1042 ),
1043 BanRule(
1044 r'/\bstd::function\b',
1045 ('std::function is banned. Use base::{Once,Repeating}Callback instead.',
1046 ),
1047 True,
1048 [
1049 # Has tests that template trait helpers don't unintentionally match
1050 # std::function.
1051 r'base/functional/callback_helpers_unittest\.cc',
1052 # Required to implement interfaces from the third-party perfetto
1053 # library.
1054 r'base/tracing/perfetto_task_runner\.cc',
1055 r'base/tracing/perfetto_task_runner\.h',
1056 # Needed for interop with the third-party nearby library type
1057 # location::nearby::connections::ResultCallback.
Dirk Prankee4df27972025-02-26 18:39:351058 r'chrome/services/sharing/nearby/nearby_connections_conversions\.cc'
Daniel Cheng566634ff2024-06-29 14:56:531059 # Needed for interop with the internal libassistant library.
Dirk Prankee4df27972025-02-26 18:39:351060 r'chromeos/ash/services/libassistant/callback_utils\.h',
Daniel Cheng566634ff2024-06-29 14:56:531061 # Needed for interop with Fuchsia fidl APIs.
Dirk Prankee4df27972025-02-26 18:39:351062 r'fuchsia_web/webengine/browser/context_impl_browsertest\.cc',
1063 r'fuchsia_web/webengine/browser/cookie_manager_impl_unittest\.cc',
1064 r'fuchsia_web/webengine/browser/media_player_impl_unittest\.cc',
Daniel Cheng566634ff2024-06-29 14:56:531065 # Required to interop with interfaces from the third-party ChromeML
1066 # library API.
Dirk Prankee4df27972025-02-26 18:39:351067 r'services/on_device_model/ml/chrome_ml_api\.h',
1068 r'services/on_device_model/ml/on_device_model_executor\.cc',
1069 r'services/on_device_model/ml/on_device_model_executor\.h',
Daniel Cheng566634ff2024-06-29 14:56:531070 # Required to interop with interfaces from the third-party perfetto
1071 # library.
Dirk Prankee4df27972025-02-26 18:39:351072 r'components/tracing/common/etw_consumer_win_unittest\.cc',
1073 r'services/tracing/public/cpp/perfetto/custom_event_recorder\.cc',
1074 r'services/tracing/public/cpp/perfetto/perfetto_traced_process\.cc',
1075 r'services/tracing/public/cpp/perfetto/perfetto_traced_process\.h',
1076 r'services/tracing/public/cpp/perfetto/perfetto_tracing_backend\.cc',
1077 r'services/tracing/public/cpp/perfetto/producer_client\.cc',
1078 r'services/tracing/public/cpp/perfetto/producer_client\.h',
1079 r'services/tracing/public/cpp/perfetto/producer_test_utils\.cc',
1080 r'services/tracing/public/cpp/perfetto/producer_test_utils\.h',
Daniel Cheng566634ff2024-06-29 14:56:531081 # Required for interop with the third-party webrtc library.
Dirk Prankee4df27972025-02-26 18:39:351082 r'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.cc',
1083 r'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.h',
Daniel Cheng566634ff2024-06-29 14:56:531084 # TODO(https://crbug.com/1364577): Various uses that should be
1085 # migrated to something else.
1086 # Should use base::OnceCallback or base::RepeatingCallback.
Dirk Prankee4df27972025-02-26 18:39:351087 r'base/allocator/dispatcher/initializer_unittest\.cc',
1088 r'chrome/browser/ash/accessibility/speech_monitor\.cc',
1089 r'chrome/browser/ash/accessibility/speech_monitor\.h',
1090 r'chrome/browser/ash/login/ash_hud_login_browsertest\.cc',
1091 r'chromecast/base/observer_unittest\.cc',
1092 r'chromecast/browser/cast_web_view\.h',
1093 r'chromecast/public/cast_media_shlib\.h',
1094 r'device/bluetooth/floss/exported_callback_manager\.h',
1095 r'device/bluetooth/floss/floss_dbus_client\.h',
1096 r'device/fido/cable/v2_handshake_unittest\.cc',
1097 r'device/fido/pin\.cc',
1098 r'services/tracing/perfetto/test_utils\.h',
Daniel Cheng566634ff2024-06-29 14:56:531099 # Should use base::FunctionRef.
Dirk Prankee4df27972025-02-26 18:39:351100 r'chrome/browser/media/webrtc/test_stats_dictionary\.cc',
1101 r'chrome/browser/media/webrtc/test_stats_dictionary\.h',
1102 r'chromeos/ash/services/libassistant/device_settings_controller\.cc',
1103 r'components/browser_ui/client_certificate/android/ssl_client_certificate_request\.cc',
1104 r'components/gwp_asan/client/sampling_malloc_shims_unittest\.cc',
1105 r'content/browser/font_unique_name_lookup/font_unique_name_lookup_unittest\.cc',
Daniel Cheng566634ff2024-06-29 14:56:531106 # Does not need std::function at all.
Dirk Prankee4df27972025-02-26 18:39:351107 r'components/omnibox/browser/autocomplete_result\.cc',
1108 r'device/fido/win/webauthn_api\.cc',
1109 r'media/audio/alsa/alsa_util\.cc',
1110 r'media/remoting/stream_provider\.h',
1111 r'sql/vfs_wrapper\.cc',
Daniel Cheng566634ff2024-06-29 14:56:531112 # TODO(https://crbug.com/1364585): Remove usage and exception list
1113 # entries.
Dirk Prankee4df27972025-02-26 18:39:351114 r'extensions/renderer/api/automation/automation_internal_custom_bindings\.cc',
1115 r'extensions/renderer/api/automation/automation_internal_custom_bindings\.h',
Daniel Cheng566634ff2024-06-29 14:56:531116 # TODO(https://crbug.com/1364579): Remove usage and exception list
1117 # entry.
Dirk Prankee4df27972025-02-26 18:39:351118 r'ui/views/controls/focus_ring\.h',
Lei Zhang1f9d9ec42024-06-20 18:42:271119
Daniel Cheng566634ff2024-06-29 14:56:531120 # Various pre-existing uses in //tools that is low-priority to fix.
Dirk Prankee4df27972025-02-26 18:39:351121 r'tools/binary_size/libsupersize/viewer/caspian/diff\.cc',
1122 r'tools/binary_size/libsupersize/viewer/caspian/model\.cc',
1123 r'tools/binary_size/libsupersize/viewer/caspian/model\.h',
1124 r'tools/binary_size/libsupersize/viewer/caspian/tree_builder\.h',
1125 r'tools/clang/base_bind_rewriters/BaseBindRewriters\.cpp',
Daniel Chenge5583e3c2022-09-22 00:19:411126
Daniel Cheng566634ff2024-06-29 14:56:531127 # Not an error in third_party folders.
1128 _THIRD_PARTY_EXCEPT_BLINK
1129 ],
Daniel Bratell609102be2019-03-27 20:53:211130 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151131 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531132 r'/#include <X11/',
1133 ('Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.', ),
1134 True,
1135 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Tom Andersona95e12042020-09-09 23:08:001136 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151137 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531138 r'/\bstd::ratio\b',
1139 ('std::ratio is banned by the Google Style Guide.', ),
1140 True,
1141 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:451142 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151143 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531144 r'/\bstd::aligned_alloc\b',
1145 (
1146 'std::aligned_alloc() is not yet allowed (crbug.com/1412818). Use ',
1147 'base::AlignedAlloc() instead.',
1148 ),
1149 True,
1150 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181151 ),
1152 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531153 r'/#include <(barrier|latch|semaphore|stop_token)>',
1154 ('The thread support library is banned. Use base/synchronization '
1155 'instead.', ),
1156 True,
1157 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181158 ),
1159 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531160 r'/\bstd::execution::(par|seq)\b',
1161 ('std::execution::(par|seq) is banned; they do not fit into '
1162 ' Chrome\'s threading model, and libc++ doesn\'t have full '
mikt19226ff22024-08-27 05:28:211163 'support.', ),
Daniel Cheng566634ff2024-06-29 14:56:531164 True,
1165 [_THIRD_PARTY_EXCEPT_BLINK],
Helmut Januschka7cc8a84f2024-02-07 22:50:411166 ),
1167 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531168 r'/\bstd::bit_cast\b',
1169 ('std::bit_cast is banned; use base::bit_cast instead for values and '
1170 'standard C++ casting when pointers are involved.', ),
1171 True,
1172 [
1173 # Don't warn in third_party folders.
1174 _THIRD_PARTY_EXCEPT_BLINK,
1175 # //base/numerics can't use base or absl.
1176 r'base/numerics/.*'
1177 ],
Avi Drissman70cb7f72023-12-12 17:44:371178 ),
1179 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531180 r'/\bstd::(c8rtomb|mbrtoc8)\b',
1181 ('std::c8rtomb() and std::mbrtoc8() are banned.', ),
1182 True,
1183 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181184 ),
1185 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531186 r'/\bchar8_t|std::u8string\b',
1187 (
1188 'char8_t and std::u8string are not yet allowed. Can you use [unsigned]',
1189 ' char and std::string instead?',
1190 ),
1191 True,
1192 [
1193 # The demangler does not use this type but needs to know about it.
Dirk Prankee4df27972025-02-26 18:39:351194 r'base/third_party/symbolize/demangle\.cc',
Daniel Cheng566634ff2024-06-29 14:56:531195 # Don't warn in third_party folders.
1196 _THIRD_PARTY_EXCEPT_BLINK
1197 ],
Peter Kastinge2c5ee82023-02-15 17:23:081198 ),
1199 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531200 r'/(\b(co_await|co_return|co_yield)\b|#include <coroutine>)',
1201 ('Coroutines are not yet allowed (https://crbug.com/1403840).', ),
1202 True,
1203 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081204 ),
1205 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531206 r'/^\s*(export\s|import\s+["<:\w]|module(;|\s+[:\w]))',
1207 ('Modules are disallowed for now due to lack of toolchain support.', ),
1208 True,
1209 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting69357dc2023-03-14 01:34:291210 ),
1211 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531212 r'/\[\[(\w*::)?no_unique_address\]\]',
1213 (
1214 '[[no_unique_address]] does not work as expected on Windows ',
1215 '(https://crbug.com/1414621). Use NO_UNIQUE_ADDRESS instead.',
1216 ),
1217 True,
1218 [
1219 # NO_UNIQUE_ADDRESS / PA_NO_UNIQUE_ADDRESS provide canonical access.
1220 r'^base/compiler_specific\.h',
1221 r'^base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/compiler_specific\.h',
1222 # Not an error in third_party folders.
1223 _THIRD_PARTY_EXCEPT_BLINK,
1224 ],
Peter Kasting8bc046d22023-11-14 00:38:031225 ),
1226 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531227 r'/#include <format>',
1228 ('<format> is not yet allowed. Use base::StringPrintf() instead.', ),
1229 True,
1230 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081231 ),
1232 BanRule(
Daniel Cheng89719222024-07-04 04:59:291233 pattern='std::views',
Daniel Cheng6303eed2025-05-03 00:12:331234 explanation=('Use of std::views is banned in Chrome. If you need this '
1235 'functionality, please contact [email protected].', ),
Daniel Cheng89719222024-07-04 04:59:291236 treat_as_error=True,
1237 excluded_paths=[
1238 # Don't warn in third_party folders.
1239 _THIRD_PARTY_EXCEPT_BLINK
1240 ],
1241 ),
1242 BanRule(
1243 # Ban everything except specifically allowlisted constructs.
Daniel Cheng70a35272025-05-06 16:41:341244 pattern=r'/std::ranges::(?!(?:' + '|'.join((
Daniel Cheng89719222024-07-04 04:59:291245 # From https://en.cppreference.com/w/cpp/ranges:
1246 # Range access
1247 'begin',
1248 'end',
1249 'cbegin',
1250 'cend',
1251 'rbegin',
1252 'rend',
1253 'crbegin',
1254 'crend',
1255 'size',
1256 'ssize',
1257 'empty',
1258 'data',
1259 'cdata',
1260 # Range primitives
1261 'iterator_t',
1262 'const_iterator_t',
1263 'sentinel_t',
1264 'const_sentinel_t',
1265 'range_difference_t',
1266 'range_size_t',
1267 'range_value_t',
1268 'range_reference_t',
1269 'range_const_reference_t',
1270 'range_rvalue_reference_t',
1271 'range_common_reference_t',
1272 # Dangling iterator handling
1273 'dangling',
1274 'borrowed_iterator_t',
1275 # Banned: borrowed_subrange_t
1276 # Range concepts
1277 'range',
1278 'borrowed_range',
1279 'sized_range',
1280 'view',
1281 'input_range',
1282 'output_range',
1283 'forward_range',
1284 'bidirectional_range',
1285 'random_access_range',
1286 'contiguous_range',
1287 'common_range',
1288 'viewable_range',
1289 'constant_range',
Michael Tang626d8982025-05-08 23:24:291290 # Views
1291 'subrange',
Daniel Cheng89719222024-07-04 04:59:291292 # Banned: Range factories
1293 # Banned: Range adaptors
Peter Kastinga7f93752024-10-24 22:15:401294 # Incidentally listed on
1295 # https://en.cppreference.com/w/cpp/header/ranges:
1296 'enable_borrowed_range',
1297 'enable_view',
Daniel Cheng89719222024-07-04 04:59:291298 # From https://en.cppreference.com/w/cpp/algorithm/ranges:
1299 # Constrained algorithms: non-modifying sequence operations
1300 'all_of',
1301 'any_of',
1302 'none_of',
1303 'for_each',
1304 'for_each_n',
1305 'count',
1306 'count_if',
1307 'mismatch',
1308 'equal',
1309 'lexicographical_compare',
1310 'find',
1311 'find_if',
1312 'find_if_not',
1313 'find_end',
1314 'find_first_of',
1315 'adjacent_find',
1316 'search',
1317 'search_n',
1318 # Constrained algorithms: modifying sequence operations
1319 'copy',
1320 'copy_if',
1321 'copy_n',
1322 'copy_backward',
1323 'move',
1324 'move_backward',
1325 'fill',
1326 'fill_n',
1327 'transform',
1328 'generate',
1329 'generate_n',
1330 'remove',
1331 'remove_if',
1332 'remove_copy',
1333 'remove_copy_if',
1334 'replace',
1335 'replace_if',
1336 'replace_copy',
1337 'replace_copy_if',
1338 'swap_ranges',
1339 'reverse',
1340 'reverse_copy',
1341 'rotate',
1342 'rotate_copy',
1343 'shuffle',
1344 'sample',
1345 'unique',
1346 'unique_copy',
1347 # Constrained algorithms: partitioning operations
1348 'is_partitioned',
1349 'partition',
1350 'partition_copy',
1351 'stable_partition',
1352 'partition_point',
1353 # Constrained algorithms: sorting operations
1354 'is_sorted',
1355 'is_sorted_until',
1356 'sort',
1357 'partial_sort',
1358 'partial_sort_copy',
1359 'stable_sort',
1360 'nth_element',
1361 # Constrained algorithms: binary search operations (on sorted ranges)
1362 'lower_bound',
1363 'upper_bound',
1364 'binary_search',
1365 'equal_range',
1366 # Constrained algorithms: set operations (on sorted ranges)
1367 'merge',
1368 'inplace_merge',
1369 'includes',
1370 'set_difference',
1371 'set_intersection',
1372 'set_symmetric_difference',
1373 'set_union',
1374 # Constrained algorithms: heap operations
1375 'is_heap',
1376 'is_heap_until',
1377 'make_heap',
1378 'push_heap',
1379 'pop_heap',
1380 'sort_heap',
1381 # Constrained algorithms: minimum/maximum operations
1382 'max',
1383 'max_element',
1384 'min',
1385 'min_element',
1386 'minmax',
1387 'minmax_element',
1388 'clamp',
1389 # Constrained algorithms: permutation operations
1390 'is_permutation',
1391 'next_permutation',
1392 'prev_premutation',
1393 # Constrained uninitialized memory algorithms
1394 'uninitialized_copy',
1395 'uninitialized_copy_n',
1396 'uninitialized_fill',
1397 'uninitialized_fill_n',
1398 'uninitialized_move',
1399 'uninitialized_move_n',
1400 'uninitialized_default_construct',
1401 'uninitialized_default_construct_n',
1402 'uninitialized_value_construct',
1403 'uninitialized_value_construct_n',
1404 'destroy',
1405 'destroy_n',
1406 'destroy_at',
1407 'construct_at',
1408 # Return types
1409 'in_fun_result',
1410 'in_in_result',
1411 'in_out_result',
1412 'in_in_out_result',
1413 'in_out_out_result',
1414 'min_max_result',
1415 'in_found_result',
Peter Kastingf379c022025-01-13 14:01:001416 # From https://en.cppreference.com/w/cpp/header/functional
1417 'equal_to',
1418 'not_equal_to',
1419 'greater',
1420 'less',
1421 'greater_equal',
1422 'less_equal',
danakj91c715bb2024-07-10 13:24:261423 # From https://en.cppreference.com/w/cpp/iterator
1424 'advance',
1425 'distance',
1426 'next',
1427 'prev',
Daniel Cheng70a35272025-05-06 16:41:341428 # Require a word boundary at the end of negative lookahead
1429 # assertion, e.g. to ensure that even though `view` is allowed (and
1430 # should not match this regex), `views` is still treated as
1431 # disallowed (and matches the regex).
1432 )) + r')\b)\w+',
Daniel Cheng89719222024-07-04 04:59:291433 explanation=(
1434 'Use of range views and associated helpers is banned in Chrome. '
1435 'If you need this functionality, please contact [email protected].',
1436 ),
1437 treat_as_error=True,
1438 excluded_paths=[
1439 # Don't warn in third_party folders.
1440 _THIRD_PARTY_EXCEPT_BLINK
1441 ],
Peter Kastinge2c5ee82023-02-15 17:23:081442 ),
1443 BanRule(
Peter Kasting31879d82024-10-07 20:18:391444 r'/#include <regex>',
Daniel Cheng6303eed2025-05-03 00:12:331445 ('<regex> is not allowed. Use third_party/re2 instead.', ),
Peter Kasting31879d82024-10-07 20:18:391446 True,
1447 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1448 ),
1449 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531450 r'/#include <source_location>',
1451 ('<source_location> is not yet allowed. Use base/location.h instead.',
1452 ),
1453 True,
1454 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081455 ),
1456 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531457 r'/\bstd::to_address\b',
1458 (
1459 'std::to_address is banned because it is not guaranteed to be',
1460 'SFINAE-compatible. Use base::to_address from base/types/to_address.h',
1461 'instead.',
1462 ),
1463 True,
1464 [
1465 # Needed in base::to_address implementation.
1466 r'base/types/to_address.h',
1467 _THIRD_PARTY_EXCEPT_BLINK
1468 ], # Not an error in third_party folders.
Nick Diego Yamanee522ae82024-02-27 04:23:221469 ),
1470 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531471 r'/#include <syncstream>',
1472 ('<syncstream> is banned.', ),
1473 True,
1474 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181475 ),
1476 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531477 r'/\bRunMessageLoop\b',
1478 ('RunMessageLoop is deprecated, use RunLoop instead.', ),
1479 False,
1480 (),
Gabriel Charette147335ea2018-03-22 15:59:191481 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151482 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531483 'RunAllPendingInMessageLoop()',
1484 (
1485 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
1486 "if you're convinced you need this.",
1487 ),
1488 False,
1489 (),
Gabriel Charette147335ea2018-03-22 15:59:191490 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151491 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531492 'RunAllPendingInMessageLoop(BrowserThread',
1493 (
1494 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
1495 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
1496 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
1497 'async events instead of flushing threads.',
1498 ),
1499 False,
1500 (),
Gabriel Charette147335ea2018-03-22 15:59:191501 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151502 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531503 r'MessageLoopRunner',
1504 ('MessageLoopRunner is deprecated, use RunLoop instead.', ),
1505 False,
1506 (),
Gabriel Charette147335ea2018-03-22 15:59:191507 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151508 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531509 'GetDeferredQuitTaskForRunLoop',
1510 (
1511 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
1512 "gab@ if you found a use case where this is the only solution.",
1513 ),
1514 False,
1515 (),
Gabriel Charette147335ea2018-03-22 15:59:191516 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151517 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531518 'sqlite3_initialize(',
1519 (
1520 'Instead of calling sqlite3_initialize(), depend on //sql, ',
1521 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
1522 ),
1523 True,
1524 (
1525 r'^sql/initialization\.(cc|h)$',
1526 r'^third_party/sqlite/.*\.(c|cc|h)$',
1527 ),
Victor Costan3653df62018-02-08 21:38:161528 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151529 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531530 'CREATE VIEW',
1531 (
1532 'SQL views are disabled in Chromium feature code',
1533 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-views',
1534 ),
1535 True,
1536 (
1537 _THIRD_PARTY_EXCEPT_BLINK,
1538 # sql/ itself uses views when using memory-mapped IO.
1539 r'^sql/.*',
1540 # Various performance tools that do not build as part of Chrome.
1541 r'^infra/.*',
1542 r'^tools/perf.*',
1543 r'.*perfetto.*',
1544 ),
Austin Sullivand661ab52022-11-16 08:55:151545 ),
1546 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531547 'CREATE VIRTUAL TABLE',
1548 (
1549 'SQL virtual tables are disabled in Chromium feature code',
1550 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-virtual-tables',
1551 ),
1552 True,
1553 (
1554 _THIRD_PARTY_EXCEPT_BLINK,
1555 # sql/ itself uses virtual tables in the recovery module and tests.
1556 r'^sql/.*',
Daniel Cheng566634ff2024-06-29 14:56:531557 # Various performance tools that do not build as part of Chrome.
1558 r'^tools/perf.*',
1559 r'.*perfetto.*',
1560 ),
Austin Sullivand661ab52022-11-16 08:55:151561 ),
1562 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531563 'std::random_shuffle',
1564 ('std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
1565 'base::RandomShuffle instead.'),
1566 True,
1567 (),
tzik5de2157f2018-05-08 03:42:471568 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151569 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531570 'ios/web/public/test/http_server',
1571 ('web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
1572 ),
1573 False,
1574 (),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:241575 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151576 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531577 'GetAddressOf',
1578 ('Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
1579 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
1580 'operator& is generally recommended. So always use operator& instead. ',
1581 'See http://crbug.com/914910 for more conversion guidance.'),
1582 True,
1583 (),
Robert Liao764c9492019-01-24 18:46:281584 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151585 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531586 'SHFileOperation',
1587 ('SHFileOperation was deprecated in Windows Vista, and there are less ',
1588 'complex functions to achieve the same goals. Use IFileOperation for ',
1589 'any esoteric actions instead.'),
1590 True,
1591 (),
Ben Lewisa9514602019-04-29 17:53:051592 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151593 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531594 'StringFromGUID2',
1595 ('StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
1596 'Use base::win::WStringFromGUID instead.'),
1597 True,
1598 (r'/base/win/win_util_unittest.cc', ),
Cliff Smolinsky81951642019-04-30 21:39:511599 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151600 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531601 'StringFromCLSID',
1602 ('StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
1603 'Use base::win::WStringFromGUID instead.'),
1604 True,
1605 (r'/base/win/win_util_unittest.cc', ),
Cliff Smolinsky81951642019-04-30 21:39:511606 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151607 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531608 'kCFAllocatorNull',
1609 (
1610 'The use of kCFAllocatorNull with the NoCopy creation of ',
1611 'CoreFoundation types is prohibited.',
1612 ),
1613 True,
1614 (),
Avi Drissman7382afa02019-04-29 23:27:131615 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151616 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531617 'mojo::ConvertTo',
1618 ('mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1619 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1620 'StringTraits if you would like to convert between custom types and',
1621 'the wire format of mojom types.'),
1622 False,
1623 (
1624 r'^fuchsia_web/webengine/browser/url_request_rewrite_rules_manager\.cc$',
1625 r'^fuchsia_web/webengine/url_request_rewrite_type_converters\.cc$',
1626 r'^third_party/blink/.*\.(cc|h)$',
1627 r'^content/renderer/.*\.(cc|h)$',
1628 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291629 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151630 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531631 'GetInterfaceProvider',
1632 ('InterfaceProvider is deprecated.',
1633 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1634 'or Platform::GetBrowserInterfaceBroker.'),
1635 False,
1636 (),
Oksana Zhuravlovac8222d22019-12-19 19:21:161637 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151638 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531639 'CComPtr',
1640 ('New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1641 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1642 'details.'),
1643 False,
1644 (),
Robert Liao1d78df52019-11-11 20:02:011645 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151646 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531647 r'/\b(IFACE|STD)METHOD_?\(',
1648 ('IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1649 'Instead, always use IFACEMETHODIMP in the declaration.'),
1650 False,
1651 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Xiaohan Wang72bd2ba2020-02-18 21:38:201652 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151653 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531654 'RemoveAllChildViewsWithoutDeleting',
1655 ('RemoveAllChildViewsWithoutDeleting is deprecated.',
1656 'This method is deemed dangerous as, unless raw pointers are re-added,',
1657 'calls to this method introduce memory leaks.'),
1658 False,
1659 (),
Peter Boström7ff41522021-07-29 03:43:271660 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151661 BanRule(
Etienne Pierre-doraya11bca22025-08-04 18:37:191662 r'/\bTRACE_EVENT(_NESTABLE)?_ASYNC_',
Daniel Cheng566634ff2024-06-29 14:56:531663 (
Etienne Pierre-doraya11bca22025-08-04 18:37:191664 'Please use TRACE_EVENT_BEGIN/END/INSTANT macros instead',
1665 'of TRACE_EVENT_ASYNC_.. and TRACE_EVENT_NESTABLE_ASYNC_... (crbug.com/432427382).',
Daniel Cheng566634ff2024-06-29 14:56:531666 ),
1667 False,
1668 (
1669 r'^base/trace_event/.*',
1670 r'^base/tracing/.*',
1671 ),
Eric Secklerbe6f48d2020-05-06 18:09:121672 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151673 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531674 'RoInitialize',
1675 ('Improper use of [base::win]::RoInitialize() has been implicated in a ',
1676 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
1677 'instead. See http://crbug.com/1197722 for more information.'),
1678 True,
1679 (
1680 r'^base/win/scoped_winrt_initializer\.cc$',
1681 r'^third_party/abseil-cpp/absl/.*',
1682 ),
Robert Liao22f66a52021-04-10 00:57:521683 ),
Patrick Monettec343bb982022-06-01 17:18:451684 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531685 r'base::Watchdog',
1686 (
1687 'base::Watchdog is deprecated because it creates its own thread.',
1688 'Instead, manually start a timer on a SequencedTaskRunner.',
1689 ),
1690 False,
1691 (),
Patrick Monettec343bb982022-06-01 17:18:451692 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091693 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531694 'base::Passed',
1695 ('Do not use base::Passed. It is a legacy helper for capturing ',
1696 'move-only types with base::BindRepeating, but invoking the ',
1697 'resulting RepeatingCallback moves the captured value out of ',
1698 'the callback storage, and subsequent invocations may pass the ',
1699 'value in a valid but undefined state. Prefer base::BindOnce().',
1700 'See http://crbug.com/1326449 for context.'),
1701 False,
1702 (
1703 # False positive, but it is also fine to let bind internals reference
1704 # base::Passed.
1705 r'^base[\\/]functional[\\/]bind\.h',
1706 r'^base[\\/]functional[\\/]bind_internal\.h',
1707 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091708 ),
Daniel Cheng2248b332022-07-27 06:16:591709 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531710 r'base::Feature k',
1711 ('Please use BASE_DECLARE_FEATURE() or BASE_FEATURE() instead of ',
1712 'directly declaring/defining features.'),
1713 True,
1714 [
1715 # Implements BASE_DECLARE_FEATURE().
1716 r'^base/feature_list\.h',
1717 ],
Daniel Chengba3bc2e2022-10-03 02:45:431718 ),
Robert Ogden92101dcb2022-10-19 23:49:361719 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531720 r'/\bchartorune\b',
1721 ('chartorune is not memory-safe, unless you can guarantee the input ',
1722 'string is always null-terminated. Otherwise, please use charntorune ',
1723 'from libphonenumber instead.'),
1724 True,
1725 [
1726 _THIRD_PARTY_EXCEPT_BLINK,
1727 # Exceptions to this rule should have a fuzzer.
1728 ],
Robert Ogden92101dcb2022-10-19 23:49:361729 ),
Arthur Sonzogni1da65fa2023-03-27 16:01:521730 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531731 r'/\b#include "base/atomicops\.h"\b',
1732 ('Do not use base::subtle atomics, but std::atomic, which are simpler '
1733 'to use, have better understood, clearer and richer semantics, and are '
1734 'harder to mis-use. See details in base/atomicops.h.', ),
1735 False,
1736 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Benoit Lize79cf0592023-01-27 10:01:571737 ),
Daniel Cheng566634ff2024-06-29 14:56:531738 BanRule(r'CrossThreadPersistent<', (
Arthur Sonzogni60348572e2023-04-07 10:22:521739 'Do not use blink::CrossThreadPersistent, but '
Daniel Cheng566634ff2024-06-29 14:56:531740 'blink::CrossThreadHandle. It is harder to mis-use.', 'More info: '
Arthur Sonzogni60348572e2023-04-07 10:22:521741 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1742 'Please contact platform-architecture-dev@ before adding new instances.'
Daniel Cheng566634ff2024-06-29 14:56:531743 ), False, []),
1744 BanRule(r'CrossThreadWeakPersistent<', (
Arthur Sonzogni60348572e2023-04-07 10:22:521745 'Do not use blink::CrossThreadWeakPersistent, but '
Daniel Cheng566634ff2024-06-29 14:56:531746 'blink::CrossThreadWeakHandle. It is harder to mis-use.', 'More info: '
Arthur Sonzogni60348572e2023-04-07 10:22:521747 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1748 'Please contact platform-architecture-dev@ before adding new instances.'
Daniel Cheng566634ff2024-06-29 14:56:531749 ), False, []),
1750 BanRule(r'objc/objc.h', (
Avi Drissman491617c2023-04-13 17:33:151751 'Do not include <objc/objc.h>. It defines away ARC lifetime '
1752 'annotations, and is thus dangerous.',
1753 'Please use the pimpl pattern; search for `ObjCStorage` for examples.',
1754 'For further reading on how to safely mix C++ and Obj-C, see',
1755 'https://chromium.googlesource.com/chromium/src/+/main/docs/mac/mixing_cpp_and_objc.md'
Daniel Cheng566634ff2024-06-29 14:56:531756 ), True, []),
1757 BanRule(
1758 r'/#include <filesystem>',
1759 ('libc++ <filesystem> is banned per the Google C++ styleguide.', ),
1760 True,
1761 # This fuzzing framework is a standalone open source project and
1762 # cannot rely on Chromium base.
1763 (r'third_party/centipede'),
Avi Drissman491617c2023-04-13 17:33:151764 ),
Grace Park8d59b54b2023-04-26 17:53:351765 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531766 r'TopDocument()',
1767 ('TopDocument() does not work correctly with out-of-process iframes. '
1768 'Please do not introduce new uses.', ),
1769 True,
1770 (
1771 # TODO(crbug.com/617677): Remove all remaining uses.
1772 r'^third_party/blink/renderer/core/dom/document\.cc',
1773 r'^third_party/blink/renderer/core/dom/document\.h',
1774 r'^third_party/blink/renderer/core/dom/element\.cc',
1775 r'^third_party/blink/renderer/core/exported/web_disallow_transition_scope_test\.cc',
1776 r'^third_party/blink/renderer/core/exported/web_document_test\.cc',
1777 r'^third_party/blink/renderer/core/html/html_anchor_element\.cc',
1778 r'^third_party/blink/renderer/core/html/html_dialog_element\.cc',
1779 r'^third_party/blink/renderer/core/html/html_element\.cc',
1780 r'^third_party/blink/renderer/core/html/html_frame_owner_element\.cc',
1781 r'^third_party/blink/renderer/core/html/media/video_wake_lock\.cc',
1782 r'^third_party/blink/renderer/core/loader/anchor_element_interaction_tracker\.cc',
1783 r'^third_party/blink/renderer/core/page/scrolling/root_scroller_controller\.cc',
1784 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.cc',
1785 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.h',
1786 r'^third_party/blink/renderer/core/script/classic_pending_script\.cc',
1787 r'^third_party/blink/renderer/core/script/script_loader\.cc',
1788 ),
Grace Park8d59b54b2023-04-26 17:53:351789 ),
Daniel Cheng72153e02023-05-18 21:18:141790 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531791 pattern=r'base::raw_ptr<',
1792 explanation=('Do not use base::raw_ptr, use raw_ptr.', ),
1793 treat_as_error=True,
1794 excluded_paths=(
1795 '^base/',
1796 '^tools/',
1797 ),
Daniel Cheng72153e02023-05-18 21:18:141798 ),
Arthur Sonzognif0eea302023-08-18 19:20:311799 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531800 pattern=r'base:raw_ref<',
1801 explanation=('Do not use base::raw_ref, use raw_ref.', ),
1802 treat_as_error=True,
1803 excluded_paths=(
1804 '^base/',
1805 '^tools/',
1806 ),
Arthur Sonzognif0eea302023-08-18 19:20:311807 ),
1808 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531809 pattern=r'/raw_ptr<[^;}]*\w{};',
1810 explanation=(
1811 'Do not use {} for raw_ptr initialization, use = nullptr instead.',
1812 ),
1813 treat_as_error=True,
1814 excluded_paths=(
1815 '^base/',
1816 '^tools/',
1817 ),
Arthur Sonzognif0eea302023-08-18 19:20:311818 ),
Anton Maliev66751812023-08-24 16:28:131819 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531820 pattern=r'/#include "base/allocator/.*/raw_'
1821 r'(ptr|ptr_cast|ptr_exclusion|ref).h"',
1822 explanation=(
1823 'Please include the corresponding facade headers:',
1824 '- #include "base/memory/raw_ptr.h"',
1825 '- #include "base/memory/raw_ptr_cast.h"',
1826 '- #include "base/memory/raw_ptr_exclusion.h"',
1827 '- #include "base/memory/raw_ref.h"',
1828 ),
1829 treat_as_error=True,
1830 excluded_paths=(
1831 '^base/',
1832 '^tools/',
1833 ),
Tom Sepez41eb158d2023-09-12 16:16:221834 ),
1835 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531836 pattern=r'ContentSettingsType::COOKIES',
1837 explanation=
1838 ('Do not use ContentSettingsType::COOKIES to check whether cookies are '
1839 'supported in the provided context. Instead rely on the '
1840 'content_settings::CookieSettings API. If you are using '
1841 'ContentSettingsType::COOKIES to check the user preference setting '
1842 'specifically, disregard this warning.', ),
1843 treat_as_error=False,
1844 excluded_paths=(
1845 '^chrome/browser/ui/content_settings/',
1846 '^components/content_settings/',
1847 '^services/network/cookie_settings.cc',
1848 '.*test.cc',
1849 ),
Arthur Sonzogni48c6aea22023-09-04 22:25:201850 ),
1851 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531852 pattern=r'ContentSettingsType::TRACKING_PROTECTION',
1853 explanation=
1854 ('Do not directly use ContentSettingsType::TRACKING_PROTECTION to check '
1855 'for tracking protection exceptions. Instead rely on the '
1856 'privacy_sandbox::TrackingProtectionSettings API.', ),
1857 treat_as_error=False,
1858 excluded_paths=(
1859 '^chrome/browser/ui/content_settings/',
1860 '^components/content_settings/',
1861 '^components/privacy_sandbox/tracking_protection_settings.cc',
1862 '.*test.cc',
1863 ),
Anton Maliev66751812023-08-24 16:28:131864 ),
Tom Andersoncd522072023-10-03 00:52:351865 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531866 pattern=r'/\bg_signal_connect',
1867 explanation=('Use ScopedGSignal instead of g_signal_connect*()', ),
1868 treat_as_error=True,
1869 excluded_paths=('^ui/base/glib/scoped_gsignal.h', ),
Michelle Abreo6b7437822024-04-26 17:29:041870 ),
1871 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531872 pattern=r'features::kIsolatedWebApps',
1873 explanation=(
1874 'Do not use `features::kIsolatedWebApps` directly to guard Isolated ',
1875 'Web App code. ',
Andrew Rayskiy7ae2b5d2025-02-28 16:59:381876 'Use `content::AreIsolatedWebAppsEnabled()` in the browser process '
1877 'or check the `kEnableIsolatedWebAppsInRenderer` command line flag '
1878 'in the renderer process.',
Daniel Cheng566634ff2024-06-29 14:56:531879 ),
1880 treat_as_error=True,
Andrew Rayskiy7ae2b5d2025-02-28 16:59:381881 excluded_paths=_TEST_CODE_EXCLUDED_PATHS + (
1882 '^chrome/browser/about_flags.cc',
1883 '^chrome/browser/component_updater/iwa_key_distribution_component_installer.cc',
1884 '^chrome/browser/web_applications/isolated_web_apps/chrome_content_browser_client_isolated_web_apps_part.cc',
1885 '^chrome/browser/ui/startup/bad_flags_prompt.cc',
1886 '^content/shell/browser/shell_content_browser_client.cc',
1887 )),
Daniel Cheng566634ff2024-06-29 14:56:531888 BanRule(
1889 pattern=r'features::kIsolatedWebAppDevMode',
1890 explanation=(
1891 'Do not use `features::kIsolatedWebAppDevMode` directly to guard code ',
1892 'related to Isolated Web App Developer Mode. ',
1893 'Use `web_app::IsIwaDevModeEnabled()` instead.',
1894 ),
1895 treat_as_error=True,
1896 excluded_paths=_TEST_CODE_EXCLUDED_PATHS + (
1897 '^chrome/browser/about_flags.cc',
1898 '^chrome/browser/web_applications/isolated_web_apps/isolated_web_app_features.cc',
1899 '^chrome/browser/ui/startup/bad_flags_prompt.cc',
1900 )),
1901 BanRule(
1902 pattern=r'features::kIsolatedWebAppUnmanagedInstall',
1903 explanation=(
1904 'Do not use `features::kIsolatedWebAppUnmanagedInstall` directly to ',
1905 'guard code related to unmanaged install flow for Isolated Web Apps. ',
1906 'Use `web_app::IsIwaUnmanagedInstallEnabled()` instead.',
1907 ),
1908 treat_as_error=True,
1909 excluded_paths=_TEST_CODE_EXCLUDED_PATHS + (
1910 '^chrome/browser/about_flags.cc',
1911 '^chrome/browser/web_applications/isolated_web_apps/isolated_web_app_features.cc',
1912 )),
1913 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531914 pattern='/(CUIAutomation|AccessibleObjectFromWindow)',
1915 explanation=
1916 ('Direct usage of UIAutomation or IAccessible2 in client code is '
1917 'discouraged in Chromium, as it is not an assistive technology and '
1918 'should not rely on accessibility APIs directly. These APIs can '
1919 'introduce significant performance overhead. However, if you believe '
1920 'your use case warrants an exception, please discuss it with an '
1921 'accessibility owner before proceeding. For more information on the '
1922 'performance implications, see https://docs.google.com/document/d/1jN4itpCe_bDXF0BhFaYwv4xVLsCWkL9eULdzjmLzkuk/edit#heading=h.pwth3nbwdub0.',
1923 ),
1924 treat_as_error=False,
Andrew Rayskiycdd45e732024-03-20 14:32:391925 ),
1926 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531927 pattern=r'/WIDGET_OWNS_NATIVE_WIDGET|'
1928 r'NATIVE_WIDGET_OWNS_WIDGET',
1929 explanation=
1930 ('WIDGET_OWNS_NATIVE_WIDGET and NATIVE_WIDGET_OWNS_WIDGET are in the '
1931 'process of being deprecated. Consider using the new '
1932 'CLIENT_OWNS_WIDGET ownership model. Eventually, this will be the only '
1933 'available ownership model available and the associated enumeration'
1934 'will be removed.', ),
1935 treat_as_error=False,
Andrew Rayskiycdd45e732024-03-20 14:32:391936 ),
1937 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531938 pattern='ProfileManager::GetLastUsedProfile',
1939 explanation=
1940 ('Most code should already be scoped to a Profile. Pass in a Profile* '
Vikram Pasupathyb052c892025-07-08 18:10:001941 'or retrieve from an existing entity with a reference to the Profile '
Daniel Cheng566634ff2024-06-29 14:56:531942 '(e.g. WebContents).', ),
1943 treat_as_error=False,
Arthur Sonzogni5cbd3e32024-02-08 17:51:321944 ),
Helmut Januschkab3f71ab52024-03-12 02:48:051945 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531946 pattern=(r'/FindBrowserWithUiElementContext|'
1947 r'FindBrowserWithTab|'
1948 r'FindBrowserWithGroup|'
1949 r'FindTabbedBrowser|'
1950 r'FindAnyBrowser|'
1951 r'FindBrowserWithProfile|'
Erik Chen5f02eb4c2024-08-23 06:30:441952 r'FindLastActive|'
Daniel Cheng566634ff2024-06-29 14:56:531953 r'FindBrowserWithActiveWindow'),
1954 explanation=
1955 ('Most code should already be scoped to a Browser. Pass in a Browser* '
Vikram Pasupathyb052c892025-07-08 18:10:001956 'or retrieve from an existing entity with a reference to the Browser.',
Daniel Cheng566634ff2024-06-29 14:56:531957 ),
1958 treat_as_error=False,
Helmut Januschkab3f71ab52024-03-12 02:48:051959 ),
1960 BanRule(
Tom Sepezd3272cd2025-02-21 19:11:311961 pattern=r'subspan(0u,',
Daniel Cheng6303eed2025-05-03 00:12:331962 explanation=(
1963 'Prefer first(n) over subspan(0u, n) as it is shorter, and the '
1964 'compiler may have to emit a branch for the n == dynamic_extent '
1965 'case of subspan().', ),
Tom Sepezd3272cd2025-02-21 19:11:311966 treat_as_error=False,
1967 ),
1968 BanRule(
Tom Sepezea67b6e2024-08-08 18:17:271969 pattern=r'UNSAFE_TODO(',
Daniel Cheng6303eed2025-05-03 00:12:331970 explanation=(
1971 'Do not use UNSAFE_TODO() to write new unsafe code. Use only when '
1972 'removing a pre-existing file-wide allow_unsafe_buffers pragma, or '
1973 'when incrementally converting code off of unsafe interfaces', ),
Tom Sepezea67b6e2024-08-08 18:17:271974 treat_as_error=False,
1975 ),
1976 BanRule(
Claudio DeSouzaad1d1f252025-04-22 23:38:581977 pattern='#pragma allow_unsafe_buffers',
1978 explanation=
1979 ('Do not use allow_unsafe_buffers to write new unsafe code. Use only '
Daniel Cheng6303eed2025-05-03 00:12:331980 'when enabling unsafe buffers checks under a new uncovered path.', ),
Claudio DeSouzaad1d1f252025-04-22 23:38:581981 treat_as_error=False,
1982 ),
1983 BanRule(
Tom Sepezea67b6e2024-08-08 18:17:271984 pattern=r'UNSAFE_BUFFERS(',
1985 explanation=
Tom Sepeza90f92b2024-08-15 16:01:351986 ('Try to avoid using UNSAFE_BUFFERS() if at all possible. Otherwise, '
1987 'be sure to justify in a // SAFETY comment why other options are not '
Daniel Cheng6303eed2025-05-03 00:12:331988 'available, and why the code is safe.', ),
Tom Sepezea67b6e2024-08-08 18:17:271989 treat_as_error=False,
1990 ),
Erik Chend086ae02024-08-20 22:53:331991 BanRule(
1992 pattern='BrowserWithTestWindowTest',
1993 explanation=
1994 ('Do not use BrowserWithTestWindowTest. By instantiating an instance '
1995 'of class Browser, the test is no longer a unit test but is instead a '
1996 'browser test. The class BrowserWithTestWindowTest forces production '
1997 'logic to take on test-only conditionals, which is an anti-pattern. '
1998 'Features should be performing dependency injection rather than '
1999 'directly using class Browser. See '
Daniel Cheng6303eed2025-05-03 00:12:332000 'docs/chrome_browser_design_principles.md for more details.', ),
Erik Chend086ae02024-08-20 22:53:332001 treat_as_error=False,
2002 ),
Erik Chen8cf3a652024-08-23 17:13:302003 BanRule(
Erik Chen959cdd72024-08-29 02:11:212004 pattern='TestWithBrowserView',
2005 explanation=
Daniel Cheng6303eed2025-05-03 00:12:332006 ('Do not use TestWithBrowserView. See '
2007 'docs/chrome_browser_design_principles.md for details. If you want '
2008 'to write a test that has both a Browser and a BrowserView, create '
2009 'a browser_test. If you want to write a unit_test, your code must '
2010 'not reference Browser*.', ),
Erik Chen959cdd72024-08-29 02:11:212011 treat_as_error=False,
2012 ),
2013 BanRule(
Erik Chene89ebe32025-02-22 02:46:492014 pattern='CreateBrowserWithTestWindow',
2015 explanation=
Daniel Cheng6303eed2025-05-03 00:12:332016 ('Do not use CreateBrowserWithTestWindow. See '
2017 'docs/chrome_browser_design_principles.md for details. If you want '
2018 'to write a test that has a Browser, create a browser_test. If you '
2019 'want to write a unit_test, your code must not reference Browser*.',
Erik Chene89ebe32025-02-22 02:46:492020 ),
2021 treat_as_error=False,
2022 ),
2023 BanRule(
Erik Chenf12a06642025-03-13 23:30:342024 pattern='CreateBrowserWithTestWindowForParams',
2025 explanation=
Daniel Cheng6303eed2025-05-03 00:12:332026 ('Do not use CreateBrowserWithTestWindowForParams. See '
2027 'docs/chrome_browser_design_principles.md for details. If you want '
2028 'to write a test that has a Browser, create a browser_test and use '
2029 'Browser::Browser. If you want to write a unit_test, your code must '
2030 'not reference Browser*.', ),
Erik Chenf12a06642025-03-13 23:30:342031 treat_as_error=False,
2032 ),
2033 BanRule(
Mikita Kuchyn383c9bab2025-05-23 15:15:232034 pattern='TestBrowserWindow',
2035 explanation=(
2036 'Do not use TestBrowserWindow. See '
2037 'docs/chrome_browser_design_principles.md for details. If you want '
2038 'to write a test that has a Browser, create a browser_test. If you'
2039 'want to write a unit_test, your code should not reference Browser'
2040 'or BrowserWindow.',
2041 ),
2042 treat_as_error=False,
2043 ),
2044 BanRule(
Erik Chen8cf3a652024-08-23 17:13:302045 pattern='RunUntilIdle',
2046 explanation=
2047 ('Do not RunUntilIdle. If possible, explicitly quit the run loop using '
2048 'run_loop.Quit() or run_loop.QuitClosure() if completion can be '
2049 'observed using a lambda or callback. Otherwise, wait for the '
Daniel Cheng6303eed2025-05-03 00:12:332050 'condition to be true via base::test::RunUntil().', ),
Erik Chen8cf3a652024-08-23 17:13:302051 treat_as_error=False,
2052 ),
Daniel Chengddde13a2024-09-05 21:39:282053 BanRule(
2054 pattern=r'/\bstd::(literals|string_literals|string_view_literals)\b',
Daniel Cheng6303eed2025-05-03 00:12:332055 explanation=(
Daniel Chengddde13a2024-09-05 21:39:282056 'User-defined literals are banned by the Google C++ style guide. '
2057 'Exceptions are provided in Chrome for string and string_view '
Daniel Cheng6303eed2025-05-03 00:12:332058 'literals that embed \\0.', ),
Daniel Chengddde13a2024-09-05 21:39:282059 treat_as_error=True,
2060 excluded_paths=(
2061 # Various tests or test helpers that embed NUL in strings or
2062 # string_views.
Daniel Chengddde13a2024-09-05 21:39:282063 r'^base/strings/string_util_unittest\.cc',
2064 r'^base/strings/utf_string_conversions_unittest\.cc',
Hidehiko Abe51601812025-01-12 16:17:352065 r'^chromeos/ash/experiences/arc/session/serial_number_util_unittest\.cc',
Daniel Chengddde13a2024-09-05 21:39:282066 r'^components/history/core/browser/visit_annotations_database\.cc',
2067 r'^components/history/core/browser/visit_annotations_database_unittest\.cc',
2068 r'^components/os_crypt/sync/os_crypt_unittest\.cc',
2069 r'^components/password_manager/core/browser/credentials_cleaner_unittest\.cc',
2070 r'^content/browser/file_system_access/file_system_access_file_writer_impl_unittest\.cc',
2071 r'^net/cookies/parsed_cookie_unittest\.cc',
2072 r'^third_party/blink/renderer/modules/webcodecs/test_helpers\.cc',
2073 r'^third_party/blink/renderer/modules/websockets/websocket_channel_impl_test\.cc',
2074 ),
Erik Chenba8b0cd32024-10-01 08:36:362075 ),
2076 BanRule(
2077 pattern='BUILDFLAG(GOOGLE_CHROME_BRANDING)',
2078 explanation=
2079 ('Code gated by GOOGLE_CHROME_BRANDING is effectively untested. This '
2080 'is typically wrong. Valid use cases are glue for private modules '
Daniel Cheng6303eed2025-05-03 00:12:332081 'shipped alongside Chrome, and installation-related logic.', ),
Erik Chenba8b0cd32024-10-01 08:36:362082 treat_as_error=False,
2083 ),
2084 BanRule(
2085 pattern='defined(OFFICIAL_BUILD)',
2086 explanation=
2087 ('Code gated by OFFICIAL_BUILD is effectively untested. This '
2088 'is typically wrong. One valid use case is low-level code that '
2089 'handles subtleties related to high-levels of optimizations that come '
Daniel Cheng6303eed2025-05-03 00:12:332090 'with OFFICIAL_BUILD.', ),
Erik Chenba8b0cd32024-10-01 08:36:362091 treat_as_error=False,
2092 ),
Erik Chen95b9c782024-11-08 03:26:272093 BanRule(
2094 pattern='WebContentsDestroyed',
2095 explanation=
2096 ('Do not use this method. It is invoked half-way through the '
2097 'destructor of WebContentsImpl and using it often results in crashes '
2098 'or surprising behavior. Conceptually, this is only necessary by '
2099 'objects that depend on, but outlive the WebContents. These objects '
2100 'should instead coordinate with the owner of the WebContents which is '
Daniel Cheng6303eed2025-05-03 00:12:332101 'responsible for destroying the WebContents.', ),
Erik Chen95b9c782024-11-08 03:26:272102 treat_as_error=False,
2103 ),
Maksim Sisovc98fdfa2024-11-16 20:12:272104 BanRule(
Georg Neisa7f94e62025-02-28 07:01:482105 pattern='IS_CHROMEOS_ASH',
Maksim Sisovc98fdfa2024-11-16 20:12:272106 explanation=
Georg Neisa7f94e62025-02-28 07:01:482107 ('IS_CHROMEOS_ASH is deprecated. Please use the equivalent IS_CHROMEOS '
Daniel Cheng6303eed2025-05-03 00:12:332108 'instead (Lacros is gone).', ),
Maksim Sisovc98fdfa2024-11-16 20:12:272109 treat_as_error=False,
2110 ),
Erik Chen1396bbe2025-01-27 23:39:362111 BanRule(
2112 pattern=(r'namespace {'),
2113 explanation=
2114 ('Anonymous namespaces are disallowed in C++ header files. See '
2115 'https://google.github.io/styleguide/cppguide.html#Internal_Linkage '
Daniel Cheng6303eed2025-05-03 00:12:332116 ' for details.', ),
Erik Chen1396bbe2025-01-27 23:39:362117 treat_as_error=False,
2118 excluded_paths=[
Daniel Cheng6303eed2025-05-03 00:12:332119 _THIRD_PARTY_EXCEPT_BLINK, # Don't warn in third_party folders.
2120 r'^(?!.*\.h$).*$', # Exclude all files except those that end in .h
Erik Chen1396bbe2025-01-27 23:39:362121 ],
2122 ),
Keren Zhuf06d757d2025-03-04 05:32:362123 BanRule(
2124 pattern=('AddChildViewRaw'),
2125 explanation=(
2126 'Do not use AddChildViewRaw. It is prone to memory leaks and '
2127 'use-after-free bugs. Instead, use AddChildView(std::unique_ptr). '
2128 'See https://crbug.com/40485510 for more details.', ),
2129 treat_as_error=False,
2130 ),
Nate Fischerd541ff82025-03-11 21:34:192131 BanRule(
2132 pattern=(r'IS_DESKTOP_ANDROID'),
2133 explanation=(
Sirisha Kavuluru7fbc3c12025-08-20 19:23:362134 'Usage of IS_DESKTOP_ANDROID build flag '
2135 'is discouraged. Use system affordances to determine feature '
2136 'availablility. Refer to https://source.chromium.org/chromium/chromium/src/+/main:docs/ui/android/device_form_factor.md for guidelines.'
2137 'To request an exception, file a bug at '
2138 'https://b.corp.google.com/issues/new?component=1753515&template=2172655'
2139 'Once approved, use centralized util DeviceInfo.isDesktop() '
2140 'instead of direct build flag or PackageManager.FEATURE_PC checks.'
Eric Lokc26a46662025-05-02 01:04:032141 'Allowances may be granted to only the directories below: '
Sirisha Kavuluru7fbc3c12025-08-20 19:23:362142 '[build/, chrome/, components/, extensions/, infra/, tools/]'
Eric Lokc26a46662025-05-02 01:04:032143 'Note: in particular we need to avoid components shared with '
2144 'WebView.',
2145 ),
Nate Fischerd541ff82025-03-11 21:34:192146 treat_as_error=False,
Ben Pastenee79d66112025-04-23 19:46:152147 surface_as_gerrit_lint=True,
Nate Fischerd541ff82025-03-11 21:34:192148 ),
[email protected]127f18ec2012-06-16 05:05:592149)
2150
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152151_DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING = (
Daniel Cheng6303eed2025-05-03 00:12:332152 'Used a predicate related to signin::ConsentLevel::kSync which will always '
2153 'return false in the future (crbug.com/40066949). Prefer using a predicate '
2154 'that also supports signin::ConsentLevel::kSignin when appropriate. It is '
2155 'safe to ignore this warning if you are just moving an existing call, or if '
2156 'you want special handling for users in the legacy state. In doubt, reach '
2157 'out to //components/sync/OWNERS.', )
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152158
2159# C++ functions related to signin::ConsentLevel::kSync which are deprecated.
Daniel Cheng6303eed2025-05-03 00:12:332160_DEPRECATED_SYNC_CONSENT_CPP_FUNCTIONS: Sequence[BanRule] = (
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152161 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:332162 'HasSyncConsent',
2163 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2164 False,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152165 ),
2166 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:332167 'CanSyncFeatureStart',
2168 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2169 False,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152170 ),
2171 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:332172 'IsSyncFeatureEnabled',
2173 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2174 False,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152175 ),
2176 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:332177 'IsSyncFeatureActive',
2178 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2179 False,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152180 ),
2181)
2182
2183# Java functions related to signin::ConsentLevel::kSync which are deprecated.
Daniel Cheng6303eed2025-05-03 00:12:332184_DEPRECATED_SYNC_CONSENT_JAVA_FUNCTIONS: Sequence[BanRule] = (
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152185 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:332186 'hasSyncConsent',
2187 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2188 False,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152189 ),
2190 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:332191 'canSyncFeatureStart',
2192 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2193 False,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152194 ),
2195 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:332196 'isSyncFeatureEnabled',
2197 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2198 False,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152199 ),
2200 BanRule(
Daniel Cheng6303eed2025-05-03 00:12:332201 'isSyncFeatureActive',
2202 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2203 False,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152204 ),
2205)
2206
Justin Lulejian09fd06872025-04-01 22:03:282207_BANNED_MOJOM_PATTERNS: Sequence[BanRule] = (
Daniel Cheng92c15e32022-03-16 17:48:222208 BanRule(
2209 'handle<shared_buffer>',
2210 (
Justin Lulejian09fd06872025-04-01 22:03:282211 'Please use one of the more specific shared memory types instead:',
2212 ' mojo_base.mojom.ReadOnlySharedMemoryRegion',
2213 ' mojo_base.mojom.WritableSharedMemoryRegion',
2214 ' mojo_base.mojom.UnsafeSharedMemoryRegion',
Daniel Cheng92c15e32022-03-16 17:48:222215 ),
2216 True,
2217 ),
Justin Lulejian09fd06872025-04-01 22:03:282218 BanRule(
2219 'string extension_id',
2220 (
2221 'Please use the extensions::mojom::ExtensionId struct when '
2222 'passing extensions::ExtensionIds as mojom messages in order to ',
2223 'provide message validation.',
2224 ),
2225 True,
2226 # Only apply this to (mojom) files in a subdirectory of extensions.
2227 excluded_paths=(r'^((?!extensions/).)*$', ),
2228 ),
Daniel Cheng92c15e32022-03-16 17:48:222229)
2230
mlamouria82272622014-09-16 18:45:042231_IPC_ENUM_TRAITS_DEPRECATED = (
2232 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:502233 'See http://www.chromium.org/Home/chromium-security/education/'
2234 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:042235
Stephen Martinis97a394142018-06-07 23:06:052236_LONG_PATH_ERROR = (
2237 'Some files included in this CL have file names that are too long (> 200'
2238 ' characters). If committed, these files will cause issues on Windows. See'
Daniel Cheng6303eed2025-05-03 00:12:332239 ' https://crbug.com/612667 for more details.')
Stephen Martinis97a394142018-06-07 23:06:052240
Shenghua Zhangbfaa38b82017-11-16 21:58:022241_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Bruce Dawson40fece62022-09-16 19:58:312242 r".*/BuildHooksAndroidImpl\.java",
2243 r".*/LicenseContentProvider\.java",
2244 r".*/PlatformServiceBridgeImpl.java",
2245 r".*chrome/android/feed/dummy/.*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:022246]
[email protected]127f18ec2012-06-16 05:05:592247
Mohamed Heikald048240a2019-11-12 16:57:372248# List of image extensions that are used as resources in chromium.
2249_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
2250
Sean Kau46e29bc2017-08-28 16:31:162251# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:402252_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Bruce Dawson40fece62022-09-16 19:58:312253 r'test/data/',
2254 r'testing/buildbot/',
2255 r'^components/policy/resources/policy_templates\.json$',
2256 r'^third_party/protobuf/',
Camillo Bruni1411a352023-05-24 12:39:032257 r'^third_party/blink/perf_tests/speedometer.*/resources/todomvc/learn\.json',
Bruce Dawson40fece62022-09-16 19:58:312258 r'^third_party/blink/renderer/devtools/protocol\.json$',
2259 r'^third_party/blink/web_tests/external/wpt/',
2260 r'^tools/perf/',
2261 r'^tools/traceline/svgui/startup-release.json',
Daniel Cheng2d4c2d192022-07-01 01:38:312262 # vscode configuration files allow comments
Bruce Dawson40fece62022-09-16 19:58:312263 r'^tools/vscode/',
Sean Kau46e29bc2017-08-28 16:31:162264]
2265
Andrew Grieveb773bad2020-06-05 18:00:382266# These are not checked on the public chromium-presubmit trybot.
2267# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:042268# checkouts.
agrievef32bcc72016-04-04 14:57:402269_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:382270 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382271]
2272
Andrew Grieveb773bad2020-06-05 18:00:382273_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:042274 'android_webview/tools/run_cts.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:362275 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042276 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362277 'build/android/gyp/aar.pydeps',
2278 'build/android/gyp/aidl.pydeps',
2279 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:382280 'build/android/gyp/assert_static_initializers.pydeps',
Mohamed Heikal133e1f22023-04-18 20:04:372281 'build/android/gyp/binary_baseline_profile.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:022282 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:222283 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieveacac4242024-12-20 19:39:422284 'build/android/gyp/check_for_missing_direct_deps.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:112285 'build/android/gyp/compile_java.pydeps',
Peter Weneaa963f2023-01-20 19:40:302286 'build/android/gyp/compile_kt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362287 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362288 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362289 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:112290 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042291 'build/android/gyp/create_app_bundle_apks.pydeps',
2292 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362293 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:122294 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:092295 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:222296 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve2d972e5f2025-01-28 18:28:142297 'build/android/gyp/create_stub_manifest.pydeps',
Peter Wene6e017e2022-07-27 21:40:402298 'build/android/gyp/create_test_apk_wrapper_script.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002299 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362300 'build/android/gyp/dex.pydeps',
2301 'build/android/gyp/dist_aar.pydeps',
Andrew Grieve651ddb32025-01-23 03:27:342302 'build/android/gyp/errorprone.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362303 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:212304 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362305 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:362306 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362307 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:582308 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362309 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:142310 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:262311 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:472312 'build/android/gyp/java_google_api_keys.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042313 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362314 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362315 'build/android/gyp/merge_manifest.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:102316 'build/android/gyp/optimize_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362317 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:222318 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362319 'build/android/gyp/proguard.pydeps',
Mohamed Heikaldd52b452024-09-10 17:10:502320 'build/android/gyp/rename_java_classes.pydeps',
Andrew Grievee3a775ab2022-05-16 15:59:222321 'build/android/gyp/system_image_apks.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:102322 'build/android/gyp/trace_event_bytecode_rewriter.pydeps',
Andrew Grieve170b9782025-02-03 15:54:532323 'build/android/gyp/tracereferences.pydeps',
Peter Wen578730b2020-03-19 19:55:462324 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:302325 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:242326 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362327 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:462328 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:562329 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362330 'build/android/incremental_install/generate_android_manifest.pydeps',
2331 'build/android/incremental_install/write_installer_json.pydeps',
Stephanie Kim392913b452022-06-15 17:25:322332 'build/android/pylib/results/presentation/test_results_presentation.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042333 'build/android/resource_sizes.pydeps',
2334 'build/android/test_runner.pydeps',
2335 'build/android/test_wrapper/logdog_wrapper.pydeps',
zijiehe-google-com356980f2025-05-08 20:58:152336 'build/fuchsia/test/component_storage_test.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362337 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:322338 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:272339 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
2340 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Bailey Myers-Morganbd122132025-03-26 23:09:162341 'chrome/test/media_router/performance/performance_test.pydeps',
Junbo Kedcd3a452021-03-19 17:55:042342 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Mohannad Farrag19102742023-12-01 01:16:302343 'components/cronet/tools/check_combined_proguard_file.pydeps',
2344 'components/cronet/tools/generate_proguard_file.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002345 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382346 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002347 'content/public/android/generate_child_service.pydeps',
Hzj_jie77bdb802024-07-22 18:14:512348 'fuchsia_web/av_testing/av_sync_tests.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:182349 'testing/scripts/run_isolated_script_test.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:412350 'testing/merge_scripts/standard_isolated_script_merge.pydeps',
2351 'testing/merge_scripts/standard_gtest_merge.pydeps',
2352 'testing/merge_scripts/code_coverage/merge_results.pydeps',
2353 'testing/merge_scripts/code_coverage/merge_steps.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042354 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:422355 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
Yuki Shiino38eeaad12022-08-11 06:40:252356 'third_party/blink/renderer/bindings/scripts/check_generated_file_list.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:422357 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:132358 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Yuki Shiinoea477d32023-08-21 06:24:342359 'third_party/blink/renderer/bindings/scripts/generate_event_interface_names.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:502360 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:412361 'third_party/blink/tools/blinkpy/web_tests/merge_results.pydeps',
2362 'third_party/blink/tools/merge_web_test_results.pydeps',
John Budorickbc3571aa2019-04-25 02:20:062363 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:222364 'tools/binary_size/supersize.pydeps',
Peter Wen2dcfa6e2025-03-04 22:42:522365 'tools/cygprofile/generate_orderfile.pydeps',
Ben Pastene028104a2022-08-10 19:17:452366 'tools/perf/process_perf_results.pydeps',
Peter Wence103e12024-10-09 19:23:512367 'tools/pgo/generate_profile.pydeps',
agrievef32bcc72016-04-04 14:57:402368]
2369
2370_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
2371
Eric Boren6fd2b932018-01-25 15:05:082372# Bypass the AUTHORS check for these accounts.
Daniel Cheng6303eed2025-05-03 00:12:332373_KNOWN_ROBOTS = set() | set('%[email protected]' % s for s in (
2374 'findit-for-me', 'luci-bisection', 'predator-for-me-staging',
2375 'predator-for-me')) | set(
2376 '%[email protected]' % s
2377 for s in ('3su6n15k.default', )) | set(
2378 '%[email protected]' % s
2379 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Nate Fischer2d62ecf2025-08-01 19:31:302380 'wpt-autoroller', 'skylab-test-cros-roller',
2381 'infra-try-recipes-tester',
Daniel Cheng6303eed2025-05-03 00:12:332382 'chrome-automated-expectation',
2383 'chromium-automated-expectation', 'chrome-branch-day',
2384 'chrome-cherry-picker', 'chromium-autosharder')
2385 ) | set(
2386 '%[email protected]' % s
2387 for s in ('chromium-autoroll', 'chromium-release-autoroll')) | set(
John Chen19d466b72025-08-08 16:47:372388 '%[email protected]' % s
2389 for s in ('pinpoint-worker',)
2390 ) | set(
Daniel Cheng6303eed2025-05-03 00:12:332391 '%[email protected]' % s
2392 for s in ('chromium-internal-autoroll', )
2393 ) | set(
2394 '%[email protected]' %
2395 s for s in ('chrome-screen-ai-releaser', 'crash-eng', 'crash')
2396 ) | set(
2397 '%[email protected]' % s
2398 for s in ('swarming-tasks', )) | set(
2399 '%[email protected]' % s
2400 for s in ('global-integration-try-builder',
Rachael Newitte5664ef92025-05-08 14:00:232401 'global-integration-ci-builder')
2402 ) | set('%[email protected]' % s for s in (
2403 'chops-security-borg',
2404 'chops-security-cronjobs-cpesuggest')) | set(
2405 '%[email protected]' % s
Joey Scarrf55d5c42025-07-07 22:03:062406 for s in ('chromeos-ci-release', )) | set(
2407 '%[email protected]' % s
2408 for s in ('chromeos-ci-prod', ))
Eric Boren6fd2b932018-01-25 15:05:082409
Daniel Cheng6303eed2025-05-03 00:12:332410_INVALID_GRD_FILE_LINE = [(r'<file lang=.* path=.*',
2411 'Path should come before lang in GRD files.')]
2412
Eric Boren6fd2b932018-01-25 15:05:082413
Daniel Bratell65b033262019-04-23 08:17:062414def _IsCPlusPlusFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502415 """Returns True if this file contains C++-like code (and not Python,
2416 Go, Java, MarkDown, ...)"""
Daniel Bratell65b033262019-04-23 08:17:062417
Sam Maiera6e76d72022-02-11 21:43:502418 ext = input_api.os_path.splitext(file_path)[1]
2419 # This list is compatible with CppChecker.IsCppFile but we should
2420 # consider adding ".c" to it. If we do that we can use this function
2421 # at more places in the code.
2422 return ext in (
2423 '.h',
2424 '.cc',
2425 '.cpp',
2426 '.m',
2427 '.mm',
2428 )
2429
Daniel Bratell65b033262019-04-23 08:17:062430
2431def _IsCPlusPlusHeaderFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502432 return input_api.os_path.splitext(file_path)[1] == ".h"
Daniel Bratell65b033262019-04-23 08:17:062433
2434
2435def _IsJavaFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502436 return input_api.os_path.splitext(file_path)[1] == ".java"
Daniel Bratell65b033262019-04-23 08:17:062437
2438
2439def _IsProtoFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502440 return input_api.os_path.splitext(file_path)[1] == ".proto"
Daniel Bratell65b033262019-04-23 08:17:062441
Mohamed Heikal5e5b7922020-10-29 18:57:592442
Erik Staabc734cd7a2021-11-23 03:11:522443def _IsXmlOrGrdFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502444 ext = input_api.os_path.splitext(file_path)[1]
2445 return ext in ('.grd', '.xml')
Erik Staabc734cd7a2021-11-23 03:11:522446
2447
Sven Zheng76a79ea2022-12-21 21:25:242448def _IsMojomFile(input_api, file_path):
2449 return input_api.os_path.splitext(file_path)[1] == ".mojom"
2450
2451
Mohamed Heikal5e5b7922020-10-29 18:57:592452def CheckNoUpstreamDepsOnClank(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502453 """Prevent additions of dependencies from the upstream repo on //clank."""
2454 # clank can depend on clank
2455 if input_api.change.RepositoryRoot().endswith('clank'):
2456 return []
2457 build_file_patterns = [
2458 r'(.+/)?BUILD\.gn',
2459 r'.+\.gni',
2460 ]
2461 excluded_files = [r'build[/\\]config[/\\]android[/\\]config\.gni']
2462 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
Mohamed Heikal5e5b7922020-10-29 18:57:592463
Sam Maiera6e76d72022-02-11 21:43:502464 error_message = 'Disallowed import on //clank in an upstream build file:'
Mohamed Heikal5e5b7922020-10-29 18:57:592465
Sam Maiera6e76d72022-02-11 21:43:502466 def FilterFile(affected_file):
2467 return input_api.FilterSourceFile(affected_file,
2468 files_to_check=build_file_patterns,
2469 files_to_skip=excluded_files)
Mohamed Heikal5e5b7922020-10-29 18:57:592470
Sam Maiera6e76d72022-02-11 21:43:502471 problems = []
2472 for f in input_api.AffectedSourceFiles(FilterFile):
2473 local_path = f.LocalPath()
2474 for line_number, line in f.ChangedContents():
2475 if (bad_pattern.search(line)):
2476 problems.append('%s:%d\n %s' %
2477 (local_path, line_number, line.strip()))
2478 if problems:
2479 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
2480 else:
2481 return []
Mohamed Heikal5e5b7922020-10-29 18:57:592482
2483
Saagar Sanghavifceeaae2020-08-12 16:40:362484def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502485 """Attempts to prevent use of functions intended only for testing in
2486 non-testing code. For now this is just a best-effort implementation
2487 that ignores header files and may have some false positives. A
2488 better implementation would probably need a proper C++ parser.
2489 """
2490 # We only scan .cc files and the like, as the declaration of
2491 # for-testing functions in header files are hard to distinguish from
2492 # calls to such functions without a proper C++ parser.
2493 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:192494
Sam Maiera6e76d72022-02-11 21:43:502495 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
2496 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' %
2497 base_function_pattern)
2498 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
2499 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
2500 exclusion_pattern = input_api.re.compile(
2501 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' %
2502 (base_function_pattern, base_function_pattern))
2503 # Avoid a false positive in this case, where the method name, the ::, and
2504 # the closing { are all on different lines due to line wrapping.
2505 # HelperClassForTesting::
2506 # HelperClassForTesting(
2507 # args)
2508 # : member(0) {}
2509 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:192510
Sam Maiera6e76d72022-02-11 21:43:502511 def FilterFile(affected_file):
2512 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2513 input_api.DEFAULT_FILES_TO_SKIP)
2514 return input_api.FilterSourceFile(
2515 affected_file,
2516 files_to_check=file_inclusion_pattern,
2517 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:192518
Sam Maiera6e76d72022-02-11 21:43:502519 problems = []
2520 for f in input_api.AffectedSourceFiles(FilterFile):
2521 local_path = f.LocalPath()
2522 in_method_defn = False
2523 for line_number, line in f.ChangedContents():
2524 if (inclusion_pattern.search(line)
2525 and not comment_pattern.search(line)
2526 and not exclusion_pattern.search(line)
2527 and not allowlist_pattern.search(line)
2528 and not in_method_defn):
2529 problems.append('%s:%d\n %s' %
2530 (local_path, line_number, line.strip()))
2531 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:192532
Sam Maiera6e76d72022-02-11 21:43:502533 if problems:
2534 return [
2535 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
2536 ]
2537 else:
2538 return []
[email protected]55459852011-08-10 15:17:192539
2540
Saagar Sanghavifceeaae2020-08-12 16:40:362541def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502542 """This is a simplified version of
2543 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
2544 """
2545 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
2546 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
2547 name_pattern = r'ForTest(s|ing)?'
2548 # Describes an occurrence of "ForTest*" inside a // comment.
2549 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
2550 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
2551 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
2552 # Catch calls.
2553 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
2554 # Ignore definitions. (Comments are ignored separately.)
2555 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
Andrew Grieve40f451d2023-07-06 19:46:512556 allowlist_re = input_api.re.compile(r'// IN-TEST$')
Vaclav Brozek7dbc28c2018-03-27 08:35:232557
Sam Maiera6e76d72022-02-11 21:43:502558 problems = []
2559 sources = lambda x: input_api.FilterSourceFile(
2560 x,
Daniel Cheng6303eed2025-05-03 00:12:332561 files_to_skip=(
2562 ('(?i).*test', r'.*\/junit\/') + input_api.DEFAULT_FILES_TO_SKIP),
Sam Maiera6e76d72022-02-11 21:43:502563 files_to_check=[r'.*\.java$'])
2564 for f in input_api.AffectedFiles(include_deletes=False,
2565 file_filter=sources):
2566 local_path = f.LocalPath()
Vaclav Brozek7dbc28c2018-03-27 08:35:232567 is_inside_javadoc = False
Sam Maiera6e76d72022-02-11 21:43:502568 for line_number, line in f.ChangedContents():
2569 if is_inside_javadoc and javadoc_end_re.search(line):
2570 is_inside_javadoc = False
2571 if not is_inside_javadoc and javadoc_start_re.search(line):
2572 is_inside_javadoc = True
2573 if is_inside_javadoc:
2574 continue
2575 if (inclusion_re.search(line) and not comment_re.search(line)
2576 and not annotation_re.search(line)
Andrew Grieve40f451d2023-07-06 19:46:512577 and not allowlist_re.search(line)
Sam Maiera6e76d72022-02-11 21:43:502578 and not exclusion_re.search(line)):
2579 problems.append('%s:%d\n %s' %
2580 (local_path, line_number, line.strip()))
Vaclav Brozek7dbc28c2018-03-27 08:35:232581
Sam Maiera6e76d72022-02-11 21:43:502582 if problems:
2583 return [
2584 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
2585 ]
2586 else:
2587 return []
Vaclav Brozek7dbc28c2018-03-27 08:35:232588
2589
Saagar Sanghavifceeaae2020-08-12 16:40:362590def CheckNoIOStreamInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502591 """Checks to make sure no .h files include <iostream>."""
2592 files = []
2593 pattern = input_api.re.compile(r'^#include\s*<iostream>',
2594 input_api.re.MULTILINE)
2595 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2596 if not f.LocalPath().endswith('.h'):
2597 continue
2598 contents = input_api.ReadFile(f)
2599 if pattern.search(contents):
2600 files.append(f)
[email protected]10689ca2011-09-02 02:31:542601
Sam Maiera6e76d72022-02-11 21:43:502602 if len(files):
2603 return [
2604 output_api.PresubmitError(
2605 'Do not #include <iostream> in header files, since it inserts static '
2606 'initialization into every file including the header. Instead, '
2607 '#include <ostream>. See http://crbug.com/94794', files)
2608 ]
2609 return []
2610
[email protected]10689ca2011-09-02 02:31:542611
Aleksey Khoroshilov9b28c032022-06-03 16:35:322612def CheckNoStrCatRedefines(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502613 """Checks no windows headers with StrCat redefined are included directly."""
2614 files = []
Aleksey Khoroshilov9b28c032022-06-03 16:35:322615 files_to_check = (r'.+%s' % _HEADER_EXTENSIONS,
2616 r'.+%s' % _IMPLEMENTATION_EXTENSIONS)
2617 files_to_skip = (input_api.DEFAULT_FILES_TO_SKIP +
2618 _NON_BASE_DEPENDENT_PATHS)
2619 sources_filter = lambda f: input_api.FilterSourceFile(
2620 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
2621
Sam Maiera6e76d72022-02-11 21:43:502622 pattern_deny = input_api.re.compile(
2623 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
2624 input_api.re.MULTILINE)
2625 pattern_allow = input_api.re.compile(
2626 r'^#include\s"base/win/windows_defines.inc"', input_api.re.MULTILINE)
Aleksey Khoroshilov9b28c032022-06-03 16:35:322627 for f in input_api.AffectedSourceFiles(sources_filter):
Sam Maiera6e76d72022-02-11 21:43:502628 contents = input_api.ReadFile(f)
2629 if pattern_deny.search(
2630 contents) and not pattern_allow.search(contents):
2631 files.append(f.LocalPath())
Danil Chapovalov3518f362018-08-11 16:13:432632
Sam Maiera6e76d72022-02-11 21:43:502633 if len(files):
2634 return [
2635 output_api.PresubmitError(
2636 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
2637 'directly since they pollute code with StrCat macro. Instead, '
2638 'include matching header from base/win. See http://crbug.com/856536',
2639 files)
2640 ]
2641 return []
Danil Chapovalov3518f362018-08-11 16:13:432642
[email protected]10689ca2011-09-02 02:31:542643
Andrew Williamsc9f69b482023-07-10 16:07:362644def _CheckNoUNIT_TESTInSourceFiles(input_api, f):
2645 problems = []
2646
2647 unit_test_macro = input_api.re.compile(
Daniel Cheng6303eed2025-05-03 00:12:332648 r'^\s*#.*(?:ifn?def\s+UNIT_TEST|defined\s*\(?\s*UNIT_TEST\s*\)?)(?:$|\s+)'
2649 )
Andrew Williamsc9f69b482023-07-10 16:07:362650 for line_num, line in f.ChangedContents():
2651 if unit_test_macro.match(line):
2652 problems.append(' %s:%d' % (f.LocalPath(), line_num))
2653
2654 return problems
2655
2656
Saagar Sanghavifceeaae2020-08-12 16:40:362657def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502658 """Checks to make sure no source files use UNIT_TEST."""
2659 problems = []
2660 for f in input_api.AffectedFiles():
2661 if (not f.LocalPath().endswith(('.cc', '.mm'))):
2662 continue
Daniel Cheng6303eed2025-05-03 00:12:332663 problems.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, f))
[email protected]72df4e782012-06-21 16:28:182664
Sam Maiera6e76d72022-02-11 21:43:502665 if not problems:
2666 return []
2667 return [
2668 output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
2669 '\n'.join(problems))
2670 ]
2671
[email protected]72df4e782012-06-21 16:28:182672
Saagar Sanghavifceeaae2020-08-12 16:40:362673def CheckNoDISABLETypoInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502674 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
Dominic Battre033531052018-09-24 15:45:342675
Sam Maiera6e76d72022-02-11 21:43:502676 This test warns if somebody tries to disable a test with the DISABLE_ prefix
2677 instead of DISABLED_. To filter false positives, reports are only generated
2678 if a corresponding MAYBE_ line exists.
2679 """
2680 problems = []
Dominic Battre033531052018-09-24 15:45:342681
Sam Maiera6e76d72022-02-11 21:43:502682 # The following two patterns are looked for in tandem - is a test labeled
2683 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
2684 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
2685 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
Dominic Battre033531052018-09-24 15:45:342686
Sam Maiera6e76d72022-02-11 21:43:502687 # This is for the case that a test is disabled on all platforms.
2688 full_disable_pattern = input_api.re.compile(
2689 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
2690 input_api.re.MULTILINE)
Dominic Battre033531052018-09-24 15:45:342691
Arthur Sonzognic66e9c82024-04-23 07:53:042692 for f in input_api.AffectedFiles(include_deletes=False):
Sam Maiera6e76d72022-02-11 21:43:502693 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2694 continue
Dominic Battre033531052018-09-24 15:45:342695
Arthur Sonzognic66e9c82024-04-23 07:53:042696 # Search for MAYBE_, DISABLE_ pairs.
Sam Maiera6e76d72022-02-11 21:43:502697 disable_lines = {} # Maps of test name to line number.
2698 maybe_lines = {}
2699 for line_num, line in f.ChangedContents():
2700 disable_match = disable_pattern.search(line)
2701 if disable_match:
2702 disable_lines[disable_match.group(1)] = line_num
2703 maybe_match = maybe_pattern.search(line)
2704 if maybe_match:
2705 maybe_lines[maybe_match.group(1)] = line_num
Dominic Battre033531052018-09-24 15:45:342706
Sam Maiera6e76d72022-02-11 21:43:502707 # Search for DISABLE_ occurrences within a TEST() macro.
2708 disable_tests = set(disable_lines.keys())
2709 maybe_tests = set(maybe_lines.keys())
2710 for test in disable_tests.intersection(maybe_tests):
2711 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
Dominic Battre033531052018-09-24 15:45:342712
Sam Maiera6e76d72022-02-11 21:43:502713 contents = input_api.ReadFile(f)
2714 full_disable_match = full_disable_pattern.search(contents)
2715 if full_disable_match:
2716 problems.append(' %s' % f.LocalPath())
Dominic Battre033531052018-09-24 15:45:342717
Sam Maiera6e76d72022-02-11 21:43:502718 if not problems:
2719 return []
2720 return [
2721 output_api.PresubmitPromptWarning(
2722 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
2723 '\n'.join(problems))
2724 ]
2725
Dominic Battre033531052018-09-24 15:45:342726
Nina Satragnof7660532021-09-20 18:03:352727def CheckForgettingMAYBEInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502728 """Checks to make sure tests disabled conditionally are not missing a
2729 corresponding MAYBE_ prefix.
2730 """
2731 # Expect at least a lowercase character in the test name. This helps rule out
2732 # false positives with macros wrapping the actual tests name.
2733 define_maybe_pattern = input_api.re.compile(
2734 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
Bruce Dawsonffc55292022-04-20 04:18:192735 # The test_maybe_pattern needs to handle all of these forms. The standard:
2736 # IN_PROC_TEST_F(SyncTest, MAYBE_Start) {
2737 # With a wrapper macro around the test name:
2738 # IN_PROC_TEST_F(SyncTest, E2E_ENABLED(MAYBE_Start)) {
Bruce Dawsonffc55292022-04-20 04:18:192739 # The optional E2E_ENABLED-style is handled with (\w*\()?
Bruce Dawsonffc55292022-04-20 04:18:192740 test_maybe_pattern = (
Fabian Sommera32b77a2025-07-23 12:41:202741 r'^\s*\w*TEST[^(]*\(\s*\w+,\s*(\w*\()?MAYBE_{test_name}')
2742 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}'
Sam Maiera6e76d72022-02-11 21:43:502743 warnings = []
Nina Satragnof7660532021-09-20 18:03:352744
Sam Maiera6e76d72022-02-11 21:43:502745 # Read the entire files. We can't just read the affected lines, forgetting to
2746 # add MAYBE_ on a change would not show up otherwise.
Arthur Sonzognic66e9c82024-04-23 07:53:042747 for f in input_api.AffectedFiles(include_deletes=False):
Sam Maiera6e76d72022-02-11 21:43:502748 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2749 continue
2750 contents = input_api.ReadFile(f)
2751 lines = contents.splitlines(True)
2752 current_position = 0
2753 warning_test_names = set()
2754 for line_num, line in enumerate(lines, start=1):
2755 current_position += len(line)
2756 maybe_match = define_maybe_pattern.search(line)
2757 if maybe_match:
2758 test_name = maybe_match.group('test_name')
2759 # Do not warn twice for the same test.
2760 if (test_name in warning_test_names):
2761 continue
2762 warning_test_names.add(test_name)
Nina Satragnof7660532021-09-20 18:03:352763
Sam Maiera6e76d72022-02-11 21:43:502764 # Attempt to find the corresponding MAYBE_ test or suite, starting from
2765 # the current position.
2766 test_match = input_api.re.compile(
2767 test_maybe_pattern.format(test_name=test_name),
2768 input_api.re.MULTILINE).search(contents, current_position)
2769 suite_match = input_api.re.compile(
2770 suite_maybe_pattern.format(test_name=test_name),
2771 input_api.re.MULTILINE).search(contents, current_position)
2772 if not test_match and not suite_match:
2773 warnings.append(
2774 output_api.PresubmitPromptWarning(
2775 '%s:%d found MAYBE_ defined without corresponding test %s'
2776 % (f.LocalPath(), line_num, test_name)))
2777 return warnings
2778
[email protected]72df4e782012-06-21 16:28:182779
Saagar Sanghavifceeaae2020-08-12 16:40:362780def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502781 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
2782 errors = []
Kalvin Lee4a3b79de2022-05-26 16:00:162783 pattern = input_api.re.compile(r'\bDCHECK_IS_ON\b(?!\(\))',
Sam Maiera6e76d72022-02-11 21:43:502784 input_api.re.MULTILINE)
2785 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2786 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
2787 continue
2788 for lnum, line in f.ChangedContents():
2789 if input_api.re.search(pattern, line):
2790 errors.append(
2791 output_api.PresubmitError((
2792 '%s:%d: Use of DCHECK_IS_ON() must be written as "#if '
2793 + 'DCHECK_IS_ON()", not forgetting the parentheses.') %
2794 (f.LocalPath(), lnum)))
2795 return errors
danakj61c1aa22015-10-26 19:55:522796
2797
Weilun Shia487fad2020-10-28 00:10:342798# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
2799# more reliable way. See
2800# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:192801
wnwenbdc444e2016-05-25 13:44:152802
Saagar Sanghavifceeaae2020-08-12 16:40:362803def CheckFlakyTestUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502804 """Check that FlakyTest annotation is our own instead of the android one"""
2805 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
2806 files = []
2807 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2808 if f.LocalPath().endswith('Test.java'):
2809 if pattern.search(input_api.ReadFile(f)):
2810 files.append(f)
2811 if len(files):
2812 return [
2813 output_api.PresubmitError(
2814 'Use org.chromium.base.test.util.FlakyTest instead of '
2815 'android.test.FlakyTest', files)
2816 ]
2817 return []
mcasasb7440c282015-02-04 14:52:192818
wnwenbdc444e2016-05-25 13:44:152819
Saagar Sanghavifceeaae2020-08-12 16:40:362820def CheckNoDEPSGIT(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502821 """Make sure .DEPS.git is never modified manually."""
2822 if any(f.LocalPath().endswith('.DEPS.git')
2823 for f in input_api.AffectedFiles()):
2824 return [
2825 output_api.PresubmitError(
2826 'Never commit changes to .DEPS.git. This file is maintained by an\n'
2827 'automated system based on what\'s in DEPS and your changes will be\n'
2828 'overwritten.\n'
2829 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
2830 'get-the-code#Rolling_DEPS\n'
2831 'for more information')
2832 ]
2833 return []
[email protected]2a8ac9c2011-10-19 17:20:442834
2835
Sven Zheng76a79ea2022-12-21 21:25:242836def CheckCrosApiNeedBrowserTest(input_api, output_api):
2837 """Check new crosapi should add browser test."""
2838 has_new_crosapi = False
2839 has_browser_test = False
2840 for f in input_api.AffectedFiles():
Anton Bershanskyi4253349482025-02-11 21:01:272841 path = f.UnixLocalPath()
Daniel Cheng6303eed2025-05-03 00:12:332842 if (path.startswith('chromeos/crosapi/mojom')
2843 and _IsMojomFile(input_api, path) and f.Action() == 'A'):
Sven Zheng76a79ea2022-12-21 21:25:242844 has_new_crosapi = True
2845 if path.endswith('browsertest.cc') or path.endswith('browser_test.cc'):
2846 has_browser_test = True
2847 if has_new_crosapi and not has_browser_test:
2848 return [
2849 output_api.PresubmitPromptWarning(
2850 'You are adding a new crosapi, but there is no file ends with '
2851 'browsertest.cc file being added or modified. It is important '
2852 'to add crosapi browser test coverage to avoid version '
2853 ' skew issues.\n'
2854 'Check //docs/lacros/test_instructions.md for more information.'
Daniel Cheng6303eed2025-05-03 00:12:332855 )
Sven Zheng76a79ea2022-12-21 21:25:242856 ]
2857 return []
2858
2859
Mario Sanchez Prada2472cab2019-09-18 10:58:312860def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152861 ban_rule):
Allen Bauer84778682022-09-22 16:28:562862 """Helper method for checking for banned constructs.
Mario Sanchez Prada2472cab2019-09-18 10:58:312863
Sam Maiera6e76d72022-02-11 21:43:502864 Returns an string composed of the name of the file, the line number where the
2865 match has been found and the additional text passed as |message| in case the
2866 target type name matches the text inside the line passed as parameter.
2867 """
2868 result = []
Peng Huang9c5949a02020-06-11 19:20:542869
Daniel Chenga44a1bcd2022-03-15 20:00:152870 # Ignore comments about banned types.
2871 if input_api.re.search(r"^ *//", line):
Sam Maiera6e76d72022-02-11 21:43:502872 return result
Daniel Chenga44a1bcd2022-03-15 20:00:152873 # A // nocheck comment will bypass this error.
2874 if line.endswith(" nocheck"):
Sam Maiera6e76d72022-02-11 21:43:502875 return result
2876
2877 matched = False
Daniel Chenga44a1bcd2022-03-15 20:00:152878 if ban_rule.pattern[0:1] == '/':
2879 regex = ban_rule.pattern[1:]
Sam Maiera6e76d72022-02-11 21:43:502880 if input_api.re.search(regex, line):
2881 matched = True
Daniel Chenga44a1bcd2022-03-15 20:00:152882 elif ban_rule.pattern in line:
Sam Maiera6e76d72022-02-11 21:43:502883 matched = True
2884
2885 if matched:
2886 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
Daniel Chenga44a1bcd2022-03-15 20:00:152887 for line in ban_rule.explanation:
2888 result.append(' %s' % line)
Sam Maiera6e76d72022-02-11 21:43:502889
danakjd18e8892020-12-17 17:42:012890 return result
Mario Sanchez Prada2472cab2019-09-18 10:58:312891
2892
Saagar Sanghavifceeaae2020-08-12 16:40:362893def CheckNoBannedFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502894 """Make sure that banned functions are not used."""
Daniel Cheng6303eed2025-05-03 00:12:332895 results = []
[email protected]127f18ec2012-06-16 05:05:592896
Sam Maiera6e76d72022-02-11 21:43:502897 def IsExcludedFile(affected_file, excluded_paths):
Daniel Chenga44a1bcd2022-03-15 20:00:152898 if not excluded_paths:
2899 return False
2900
Anton Bershanskyi4253349482025-02-11 21:01:272901 local_path = affected_file.UnixLocalPath()
Sam Maiera6e76d72022-02-11 21:43:502902 for item in excluded_paths:
2903 if input_api.re.match(item, local_path):
2904 return True
2905 return False
wnwenbdc444e2016-05-25 13:44:152906
Sam Maiera6e76d72022-02-11 21:43:502907 def IsIosObjcFile(affected_file):
2908 local_path = affected_file.LocalPath()
2909 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m',
2910 '.h'):
2911 return False
2912 basename = input_api.os_path.basename(local_path)
2913 if 'ios' in basename.split('_'):
2914 return True
2915 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
2916 if sep and 'ios' in local_path.split(sep):
2917 return True
2918 return False
Sylvain Defresnea8b73d252018-02-28 15:45:542919
Daniel Chenga44a1bcd2022-03-15 20:00:152920 def CheckForMatch(affected_file, line_num: int, line: str,
2921 ban_rule: BanRule):
2922 if IsExcludedFile(affected_file, ban_rule.excluded_paths):
2923 return
2924
Ben Pastenee79d66112025-04-23 19:46:152925 message = _GetMessageForMatchingType(input_api, f, line_num, line,
2926 ban_rule)
2927 if message:
2928 result_loc = []
2929 if ban_rule.surface_as_gerrit_lint:
Daniel Cheng6303eed2025-05-03 00:12:332930 result_loc.append(
2931 output_api.PresubmitResultLocation(
2932 file_path=affected_file.LocalPath(),
2933 start_line=line_num,
2934 end_line=line_num,
2935 ))
Daniel Chenga44a1bcd2022-03-15 20:00:152936 if ban_rule.treat_as_error is not None and ban_rule.treat_as_error:
Ben Pastenee79d66112025-04-23 19:46:152937 results.append(
2938 output_api.PresubmitError('A banned function was used.\n' +
2939 '\n'.join(message),
2940 locations=result_loc))
2941
Sam Maiera6e76d72022-02-11 21:43:502942 else:
Ben Pastenee79d66112025-04-23 19:46:152943 results.append(
Daniel Cheng6303eed2025-05-03 00:12:332944 output_api.PresubmitPromptWarning(
2945 'A banned function was used.\n' + '\n'.join(message),
2946 locations=result_loc))
wnwenbdc444e2016-05-25 13:44:152947
Sam Maiera6e76d72022-02-11 21:43:502948 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2949 for f in input_api.AffectedFiles(file_filter=file_filter):
2950 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152951 for ban_rule in _BANNED_JAVA_FUNCTIONS:
2952 CheckForMatch(f, line_num, line, ban_rule)
Eric Stevensona9a980972017-09-23 00:04:412953
Clement Yan9b330cb2022-11-17 05:25:292954 file_filter = lambda f: f.LocalPath().endswith(('.js', '.ts'))
2955 for f in input_api.AffectedFiles(file_filter=file_filter):
2956 for line_num, line in f.ChangedContents():
2957 for ban_rule in _BANNED_JAVASCRIPT_FUNCTIONS:
2958 CheckForMatch(f, line_num, line, ban_rule)
2959
Sam Maiera6e76d72022-02-11 21:43:502960 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
2961 for f in input_api.AffectedFiles(file_filter=file_filter):
2962 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152963 for ban_rule in _BANNED_OBJC_FUNCTIONS:
2964 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:592965
Sam Maiera6e76d72022-02-11 21:43:502966 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
2967 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152968 for ban_rule in _BANNED_IOS_OBJC_FUNCTIONS:
2969 CheckForMatch(f, line_num, line, ban_rule)
Sylvain Defresnea8b73d252018-02-28 15:45:542970
Sam Maiera6e76d72022-02-11 21:43:502971 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
2972 for f in input_api.AffectedFiles(file_filter=egtest_filter):
2973 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152974 for ban_rule in _BANNED_IOS_EGTEST_FUNCTIONS:
2975 CheckForMatch(f, line_num, line, ban_rule)
Peter K. Lee6c03ccff2019-07-15 14:40:052976
Sam Maiera6e76d72022-02-11 21:43:502977 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
2978 for f in input_api.AffectedFiles(file_filter=file_filter):
2979 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152980 for ban_rule in _BANNED_CPP_FUNCTIONS:
2981 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:592982
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152983 # As of 05/2024, iOS fully migrated ConsentLevel::kSync to kSignin, and
2984 # Android is in the process of preventing new users from entering kSync.
2985 # So the warning is restricted to those platforms.
Riley Wong49be8a882025-02-27 00:38:232986 ios_pattern = input_api.re.compile(r'(^|[\W_])ios[\W_]')
Daniel Cheng6303eed2025-05-03 00:12:332987 file_filter = lambda f: (
2988 f.LocalPath().endswith(('.cc', '.mm', '.h')) and
2989 ('android' in f.LocalPath() or
2990 # Simply checking for an 'ios' substring would
2991 # catch unrelated cases, use a regex.
2992 ios_pattern.search(f.LocalPath())))
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152993 for f in input_api.AffectedFiles(file_filter=file_filter):
2994 for line_num, line in f.ChangedContents():
2995 for ban_rule in _DEPRECATED_SYNC_CONSENT_CPP_FUNCTIONS:
2996 CheckForMatch(f, line_num, line, ban_rule)
2997
2998 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2999 for f in input_api.AffectedFiles(file_filter=file_filter):
3000 for line_num, line in f.ChangedContents():
3001 for ban_rule in _DEPRECATED_SYNC_CONSENT_JAVA_FUNCTIONS:
3002 CheckForMatch(f, line_num, line, ban_rule)
3003
Daniel Cheng92c15e32022-03-16 17:48:223004 file_filter = lambda f: f.LocalPath().endswith(('.mojom'))
3005 for f in input_api.AffectedFiles(file_filter=file_filter):
3006 for line_num, line in f.ChangedContents():
3007 for ban_rule in _BANNED_MOJOM_PATTERNS:
3008 CheckForMatch(f, line_num, line, ban_rule)
3009
Ben Pastenee79d66112025-04-23 19:46:153010 return results
Daniel Cheng92c15e32022-03-16 17:48:223011
[email protected]127f18ec2012-06-16 05:05:593012
Michael Thiessen44457642020-02-06 00:24:153013def _CheckAndroidNoBannedImports(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503014 """Make sure that banned java imports are not used."""
3015 errors = []
Michael Thiessen44457642020-02-06 00:24:153016
Sam Maiera6e76d72022-02-11 21:43:503017 file_filter = lambda f: f.LocalPath().endswith(('.java'))
3018 for f in input_api.AffectedFiles(file_filter=file_filter):
3019 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:153020 for ban_rule in _BANNED_JAVA_IMPORTS:
3021 # Consider merging this into the above function. There is no
3022 # real difference anymore other than helping with a little
3023 # bit of boilerplate text. Doing so means things like
3024 # `treat_as_error` will also be uniformly handled.
Sam Maiera6e76d72022-02-11 21:43:503025 problems = _GetMessageForMatchingType(input_api, f, line_num,
Daniel Chenga44a1bcd2022-03-15 20:00:153026 line, ban_rule)
Sam Maiera6e76d72022-02-11 21:43:503027 if problems:
3028 errors.extend(problems)
3029 result = []
3030 if (errors):
3031 result.append(
3032 output_api.PresubmitError('Banned imports were used.\n' +
3033 '\n'.join(errors)))
3034 return result
Michael Thiessen44457642020-02-06 00:24:153035
3036
Saagar Sanghavifceeaae2020-08-12 16:40:363037def CheckNoPragmaOnce(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503038 """Make sure that banned functions are not used."""
3039 files = []
3040 pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
3041 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
3042 if not f.LocalPath().endswith('.h'):
3043 continue
Bruce Dawson4c4c2922022-05-02 18:07:333044 if f.LocalPath().endswith('com_imported_mstscax.h'):
3045 continue
Sam Maiera6e76d72022-02-11 21:43:503046 contents = input_api.ReadFile(f)
3047 if pattern.search(contents):
3048 files.append(f)
[email protected]6c063c62012-07-11 19:11:063049
Sam Maiera6e76d72022-02-11 21:43:503050 if files:
3051 return [
3052 output_api.PresubmitError(
3053 'Do not use #pragma once in header files.\n'
3054 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
3055 files)
3056 ]
3057 return []
[email protected]6c063c62012-07-11 19:11:063058
[email protected]127f18ec2012-06-16 05:05:593059
Saagar Sanghavifceeaae2020-08-12 16:40:363060def CheckNoTrinaryTrueFalse(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503061 """Checks to make sure we don't introduce use of foo ? true : false."""
3062 problems = []
3063 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
3064 for f in input_api.AffectedFiles():
3065 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
3066 continue
[email protected]e7479052012-09-19 00:26:123067
Sam Maiera6e76d72022-02-11 21:43:503068 for line_num, line in f.ChangedContents():
3069 if pattern.match(line):
3070 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]e7479052012-09-19 00:26:123071
Sam Maiera6e76d72022-02-11 21:43:503072 if not problems:
3073 return []
3074 return [
3075 output_api.PresubmitPromptWarning(
3076 'Please consider avoiding the "? true : false" pattern if possible.\n'
3077 + '\n'.join(problems))
3078 ]
[email protected]e7479052012-09-19 00:26:123079
3080
Saagar Sanghavifceeaae2020-08-12 16:40:363081def CheckUnwantedDependencies(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503082 """Runs checkdeps on #include and import statements added in this
3083 change. Breaking - rules is an error, breaking ! rules is a
3084 warning.
3085 """
3086 # Return early if no relevant file types were modified.
3087 for f in input_api.AffectedFiles():
3088 path = f.LocalPath()
3089 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path)
3090 or _IsJavaFile(input_api, path)):
3091 break
[email protected]55f9f382012-07-31 11:02:183092 else:
Sam Maiera6e76d72022-02-11 21:43:503093 return []
rhalavati08acd232017-04-03 07:23:283094
Sam Maiera6e76d72022-02-11 21:43:503095 import sys
3096 # We need to wait until we have an input_api object and use this
3097 # roundabout construct to import checkdeps because this file is
3098 # eval-ed and thus doesn't have __file__.
3099 original_sys_path = sys.path
3100 try:
3101 sys.path = sys.path + [
3102 input_api.os_path.join(input_api.PresubmitLocalPath(),
3103 'buildtools', 'checkdeps')
3104 ]
3105 import checkdeps
3106 from rules import Rule
3107 finally:
3108 # Restore sys.path to what it was before.
3109 sys.path = original_sys_path
[email protected]55f9f382012-07-31 11:02:183110
Sam Maiera6e76d72022-02-11 21:43:503111 added_includes = []
3112 added_imports = []
3113 added_java_imports = []
3114 for f in input_api.AffectedFiles():
3115 if _IsCPlusPlusFile(input_api, f.LocalPath()):
3116 changed_lines = [line for _, line in f.ChangedContents()]
3117 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
3118 elif _IsProtoFile(input_api, f.LocalPath()):
3119 changed_lines = [line for _, line in f.ChangedContents()]
3120 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
3121 elif _IsJavaFile(input_api, f.LocalPath()):
3122 changed_lines = [line for _, line in f.ChangedContents()]
3123 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:243124
Sam Maiera6e76d72022-02-11 21:43:503125 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
3126
3127 error_descriptions = []
3128 warning_descriptions = []
3129 error_subjects = set()
3130 warning_subjects = set()
3131
3132 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
3133 added_includes):
3134 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3135 description_with_path = '%s\n %s' % (path, rule_description)
3136 if rule_type == Rule.DISALLOW:
3137 error_descriptions.append(description_with_path)
3138 error_subjects.add("#includes")
3139 else:
3140 warning_descriptions.append(description_with_path)
3141 warning_subjects.add("#includes")
3142
3143 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
3144 added_imports):
3145 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3146 description_with_path = '%s\n %s' % (path, rule_description)
3147 if rule_type == Rule.DISALLOW:
3148 error_descriptions.append(description_with_path)
3149 error_subjects.add("imports")
3150 else:
3151 warning_descriptions.append(description_with_path)
3152 warning_subjects.add("imports")
3153
3154 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
3155 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
3156 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3157 description_with_path = '%s\n %s' % (path, rule_description)
3158 if rule_type == Rule.DISALLOW:
3159 error_descriptions.append(description_with_path)
3160 error_subjects.add("imports")
3161 else:
3162 warning_descriptions.append(description_with_path)
3163 warning_subjects.add("imports")
3164
3165 results = []
3166 if error_descriptions:
3167 results.append(
3168 output_api.PresubmitError(
3169 'You added one or more %s that violate checkdeps rules.' %
3170 " and ".join(error_subjects), error_descriptions))
3171 if warning_descriptions:
3172 results.append(
3173 output_api.PresubmitPromptOrNotify(
3174 'You added one or more %s of files that are temporarily\n'
3175 'allowed but being removed. Can you avoid introducing the\n'
3176 '%s? See relevant DEPS file(s) for details and contacts.' %
3177 (" and ".join(warning_subjects), "/".join(warning_subjects)),
3178 warning_descriptions))
3179 return results
[email protected]55f9f382012-07-31 11:02:183180
3181
Saagar Sanghavifceeaae2020-08-12 16:40:363182def CheckFilePermissions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503183 """Check that all files have their permissions properly set."""
3184 if input_api.platform == 'win32':
3185 return []
3186 checkperms_tool = input_api.os_path.join(input_api.PresubmitLocalPath(),
3187 'tools', 'checkperms',
3188 'checkperms.py')
3189 args = [
Bruce Dawson8a43cf72022-05-13 17:10:323190 input_api.python3_executable, checkperms_tool, '--root',
Sam Maiera6e76d72022-02-11 21:43:503191 input_api.change.RepositoryRoot()
3192 ]
3193 with input_api.CreateTemporaryFile() as file_list:
3194 for f in input_api.AffectedFiles():
3195 # checkperms.py file/directory arguments must be relative to the
3196 # repository.
3197 file_list.write((f.LocalPath() + '\n').encode('utf8'))
3198 file_list.close()
3199 args += ['--file-list', file_list.name]
3200 try:
3201 input_api.subprocess.check_output(args)
3202 return []
3203 except input_api.subprocess.CalledProcessError as error:
3204 return [
3205 output_api.PresubmitError('checkperms.py failed:',
3206 long_text=error.output.decode(
3207 'utf-8', 'ignore'))
3208 ]
[email protected]fbcafe5a2012-08-08 15:31:223209
3210
Saagar Sanghavifceeaae2020-08-12 16:40:363211def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503212 """Makes sure we don't include ui/aura/window_property.h
3213 in header files.
3214 """
3215 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
3216 errors = []
3217 for f in input_api.AffectedFiles():
3218 if not f.LocalPath().endswith('.h'):
3219 continue
3220 for line_num, line in f.ChangedContents():
3221 if pattern.match(line):
3222 errors.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]c8278b32012-10-30 20:35:493223
Sam Maiera6e76d72022-02-11 21:43:503224 results = []
3225 if errors:
3226 results.append(
3227 output_api.PresubmitError(
3228 'Header files should not include ui/aura/window_property.h',
3229 errors))
3230 return results
[email protected]c8278b32012-10-30 20:35:493231
3232
Omer Katzcc77ea92021-04-26 10:23:283233def CheckNoInternalHeapIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503234 """Makes sure we don't include any headers from
3235 third_party/blink/renderer/platform/heap/impl or
3236 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
3237 third_party/blink/renderer/platform/heap
3238 """
3239 impl_pattern = input_api.re.compile(
3240 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
3241 v8_wrapper_pattern = input_api.re.compile(
3242 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"'
3243 )
3244 file_filter = lambda f: not input_api.re.match(
Daniel Cheng6303eed2025-05-03 00:12:333245 r"^third_party/blink/renderer/platform/heap/.*", f.UnixLocalPath())
Sam Maiera6e76d72022-02-11 21:43:503246 errors = []
Omer Katzcc77ea92021-04-26 10:23:283247
Sam Maiera6e76d72022-02-11 21:43:503248 for f in input_api.AffectedFiles(file_filter=file_filter):
3249 for line_num, line in f.ChangedContents():
3250 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
3251 errors.append(' %s:%d' % (f.LocalPath(), line_num))
Omer Katzcc77ea92021-04-26 10:23:283252
Sam Maiera6e76d72022-02-11 21:43:503253 results = []
3254 if errors:
3255 results.append(
3256 output_api.PresubmitError(
3257 'Do not include files from third_party/blink/renderer/platform/heap/impl'
3258 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
3259 'relevant counterparts from third_party/blink/renderer/platform/heap',
3260 errors))
3261 return results
Omer Katzcc77ea92021-04-26 10:23:283262
3263
[email protected]70ca77752012-11-20 03:45:033264def _CheckForVersionControlConflictsInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:503265 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
3266 errors = []
3267 for line_num, line in f.ChangedContents():
3268 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
3269 # First-level headers in markdown look a lot like version control
3270 # conflict markers. http://daringfireball.net/projects/markdown/basics
3271 continue
3272 if pattern.match(line):
3273 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
3274 return errors
[email protected]70ca77752012-11-20 03:45:033275
3276
Saagar Sanghavifceeaae2020-08-12 16:40:363277def CheckForVersionControlConflicts(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503278 """Usually this is not intentional and will cause a compile failure."""
3279 errors = []
3280 for f in input_api.AffectedFiles():
3281 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
[email protected]70ca77752012-11-20 03:45:033282
Sam Maiera6e76d72022-02-11 21:43:503283 results = []
3284 if errors:
3285 results.append(
3286 output_api.PresubmitError(
3287 'Version control conflict markers found, please resolve.',
3288 errors))
3289 return results
[email protected]70ca77752012-11-20 03:45:033290
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203291
Saagar Sanghavifceeaae2020-08-12 16:40:363292def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
Dirk Prankee4df27972025-02-26 18:39:353293 pattern = input_api.re.compile(r'support\.google\.com\/chrome.*/answer')
Sam Maiera6e76d72022-02-11 21:43:503294 errors = []
3295 for f in input_api.AffectedFiles():
3296 for line_num, line in f.ChangedContents():
3297 if pattern.search(line):
3298 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
estadee17314a02017-01-12 16:22:163299
Sam Maiera6e76d72022-02-11 21:43:503300 results = []
3301 if errors:
3302 results.append(
3303 output_api.PresubmitPromptWarning(
3304 'Found Google support URL addressed by answer number. Please replace '
3305 'with a p= identifier instead. See crbug.com/679462\n',
3306 errors))
3307 return results
estadee17314a02017-01-12 16:22:163308
[email protected]70ca77752012-11-20 03:45:033309
Saagar Sanghavifceeaae2020-08-12 16:40:363310def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
Daniel Cheng6303eed2025-05-03 00:12:333311
Sam Maiera6e76d72022-02-11 21:43:503312 def FilterFile(affected_file):
3313 """Filter function for use with input_api.AffectedSourceFiles,
3314 below. This filters out everything except non-test files from
3315 top-level directories that generally speaking should not hard-code
3316 service URLs (e.g. src/android_webview/, src/content/ and others).
3317 """
3318 return input_api.FilterSourceFile(
3319 affected_file,
Bruce Dawson40fece62022-09-16 19:58:313320 files_to_check=[r'^(android_webview|base|content|net)/.*'],
Sam Maiera6e76d72022-02-11 21:43:503321 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3322 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:443323
Dirk Prankee4df27972025-02-26 18:39:353324 base_pattern = (r'"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
3325 r'\.(com|net)[^"]*"')
Sam Maiera6e76d72022-02-11 21:43:503326 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
3327 pattern = input_api.re.compile(base_pattern)
3328 problems = [] # items are (filename, line_number, line)
3329 for f in input_api.AffectedSourceFiles(FilterFile):
3330 for line_num, line in f.ChangedContents():
3331 if not comment_pattern.search(line) and pattern.search(line):
3332 problems.append((f.LocalPath(), line_num, line))
[email protected]06e6d0ff2012-12-11 01:36:443333
Sam Maiera6e76d72022-02-11 21:43:503334 if problems:
3335 return [
3336 output_api.PresubmitPromptOrNotify(
3337 'Most layers below src/chrome/ should not hardcode service URLs.\n'
3338 'Are you sure this is correct?', [
3339 ' %s:%d: %s' % (problem[0], problem[1], problem[2])
3340 for problem in problems
3341 ])
3342 ]
3343 else:
3344 return []
[email protected]06e6d0ff2012-12-11 01:36:443345
3346
Saagar Sanghavifceeaae2020-08-12 16:40:363347def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503348 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
James Cook6b6597c2019-11-06 22:05:293349
Sam Maiera6e76d72022-02-11 21:43:503350 def FileFilter(affected_file):
3351 """Includes directories known to be Chrome OS only."""
3352 return input_api.FilterSourceFile(
3353 affected_file,
3354 files_to_check=(
3355 '^ash/',
3356 '^chromeos/', # Top-level src/chromeos.
3357 '.*/chromeos/', # Any path component.
3358 '^components/arc',
3359 '^components/exo'),
3360 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:293361
Sam Maiera6e76d72022-02-11 21:43:503362 prefs = []
3363 priority_prefs = []
3364 for f in input_api.AffectedFiles(file_filter=FileFilter):
3365 for line_num, line in f.ChangedContents():
3366 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF',
3367 line):
3368 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
3369 prefs.append(' %s' % line)
3370 if input_api.re.search(
3371 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
3372 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
3373 priority_prefs.append(' %s' % line)
3374
3375 results = []
3376 if (prefs):
3377 results.append(
3378 output_api.PresubmitPromptWarning(
3379 'Preferences were registered as SYNCABLE_PREF and will be controlled '
3380 'by browser sync settings. If these prefs should be controlled by OS '
3381 'sync settings use SYNCABLE_OS_PREF instead.\n' +
3382 '\n'.join(prefs)))
3383 if (priority_prefs):
3384 results.append(
3385 output_api.PresubmitPromptWarning(
3386 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
3387 'controlled by browser sync settings. If these prefs should be '
3388 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
3389 'instead.\n' + '\n'.join(prefs)))
3390 return results
James Cook6b6597c2019-11-06 22:05:293391
3392
Saagar Sanghavifceeaae2020-08-12 16:40:363393def CheckNoAbbreviationInPngFileName(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503394 """Makes sure there are no abbreviations in the name of PNG files.
3395 The native_client_sdk directory is excluded because it has auto-generated PNG
3396 files for documentation.
3397 """
3398 errors = []
Yuanqing Zhu9eef02832022-12-04 14:42:173399 files_to_check = [r'.*\.png$']
Daniel Cheng6303eed2025-05-03 00:12:333400 files_to_skip = [
3401 r'^native_client_sdk/',
3402 r'^services/test/',
3403 r'^third_party/blink/web_tests/',
3404 ]
Sam Maiera6e76d72022-02-11 21:43:503405 file_filter = lambda f: input_api.FilterSourceFile(
3406 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Dirk Prankee4df27972025-02-26 18:39:353407 abbreviation = input_api.re.compile(r'.+_[a-z]\.png|.+_[a-z]_.*\.png')
Sam Maiera6e76d72022-02-11 21:43:503408 for f in input_api.AffectedFiles(include_deletes=False,
3409 file_filter=file_filter):
Yuanqing Zhu9eef02832022-12-04 14:42:173410 file_name = input_api.os_path.split(f.LocalPath())[1]
3411 if abbreviation.search(file_name):
3412 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:273413
Sam Maiera6e76d72022-02-11 21:43:503414 results = []
3415 if errors:
3416 results.append(
3417 output_api.PresubmitError(
3418 'The name of PNG files should not have abbreviations. \n'
3419 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
3420 'Contact [email protected] if you have questions.', errors))
3421 return results
[email protected]d2530012013-01-25 16:39:273422
Daniel Cheng6303eed2025-05-03 00:12:333423
Evan Stade7cd4a2c2022-08-04 23:37:253424def CheckNoProductIconsAddedToPublicRepo(input_api, output_api):
3425 """Heuristically identifies product icons based on their file name and reminds
3426 contributors not to add them to the Chromium repository.
3427 """
Peter Kotwiczf634d072025-04-28 22:48:153428
3429 if input_api.change.RepositoryRoot().endswith('clank'):
Daniel Cheng6303eed2025-05-03 00:12:333430 # TODO(crbug.com/414435241): Change check to compute whether change
3431 # belongs to internal repository instead of relying on string matching.
3432 return []
Peter Kotwiczf634d072025-04-28 22:48:153433
Evan Stade7cd4a2c2022-08-04 23:37:253434 errors = []
3435 files_to_check = [r'.*google.*\.png$|.*google.*\.svg$|.*google.*\.icon$']
3436 file_filter = lambda f: input_api.FilterSourceFile(
3437 f, files_to_check=files_to_check)
3438 for f in input_api.AffectedFiles(include_deletes=False,
3439 file_filter=file_filter):
3440 errors.append(' %s' % f.LocalPath())
3441
3442 results = []
3443 if errors:
Bruce Dawson3bcf0c92022-08-12 00:03:083444 # Give warnings instead of errors on presubmit --all and presubmit
3445 # --files.
Daniel Cheng6303eed2025-05-03 00:12:333446 message_type = (output_api.PresubmitNotifyResult
3447 if input_api.no_diffs else output_api.PresubmitError)
Evan Stade7cd4a2c2022-08-04 23:37:253448 results.append(
Bruce Dawson3bcf0c92022-08-12 00:03:083449 message_type(
Evan Stade7cd4a2c2022-08-04 23:37:253450 'Trademarked images should not be added to the public repo. '
3451 'See crbug.com/944754', errors))
3452 return results
3453
[email protected]d2530012013-01-25 16:39:273454
Daniel Cheng4dcdb6b2017-04-13 08:30:173455def _ExtractAddRulesFromParsedDeps(parsed_deps):
Sam Maiera6e76d72022-02-11 21:43:503456 """Extract the rules that add dependencies from a parsed DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:173457
Sam Maiera6e76d72022-02-11 21:43:503458 Args:
3459 parsed_deps: the locals dictionary from evaluating the DEPS file."""
3460 add_rules = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:173461 add_rules.update([
Sam Maiera6e76d72022-02-11 21:43:503462 rule[1:] for rule in parsed_deps.get('include_rules', [])
Daniel Cheng4dcdb6b2017-04-13 08:30:173463 if rule.startswith('+') or rule.startswith('!')
3464 ])
Sam Maiera6e76d72022-02-11 21:43:503465 for _, rules in parsed_deps.get('specific_include_rules', {}).items():
3466 add_rules.update([
3467 rule[1:] for rule in rules
3468 if rule.startswith('+') or rule.startswith('!')
3469 ])
3470 return add_rules
Daniel Cheng4dcdb6b2017-04-13 08:30:173471
3472
3473def _ParseDeps(contents):
Sam Maiera6e76d72022-02-11 21:43:503474 """Simple helper for parsing DEPS files."""
Daniel Cheng4dcdb6b2017-04-13 08:30:173475
Sam Maiera6e76d72022-02-11 21:43:503476 # Stubs for handling special syntax in the root DEPS file.
3477 class _VarImpl:
Daniel Cheng6303eed2025-05-03 00:12:333478
Sam Maiera6e76d72022-02-11 21:43:503479 def __init__(self, local_scope):
3480 self._local_scope = local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:173481
Sam Maiera6e76d72022-02-11 21:43:503482 def Lookup(self, var_name):
3483 """Implements the Var syntax."""
3484 try:
3485 return self._local_scope['vars'][var_name]
3486 except KeyError:
3487 raise Exception('Var is not defined: %s' % var_name)
Daniel Cheng4dcdb6b2017-04-13 08:30:173488
Sam Maiera6e76d72022-02-11 21:43:503489 local_scope = {}
3490 global_scope = {
3491 'Var': _VarImpl(local_scope).Lookup,
3492 'Str': str,
3493 }
Dirk Pranke1b9e06382021-05-14 01:16:223494
Sam Maiera6e76d72022-02-11 21:43:503495 exec(contents, global_scope, local_scope)
3496 return local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:173497
3498
Andrew Grieveb77ac76d2024-11-29 15:01:483499def _FindAllDepsFilesForSubpath(input_api, subpath):
3500 ret = []
3501 while subpath:
Daniel Cheng6303eed2025-05-03 00:12:333502 cur = input_api.os_path.join(input_api.change.RepositoryRoot(),
3503 subpath, 'DEPS')
Joanna Wang130e7bdd2024-12-10 17:39:033504 if input_api.os_path.isfile(cur):
Andrew Grieveb77ac76d2024-11-29 15:01:483505 ret.append(cur)
3506 subpath = input_api.os_path.dirname(subpath)
3507 return ret
3508
3509
3510def _FindAddedDepsThatRequireReview(input_api, depended_on_paths):
3511 """Filters to those whose DEPS set new_usages_require_review=True"""
3512 ret = set()
3513 cache = {}
3514 for target_path in depended_on_paths:
3515 for subpath in _FindAllDepsFilesForSubpath(input_api, target_path):
3516 config = cache.get(subpath)
3517 if config is None:
3518 config = _ParseDeps(input_api.ReadFile(subpath))
3519 cache[subpath] = config
3520 if config.get('new_usages_require_review'):
3521 ret.add(target_path)
3522 break
3523 return ret
3524
3525
Daniel Cheng4dcdb6b2017-04-13 08:30:173526def _CalculateAddedDeps(os_path, old_contents, new_contents):
Sam Maiera6e76d72022-02-11 21:43:503527 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
3528 a set of DEPS entries that we should look up.
[email protected]14a6131c2014-01-08 01:15:413529
Sam Maiera6e76d72022-02-11 21:43:503530 For a directory (rather than a specific filename) we fake a path to
3531 a specific filename by adding /DEPS. This is chosen as a file that
3532 will seldom or never be subject to per-file include_rules.
3533 """
3534 # We ignore deps entries on auto-generated directories.
3535 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:083536
Sam Maiera6e76d72022-02-11 21:43:503537 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
3538 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
Daniel Cheng4dcdb6b2017-04-13 08:30:173539
Sam Maiera6e76d72022-02-11 21:43:503540 added_deps = new_deps.difference(old_deps)
Daniel Cheng4dcdb6b2017-04-13 08:30:173541
Sam Maiera6e76d72022-02-11 21:43:503542 results = set()
3543 for added_dep in added_deps:
3544 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
3545 continue
3546 # Assume that a rule that ends in .h is a rule for a specific file.
3547 if added_dep.endswith('.h'):
3548 results.add(added_dep)
3549 else:
3550 results.add(os_path.join(added_dep, 'DEPS'))
3551 return results
[email protected]f32e2d1e2013-07-26 21:39:083552
Daniel Cheng6303eed2025-05-03 00:12:333553
Stephanie Kimec4f55a2024-04-24 16:54:023554def CheckForNewDEPSDownloadFromGoogleStorageHooks(input_api, output_api):
3555 """Checks that there are no new download_from_google_storage hooks"""
3556 for f in input_api.AffectedFiles(include_deletes=False):
3557 if f.LocalPath() == 'DEPS':
3558 old_hooks = _ParseDeps('\n'.join(f.OldContents()))['hooks']
3559 new_hooks = _ParseDeps('\n'.join(f.NewContents()))['hooks']
3560 old_name_to_hook = {hook['name']: hook for hook in old_hooks}
3561 new_name_to_hook = {hook['name']: hook for hook in new_hooks}
3562 added_hook_names = set(new_name_to_hook.keys()) - set(
3563 old_name_to_hook.keys())
3564 if not added_hook_names:
3565 return []
3566 new_download_from_google_storage_hooks = []
3567 for new_hook in added_hook_names:
3568 hook = new_name_to_hook[new_hook]
3569 action_cmd = hook['action']
3570 if any('download_from_google_storage' in arg
Daniel Cheng6303eed2025-05-03 00:12:333571 for arg in action_cmd):
Stephanie Kimec4f55a2024-04-24 16:54:023572 new_download_from_google_storage_hooks.append(new_hook)
3573 if new_download_from_google_storage_hooks:
3574 return [
3575 output_api.PresubmitError(
3576 'Please do not add new download_from_google_storage '
3577 'hooks. Instead, add a `gcs` dep_type entry to `deps`. '
3578 'See https://chromium.googlesource.com/chromium/src.git'
3579 '/+/refs/heads/main/docs/gcs_dependencies.md for more '
3580 'info. Added hooks:',
3581 items=new_download_from_google_storage_hooks)
3582 ]
3583 return []
3584
[email protected]f32e2d1e2013-07-26 21:39:083585
Rasika Navarangec2d33d22024-05-23 15:19:023586def CheckEachPerfettoTestDataFileHasDepsEntry(input_api, output_api):
3587 test_data_filter = lambda f: input_api.FilterSourceFile(
Rasika Navarange08e542162024-05-31 13:31:263588 f, files_to_check=[r'^base/tracing/test/data_sha256/.*\.sha256'])
Rasika Navarangec2d33d22024-05-23 15:19:023589 if not any(input_api.AffectedFiles(file_filter=test_data_filter)):
3590 return []
3591
3592 # Find DEPS entry
3593 deps_entry = []
Rasika Navarange277cd662024-06-04 10:14:593594 old_deps_entry = []
Rasika Navarangec2d33d22024-05-23 15:19:023595 for f in input_api.AffectedFiles(include_deletes=False):
3596 if f.LocalPath() == 'DEPS':
3597 new_deps = _ParseDeps('\n'.join(f.NewContents()))['deps']
3598 deps_entry = new_deps['src/base/tracing/test/data']
Rasika Navarange277cd662024-06-04 10:14:593599 old_deps = _ParseDeps('\n'.join(f.OldContents()))['deps']
3600 old_deps_entry = old_deps['src/base/tracing/test/data']
Rasika Navarangec2d33d22024-05-23 15:19:023601 if not deps_entry:
Rasika Navarange08e542162024-05-31 13:31:263602 # TODO(312895063):Add back error when .sha256 files have been moved.
Daniel Cheng6303eed2025-05-03 00:12:333603 return [
3604 output_api.PresubmitError(
3605 'You must update the DEPS file when you update a '
3606 '.sha256 file in base/tracing/test/data_sha256')
3607 ]
Rasika Navarangec2d33d22024-05-23 15:19:023608
3609 output = []
3610 for f in input_api.AffectedFiles(file_filter=test_data_filter):
3611 objects = deps_entry['objects']
3612 if not f.NewContents():
3613 # Deleted file so check that DEPS entry removed
3614 sha256_from_file = f.OldContents()[0]
3615 object_entry = next(
Daniel Cheng6303eed2025-05-03 00:12:333616 (item
3617 for item in objects if item["sha256sum"] == sha256_from_file),
Rasika Navarangec2d33d22024-05-23 15:19:023618 None)
Daniel Cheng6303eed2025-05-03 00:12:333619 old_entry = next((item for item in old_deps_entry['objects']
3620 if item["sha256sum"] == sha256_from_file), None)
Rasika Navarangec2d33d22024-05-23 15:19:023621 if object_entry:
Rasika Navarange277cd662024-06-04 10:14:593622 # Allow renaming of objects with the same hash
3623 if object_entry['object_name'] != old_entry['object_name']:
3624 continue
Daniel Cheng6303eed2025-05-03 00:12:333625 output.append(
3626 output_api.PresubmitError(
3627 'You deleted %s so you must also remove the corresponding DEPS entry.'
3628 % f.LocalPath()))
Rasika Navarangec2d33d22024-05-23 15:19:023629 continue
3630
3631 sha256_from_file = f.NewContents()[0]
3632 object_entry = next(
Daniel Cheng6303eed2025-05-03 00:12:333633 (item
3634 for item in objects if item["sha256sum"] == sha256_from_file),
Rasika Navarangec2d33d22024-05-23 15:19:023635 None)
3636 if not object_entry:
Daniel Cheng6303eed2025-05-03 00:12:333637 output.append(
3638 output_api.PresubmitError(
3639 'No corresponding DEPS entry found for %s. '
3640 'Run `base/tracing/test/test_data.py get_deps --filepath %s` '
3641 'to generate the DEPS entry.' %
3642 (f.LocalPath(), f.LocalPath())))
Rasika Navarangec2d33d22024-05-23 15:19:023643
3644 if output:
Daniel Cheng6303eed2025-05-03 00:12:333645 output.append(
3646 output_api.PresubmitError(
3647 'The DEPS entry for `src/base/tracing/test/data` in the DEPS file has not been '
3648 'updated properly. Run `base/tracing/test/test_data.py get_all_deps` to see what '
3649 'the DEPS entry should look like.'))
Rasika Navarangec2d33d22024-05-23 15:19:023650 return output
3651
3652
Saagar Sanghavifceeaae2020-08-12 16:40:363653def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503654 """When a dependency prefixed with + is added to a DEPS file, we
3655 want to make sure that the change is reviewed by an OWNER of the
3656 target file or directory, to avoid layering violations from being
3657 introduced. This check verifies that this happens.
3658 """
3659 # We rely on Gerrit's code-owners to check approvals.
3660 # input_api.gerrit is always set for Chromium, but other projects
3661 # might not use Gerrit.
Bruce Dawson344ab262022-06-04 11:35:103662 if not input_api.gerrit or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:503663 return []
Bruce Dawsonb357aeb2022-08-09 15:38:303664 if 'PRESUBMIT_SKIP_NETWORK' in input_api.environ:
Sam Maiera6e76d72022-02-11 21:43:503665 return []
Bruce Dawsonb357aeb2022-08-09 15:38:303666 try:
Daniel Cheng6303eed2025-05-03 00:12:333667 if (input_api.change.issue
3668 and input_api.gerrit.IsOwnersOverrideApproved(
3669 input_api.change.issue)):
Bruce Dawsonb357aeb2022-08-09 15:38:303670 # Skip OWNERS check when Owners-Override label is approved. This is
3671 # intended for global owners, trusted bots, and on-call sheriffs.
3672 # Review is still required for these changes.
3673 return []
3674 except Exception as e:
Daniel Cheng6303eed2025-05-03 00:12:333675 return [
3676 output_api.PresubmitPromptWarning(
3677 'Failed to retrieve owner override status - %s' % str(e))
3678 ]
Edward Lesmes6fba51082021-01-20 04:20:233679
Andrew Grieveb77ac76d2024-11-29 15:01:483680 # A set of paths (that might not exist) that are being added as DEPS
3681 # (via lines like "+foo/bar/baz").
3682 depended_on_paths = set()
jochen53efcdd2016-01-29 05:09:243683
Daniel Cheng6303eed2025-05-03 00:12:333684 file_filter = lambda f: not input_api.re.match(r"^third_party/blink/.*",
3685 f.UnixLocalPath())
Sam Maiera6e76d72022-02-11 21:43:503686 for f in input_api.AffectedFiles(include_deletes=False,
3687 file_filter=file_filter):
3688 filename = input_api.os_path.basename(f.LocalPath())
3689 if filename == 'DEPS':
Andrew Grieveb77ac76d2024-11-29 15:01:483690 depended_on_paths.update(
Sam Maiera6e76d72022-02-11 21:43:503691 _CalculateAddedDeps(input_api.os_path,
3692 '\n'.join(f.OldContents()),
3693 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:553694
Andrew Grieveb77ac76d2024-11-29 15:01:483695 # Requiring reviews is opt-in as of https://crbug.com/365797506
Daniel Cheng6303eed2025-05-03 00:12:333696 depended_on_paths = _FindAddedDepsThatRequireReview(
3697 input_api, depended_on_paths)
Andrew Grieveb77ac76d2024-11-29 15:01:483698 if not depended_on_paths:
Sam Maiera6e76d72022-02-11 21:43:503699 return []
[email protected]e871964c2013-05-13 14:14:553700
Sam Maiera6e76d72022-02-11 21:43:503701 if input_api.is_committing:
3702 if input_api.tbr:
3703 return [
3704 output_api.PresubmitNotifyResult(
3705 '--tbr was specified, skipping OWNERS check for DEPS additions'
3706 )
3707 ]
Daniel Cheng3008dc12022-05-13 04:02:113708 # TODO(dcheng): Make this generate an error on dry runs if the reviewer
3709 # is not added, to prevent review serialization.
Sam Maiera6e76d72022-02-11 21:43:503710 if input_api.dry_run:
3711 return [
3712 output_api.PresubmitNotifyResult(
3713 'This is a dry run, skipping OWNERS check for DEPS additions'
3714 )
3715 ]
3716 if not input_api.change.issue:
3717 return [
3718 output_api.PresubmitError(
3719 "DEPS approval by OWNERS check failed: this change has "
3720 "no change number, so we can't check it for approvals.")
3721 ]
3722 output = output_api.PresubmitError
[email protected]14a6131c2014-01-08 01:15:413723 else:
Sam Maiera6e76d72022-02-11 21:43:503724 output = output_api.PresubmitNotifyResult
[email protected]e871964c2013-05-13 14:14:553725
Sam Maiera6e76d72022-02-11 21:43:503726 owner_email, reviewers = (
3727 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3728 input_api, None, approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:553729
Sam Maiera6e76d72022-02-11 21:43:503730 owner_email = owner_email or input_api.change.author_email
3731
3732 approval_status = input_api.owners_client.GetFilesApprovalStatus(
Andrew Grieveb77ac76d2024-11-29 15:01:483733 depended_on_paths, reviewers.union([owner_email]), [])
Sam Maiera6e76d72022-02-11 21:43:503734 missing_files = [
Andrew Grieveb77ac76d2024-11-29 15:01:483735 p for p in depended_on_paths
3736 if approval_status[p] != input_api.owners_client.APPROVED
Sam Maiera6e76d72022-02-11 21:43:503737 ]
3738
3739 # We strip the /DEPS part that was added by
3740 # _FilesToCheckForIncomingDeps to fake a path to a file in a
3741 # directory.
3742 def StripDeps(path):
3743 start_deps = path.rfind('/DEPS')
3744 if start_deps != -1:
3745 return path[:start_deps]
3746 else:
3747 return path
3748
Scott Leebf6a0942024-06-26 22:59:393749 submodule_paths = set(input_api.ListSubmodules())
Daniel Cheng6303eed2025-05-03 00:12:333750
Scott Leebf6a0942024-06-26 22:59:393751 def is_from_submodules(path, submodule_paths):
3752 path = input_api.os_path.normpath(path)
3753 while path:
3754 if path in submodule_paths:
3755 return True
3756
3757 # All deps should be a relative path from the checkout.
3758 # i.e., shouldn't start with "/" or "c:\", for example.
3759 #
3760 # That said, this is to prevent an infinite loop, just in case
3761 # an input dep path starts with "/", because
3762 # os.path.dirname("/") => "/"
3763 parent = input_api.os_path.dirname(path)
3764 if parent == path:
3765 break
3766 path = parent
3767
3768 return False
3769
Sam Maiera6e76d72022-02-11 21:43:503770 unapproved_dependencies = [
3771 "'+%s'," % StripDeps(path) for path in missing_files
Scott Leebf6a0942024-06-26 22:59:393772 # if a newly added dep is from a submodule, it becomes trickier
3773 # to get suggested owners, especially it is from a different host.
3774 #
3775 # skip the review enforcement for cross-repo deps.
3776 if not is_from_submodules(path, submodule_paths)
Sam Maiera6e76d72022-02-11 21:43:503777 ]
3778
3779 if unapproved_dependencies:
3780 output_list = [
3781 output(
3782 'You need LGTM from owners of depends-on paths in DEPS that were '
3783 'modified in this CL:\n %s' %
3784 '\n '.join(sorted(unapproved_dependencies)))
3785 ]
3786 suggested_owners = input_api.owners_client.SuggestOwners(
3787 missing_files, exclude=[owner_email])
3788 output_list.append(
3789 output('Suggested missing target path OWNERS:\n %s' %
3790 '\n '.join(suggested_owners or [])))
3791 return output_list
3792
3793 return []
[email protected]e871964c2013-05-13 14:14:553794
3795
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493796# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:363797def CheckSpamLogging(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503798 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3799 files_to_skip = (
3800 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3801 input_api.DEFAULT_FILES_TO_SKIP + (
Jaewon Jung2f323bb2022-12-07 23:55:013802 r"^base/fuchsia/scoped_fx_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313803 r"^base/logging\.h$",
3804 r"^base/logging\.cc$",
3805 r"^base/task/thread_pool/task_tracker\.cc$",
3806 r"^chrome/app/chrome_main_delegate\.cc$",
Yao Li359937b2023-02-15 23:43:033807 r"^chrome/browser/ash/arc/enterprise/cert_store/arc_cert_installer\.cc$",
3808 r"^chrome/browser/ash/policy/remote_commands/user_command_arc_job\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313809 r"^chrome/browser/chrome_browser_main\.cc$",
3810 r"^chrome/browser/ui/startup/startup_browser_creator\.cc$",
3811 r"^chrome/browser/browser_switcher/bho/.*",
3812 r"^chrome/browser/diagnostics/diagnostics_writer\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313813 r"^chrome/chrome_elf/dll_hash/dll_hash_main\.cc$",
3814 r"^chrome/installer/setup/.*",
Daniel Ruberyad36eea2024-08-01 01:38:323815 # crdmg runs as a separate binary which intentionally does
3816 # not depend on base logging.
3817 r"^chrome/utility/safe_browsing/mac/crdmg\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313818 r"^chromecast/",
Vigen Issahhanjane2d93822023-06-30 15:57:203819 r"^components/cast",
Bruce Dawson40fece62022-09-16 19:58:313820 r"^components/media_control/renderer/media_playback_options\.cc$",
Salma Elmahallawy52976452023-01-27 17:04:493821 r"^components/policy/core/common/policy_logger\.cc$",
Tomek Jurkiewicz06fd6a72025-06-18 15:24:283822 r"^components/supervised_user/core/browser/android/content_filters_observer_bridge\.cc",
Bruce Dawson40fece62022-09-16 19:58:313823 r"^components/viz/service/display/"
Sam Maiera6e76d72022-02-11 21:43:503824 r"overlay_strategy_underlay_cast\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313825 r"^components/zucchini/.*",
Sam Maiera6e76d72022-02-11 21:43:503826 # TODO(peter): Remove exception. https://crbug.com/534537
Bruce Dawson40fece62022-09-16 19:58:313827 r"^content/browser/notifications/"
Sam Maiera6e76d72022-02-11 21:43:503828 r"notification_event_dispatcher_impl\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313829 r"^content/common/gpu/client/gl_helper_benchmark\.cc$",
3830 r"^courgette/courgette_minimal_tool\.cc$",
3831 r"^courgette/courgette_tool\.cc$",
3832 r"^extensions/renderer/logging_native_handler\.cc$",
3833 r"^fuchsia_web/common/init_logging\.cc$",
3834 r"^fuchsia_web/runners/common/web_component\.cc$",
Caroline Liua7050132023-02-13 22:23:153835 r"^fuchsia_web/shell/.*\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313836 r"^headless/app/headless_shell\.cc$",
3837 r"^ipc/ipc_logging\.cc$",
3838 r"^native_client_sdk/",
3839 r"^remoting/base/logging\.h$",
3840 r"^remoting/host/.*",
3841 r"^sandbox/linux/.*",
Austin Sullivana6054e02024-05-20 16:31:293842 r"^services/webnn/tflite/graph_impl_tflite\.cc$",
3843 r"^services/webnn/coreml/graph_impl_coreml\.mm$",
Bruce Dawson40fece62022-09-16 19:58:313844 r"^storage/browser/file_system/dump_file_system\.cc$",
Steinar H. Gundersone5689e42024-08-07 18:17:193845 r"^testing/perf/",
Bruce Dawson40fece62022-09-16 19:58:313846 r"^tools/",
3847 r"^ui/base/resource/data_pack\.cc$",
3848 r"^ui/aura/bench/bench_main\.cc$",
3849 r"^ui/ozone/platform/cast/",
3850 r"^ui/base/x/xwmstartupcheck/"
Sam Maiera6e76d72022-02-11 21:43:503851 r"xwmstartupcheck\.cc$"))
3852 source_file_filter = lambda x: input_api.FilterSourceFile(
3853 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:403854
Sam Maiera6e76d72022-02-11 21:43:503855 log_info = set([])
3856 printf = set([])
[email protected]85218562013-11-22 07:41:403857
Sam Maiera6e76d72022-02-11 21:43:503858 for f in input_api.AffectedSourceFiles(source_file_filter):
3859 for _, line in f.ChangedContents():
3860 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
3861 log_info.add(f.LocalPath())
3862 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
3863 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:373864
Sam Maiera6e76d72022-02-11 21:43:503865 if input_api.re.search(r"\bprintf\(", line):
3866 printf.add(f.LocalPath())
3867 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
3868 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:403869
Sam Maiera6e76d72022-02-11 21:43:503870 if log_info:
3871 return [
3872 output_api.PresubmitError(
3873 'These files spam the console log with LOG(INFO):',
3874 items=log_info)
3875 ]
3876 if printf:
3877 return [
3878 output_api.PresubmitError(
3879 'These files spam the console log with printf/fprintf:',
3880 items=printf)
3881 ]
3882 return []
[email protected]85218562013-11-22 07:41:403883
3884
Saagar Sanghavifceeaae2020-08-12 16:40:363885def CheckForAnonymousVariables(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503886 """These types are all expected to hold locks while in scope and
3887 so should never be anonymous (which causes them to be immediately
3888 destroyed)."""
3889 they_who_must_be_named = [
3890 'base::AutoLock',
3891 'base::AutoReset',
3892 'base::AutoUnlock',
3893 'SkAutoAlphaRestore',
3894 'SkAutoBitmapShaderInstall',
3895 'SkAutoBlitterChoose',
3896 'SkAutoBounderCommit',
3897 'SkAutoCallProc',
3898 'SkAutoCanvasRestore',
3899 'SkAutoCommentBlock',
3900 'SkAutoDescriptor',
3901 'SkAutoDisableDirectionCheck',
3902 'SkAutoDisableOvalCheck',
3903 'SkAutoFree',
3904 'SkAutoGlyphCache',
3905 'SkAutoHDC',
3906 'SkAutoLockColors',
3907 'SkAutoLockPixels',
3908 'SkAutoMalloc',
3909 'SkAutoMaskFreeImage',
3910 'SkAutoMutexAcquire',
3911 'SkAutoPathBoundsUpdate',
3912 'SkAutoPDFRelease',
3913 'SkAutoRasterClipValidate',
3914 'SkAutoRef',
3915 'SkAutoTime',
3916 'SkAutoTrace',
3917 'SkAutoUnref',
3918 ]
3919 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
3920 # bad: base::AutoLock(lock.get());
3921 # not bad: base::AutoLock lock(lock.get());
3922 bad_pattern = input_api.re.compile(anonymous)
3923 # good: new base::AutoLock(lock.get())
3924 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
3925 errors = []
[email protected]49aa76a2013-12-04 06:59:163926
Sam Maiera6e76d72022-02-11 21:43:503927 for f in input_api.AffectedFiles():
3928 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
3929 continue
3930 for linenum, line in f.ChangedContents():
3931 if bad_pattern.search(line) and not good_pattern.search(line):
3932 errors.append('%s:%d' % (f.LocalPath(), linenum))
[email protected]49aa76a2013-12-04 06:59:163933
Sam Maiera6e76d72022-02-11 21:43:503934 if errors:
3935 return [
3936 output_api.PresubmitError(
3937 'These lines create anonymous variables that need to be named:',
3938 items=errors)
3939 ]
3940 return []
[email protected]49aa76a2013-12-04 06:59:163941
3942
Saagar Sanghavifceeaae2020-08-12 16:40:363943def CheckUniquePtrOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503944 # Returns whether |template_str| is of the form <T, U...> for some types T
Glen Robertson9142ffd72024-05-16 01:37:473945 # and U, or is invalid due to mismatched angle bracket pairs. Assumes that
3946 # |template_str| is already in the form <...>.
3947 def HasMoreThanOneArgOrInvalid(template_str):
Sam Maiera6e76d72022-02-11 21:43:503948 # Level of <...> nesting.
3949 nesting = 0
3950 for c in template_str:
3951 if c == '<':
3952 nesting += 1
3953 elif c == '>':
3954 nesting -= 1
3955 elif c == ',' and nesting == 1:
3956 return True
Glen Robertson9142ffd72024-05-16 01:37:473957 if nesting != 0:
Daniel Cheng566634ff2024-06-29 14:56:533958 # Invalid.
3959 return True
Sam Maiera6e76d72022-02-11 21:43:503960 return False
Vaclav Brozekb7fadb692018-08-30 06:39:533961
Sam Maiera6e76d72022-02-11 21:43:503962 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3963 sources = lambda affected_file: input_api.FilterSourceFile(
3964 affected_file,
3965 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3966 DEFAULT_FILES_TO_SKIP),
3967 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:553968
Sam Maiera6e76d72022-02-11 21:43:503969 # Pattern to capture a single "<...>" block of template arguments. It can
3970 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
3971 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
3972 # latter would likely require counting that < and > match, which is not
3973 # expressible in regular languages. Should the need arise, one can introduce
3974 # limited counting (matching up to a total number of nesting depth), which
3975 # should cover all practical cases for already a low nesting limit.
3976 template_arg_pattern = (
3977 r'<[^>]*' # Opening block of <.
3978 r'>([^<]*>)?') # Closing block of >.
3979 # Prefix expressing that whatever follows is not already inside a <...>
3980 # block.
3981 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
3982 null_construct_pattern = input_api.re.compile(
3983 not_inside_template_arg_pattern + r'\bstd::unique_ptr' +
3984 template_arg_pattern + r'\(\)')
Vaclav Brozeka54c528b2018-04-06 19:23:553985
Sam Maiera6e76d72022-02-11 21:43:503986 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
3987 template_arg_no_array_pattern = (
3988 r'<[^>]*[^]]' # Opening block of <.
3989 r'>([^(<]*[^]]>)?') # Closing block of >.
3990 # Prefix saying that what follows is the start of an expression.
3991 start_of_expr_pattern = r'(=|\breturn|^)\s*'
3992 # Suffix saying that what follows are call parentheses with a non-empty list
3993 # of arguments.
3994 nonempty_arg_list_pattern = r'\(([^)]|$)'
3995 # Put the template argument into a capture group for deeper examination later.
3996 return_construct_pattern = input_api.re.compile(
3997 start_of_expr_pattern + r'std::unique_ptr' + '(?P<template_arg>' +
3998 template_arg_no_array_pattern + ')' + nonempty_arg_list_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:553999
Sam Maiera6e76d72022-02-11 21:43:504000 problems_constructor = []
4001 problems_nullptr = []
4002 for f in input_api.AffectedSourceFiles(sources):
4003 for line_number, line in f.ChangedContents():
4004 # Disallow:
4005 # return std::unique_ptr<T>(foo);
4006 # bar = std::unique_ptr<T>(foo);
4007 # But allow:
4008 # return std::unique_ptr<T[]>(foo);
4009 # bar = std::unique_ptr<T[]>(foo);
4010 # And also allow cases when the second template argument is present. Those
4011 # cases cannot be handled by std::make_unique:
4012 # return std::unique_ptr<T, U>(foo);
4013 # bar = std::unique_ptr<T, U>(foo);
4014 local_path = f.LocalPath()
4015 return_construct_result = return_construct_pattern.search(line)
Glen Robertson9142ffd72024-05-16 01:37:474016 if return_construct_result and not HasMoreThanOneArgOrInvalid(
Sam Maiera6e76d72022-02-11 21:43:504017 return_construct_result.group('template_arg')):
4018 problems_constructor.append(
4019 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4020 # Disallow:
4021 # std::unique_ptr<T>()
4022 if null_construct_pattern.search(line):
4023 problems_nullptr.append(
4024 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Vaclav Brozek851d9602018-04-04 16:13:054025
Sam Maiera6e76d72022-02-11 21:43:504026 errors = []
4027 if problems_nullptr:
4028 errors.append(
4029 output_api.PresubmitPromptWarning(
4030 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
4031 problems_nullptr))
4032 if problems_constructor:
4033 errors.append(
4034 output_api.PresubmitError(
4035 'The following files use explicit std::unique_ptr constructor. '
4036 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
4037 'std::make_unique is not an option.', problems_constructor))
4038 return errors
Peter Kasting4844e46e2018-02-23 07:27:104039
4040
Saagar Sanghavifceeaae2020-08-12 16:40:364041def CheckUserActionUpdate(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504042 """Checks if any new user action has been added."""
4043 if any('actions.xml' == input_api.os_path.basename(f)
4044 for f in input_api.LocalPaths()):
4045 # If actions.xml is already included in the changelist, the PRESUBMIT
4046 # for actions.xml will do a more complete presubmit check.
4047 return []
4048
4049 file_inclusion_pattern = [r'.*\.(cc|mm)$']
4050 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
4051 input_api.DEFAULT_FILES_TO_SKIP)
4052 file_filter = lambda f: input_api.FilterSourceFile(
4053 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
4054
4055 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
4056 current_actions = None
4057 for f in input_api.AffectedFiles(file_filter=file_filter):
4058 for line_num, line in f.ChangedContents():
4059 match = input_api.re.search(action_re, line)
4060 if match:
4061 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
4062 # loaded only once.
4063 if not current_actions:
Bruce Dawson6cb2d4d2023-03-01 21:35:094064 with open('tools/metrics/actions/actions.xml',
4065 encoding='utf-8') as actions_f:
Sam Maiera6e76d72022-02-11 21:43:504066 current_actions = actions_f.read()
4067 # Search for the matched user action name in |current_actions|.
4068 for action_name in match.groups():
4069 action = 'name="{0}"'.format(action_name)
4070 if action not in current_actions:
4071 return [
4072 output_api.PresubmitPromptWarning(
4073 'File %s line %d: %s is missing in '
4074 'tools/metrics/actions/actions.xml. Please run '
4075 'tools/metrics/actions/extract_actions.py to update.'
4076 % (f.LocalPath(), line_num, action_name))
4077 ]
[email protected]999261d2014-03-03 20:08:084078 return []
4079
[email protected]999261d2014-03-03 20:08:084080
Daniel Cheng13ca61a882017-08-25 15:11:254081def _ImportJSONCommentEater(input_api):
Sam Maiera6e76d72022-02-11 21:43:504082 import sys
4083 sys.path = sys.path + [
4084 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4085 'json_comment_eater')
4086 ]
4087 import json_comment_eater
4088 return json_comment_eater
Daniel Cheng13ca61a882017-08-25 15:11:254089
4090
[email protected]99171a92014-06-03 08:44:474091def _GetJSONParseError(input_api, filename, eat_comments=True):
dchenge07de812016-06-20 19:27:174092 try:
Sam Maiera6e76d72022-02-11 21:43:504093 contents = input_api.ReadFile(filename)
4094 if eat_comments:
4095 json_comment_eater = _ImportJSONCommentEater(input_api)
4096 contents = json_comment_eater.Nom(contents)
dchenge07de812016-06-20 19:27:174097
Sam Maiera6e76d72022-02-11 21:43:504098 input_api.json.loads(contents)
4099 except ValueError as e:
4100 return e
Andrew Grieve4deedb12022-02-03 21:34:504101 return None
4102
4103
Sam Maiera6e76d72022-02-11 21:43:504104def _GetIDLParseError(input_api, filename):
4105 try:
4106 contents = input_api.ReadFile(filename)
Devlin Croninf7582a12022-04-21 21:14:284107 for i, char in enumerate(contents):
Daniel Chenga37c03db2022-05-12 17:20:344108 if not char.isascii():
4109 return (
4110 'Non-ascii character "%s" (ord %d) found at offset %d.' %
4111 (char, ord(char), i))
Sam Maiera6e76d72022-02-11 21:43:504112 idl_schema = input_api.os_path.join(input_api.PresubmitLocalPath(),
4113 'tools', 'json_schema_compiler',
4114 'idl_schema.py')
4115 process = input_api.subprocess.Popen(
Bruce Dawson679fb082022-04-14 00:47:284116 [input_api.python3_executable, idl_schema],
Sam Maiera6e76d72022-02-11 21:43:504117 stdin=input_api.subprocess.PIPE,
4118 stdout=input_api.subprocess.PIPE,
4119 stderr=input_api.subprocess.PIPE,
4120 universal_newlines=True)
4121 (_, error) = process.communicate(input=contents)
4122 return error or None
4123 except ValueError as e:
4124 return e
agrievef32bcc72016-04-04 14:57:404125
agrievef32bcc72016-04-04 14:57:404126
Sam Maiera6e76d72022-02-11 21:43:504127def CheckParseErrors(input_api, output_api):
4128 """Check that IDL and JSON files do not contain syntax errors."""
4129 actions = {
4130 '.idl': _GetIDLParseError,
4131 '.json': _GetJSONParseError,
4132 }
4133 # Most JSON files are preprocessed and support comments, but these do not.
4134 json_no_comments_patterns = [
Bruce Dawson40fece62022-09-16 19:58:314135 r'^testing/',
Sam Maiera6e76d72022-02-11 21:43:504136 ]
4137 # Only run IDL checker on files in these directories.
4138 idl_included_patterns = [
Bruce Dawson40fece62022-09-16 19:58:314139 r'^chrome/common/extensions/api/',
4140 r'^extensions/common/api/',
Sam Maiera6e76d72022-02-11 21:43:504141 ]
agrievef32bcc72016-04-04 14:57:404142
Sam Maiera6e76d72022-02-11 21:43:504143 def get_action(affected_file):
4144 filename = affected_file.LocalPath()
4145 return actions.get(input_api.os_path.splitext(filename)[1])
agrievef32bcc72016-04-04 14:57:404146
Sam Maiera6e76d72022-02-11 21:43:504147 def FilterFile(affected_file):
4148 action = get_action(affected_file)
4149 if not action:
4150 return False
Anton Bershanskyi4253349482025-02-11 21:01:274151 path = affected_file.UnixLocalPath()
agrievef32bcc72016-04-04 14:57:404152
Sam Maiera6e76d72022-02-11 21:43:504153 if _MatchesFile(input_api,
4154 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS, path):
4155 return False
4156
4157 if (action == _GetIDLParseError
4158 and not _MatchesFile(input_api, idl_included_patterns, path)):
4159 return False
4160 return True
4161
4162 results = []
4163 for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
4164 include_deletes=False):
4165 action = get_action(affected_file)
4166 kwargs = {}
4167 if (action == _GetJSONParseError
4168 and _MatchesFile(input_api, json_no_comments_patterns,
Anton Bershanskyi4253349482025-02-11 21:01:274169 affected_file.UnixLocalPath())):
Sam Maiera6e76d72022-02-11 21:43:504170 kwargs['eat_comments'] = False
4171 parse_error = action(input_api, affected_file.AbsoluteLocalPath(),
4172 **kwargs)
4173 if parse_error:
4174 results.append(
4175 output_api.PresubmitError(
4176 '%s could not be parsed: %s' %
4177 (affected_file.LocalPath(), parse_error)))
4178 return results
4179
4180
4181def CheckJavaStyle(input_api, output_api):
4182 """Runs checkstyle on changed java files and returns errors if any exist."""
4183
4184 # Return early if no java files were modified.
4185 if not any(
4186 _IsJavaFile(input_api, f.LocalPath())
4187 for f in input_api.AffectedFiles()):
4188 return []
4189
4190 import sys
4191 original_sys_path = sys.path
4192 try:
4193 sys.path = sys.path + [
4194 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4195 'android', 'checkstyle')
4196 ]
4197 import checkstyle
4198 finally:
4199 # Restore sys.path to what it was before.
4200 sys.path = original_sys_path
4201
Daniel Cheng6303eed2025-05-03 00:12:334202 return checkstyle.run_presubmit(input_api,
4203 output_api,
4204 files_to_skip=_EXCLUDED_PATHS +
4205 input_api.DEFAULT_FILES_TO_SKIP)
Sam Maiera6e76d72022-02-11 21:43:504206
4207
4208def CheckPythonDevilInit(input_api, output_api):
4209 """Checks to make sure devil is initialized correctly in python scripts."""
4210 script_common_initialize_pattern = input_api.re.compile(
4211 r'script_common\.InitializeEnvironment\(')
4212 devil_env_config_initialize = input_api.re.compile(
4213 r'devil_env\.config\.Initialize\(')
4214
4215 errors = []
4216
4217 sources = lambda affected_file: input_api.FilterSourceFile(
4218 affected_file,
4219 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314220 r'^build/android/devil_chromium\.py',
Sven Zheng8e079562024-05-10 20:11:064221 r'^tools/bisect-builds\.py',
Bruce Dawson40fece62022-09-16 19:58:314222 r'^third_party/.*',
Sam Maiera6e76d72022-02-11 21:43:504223 )),
4224 files_to_check=[r'.*\.py$'])
4225
4226 for f in input_api.AffectedSourceFiles(sources):
4227 for line_num, line in f.ChangedContents():
4228 if (script_common_initialize_pattern.search(line)
4229 or devil_env_config_initialize.search(line)):
4230 errors.append("%s:%d" % (f.LocalPath(), line_num))
4231
4232 results = []
4233
4234 if errors:
4235 results.append(
4236 output_api.PresubmitError(
4237 'Devil initialization should always be done using '
4238 'devil_chromium.Initialize() in the chromium project, to use better '
4239 'defaults for dependencies (ex. up-to-date version of adb).',
4240 errors))
4241
4242 return results
4243
4244
4245def _MatchesFile(input_api, patterns, path):
4246 for pattern in patterns:
4247 if input_api.re.search(pattern, path):
4248 return True
4249 return False
4250
4251
Daniel Chenga37c03db2022-05-12 17:20:344252def _ChangeHasSecurityReviewer(input_api, owners_file):
4253 """Returns True iff the CL has a reviewer from SECURITY_OWNERS.
Sam Maiera6e76d72022-02-11 21:43:504254
Daniel Chenga37c03db2022-05-12 17:20:344255 Args:
4256 input_api: The presubmit input API.
4257 owners_file: OWNERS file with required reviewers. Typically, this is
4258 something like ipc/SECURITY_OWNERS.
4259
4260 Note: if the presubmit is running for commit rather than for upload, this
4261 only returns True if a security reviewer has also approved the CL.
Sam Maiera6e76d72022-02-11 21:43:504262 """
Daniel Chengd88244472022-05-16 09:08:474263 # Owners-Override should bypass all additional OWNERS enforcement checks.
4264 # A CR+1 vote will still be required to land this change.
4265 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
4266 input_api.change.issue)):
4267 return True
4268
Daniel Chenga37c03db2022-05-12 17:20:344269 owner_email, reviewers = (
4270 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
Daniel Cheng3008dc12022-05-13 04:02:114271 input_api,
4272 None,
4273 approval_needed=input_api.is_committing and not input_api.dry_run))
Sam Maiera6e76d72022-02-11 21:43:504274
Daniel Chenga37c03db2022-05-12 17:20:344275 security_owners = input_api.owners_client.ListOwners(owners_file)
4276 return any(owner in reviewers for owner in security_owners)
Sam Maiera6e76d72022-02-11 21:43:504277
Daniel Chenga37c03db2022-05-12 17:20:344278
4279@dataclass
Daniel Cheng171dad8d2022-05-21 00:40:254280class _SecurityProblemWithItems:
4281 problem: str
4282 items: Sequence[str]
4283
4284
4285@dataclass
Daniel Chenga37c03db2022-05-12 17:20:344286class _MissingSecurityOwnersResult:
Daniel Cheng171dad8d2022-05-21 00:40:254287 owners_file_problems: Sequence[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:344288 has_security_sensitive_files: bool
Daniel Cheng171dad8d2022-05-21 00:40:254289 missing_reviewer_problem: Optional[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:344290
4291
Daniel Cheng6303eed2025-05-03 00:12:334292def _FindMissingSecurityOwners(
4293 input_api,
4294 output_api,
4295 file_patterns: Sequence[str],
4296 excluded_patterns: Sequence[str],
4297 required_owners_file: str,
4298 custom_rule_function: Optional[Callable] = None
4299) -> _MissingSecurityOwnersResult:
Daniel Chenga37c03db2022-05-12 17:20:344300 """Find OWNERS files missing per-file rules for security-sensitive files.
4301
4302 Args:
4303 input_api: the PRESUBMIT input API object.
4304 output_api: the PRESUBMIT output API object.
4305 file_patterns: basename patterns that require a corresponding per-file
4306 security restriction.
4307 excluded_patterns: path patterns that should be exempted from
4308 requiring a security restriction.
4309 required_owners_file: path to the required OWNERS file, e.g.
4310 ipc/SECURITY_OWNERS
4311 cc_alias: If not None, email that will be CCed automatically if the
4312 change contains security-sensitive files, as determined by
4313 `file_patterns` and `excluded_patterns`.
4314 custom_rule_function: If not None, will be called with `input_api` and
4315 the current file under consideration. Returning True will add an
4316 exact match per-file rule check for the current file.
4317 """
4318
4319 # `to_check` is a mapping of an OWNERS file path to Patterns.
4320 #
4321 # Patterns is a dictionary mapping glob patterns (suitable for use in
4322 # per-file rules) to a PatternEntry.
4323 #
Sam Maiera6e76d72022-02-11 21:43:504324 # PatternEntry is a dictionary with two keys:
4325 # - 'files': the files that are matched by this pattern
4326 # - 'rules': the per-file rules needed for this pattern
Daniel Chenga37c03db2022-05-12 17:20:344327 #
Sam Maiera6e76d72022-02-11 21:43:504328 # For example, if we expect OWNERS file to contain rules for *.mojom and
4329 # *_struct_traits*.*, Patterns might look like this:
4330 # {
4331 # '*.mojom': {
4332 # 'files': ...,
4333 # 'rules': [
4334 # 'per-file *.mojom=set noparent',
4335 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
4336 # ],
4337 # },
4338 # '*_struct_traits*.*': {
4339 # 'files': ...,
4340 # 'rules': [
4341 # 'per-file *_struct_traits*.*=set noparent',
4342 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
4343 # ],
4344 # },
4345 # }
4346 to_check = {}
Daniel Chenga37c03db2022-05-12 17:20:344347 files_to_review = []
Sam Maiera6e76d72022-02-11 21:43:504348
Daniel Chenga37c03db2022-05-12 17:20:344349 def AddPatternToCheck(file, pattern):
Sam Maiera6e76d72022-02-11 21:43:504350 owners_file = input_api.os_path.join(
Daniel Chengd88244472022-05-16 09:08:474351 input_api.os_path.dirname(file.LocalPath()), 'OWNERS')
Sam Maiera6e76d72022-02-11 21:43:504352 if owners_file not in to_check:
4353 to_check[owners_file] = {}
4354 if pattern not in to_check[owners_file]:
4355 to_check[owners_file][pattern] = {
4356 'files': [],
4357 'rules': [
Daniel Chenga37c03db2022-05-12 17:20:344358 f'per-file {pattern}=set noparent',
4359 f'per-file {pattern}=file://{required_owners_file}',
Sam Maiera6e76d72022-02-11 21:43:504360 ]
4361 }
Daniel Chenged57a162022-05-25 02:56:344362 to_check[owners_file][pattern]['files'].append(file.LocalPath())
Daniel Chenga37c03db2022-05-12 17:20:344363 files_to_review.append(file.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:504364
Daniel Chenga37c03db2022-05-12 17:20:344365 # Only enforce security OWNERS rules for a directory if that directory has a
4366 # file that matches `file_patterns`. For example, if a directory only
4367 # contains *.mojom files and no *_messages*.h files, the check should only
4368 # ensure that rules for *.mojom files are present.
4369 for file in input_api.AffectedFiles(include_deletes=False):
4370 file_basename = input_api.os_path.basename(file.LocalPath())
4371 if custom_rule_function is not None and custom_rule_function(
4372 input_api, file):
4373 AddPatternToCheck(file, file_basename)
4374 continue
Sam Maiera6e76d72022-02-11 21:43:504375
Daniel Chenga37c03db2022-05-12 17:20:344376 if any(
4377 input_api.fnmatch.fnmatch(file.LocalPath(), pattern)
4378 for pattern in excluded_patterns):
Sam Maiera6e76d72022-02-11 21:43:504379 continue
4380
4381 for pattern in file_patterns:
Daniel Chenga37c03db2022-05-12 17:20:344382 # Unlike `excluded_patterns`, `file_patterns` is checked only against the
4383 # file's basename.
4384 if input_api.fnmatch.fnmatch(file_basename, pattern):
4385 AddPatternToCheck(file, pattern)
Sam Maiera6e76d72022-02-11 21:43:504386 break
4387
Daniel Chenga37c03db2022-05-12 17:20:344388 has_security_sensitive_files = bool(to_check)
Daniel Cheng171dad8d2022-05-21 00:40:254389
4390 # Check if any newly added lines in OWNERS files intersect with required
4391 # per-file OWNERS lines. If so, ensure that a security reviewer is included.
4392 # This is a hack, but is needed because the OWNERS check (by design) ignores
4393 # new OWNERS entries; otherwise, a non-owner could add someone as a new
4394 # OWNER and have that newly-added OWNER self-approve their own addition.
4395 newly_covered_files = []
4396 for file in input_api.AffectedFiles(include_deletes=False):
4397 if not file.LocalPath() in to_check:
4398 continue
4399 for _, line in file.ChangedContents():
4400 for _, entry in to_check[file.LocalPath()].items():
4401 if line in entry['rules']:
4402 newly_covered_files.extend(entry['files'])
4403
4404 missing_reviewer_problems = None
4405 if newly_covered_files and not _ChangeHasSecurityReviewer(
Daniel Chenga37c03db2022-05-12 17:20:344406 input_api, required_owners_file):
Daniel Cheng171dad8d2022-05-21 00:40:254407 missing_reviewer_problems = _SecurityProblemWithItems(
4408 f'Review from an owner in {required_owners_file} is required for '
4409 'the following newly-added files:',
4410 [f'{file}' for file in sorted(set(newly_covered_files))])
Sam Maiera6e76d72022-02-11 21:43:504411
4412 # Go through the OWNERS files to check, filtering out rules that are already
4413 # present in that OWNERS file.
4414 for owners_file, patterns in to_check.items():
4415 try:
Daniel Cheng171dad8d2022-05-21 00:40:254416 lines = set(
4417 input_api.ReadFile(
4418 input_api.os_path.join(input_api.change.RepositoryRoot(),
4419 owners_file)).splitlines())
4420 for entry in patterns.values():
4421 entry['rules'] = [
4422 rule for rule in entry['rules'] if rule not in lines
4423 ]
Sam Maiera6e76d72022-02-11 21:43:504424 except IOError:
4425 # No OWNERS file, so all the rules are definitely missing.
4426 continue
4427
4428 # All the remaining lines weren't found in OWNERS files, so emit an error.
Daniel Cheng171dad8d2022-05-21 00:40:254429 owners_file_problems = []
Daniel Chenga37c03db2022-05-12 17:20:344430
Sam Maiera6e76d72022-02-11 21:43:504431 for owners_file, patterns in to_check.items():
4432 missing_lines = []
4433 files = []
4434 for _, entry in patterns.items():
Daniel Chenged57a162022-05-25 02:56:344435 files.extend(entry['files'])
Sam Maiera6e76d72022-02-11 21:43:504436 missing_lines.extend(entry['rules'])
Sam Maiera6e76d72022-02-11 21:43:504437 if missing_lines:
Daniel Cheng171dad8d2022-05-21 00:40:254438 joined_missing_lines = '\n'.join(line for line in missing_lines)
4439 owners_file_problems.append(
4440 _SecurityProblemWithItems(
4441 'Found missing OWNERS lines for security-sensitive files. '
4442 f'Please add the following lines to {owners_file}:\n'
4443 f'{joined_missing_lines}\n\nTo ensure security review for:',
4444 files))
Daniel Chenga37c03db2022-05-12 17:20:344445
Daniel Cheng171dad8d2022-05-21 00:40:254446 return _MissingSecurityOwnersResult(owners_file_problems,
Daniel Chenga37c03db2022-05-12 17:20:344447 has_security_sensitive_files,
Daniel Cheng171dad8d2022-05-21 00:40:254448 missing_reviewer_problems)
Daniel Chenga37c03db2022-05-12 17:20:344449
4450
4451def _CheckChangeForIpcSecurityOwners(input_api, output_api):
4452 # Whether or not a file affects IPC is (mostly) determined by a simple list
4453 # of filename patterns.
4454 file_patterns = [
4455 # Legacy IPC:
4456 '*_messages.cc',
4457 '*_messages*.h',
4458 '*_param_traits*.*',
4459 # Mojo IPC:
4460 '*.mojom',
4461 '*_mojom_traits*.*',
4462 '*_type_converter*.*',
4463 # Android native IPC:
4464 '*.aidl',
4465 ]
4466
Daniel Chenga37c03db2022-05-12 17:20:344467 excluded_patterns = [
Daniel Cheng518943f2022-05-12 22:15:464468 # These third_party directories do not contain IPCs, but contain files
4469 # matching the above patterns, which trigger false positives.
Daniel Chenga37c03db2022-05-12 17:20:344470 'third_party/crashpad/*',
4471 'third_party/blink/renderer/platform/bindings/*',
Evan Stade23a77da2025-02-06 21:15:314472 'third_party/protobuf/*',
Daniel Chenga37c03db2022-05-12 17:20:344473 'third_party/win_build_output/*',
Daniel Chengd88244472022-05-16 09:08:474474 # Enum-only mojoms used for web metrics, so no security review needed.
4475 'third_party/blink/public/mojom/use_counter/metrics/*',
Daniel Chenga37c03db2022-05-12 17:20:344476 ]
4477
4478 def IsMojoServiceManifestFile(input_api, file):
Dirk Prankee4df27972025-02-26 18:39:354479 manifest_pattern = input_api.re.compile(r'manifests?\.(cc|h)$')
Daniel Cheng6303eed2025-05-03 00:12:334480 test_manifest_pattern = input_api.re.compile(
4481 r'test_manifests?\.(cc|h)')
Daniel Chenga37c03db2022-05-12 17:20:344482 if not manifest_pattern.search(file.LocalPath()):
4483 return False
4484
4485 if test_manifest_pattern.search(file.LocalPath()):
4486 return False
4487
4488 # All actual service manifest files should contain at least one
4489 # qualified reference to service_manager::Manifest.
4490 return any('service_manager::Manifest' in line
4491 for line in file.NewContents())
4492
4493 return _FindMissingSecurityOwners(
4494 input_api,
4495 output_api,
4496 file_patterns,
4497 excluded_patterns,
4498 'ipc/SECURITY_OWNERS',
4499 custom_rule_function=IsMojoServiceManifestFile)
4500
4501
4502def _CheckChangeForFuchsiaSecurityOwners(input_api, output_api):
4503 file_patterns = [
4504 # Component specifications.
4505 '*.cml', # Component Framework v2.
4506 '*.cmx', # Component Framework v1.
4507
4508 # Fuchsia IDL protocol specifications.
4509 '*.fidl',
4510 ]
4511
4512 # Don't check for owners files for changes in these directories.
4513 excluded_patterns = [
4514 'third_party/crashpad/*',
4515 ]
4516
4517 return _FindMissingSecurityOwners(input_api, output_api, file_patterns,
4518 excluded_patterns,
4519 'build/fuchsia/SECURITY_OWNERS')
4520
4521
4522def CheckSecurityOwners(input_api, output_api):
4523 """Checks that various security-sensitive files have an IPC OWNERS rule."""
4524 ipc_results = _CheckChangeForIpcSecurityOwners(input_api, output_api)
4525 fuchsia_results = _CheckChangeForFuchsiaSecurityOwners(
4526 input_api, output_api)
4527
4528 if ipc_results.has_security_sensitive_files:
4529 output_api.AppendCC('[email protected]')
Sam Maiera6e76d72022-02-11 21:43:504530
4531 results = []
Daniel Chenga37c03db2022-05-12 17:20:344532
Daniel Cheng171dad8d2022-05-21 00:40:254533 missing_reviewer_problems = []
4534 if ipc_results.missing_reviewer_problem:
4535 missing_reviewer_problems.append(ipc_results.missing_reviewer_problem)
4536 if fuchsia_results.missing_reviewer_problem:
4537 missing_reviewer_problems.append(
4538 fuchsia_results.missing_reviewer_problem)
Daniel Chenga37c03db2022-05-12 17:20:344539
Daniel Cheng171dad8d2022-05-21 00:40:254540 # Missing reviewers are an error unless there's no issue number
4541 # associated with this branch; in that case, the presubmit is being run
4542 # with --all or --files.
4543 #
4544 # Note that upload should never be an error; otherwise, it would be
4545 # impossible to upload changes at all.
4546 if input_api.is_committing and input_api.change.issue:
4547 make_presubmit_message = output_api.PresubmitError
4548 else:
4549 make_presubmit_message = output_api.PresubmitNotifyResult
4550 for problem in missing_reviewer_problems:
Sam Maiera6e76d72022-02-11 21:43:504551 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:254552 make_presubmit_message(problem.problem, items=problem.items))
Daniel Chenga37c03db2022-05-12 17:20:344553
Daniel Cheng171dad8d2022-05-21 00:40:254554 owners_file_problems = []
4555 owners_file_problems.extend(ipc_results.owners_file_problems)
4556 owners_file_problems.extend(fuchsia_results.owners_file_problems)
Daniel Chenga37c03db2022-05-12 17:20:344557
Daniel Cheng171dad8d2022-05-21 00:40:254558 for problem in owners_file_problems:
Daniel Cheng3008dc12022-05-13 04:02:114559 # Missing per-file rules are always an error. While swarming and caching
4560 # means that uploading a patchset with updated OWNERS files and sending
4561 # it to the CQ again should not have a large incremental cost, it is
4562 # still frustrating to discover the error only after the change has
4563 # already been uploaded.
Daniel Chenga37c03db2022-05-12 17:20:344564 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:254565 output_api.PresubmitError(problem.problem, items=problem.items))
Sam Maiera6e76d72022-02-11 21:43:504566
4567 return results
4568
4569
4570def _GetFilesUsingSecurityCriticalFunctions(input_api):
4571 """Checks affected files for changes to security-critical calls. This
4572 function checks the full change diff, to catch both additions/changes
4573 and removals.
4574
4575 Returns a dict keyed by file name, and the value is a set of detected
4576 functions.
4577 """
4578 # Map of function pretty name (displayed in an error) to the pattern to
4579 # match it with.
4580 _PATTERNS_TO_CHECK = {
4581 'content::GetServiceSandboxType<>()': 'GetServiceSandboxType\\<'
4582 }
4583 _PATTERNS_TO_CHECK = {
4584 k: input_api.re.compile(v)
4585 for k, v in _PATTERNS_TO_CHECK.items()
4586 }
4587
Sam Maiera6e76d72022-02-11 21:43:504588 # We don't want to trigger on strings within this file.
4589 def presubmit_file_filter(f):
Daniel Chenga37c03db2022-05-12 17:20:344590 return 'PRESUBMIT.py' != input_api.os_path.split(f.LocalPath())[1]
Sam Maiera6e76d72022-02-11 21:43:504591
4592 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
4593 files_to_functions = {}
4594 for f in input_api.AffectedFiles(file_filter=presubmit_file_filter):
4595 diff = f.GenerateScmDiff()
4596 for line in diff.split('\n'):
4597 # Not using just RightHandSideLines() because removing a
4598 # call to a security-critical function can be just as important
4599 # as adding or changing the arguments.
4600 if line.startswith('-') or (line.startswith('+')
4601 and not line.startswith('++')):
4602 for name, pattern in _PATTERNS_TO_CHECK.items():
4603 if pattern.search(line):
4604 path = f.LocalPath()
4605 if not path in files_to_functions:
4606 files_to_functions[path] = set()
4607 files_to_functions[path].add(name)
4608 return files_to_functions
4609
4610
4611def CheckSecurityChanges(input_api, output_api):
4612 """Checks that changes involving security-critical functions are reviewed
4613 by the security team.
4614 """
4615 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
4616 if not len(files_to_functions):
4617 return []
4618
Sam Maiera6e76d72022-02-11 21:43:504619 owners_file = 'ipc/SECURITY_OWNERS'
Daniel Chenga37c03db2022-05-12 17:20:344620 if _ChangeHasSecurityReviewer(input_api, owners_file):
Sam Maiera6e76d72022-02-11 21:43:504621 return []
4622
Daniel Chenga37c03db2022-05-12 17:20:344623 msg = 'The following files change calls to security-sensitive functions\n' \
Sam Maiera6e76d72022-02-11 21:43:504624 'that need to be reviewed by {}.\n'.format(owners_file)
4625 for path, names in files_to_functions.items():
4626 msg += ' {}\n'.format(path)
4627 for name in names:
4628 msg += ' {}\n'.format(name)
4629 msg += '\n'
4630
4631 if input_api.is_committing:
4632 output = output_api.PresubmitError
Mohamed Heikale217fc852020-07-06 19:44:034633 else:
Sam Maiera6e76d72022-02-11 21:43:504634 output = output_api.PresubmitNotifyResult
4635 return [output(msg)]
4636
4637
4638def CheckSetNoParent(input_api, output_api):
4639 """Checks that set noparent is only used together with an OWNERS file in
4640 //build/OWNERS.setnoparent (see also
4641 //docs/code_reviews.md#owners-files-details)
4642 """
4643 # Return early if no OWNERS files were modified.
4644 if not any(f.LocalPath().endswith('OWNERS')
4645 for f in input_api.AffectedFiles(include_deletes=False)):
4646 return []
4647
4648 errors = []
4649
4650 allowed_owners_files_file = 'build/OWNERS.setnoparent'
4651 allowed_owners_files = set()
Bruce Dawson58a45d22023-02-27 11:24:164652 with open(allowed_owners_files_file, 'r', encoding='utf-8') as f:
Sam Maiera6e76d72022-02-11 21:43:504653 for line in f:
4654 line = line.strip()
4655 if not line or line.startswith('#'):
4656 continue
4657 allowed_owners_files.add(line)
4658
4659 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
4660
4661 for f in input_api.AffectedFiles(include_deletes=False):
4662 if not f.LocalPath().endswith('OWNERS'):
4663 continue
4664
4665 found_owners_files = set()
4666 found_set_noparent_lines = dict()
4667
4668 # Parse the OWNERS file.
4669 for lineno, line in enumerate(f.NewContents(), 1):
4670 line = line.strip()
4671 if line.startswith('set noparent'):
4672 found_set_noparent_lines[''] = lineno
4673 if line.startswith('file://'):
4674 if line in allowed_owners_files:
4675 found_owners_files.add('')
4676 if line.startswith('per-file'):
4677 match = per_file_pattern.match(line)
4678 if match:
4679 glob = match.group(1).strip()
4680 directive = match.group(2).strip()
4681 if directive == 'set noparent':
4682 found_set_noparent_lines[glob] = lineno
4683 if directive.startswith('file://'):
4684 if directive in allowed_owners_files:
4685 found_owners_files.add(glob)
4686
4687 # Check that every set noparent line has a corresponding file:// line
4688 # listed in build/OWNERS.setnoparent. An exception is made for top level
4689 # directories since src/OWNERS shouldn't review them.
Anton Bershanskyi4253349482025-02-11 21:01:274690 linux_path = f.UnixLocalPath()
Bruce Dawson6bb0d672022-04-06 15:13:494691 if (linux_path.count('/') != 1
4692 and (not linux_path in _EXCLUDED_SET_NO_PARENT_PATHS)):
Sam Maiera6e76d72022-02-11 21:43:504693 for set_noparent_line in found_set_noparent_lines:
4694 if set_noparent_line in found_owners_files:
4695 continue
Daniel Cheng6303eed2025-05-03 00:12:334696 errors.append(
4697 ' %s:%d' %
4698 (linux_path, found_set_noparent_lines[set_noparent_line]))
Sam Maiera6e76d72022-02-11 21:43:504699
4700 results = []
4701 if errors:
4702 if input_api.is_committing:
4703 output = output_api.PresubmitError
4704 else:
4705 output = output_api.PresubmitPromptWarning
4706 results.append(
4707 output(
4708 'Found the following "set noparent" restrictions in OWNERS files that '
4709 'do not include owners from build/OWNERS.setnoparent:',
4710 long_text='\n\n'.join(errors)))
4711 return results
4712
4713
4714def CheckUselessForwardDeclarations(input_api, output_api):
4715 """Checks that added or removed lines in non third party affected
4716 header files do not lead to new useless class or struct forward
4717 declaration.
4718 """
4719 results = []
4720 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
4721 input_api.re.MULTILINE)
4722 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
4723 input_api.re.MULTILINE)
4724 for f in input_api.AffectedFiles(include_deletes=False):
Anton Bershanskyi4253349482025-02-11 21:01:274725 local_path = f.UnixLocalPath()
4726 if (local_path.startswith('third_party')
4727 and not local_path.startswith('third_party/blink')):
Sam Maiera6e76d72022-02-11 21:43:504728 continue
4729
Anton Bershanskyi4253349482025-02-11 21:01:274730 if not local_path.endswith('.h'):
Sam Maiera6e76d72022-02-11 21:43:504731 continue
4732
4733 contents = input_api.ReadFile(f)
4734 fwd_decls = input_api.re.findall(class_pattern, contents)
4735 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
4736
4737 useless_fwd_decls = []
4738 for decl in fwd_decls:
4739 count = sum(1 for _ in input_api.re.finditer(
4740 r'\b%s\b' % input_api.re.escape(decl), contents))
4741 if count == 1:
4742 useless_fwd_decls.append(decl)
4743
4744 if not useless_fwd_decls:
4745 continue
4746
4747 for line in f.GenerateScmDiff().splitlines():
4748 if (line.startswith('-') and not line.startswith('--')
4749 or line.startswith('+') and not line.startswith('++')):
4750 for decl in useless_fwd_decls:
4751 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
4752 results.append(
4753 output_api.PresubmitPromptWarning(
4754 '%s: %s forward declaration is no longer needed'
4755 % (f.LocalPath(), decl)))
4756 useless_fwd_decls.remove(decl)
4757
4758 return results
4759
4760
4761def _CheckAndroidDebuggableBuild(input_api, output_api):
4762 """Checks that code uses BuildInfo.isDebugAndroid() instead of
4763 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
4764 this is a debuggable build of Android.
4765 """
4766 build_type_check_pattern = input_api.re.compile(
4767 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
4768
4769 errors = []
4770
4771 sources = lambda affected_file: input_api.FilterSourceFile(
4772 affected_file,
4773 files_to_skip=(
4774 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4775 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314776 r"^android_webview/support_library/boundary_interfaces/",
4777 r"^chrome/android/webapk/.*",
4778 r'^third_party/.*',
4779 r"tools/android/customtabs_benchmark/.*",
4780 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504781 )),
4782 files_to_check=[r'.*\.java$'])
4783
4784 for f in input_api.AffectedSourceFiles(sources):
4785 for line_num, line in f.ChangedContents():
4786 if build_type_check_pattern.search(line):
4787 errors.append("%s:%d" % (f.LocalPath(), line_num))
4788
4789 results = []
4790
4791 if errors:
4792 results.append(
4793 output_api.PresubmitPromptWarning(
4794 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
4795 ' Please use BuildInfo.isDebugAndroid() instead.', errors))
4796
4797 return results
4798
Daniel Cheng6303eed2025-05-03 00:12:334799
Sam Maiera6e76d72022-02-11 21:43:504800# TODO: add unit tests
4801def _CheckAndroidToastUsage(input_api, output_api):
4802 """Checks that code uses org.chromium.ui.widget.Toast instead of
4803 android.widget.Toast (Chromium Toast doesn't force hardware
4804 acceleration on low-end devices, saving memory).
4805 """
4806 toast_import_pattern = input_api.re.compile(
4807 r'^import android\.widget\.Toast;$')
4808
4809 errors = []
4810
4811 sources = lambda affected_file: input_api.FilterSourceFile(
4812 affected_file,
4813 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
Daniel Cheng6303eed2025-05-03 00:12:334814 DEFAULT_FILES_TO_SKIP +
4815 (r'^chromecast/.*', r'^remoting/.*')),
Sam Maiera6e76d72022-02-11 21:43:504816 files_to_check=[r'.*\.java$'])
4817
4818 for f in input_api.AffectedSourceFiles(sources):
4819 for line_num, line in f.ChangedContents():
4820 if toast_import_pattern.search(line):
4821 errors.append("%s:%d" % (f.LocalPath(), line_num))
4822
4823 results = []
4824
4825 if errors:
4826 results.append(
4827 output_api.PresubmitError(
4828 'android.widget.Toast usage is detected. Android toasts use hardware'
4829 ' acceleration, and can be\ncostly on low-end devices. Please use'
4830 ' org.chromium.ui.widget.Toast instead.\n'
4831 'Contact [email protected] if you have any questions.',
4832 errors))
4833
4834 return results
4835
4836
4837def _CheckAndroidCrLogUsage(input_api, output_api):
4838 """Checks that new logs using org.chromium.base.Log:
4839 - Are using 'TAG' as variable name for the tags (warn)
4840 - Are using a tag that is shorter than 20 characters (error)
4841 """
4842
4843 # Do not check format of logs in the given files
4844 cr_log_check_excluded_paths = [
4845 # //chrome/android/webapk cannot depend on //base
Bruce Dawson40fece62022-09-16 19:58:314846 r"^chrome/android/webapk/.*",
Sam Maiera6e76d72022-02-11 21:43:504847 # WebView license viewer code cannot depend on //base; used in stub APK.
Bruce Dawson40fece62022-09-16 19:58:314848 r"^android_webview/glue/java/src/com/android/"
4849 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504850 # The customtabs_benchmark is a small app that does not depend on Chromium
4851 # java pieces.
Bruce Dawson40fece62022-09-16 19:58:314852 r"tools/android/customtabs_benchmark/.*",
Sam Maiera6e76d72022-02-11 21:43:504853 ]
4854
4855 cr_log_import_pattern = input_api.re.compile(
4856 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
4857 class_in_base_pattern = input_api.re.compile(
4858 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
4859 has_some_log_import_pattern = input_api.re.compile(r'^import .*\.Log;$',
4860 input_api.re.MULTILINE)
4861 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
4862 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
4863 log_decl_pattern = input_api.re.compile(
4864 r'static final String TAG = "(?P<name>(.*))"')
4865 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
4866
4867 REF_MSG = ('See docs/android_logging.md for more info.')
4868 sources = lambda x: input_api.FilterSourceFile(
4869 x,
4870 files_to_check=[r'.*\.java$'],
4871 files_to_skip=cr_log_check_excluded_paths)
4872
4873 tag_decl_errors = []
Andrew Grieved3a35d82024-01-02 21:24:384874 tag_length_errors = []
Sam Maiera6e76d72022-02-11 21:43:504875 tag_errors = []
4876 tag_with_dot_errors = []
4877 util_log_errors = []
4878
4879 for f in input_api.AffectedSourceFiles(sources):
4880 file_content = input_api.ReadFile(f)
4881 has_modified_logs = False
4882 # Per line checks
4883 if (cr_log_import_pattern.search(file_content)
4884 or (class_in_base_pattern.search(file_content)
4885 and not has_some_log_import_pattern.search(file_content))):
4886 # Checks to run for files using cr log
4887 for line_num, line in f.ChangedContents():
4888 if rough_log_decl_pattern.search(line):
4889 has_modified_logs = True
4890
4891 # Check if the new line is doing some logging
4892 match = log_call_pattern.search(line)
4893 if match:
4894 has_modified_logs = True
4895
4896 # Make sure it uses "TAG"
4897 if not match.group('tag') == 'TAG':
4898 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
4899 else:
4900 # Report non cr Log function calls in changed lines
4901 for line_num, line in f.ChangedContents():
Sky Malice5766d282025-07-25 20:41:424902 if (log_call_pattern.search(line)
4903 or has_some_log_import_pattern.search(line)):
Sam Maiera6e76d72022-02-11 21:43:504904 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
4905
4906 # Per file checks
4907 if has_modified_logs:
4908 # Make sure the tag is using the "cr" prefix and is not too long
4909 match = log_decl_pattern.search(file_content)
4910 tag_name = match.group('name') if match else None
4911 if not tag_name:
4912 tag_decl_errors.append(f.LocalPath())
Andrew Grieved3a35d82024-01-02 21:24:384913 elif len(tag_name) > 20:
4914 tag_length_errors.append(f.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:504915 elif '.' in tag_name:
4916 tag_with_dot_errors.append(f.LocalPath())
4917
4918 results = []
4919 if tag_decl_errors:
4920 results.append(
4921 output_api.PresubmitPromptWarning(
4922 'Please define your tags using the suggested format: .\n'
4923 '"private static final String TAG = "<package tag>".\n'
4924 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
4925 tag_decl_errors))
4926
Andrew Grieved3a35d82024-01-02 21:24:384927 if tag_length_errors:
4928 results.append(
4929 output_api.PresubmitError(
4930 'The tag length is restricted by the system to be at most '
4931 '20 characters.\n' + REF_MSG, tag_length_errors))
4932
Sam Maiera6e76d72022-02-11 21:43:504933 if tag_errors:
4934 results.append(
4935 output_api.PresubmitPromptWarning(
4936 'Please use a variable named "TAG" for your log tags.\n' +
4937 REF_MSG, tag_errors))
4938
4939 if util_log_errors:
4940 results.append(
4941 output_api.PresubmitPromptWarning(
4942 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
4943 util_log_errors))
4944
4945 if tag_with_dot_errors:
4946 results.append(
4947 output_api.PresubmitPromptWarning(
4948 'Dot in log tags cause them to be elided in crash reports.\n' +
4949 REF_MSG, tag_with_dot_errors))
4950
4951 return results
4952
4953
Sam Maiera6e76d72022-02-11 21:43:504954def _CheckAndroidTestAnnotationUsage(input_api, output_api):
4955 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
4956 deprecated_annotation_import_pattern = input_api.re.compile(
4957 r'^import android\.test\.suitebuilder\.annotation\..*;',
4958 input_api.re.MULTILINE)
4959 sources = lambda x: input_api.FilterSourceFile(
4960 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
4961 errors = []
4962 for f in input_api.AffectedFiles(file_filter=sources):
4963 for line_num, line in f.ChangedContents():
4964 if deprecated_annotation_import_pattern.search(line):
4965 errors.append("%s:%d" % (f.LocalPath(), line_num))
4966
4967 results = []
4968 if errors:
4969 results.append(
4970 output_api.PresubmitError(
4971 'Annotations in android.test.suitebuilder.annotation have been'
Mohamed Heikal3d7a94c2023-03-28 16:55:244972 ' deprecated since API level 24. Please use androidx.test.filters'
4973 ' from //third_party/androidx:androidx_test_runner_java instead.'
Sam Maiera6e76d72022-02-11 21:43:504974 ' Contact [email protected] if you have any questions.',
4975 errors))
4976 return results
4977
4978
4979def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
4980 """Checks if MDPI assets are placed in a correct directory."""
Daniel Cheng6303eed2025-05-03 00:12:334981 file_filter = lambda f: (f.UnixLocalPath().endswith('.png') and
4982 ('/res/drawable/' in f.UnixLocalPath() or
4983 '/res/drawable-ldrtl/' in f.UnixLocalPath()))
Sam Maiera6e76d72022-02-11 21:43:504984 errors = []
4985 for f in input_api.AffectedFiles(include_deletes=False,
4986 file_filter=file_filter):
4987 errors.append(' %s' % f.LocalPath())
4988
4989 results = []
4990 if errors:
4991 results.append(
4992 output_api.PresubmitError(
4993 'MDPI assets should be placed in /res/drawable-mdpi/ or '
4994 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
4995 '/res/drawable-ldrtl/.\n'
4996 'Contact [email protected] if you have questions.', errors))
4997 return results
4998
4999
5000def _CheckAndroidWebkitImports(input_api, output_api):
5001 """Checks that code uses org.chromium.base.Callback instead of
Nate Fischer2d62ecf2025-08-01 19:31:305002 android.webview.ValueCallback except in the WebView glue layer.
Sam Maiera6e76d72022-02-11 21:43:505003 """
5004 valuecallback_import_pattern = input_api.re.compile(
5005 r'^import android\.webkit\.ValueCallback;$')
5006
5007 errors = []
5008
5009 sources = lambda affected_file: input_api.FilterSourceFile(
5010 affected_file,
5011 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
5012 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:315013 r'^android_webview/glue/.*',
elabadysayedcbbaea72024-08-01 16:10:425014 r'^android_webview/support_library/.*',
Sam Maiera6e76d72022-02-11 21:43:505015 )),
5016 files_to_check=[r'.*\.java$'])
5017
5018 for f in input_api.AffectedSourceFiles(sources):
5019 for line_num, line in f.ChangedContents():
5020 if valuecallback_import_pattern.search(line):
5021 errors.append("%s:%d" % (f.LocalPath(), line_num))
5022
5023 results = []
5024
5025 if errors:
5026 results.append(
5027 output_api.PresubmitError(
5028 'android.webkit.ValueCallback usage is detected outside of the glue'
5029 ' layer. To stay compatible with the support library, android.webkit.*'
5030 ' classes should only be used inside the glue layer and'
5031 ' org.chromium.base.Callback should be used instead.', errors))
5032
5033 return results
5034
5035
5036def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
5037 """Checks Android XML styles """
5038
5039 # Return early if no relevant files were modified.
5040 if not any(
5041 _IsXmlOrGrdFile(input_api, f.LocalPath())
5042 for f in input_api.AffectedFiles(include_deletes=False)):
5043 return []
5044
5045 import sys
5046 original_sys_path = sys.path
5047 try:
5048 sys.path = sys.path + [
5049 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5050 'android', 'checkxmlstyle')
5051 ]
5052 import checkxmlstyle
5053 finally:
5054 # Restore sys.path to what it was before.
5055 sys.path = original_sys_path
5056
5057 if is_check_on_upload:
5058 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
5059 else:
5060 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
5061
5062
5063def _CheckAndroidInfoBarDeprecation(input_api, output_api):
5064 """Checks Android Infobar Deprecation """
5065
5066 import sys
5067 original_sys_path = sys.path
5068 try:
5069 sys.path = sys.path + [
5070 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5071 'android', 'infobar_deprecation')
5072 ]
5073 import infobar_deprecation
5074 finally:
5075 # Restore sys.path to what it was before.
5076 sys.path = original_sys_path
5077
5078 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
5079
5080
5081class _PydepsCheckerResult:
Daniel Cheng6303eed2025-05-03 00:12:335082
Sam Maiera6e76d72022-02-11 21:43:505083 def __init__(self, cmd, pydeps_path, process, old_contents):
5084 self._cmd = cmd
5085 self._pydeps_path = pydeps_path
5086 self._process = process
5087 self._old_contents = old_contents
5088
5089 def GetError(self):
5090 """Returns an error message, or None."""
5091 import difflib
Andrew Grieved27620b62023-07-13 16:35:075092 new_contents = self._process.stdout.read().splitlines()[2:]
Sam Maiera6e76d72022-02-11 21:43:505093 if self._process.wait() != 0:
5094 # STDERR should already be printed.
5095 return 'Command failed: ' + self._cmd
Sam Maiera6e76d72022-02-11 21:43:505096 if self._old_contents != new_contents:
5097 diff = '\n'.join(
5098 difflib.context_diff(self._old_contents, new_contents))
5099 return ('File is stale: {}\n'
5100 'Diff (apply to fix):\n'
5101 '{}\n'
5102 'To regenerate, run:\n\n'
5103 ' {}').format(self._pydeps_path, diff, self._cmd)
5104 return None
5105
5106
5107class PydepsChecker:
Daniel Cheng6303eed2025-05-03 00:12:335108
Sam Maiera6e76d72022-02-11 21:43:505109 def __init__(self, input_api, pydeps_files):
5110 self._file_cache = {}
5111 self._input_api = input_api
5112 self._pydeps_files = pydeps_files
5113
5114 def _LoadFile(self, path):
5115 """Returns the list of paths within a .pydeps file relative to //."""
5116 if path not in self._file_cache:
5117 with open(path, encoding='utf-8') as f:
5118 self._file_cache[path] = f.read()
5119 return self._file_cache[path]
5120
5121 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
Gao Shenga79ebd42022-08-08 17:25:595122 """Returns an iterable of paths within the .pydep, relativized to //."""
Sam Maiera6e76d72022-02-11 21:43:505123 pydeps_data = self._LoadFile(pydeps_path)
5124 uses_gn_paths = '--gn-paths' in pydeps_data
5125 entries = (l for l in pydeps_data.splitlines()
5126 if not l.startswith('#'))
5127 if uses_gn_paths:
5128 # Paths look like: //foo/bar/baz
5129 return (e[2:] for e in entries)
5130 else:
5131 # Paths look like: path/relative/to/file.pydeps
5132 os_path = self._input_api.os_path
5133 pydeps_dir = os_path.dirname(pydeps_path)
5134 return (os_path.normpath(os_path.join(pydeps_dir, e))
5135 for e in entries)
5136
5137 def _CreateFilesToPydepsMap(self):
5138 """Returns a map of local_path -> list_of_pydeps."""
5139 ret = {}
5140 for pydep_local_path in self._pydeps_files:
5141 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
5142 ret.setdefault(path, []).append(pydep_local_path)
5143 return ret
5144
5145 def ComputeAffectedPydeps(self):
5146 """Returns an iterable of .pydeps files that might need regenerating."""
5147 affected_pydeps = set()
5148 file_to_pydeps_map = None
5149 for f in self._input_api.AffectedFiles(include_deletes=True):
5150 local_path = f.LocalPath()
5151 # Changes to DEPS can lead to .pydeps changes if any .py files are in
5152 # subrepositories. We can't figure out which files change, so re-check
5153 # all files.
5154 # Changes to print_python_deps.py affect all .pydeps.
5155 if local_path in ('DEPS', 'PRESUBMIT.py'
5156 ) or local_path.endswith('print_python_deps.py'):
5157 return self._pydeps_files
5158 elif local_path.endswith('.pydeps'):
5159 if local_path in self._pydeps_files:
5160 affected_pydeps.add(local_path)
5161 elif local_path.endswith('.py'):
5162 if file_to_pydeps_map is None:
5163 file_to_pydeps_map = self._CreateFilesToPydepsMap()
5164 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
5165 return affected_pydeps
5166
5167 def DetermineIfStaleAsync(self, pydeps_path):
5168 """Runs print_python_deps.py to see if the files is stale."""
5169 import os
5170
5171 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
5172 if old_pydeps_data:
5173 cmd = old_pydeps_data[1][1:].strip()
5174 if '--output' not in cmd:
5175 cmd += ' --output ' + pydeps_path
5176 old_contents = old_pydeps_data[2:]
5177 else:
5178 # A default cmd that should work in most cases (as long as pydeps filename
5179 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
5180 # file is empty/new.
5181 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
5182 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
5183 old_contents = []
5184 env = dict(os.environ)
5185 env['PYTHONDONTWRITEBYTECODE'] = '1'
5186 process = self._input_api.subprocess.Popen(
5187 cmd + ' --output ""',
5188 shell=True,
5189 env=env,
5190 stdout=self._input_api.subprocess.PIPE,
5191 encoding='utf-8')
5192 return _PydepsCheckerResult(cmd, pydeps_path, process, old_contents)
agrievef32bcc72016-04-04 14:57:405193
5194
Tibor Goldschwendt360793f72019-06-25 18:23:495195def _ParseGclientArgs():
Sam Maiera6e76d72022-02-11 21:43:505196 args = {}
5197 with open('build/config/gclient_args.gni', 'r') as f:
5198 for line in f:
5199 line = line.strip()
5200 if not line or line.startswith('#'):
5201 continue
5202 attribute, value = line.split('=')
5203 args[attribute.strip()] = value.strip()
5204 return args
Tibor Goldschwendt360793f72019-06-25 18:23:495205
5206
Saagar Sanghavifceeaae2020-08-12 16:40:365207def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
Sam Maiera6e76d72022-02-11 21:43:505208 """Checks if a .pydeps file needs to be regenerated."""
5209 # This check is for Python dependency lists (.pydeps files), and involves
5210 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
5211 # doesn't work on Windows and Mac, so skip it on other platforms.
5212 if not input_api.platform.startswith('linux'):
5213 return []
Erik Staabc734cd7a2021-11-23 03:11:525214
Sam Maiera6e76d72022-02-11 21:43:505215 results = []
5216 # First, check for new / deleted .pydeps.
5217 for f in input_api.AffectedFiles(include_deletes=True):
5218 # Check whether we are running the presubmit check for a file in src.
Sam Maiera6e76d72022-02-11 21:43:505219 if f.LocalPath().endswith('.pydeps'):
Andrew Grieve713b89b2024-10-15 20:20:085220 # f.LocalPath is relative to repo (src, or internal repo).
5221 # os_path.exists is relative to src repo.
5222 # Therefore if os_path.exists is true, it means f.LocalPath is relative
5223 # to src and we can conclude that the pydeps is in src.
5224 exists = input_api.os_path.exists(f.LocalPath())
5225 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
5226 results.append(
5227 output_api.PresubmitError(
5228 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
5229 'remove %s' % f.LocalPath()))
5230 elif (f.Action() != 'D' and exists
5231 and f.LocalPath() not in _ALL_PYDEPS_FILES):
5232 results.append(
5233 output_api.PresubmitError(
5234 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
5235 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:405236
Sam Maiera6e76d72022-02-11 21:43:505237 if results:
5238 return results
5239
Gavin Mak23884402024-07-25 20:39:265240 try:
5241 parsed_args = _ParseGclientArgs()
5242 except FileNotFoundError:
5243 message = (
5244 'build/config/gclient_args.gni not found. Please make sure your '
Daniel Cheng6303eed2025-05-03 00:12:335245 'workspace has been initialized with gclient sync.')
Gavin Mak23884402024-07-25 20:39:265246 import sys
5247 original_sys_path = sys.path
5248 try:
5249 sys.path = sys.path + [
5250 input_api.os_path.join(input_api.PresubmitLocalPath(),
Daniel Cheng6303eed2025-05-03 00:12:335251 'third_party', 'depot_tools')
Gavin Mak23884402024-07-25 20:39:265252 ]
5253 import gclient_utils
5254 if gclient_utils.IsEnvCog():
5255 # Users will always hit this when they run presubmits before cog
5256 # workspace initialization finishes. The check shouldn't fail in
5257 # this case. This is an unavoidable workaround that's needed for
5258 # good presubmit UX for cog.
5259 results.append(output_api.PresubmitPromptWarning(message))
5260 else:
5261 results.append(output_api.PresubmitError(message))
5262 return results
5263 finally:
5264 # Restore sys.path to what it was before.
5265 sys.path = original_sys_path
5266
5267 is_android = parsed_args.get('checkout_android', 'false') == 'true'
Sam Maiera6e76d72022-02-11 21:43:505268 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
5269 affected_pydeps = set(checker.ComputeAffectedPydeps())
5270 affected_android_pydeps = affected_pydeps.intersection(
5271 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
5272 if affected_android_pydeps and not is_android:
5273 results.append(
5274 output_api.PresubmitPromptOrNotify(
5275 'You have changed python files that may affect pydeps for android\n'
Gao Shenga79ebd42022-08-08 17:25:595276 'specific scripts. However, the relevant presubmit check cannot be\n'
Sam Maiera6e76d72022-02-11 21:43:505277 'run because you are not using an Android checkout. To validate that\n'
5278 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
5279 'use the android-internal-presubmit optional trybot.\n'
5280 'Possibly stale pydeps files:\n{}'.format(
5281 '\n'.join(affected_android_pydeps))))
5282
5283 all_pydeps = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
5284 pydeps_to_check = affected_pydeps.intersection(all_pydeps)
5285 # Process these concurrently, as each one takes 1-2 seconds.
5286 pydep_results = [checker.DetermineIfStaleAsync(p) for p in pydeps_to_check]
5287 for result in pydep_results:
5288 error_msg = result.GetError()
5289 if error_msg:
5290 results.append(output_api.PresubmitError(error_msg))
5291
agrievef32bcc72016-04-04 14:57:405292 return results
5293
agrievef32bcc72016-04-04 14:57:405294
Saagar Sanghavifceeaae2020-08-12 16:40:365295def CheckSingletonInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505296 """Checks to make sure no header files have |Singleton<|."""
5297
5298 def FileFilter(affected_file):
5299 # It's ok for base/memory/singleton.h to have |Singleton<|.
5300 files_to_skip = (_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
Bruce Dawson40fece62022-09-16 19:58:315301 (r"^base/memory/singleton\.h$",
5302 r"^net/quic/platform/impl/quic_singleton_impl\.h$"))
Sam Maiera6e76d72022-02-11 21:43:505303 return input_api.FilterSourceFile(affected_file,
5304 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:435305
Sam Maiera6e76d72022-02-11 21:43:505306 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
5307 files = []
5308 for f in input_api.AffectedSourceFiles(FileFilter):
5309 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx')
5310 or f.LocalPath().endswith('.hpp')
5311 or f.LocalPath().endswith('.inl')):
5312 contents = input_api.ReadFile(f)
5313 for line in contents.splitlines(False):
5314 if (not line.lstrip().startswith('//')
5315 and # Strip C++ comment.
5316 pattern.search(line)):
5317 files.append(f)
5318 break
glidere61efad2015-02-18 17:39:435319
Sam Maiera6e76d72022-02-11 21:43:505320 if files:
5321 return [
5322 output_api.PresubmitError(
5323 'Found base::Singleton<T> in the following header files.\n' +
5324 'Please move them to an appropriate source file so that the ' +
5325 'template gets instantiated in a single compilation unit.',
5326 files)
5327 ]
5328 return []
glidere61efad2015-02-18 17:39:435329
5330
[email protected]fd20b902014-05-09 02:14:535331_DEPRECATED_CSS = [
Daniel Cheng6303eed2025-05-03 00:12:335332 # Values
5333 ("-webkit-box", "flex"),
5334 ("-webkit-inline-box", "inline-flex"),
5335 ("-webkit-flex", "flex"),
5336 ("-webkit-inline-flex", "inline-flex"),
5337 ("-webkit-min-content", "min-content"),
5338 ("-webkit-max-content", "max-content"),
[email protected]fd20b902014-05-09 02:14:535339
Daniel Cheng6303eed2025-05-03 00:12:335340 # Properties
5341 ("-webkit-background-clip", "background-clip"),
5342 ("-webkit-background-origin", "background-origin"),
5343 ("-webkit-background-size", "background-size"),
5344 ("-webkit-box-shadow", "box-shadow"),
5345 ("-webkit-user-select", "user-select"),
[email protected]fd20b902014-05-09 02:14:535346
Daniel Cheng6303eed2025-05-03 00:12:335347 # Functions
5348 ("-webkit-gradient", "gradient"),
5349 ("-webkit-repeating-gradient", "repeating-gradient"),
5350 ("-webkit-linear-gradient", "linear-gradient"),
5351 ("-webkit-repeating-linear-gradient", "repeating-linear-gradient"),
5352 ("-webkit-radial-gradient", "radial-gradient"),
5353 ("-webkit-repeating-radial-gradient", "repeating-radial-gradient"),
[email protected]fd20b902014-05-09 02:14:535354]
5355
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:205356
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:495357# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:365358def CheckNoDeprecatedCss(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505359 """ Make sure that we don't use deprecated CSS
5360 properties, functions or values. Our external
5361 documentation and iOS CSS for dom distiller
5362 (reader mode) are ignored by the hooks as it
5363 needs to be consumed by WebKit. """
5364 results = []
5365 file_inclusion_pattern = [r".+\.css$"]
Daniel Cheng6303eed2025-05-03 00:12:335366 files_to_skip = (
5367 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
5368 input_api.DEFAULT_FILES_TO_SKIP +
5369 ( # Legacy CSS file using deprecated CSS.
5370 r"^chrome/browser/resources/chromeos/arc_support/cr_overlay.css$",
5371 r"^chrome/common/extensions/docs",
5372 r"^chrome/docs",
5373 r"^native_client_sdk",
5374 # The NTP team prefers reserving -webkit-line-clamp for
5375 # ellipsis effect which can only be used with -webkit-box.
5376 r"ui/webui/resources/cr_components/most_visited/.*\.css$"))
Sam Maiera6e76d72022-02-11 21:43:505377 file_filter = lambda f: input_api.FilterSourceFile(
5378 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
5379 for fpath in input_api.AffectedFiles(file_filter=file_filter):
5380 for line_num, line in fpath.ChangedContents():
5381 for (deprecated_value, value) in _DEPRECATED_CSS:
5382 if deprecated_value in line:
5383 results.append(
5384 output_api.PresubmitError(
5385 "%s:%d: Use of deprecated CSS %s, use %s instead" %
5386 (fpath.LocalPath(), line_num, deprecated_value,
5387 value)))
5388 return results
[email protected]fd20b902014-05-09 02:14:535389
mohan.reddyf21db962014-10-16 12:26:475390
Saagar Sanghavifceeaae2020-08-12 16:40:365391def CheckForRelativeIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505392 bad_files = {}
5393 for f in input_api.AffectedFiles(include_deletes=False):
Anton Bershanskyi4253349482025-02-11 21:01:275394 if (f.UnixLocalPath().startswith('third_party')
5395 and not f.LocalPath().startswith('third_party/blink')):
Sam Maiera6e76d72022-02-11 21:43:505396 continue
rlanday6802cf632017-05-30 17:48:365397
Sam Maiera6e76d72022-02-11 21:43:505398 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
5399 continue
rlanday6802cf632017-05-30 17:48:365400
Sam Maiera6e76d72022-02-11 21:43:505401 relative_includes = [
5402 line for _, line in f.ChangedContents()
5403 if "#include" in line and "../" in line
5404 ]
5405 if not relative_includes:
5406 continue
5407 bad_files[f.LocalPath()] = relative_includes
rlanday6802cf632017-05-30 17:48:365408
Sam Maiera6e76d72022-02-11 21:43:505409 if not bad_files:
5410 return []
rlanday6802cf632017-05-30 17:48:365411
Sam Maiera6e76d72022-02-11 21:43:505412 error_descriptions = []
5413 for file_path, bad_lines in bad_files.items():
5414 error_description = file_path
5415 for line in bad_lines:
5416 error_description += '\n ' + line
5417 error_descriptions.append(error_description)
rlanday6802cf632017-05-30 17:48:365418
Sam Maiera6e76d72022-02-11 21:43:505419 results = []
5420 results.append(
5421 output_api.PresubmitError(
5422 'You added one or more relative #include paths (including "../").\n'
5423 'These shouldn\'t be used because they can be used to include headers\n'
5424 'from code that\'s not correctly specified as a dependency in the\n'
5425 'relevant BUILD.gn file(s).', error_descriptions))
rlanday6802cf632017-05-30 17:48:365426
Sam Maiera6e76d72022-02-11 21:43:505427 return results
rlanday6802cf632017-05-30 17:48:365428
Takeshi Yoshinoe387aa32017-08-02 13:16:135429
Saagar Sanghavifceeaae2020-08-12 16:40:365430def CheckForCcIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505431 """Check that nobody tries to include a cc file. It's a relatively
5432 common error which results in duplicate symbols in object
5433 files. This may not always break the build until someone later gets
5434 very confusing linking errors."""
5435 results = []
5436 for f in input_api.AffectedFiles(include_deletes=False):
5437 # We let third_party code do whatever it wants
Anton Bershanskyi4253349482025-02-11 21:01:275438 if (f.UnixLocalPath().startswith('third_party')
5439 and not f.LocalPath().startswith('third_party/blink')):
Sam Maiera6e76d72022-02-11 21:43:505440 continue
Daniel Bratell65b033262019-04-23 08:17:065441
Sam Maiera6e76d72022-02-11 21:43:505442 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
5443 continue
Daniel Bratell65b033262019-04-23 08:17:065444
Sam Maiera6e76d72022-02-11 21:43:505445 for _, line in f.ChangedContents():
5446 if line.startswith('#include "'):
5447 included_file = line.split('"')[1]
5448 if _IsCPlusPlusFile(input_api, included_file):
5449 # The most common naming for external files with C++ code,
5450 # apart from standard headers, is to call them foo.inc, but
5451 # Chromium sometimes uses foo-inc.cc so allow that as well.
5452 if not included_file.endswith(('.h', '-inc.cc')):
5453 results.append(
5454 output_api.PresubmitError(
5455 'Only header files or .inc files should be included in other\n'
5456 'C++ files. Compiling the contents of a cc file more than once\n'
5457 'will cause duplicate information in the build which may later\n'
5458 'result in strange link_errors.\n' +
5459 f.LocalPath() + ':\n ' + line))
Daniel Bratell65b033262019-04-23 08:17:065460
Sam Maiera6e76d72022-02-11 21:43:505461 return results
Daniel Bratell65b033262019-04-23 08:17:065462
5463
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205464def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
Sam Maiera6e76d72022-02-11 21:43:505465 if not isinstance(key, ast.Str):
5466 return 'Key at line %d must be a string literal' % key.lineno
5467 if not isinstance(value, ast.Dict):
5468 return 'Value at line %d must be a dict' % value.lineno
5469 if len(value.keys) != 1:
5470 return 'Dict at line %d must have single entry' % value.lineno
5471 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
5472 return (
5473 'Entry at line %d must have a string literal \'filepath\' as key' %
5474 value.lineno)
5475 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:135476
Takeshi Yoshinoe387aa32017-08-02 13:16:135477
Sergey Ulanov4af16052018-11-08 02:41:465478def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Sam Maiera6e76d72022-02-11 21:43:505479 if not isinstance(key, ast.Str):
5480 return 'Key at line %d must be a string literal' % key.lineno
5481 if not isinstance(value, ast.List):
5482 return 'Value at line %d must be a list' % value.lineno
5483 for element in value.elts:
5484 if not isinstance(element, ast.Str):
5485 return 'Watchlist elements on line %d is not a string' % key.lineno
5486 if not email_regex.match(element.s):
5487 return ('Watchlist element on line %d doesn\'t look like a valid '
5488 + 'email: %s') % (key.lineno, element.s)
5489 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:135490
Takeshi Yoshinoe387aa32017-08-02 13:16:135491
Sergey Ulanov4af16052018-11-08 02:41:465492def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Sam Maiera6e76d72022-02-11 21:43:505493 mismatch_template = (
5494 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
5495 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:135496
Sam Maiera6e76d72022-02-11 21:43:505497 email_regex = input_api.re.compile(
5498 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
Sergey Ulanov4af16052018-11-08 02:41:465499
Sam Maiera6e76d72022-02-11 21:43:505500 ast = input_api.ast
5501 i = 0
5502 last_key = ''
5503 while True:
5504 if i >= len(wd_dict.keys):
5505 if i >= len(w_dict.keys):
5506 return None
5507 return mismatch_template % ('missing',
5508 'line %d' % w_dict.keys[i].lineno)
5509 elif i >= len(w_dict.keys):
5510 return (mismatch_template %
5511 ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:135512
Sam Maiera6e76d72022-02-11 21:43:505513 wd_key = wd_dict.keys[i]
5514 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:135515
Sam Maiera6e76d72022-02-11 21:43:505516 result = _CheckWatchlistDefinitionsEntrySyntax(wd_key,
5517 wd_dict.values[i], ast)
5518 if result is not None:
5519 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:135520
Sam Maiera6e76d72022-02-11 21:43:505521 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast,
5522 email_regex)
5523 if result is not None:
5524 return 'Bad entry in WATCHLISTS dict: %s' % result
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205525
Sam Maiera6e76d72022-02-11 21:43:505526 if wd_key.s != w_key.s:
5527 return mismatch_template % ('%s at line %d' %
5528 (wd_key.s, wd_key.lineno),
5529 '%s at line %d' %
5530 (w_key.s, w_key.lineno))
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205531
Sam Maiera6e76d72022-02-11 21:43:505532 if wd_key.s < last_key:
5533 return (
5534 'WATCHLISTS dict is not sorted lexicographically at line %d and %d'
5535 % (wd_key.lineno, w_key.lineno))
5536 last_key = wd_key.s
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205537
Sam Maiera6e76d72022-02-11 21:43:505538 i = i + 1
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205539
5540
Sergey Ulanov4af16052018-11-08 02:41:465541def _CheckWATCHLISTSSyntax(expression, input_api):
Sam Maiera6e76d72022-02-11 21:43:505542 ast = input_api.ast
5543 if not isinstance(expression, ast.Expression):
5544 return 'WATCHLISTS file must contain a valid expression'
5545 dictionary = expression.body
5546 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
5547 return 'WATCHLISTS file must have single dict with exactly two entries'
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205548
Sam Maiera6e76d72022-02-11 21:43:505549 first_key = dictionary.keys[0]
5550 first_value = dictionary.values[0]
5551 second_key = dictionary.keys[1]
5552 second_value = dictionary.values[1]
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205553
Sam Maiera6e76d72022-02-11 21:43:505554 if (not isinstance(first_key, ast.Str)
5555 or first_key.s != 'WATCHLIST_DEFINITIONS'
5556 or not isinstance(first_value, ast.Dict)):
5557 return ('The first entry of the dict in WATCHLISTS file must be '
5558 'WATCHLIST_DEFINITIONS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205559
Sam Maiera6e76d72022-02-11 21:43:505560 if (not isinstance(second_key, ast.Str) or second_key.s != 'WATCHLISTS'
5561 or not isinstance(second_value, ast.Dict)):
5562 return ('The second entry of the dict in WATCHLISTS file must be '
5563 'WATCHLISTS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205564
Sam Maiera6e76d72022-02-11 21:43:505565 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:135566
5567
Saagar Sanghavifceeaae2020-08-12 16:40:365568def CheckWATCHLISTS(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505569 for f in input_api.AffectedFiles(include_deletes=False):
5570 if f.LocalPath() == 'WATCHLISTS':
5571 contents = input_api.ReadFile(f, 'r')
Takeshi Yoshinoe387aa32017-08-02 13:16:135572
Sam Maiera6e76d72022-02-11 21:43:505573 try:
5574 # First, make sure that it can be evaluated.
5575 input_api.ast.literal_eval(contents)
5576 # Get an AST tree for it and scan the tree for detailed style checking.
5577 expression = input_api.ast.parse(contents,
5578 filename='WATCHLISTS',
5579 mode='eval')
5580 except ValueError as e:
5581 return [
5582 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5583 long_text=repr(e))
5584 ]
5585 except SyntaxError as e:
5586 return [
5587 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5588 long_text=repr(e))
5589 ]
5590 except TypeError as e:
5591 return [
5592 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5593 long_text=repr(e))
5594 ]
Takeshi Yoshinoe387aa32017-08-02 13:16:135595
Sam Maiera6e76d72022-02-11 21:43:505596 result = _CheckWATCHLISTSSyntax(expression, input_api)
5597 if result is not None:
5598 return [output_api.PresubmitError(result)]
5599 break
Takeshi Yoshinoe387aa32017-08-02 13:16:135600
Sam Maiera6e76d72022-02-11 21:43:505601 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:135602
Daniel Cheng6303eed2025-05-03 00:12:335603
Sean Kaucb7c9b32022-10-25 21:25:525604def CheckGnRebasePath(input_api, output_api):
Terrence Reilly313f44ff2025-01-22 15:10:145605 """Checks that target_gen_dir is not used with "//" in rebase_path().
Sean Kaucb7c9b32022-10-25 21:25:525606
5607 Developers should use root_build_dir instead of "//" when using target_gen_dir because
5608 Chromium is sometimes built outside of the source tree.
5609 """
5610
5611 def gn_files(f):
5612 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
5613
Daniel Cheng6303eed2025-05-03 00:12:335614 rebase_path_regex = input_api.re.compile(
5615 r'rebase_path\(("\$target_gen_dir"|target_gen_dir), ("/"|"//")\)')
Sean Kaucb7c9b32022-10-25 21:25:525616 problems = []
5617 for f in input_api.AffectedSourceFiles(gn_files):
5618 for line_num, line in f.ChangedContents():
5619 if rebase_path_regex.search(line):
Daniel Cheng6303eed2025-05-03 00:12:335620 problems.append('Absolute path in rebase_path() in %s:%d' %
5621 (f.LocalPath(), line_num))
Sean Kaucb7c9b32022-10-25 21:25:525622
5623 if problems:
5624 return [
5625 output_api.PresubmitPromptWarning(
5626 'Using an absolute path in rebase_path()',
5627 items=sorted(problems),
5628 long_text=(
5629 'rebase_path() should use root_build_dir instead of "/" ',
5630 'since builds can be initiated from outside of the source ',
5631 'root.'))
5632 ]
5633 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:135634
Daniel Cheng6303eed2025-05-03 00:12:335635
Andrew Grieve1b290e4a22020-11-24 20:07:015636def CheckGnGlobForward(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505637 """Checks that forward_variables_from(invoker, "*") follows best practices.
Andrew Grieve1b290e4a22020-11-24 20:07:015638
Sam Maiera6e76d72022-02-11 21:43:505639 As documented at //build/docs/writing_gn_templates.md
5640 """
Andrew Grieve1b290e4a22020-11-24 20:07:015641
Sam Maiera6e76d72022-02-11 21:43:505642 def gn_files(f):
5643 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
Andrew Grieve1b290e4a22020-11-24 20:07:015644
Sam Maiera6e76d72022-02-11 21:43:505645 problems = []
5646 for f in input_api.AffectedSourceFiles(gn_files):
5647 for line_num, line in f.ChangedContents():
5648 if 'forward_variables_from(invoker, "*")' in line:
5649 problems.append(
5650 'Bare forward_variables_from(invoker, "*") in %s:%d' %
5651 (f.LocalPath(), line_num))
5652
5653 if problems:
5654 return [
5655 output_api.PresubmitPromptWarning(
5656 'forward_variables_from("*") without exclusions',
5657 items=sorted(problems),
5658 long_text=(
Gao Shenga79ebd42022-08-08 17:25:595659 'The variables "visibility" and "test_only" should be '
Sam Maiera6e76d72022-02-11 21:43:505660 'explicitly listed in forward_variables_from(). For more '
5661 'details, see:\n'
5662 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
5663 'build/docs/writing_gn_templates.md'
5664 '#Using-forward_variables_from'))
5665 ]
5666 return []
Andrew Grieve1b290e4a22020-11-24 20:07:015667
Daniel Cheng6303eed2025-05-03 00:12:335668
Saagar Sanghavifceeaae2020-08-12 16:40:365669def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505670 """Checks that newly added header files have corresponding GN changes.
5671 Note that this is only a heuristic. To be precise, run script:
5672 build/check_gn_headers.py.
5673 """
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195674
Sam Maiera6e76d72022-02-11 21:43:505675 def headers(f):
5676 return input_api.FilterSourceFile(
5677 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195678
Sam Maiera6e76d72022-02-11 21:43:505679 new_headers = []
5680 for f in input_api.AffectedSourceFiles(headers):
5681 if f.Action() != 'A':
5682 continue
5683 new_headers.append(f.LocalPath())
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195684
Sam Maiera6e76d72022-02-11 21:43:505685 def gn_files(f):
5686 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195687
Sam Maiera6e76d72022-02-11 21:43:505688 all_gn_changed_contents = ''
5689 for f in input_api.AffectedSourceFiles(gn_files):
5690 for _, line in f.ChangedContents():
5691 all_gn_changed_contents += line
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195692
Sam Maiera6e76d72022-02-11 21:43:505693 problems = []
5694 for header in new_headers:
5695 basename = input_api.os_path.basename(header)
5696 if basename not in all_gn_changed_contents:
5697 problems.append(header)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195698
Sam Maiera6e76d72022-02-11 21:43:505699 if problems:
5700 return [
5701 output_api.PresubmitPromptWarning(
5702 'Missing GN changes for new header files',
5703 items=sorted(problems),
5704 long_text=
5705 'Please double check whether newly added header files need '
5706 'corresponding changes in gn or gni files.\nThis checking is only a '
5707 'heuristic. Run build/check_gn_headers.py to be precise.\n'
5708 'Read https://crbug.com/661774 for more info.')
5709 ]
5710 return []
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195711
5712
Saagar Sanghavifceeaae2020-08-12 16:40:365713def CheckCorrectProductNameInMessages(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505714 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
Michael Giuffridad3bc8672018-10-25 22:48:025715
Sam Maiera6e76d72022-02-11 21:43:505716 This assumes we won't intentionally reference one product from the other
5717 product.
5718 """
5719 all_problems = []
5720 test_cases = [{
5721 "filename_postfix": "google_chrome_strings.grd",
5722 "correct_name": "Chrome",
5723 "incorrect_name": "Chromium",
5724 }, {
Thiago Perrotta099034f2023-06-05 18:10:205725 "filename_postfix": "google_chrome_strings.grd",
5726 "correct_name": "Chrome",
5727 "incorrect_name": "Chrome for Testing",
5728 }, {
Sam Maiera6e76d72022-02-11 21:43:505729 "filename_postfix": "chromium_strings.grd",
5730 "correct_name": "Chromium",
5731 "incorrect_name": "Chrome",
5732 }]
Michael Giuffridad3bc8672018-10-25 22:48:025733
Sam Maiera6e76d72022-02-11 21:43:505734 for test_case in test_cases:
5735 problems = []
5736 filename_filter = lambda x: x.LocalPath().endswith(test_case[
5737 "filename_postfix"])
Michael Giuffridad3bc8672018-10-25 22:48:025738
Sam Maiera6e76d72022-02-11 21:43:505739 # Check each new line. Can yield false positives in multiline comments, but
5740 # easier than trying to parse the XML because messages can have nested
5741 # children, and associating message elements with affected lines is hard.
5742 for f in input_api.AffectedSourceFiles(filename_filter):
5743 for line_num, line in f.ChangedContents():
5744 if "<message" in line or "<!--" in line or "-->" in line:
5745 continue
5746 if test_case["incorrect_name"] in line:
Thiago Perrotta099034f2023-06-05 18:10:205747 # Chrome for Testing is a special edge case: https://goo.gle/chrome-for-testing#bookmark=id.n1rat320av91
Daniel Cheng6303eed2025-05-03 00:12:335748 if (test_case["correct_name"] == "Chromium"
5749 and line.count("Chrome")
5750 == line.count("Chrome for Testing")):
Thiago Perrotta099034f2023-06-05 18:10:205751 continue
Sam Maiera6e76d72022-02-11 21:43:505752 problems.append("Incorrect product name in %s:%d" %
5753 (f.LocalPath(), line_num))
Michael Giuffridad3bc8672018-10-25 22:48:025754
Sam Maiera6e76d72022-02-11 21:43:505755 if problems:
5756 message = (
5757 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
5758 % (test_case["correct_name"], test_case["correct_name"],
5759 test_case["incorrect_name"]))
5760 all_problems.append(
5761 output_api.PresubmitPromptWarning(message, items=problems))
Michael Giuffridad3bc8672018-10-25 22:48:025762
Sam Maiera6e76d72022-02-11 21:43:505763 return all_problems
Michael Giuffridad3bc8672018-10-25 22:48:025764
5765
Saagar Sanghavifceeaae2020-08-12 16:40:365766def CheckForTooLargeFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505767 """Avoid large files, especially binary files, in the repository since
5768 git doesn't scale well for those. They will be in everyone's repo
5769 clones forever, forever making Chromium slower to clone and work
5770 with."""
Daniel Bratell93eb6c62019-04-29 20:13:365771
Sam Maiera6e76d72022-02-11 21:43:505772 # Uploading files to cloud storage is not trivial so we don't want
5773 # to set the limit too low, but the upper limit for "normal" large
5774 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
5775 # anything over 20 MB is exceptional.
Bruce Dawsonbb414db2022-12-27 20:21:255776 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024
Daniel Bratell93eb6c62019-04-29 20:13:365777
Sam Maiera6e76d72022-02-11 21:43:505778 too_large_files = []
5779 for f in input_api.AffectedFiles():
5780 # Check both added and modified files (but not deleted files).
5781 if f.Action() in ('A', 'M'):
5782 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Joe DeBlasio10a832f2023-04-21 20:20:185783 if size > TOO_LARGE_FILE_SIZE_LIMIT:
Sam Maiera6e76d72022-02-11 21:43:505784 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
Daniel Bratell93eb6c62019-04-29 20:13:365785
Sam Maiera6e76d72022-02-11 21:43:505786 if too_large_files:
5787 message = (
5788 'Do not commit large files to git since git scales badly for those.\n'
5789 +
5790 'Instead put the large files in cloud storage and use DEPS to\n' +
5791 'fetch them.\n' + '\n'.join(too_large_files))
5792 return [
5793 output_api.PresubmitError('Too large files found in commit',
5794 long_text=message + '\n')
5795 ]
5796 else:
5797 return []
Daniel Bratell93eb6c62019-04-29 20:13:365798
Max Morozb47503b2019-08-08 21:03:275799
Saagar Sanghavifceeaae2020-08-12 16:40:365800def CheckFuzzTargetsOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505801 """Checks specific for fuzz target sources."""
5802 EXPORTED_SYMBOLS = [
5803 'LLVMFuzzerInitialize',
5804 'LLVMFuzzerCustomMutator',
5805 'LLVMFuzzerCustomCrossOver',
5806 'LLVMFuzzerMutate',
5807 ]
Max Morozb47503b2019-08-08 21:03:275808
Sam Maiera6e76d72022-02-11 21:43:505809 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
Max Morozb47503b2019-08-08 21:03:275810
Sam Maiera6e76d72022-02-11 21:43:505811 def FilterFile(affected_file):
5812 """Ignore libFuzzer source code."""
5813 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
Bruce Dawson40fece62022-09-16 19:58:315814 files_to_skip = r"^third_party/libFuzzer"
Max Morozb47503b2019-08-08 21:03:275815
Sam Maiera6e76d72022-02-11 21:43:505816 return input_api.FilterSourceFile(affected_file,
5817 files_to_check=[files_to_check],
5818 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:275819
Sam Maiera6e76d72022-02-11 21:43:505820 files_with_missing_header = []
5821 for f in input_api.AffectedSourceFiles(FilterFile):
5822 contents = input_api.ReadFile(f, 'r')
5823 if REQUIRED_HEADER in contents:
5824 continue
Max Morozb47503b2019-08-08 21:03:275825
Sam Maiera6e76d72022-02-11 21:43:505826 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
5827 files_with_missing_header.append(f.LocalPath())
Max Morozb47503b2019-08-08 21:03:275828
Sam Maiera6e76d72022-02-11 21:43:505829 if not files_with_missing_header:
5830 return []
Max Morozb47503b2019-08-08 21:03:275831
Sam Maiera6e76d72022-02-11 21:43:505832 long_text = (
5833 'If you define any of the libFuzzer optional functions (%s), it is '
5834 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
5835 'work incorrectly on Mac (crbug.com/687076).\nNote that '
5836 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
5837 'to access command line arguments passed to the fuzzer. Instead, prefer '
5838 'static initialization and shared resources as documented in '
5839 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
5840 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n'
5841 % (', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER))
Max Morozb47503b2019-08-08 21:03:275842
Sam Maiera6e76d72022-02-11 21:43:505843 return [
5844 output_api.PresubmitPromptWarning(message="Missing '%s' in:" %
5845 REQUIRED_HEADER,
5846 items=files_with_missing_header,
5847 long_text=long_text)
5848 ]
Max Morozb47503b2019-08-08 21:03:275849
5850
Mohamed Heikald048240a2019-11-12 16:57:375851def _CheckNewImagesWarning(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505852 """
5853 Warns authors who add images into the repo to make sure their images are
5854 optimized before committing.
5855 """
5856 images_added = False
5857 image_paths = []
5858 errors = []
5859 filter_lambda = lambda x: input_api.FilterSourceFile(
5860 x,
Daniel Cheng6303eed2025-05-03 00:12:335861 files_to_skip=(
5862 ('(?i).*test', r'.*\/junit\/') + input_api.DEFAULT_FILES_TO_SKIP),
Sam Maiera6e76d72022-02-11 21:43:505863 files_to_check=[r'.*\/(drawable|mipmap)'])
5864 for f in input_api.AffectedFiles(include_deletes=False,
5865 file_filter=filter_lambda):
5866 local_path = f.LocalPath().lower()
5867 if any(
5868 local_path.endswith(extension)
5869 for extension in _IMAGE_EXTENSIONS):
5870 images_added = True
5871 image_paths.append(f)
5872 if images_added:
5873 errors.append(
5874 output_api.PresubmitPromptWarning(
5875 'It looks like you are trying to commit some images. If these are '
5876 'non-test-only images, please make sure to read and apply the tips in '
5877 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
5878 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
5879 'FYI only and will not block your CL on the CQ.', image_paths))
5880 return errors
Mohamed Heikald048240a2019-11-12 16:57:375881
5882
Saagar Sanghavifceeaae2020-08-12 16:40:365883def ChecksAndroidSpecificOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505884 """Groups upload checks that target android code."""
5885 results = []
5886 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
5887 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
5888 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
5889 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505890 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
5891 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
5892 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
5893 results.extend(_CheckNewImagesWarning(input_api, output_api))
5894 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
5895 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
Daniel Cheng6303eed2025-05-03 00:12:335896 results.extend(_CheckAndroidNullAwayAnnotatedClasses(
5897 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505898 return results
5899
Becky Zhou7c69b50992018-12-10 19:37:575900
Saagar Sanghavifceeaae2020-08-12 16:40:365901def ChecksAndroidSpecificOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505902 """Groups commit checks that target android code."""
5903 results = []
5904 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
Daniel Cheng6303eed2025-05-03 00:12:335905 results.extend(_CheckAndroidNullAwayAnnotatedClasses(
5906 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505907 return results
dgnaa68d5e2015-06-10 10:08:225908
Daniel Cheng6303eed2025-05-03 00:12:335909
Chris Hall59f8d0c72020-05-01 07:31:195910# TODO(chrishall): could we additionally match on any path owned by
5911# ui/accessibility/OWNERS ?
5912_ACCESSIBILITY_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:315913 r"^chrome/browser.*/accessibility/",
5914 r"^chrome/browser/extensions/api/automation.*/",
5915 r"^chrome/renderer/extensions/accessibility_.*",
5916 r"^chrome/tests/data/accessibility/",
5917 r"^content/browser/accessibility/",
5918 r"^content/renderer/accessibility/",
5919 r"^content/tests/data/accessibility/",
5920 r"^extensions/renderer/api/automation/",
Katie Dektar58ef07b2022-09-27 13:19:175921 r"^services/accessibility/",
Abigail Klein7a63c572024-02-28 20:45:095922 r"^services/screen_ai/",
Bruce Dawson40fece62022-09-16 19:58:315923 r"^ui/accessibility/",
5924 r"^ui/views/accessibility/",
Chris Hall59f8d0c72020-05-01 07:31:195925)
5926
Daniel Cheng6303eed2025-05-03 00:12:335927
Saagar Sanghavifceeaae2020-08-12 16:40:365928def CheckAccessibilityRelnotesField(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505929 """Checks that commits to accessibility code contain an AX-Relnotes field in
5930 their commit message."""
Chris Hall59f8d0c72020-05-01 07:31:195931
Sam Maiera6e76d72022-02-11 21:43:505932 def FileFilter(affected_file):
5933 paths = _ACCESSIBILITY_PATHS
5934 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:195935
Sam Maiera6e76d72022-02-11 21:43:505936 # Only consider changes affecting accessibility paths.
5937 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
5938 return []
Akihiro Ota08108e542020-05-20 15:30:535939
Sam Maiera6e76d72022-02-11 21:43:505940 # AX-Relnotes can appear in either the description or the footer.
5941 # When searching the description, require 'AX-Relnotes:' to appear at the
5942 # beginning of a line.
5943 ax_regex = input_api.re.compile('ax-relnotes[:=]')
5944 description_has_relnotes = any(
5945 ax_regex.match(line)
5946 for line in input_api.change.DescriptionText().lower().splitlines())
Chris Hall59f8d0c72020-05-01 07:31:195947
Sam Maiera6e76d72022-02-11 21:43:505948 footer_relnotes = input_api.change.GitFootersFromDescription().get(
5949 'AX-Relnotes', [])
5950 if description_has_relnotes or footer_relnotes:
5951 return []
Chris Hall59f8d0c72020-05-01 07:31:195952
Sam Maiera6e76d72022-02-11 21:43:505953 # TODO(chrishall): link to Relnotes documentation in message.
5954 message = (
5955 "Missing 'AX-Relnotes:' field required for accessibility changes"
5956 "\n please add 'AX-Relnotes: [release notes].' to describe any "
5957 "user-facing changes"
5958 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
5959 "user-facing effects"
5960 "\n if this is confusing or annoying then please contact members "
5961 "of ui/accessibility/OWNERS.")
5962
5963 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:225964
Mark Schillaci44c90b42024-11-22 20:44:385965
5966_ACCESSIBILITY_ARIA_METHOD_CANDIDATES_PATTERNS = r'(\-\>|\.)(get|has|FastGet|FastHas)Attribute\('
5967
Daniel Cheng6303eed2025-05-03 00:12:335968_ACCESSIBILITY_ARIA_BAD_PARAMS_PATTERNS = (r"\(html_names::kAria(.*)Attr\)",
5969 r"\(html_names::kRoleAttr\)")
Mark Schillaci44c90b42024-11-22 20:44:385970
Daniel Cheng6303eed2025-05-03 00:12:335971_ACCESSIBILITY_ARIA_FILE_CANDIDATES_PATTERNS = (r".*/accessibility/.*.(cc|h)",
5972 r".*/ax_.*.(cc|h)")
5973
Mark Schillaci44c90b42024-11-22 20:44:385974
5975def CheckAccessibilityAriaElementAttributeGetters(input_api, output_api):
5976 """Checks that the blink accessibility code follows the defined patterns
5977 for checking aria attributes, so that ElementInternals is not bypassed."""
5978
5979 # Limit to accessibility-related files.
5980 def FileFilter(affected_file):
5981 paths = _ACCESSIBILITY_ARIA_FILE_CANDIDATES_PATTERNS
5982 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
5983
Daniel Cheng6303eed2025-05-03 00:12:335984 aria_method_regex = input_api.re.compile(
5985 _ACCESSIBILITY_ARIA_METHOD_CANDIDATES_PATTERNS)
Mark Schillaci44c90b42024-11-22 20:44:385986 aria_bad_params_regex = input_api.re.compile(
Daniel Cheng6303eed2025-05-03 00:12:335987 "|".join(_ACCESSIBILITY_ARIA_BAD_PARAMS_PATTERNS))
Mark Schillaci44c90b42024-11-22 20:44:385988 problems = []
5989
5990 for f in input_api.AffectedSourceFiles(FileFilter):
5991 for line_num, line in f.ChangedContents():
Daniel Cheng6303eed2025-05-03 00:12:335992 if aria_method_regex.search(line) and aria_bad_params_regex.search(
5993 line):
5994 problems.append(
5995 f"{f.LocalPath()}:{line_num}\n {line.strip()}")
Mark Schillaci44c90b42024-11-22 20:44:385996
5997 if problems:
5998 return [
5999 output_api.PresubmitPromptWarning(
6000 "Accessibility code should not use element methods to get or check"
6001 "\nthe presence of aria attributes"
6002 "\nPlease use ARIA-specific attribute access, e.g. HasAriaAttribute(),"
6003 "\nAriaTokenAttribute(), AriaBoolAttribute(), AriaBooleanAttribute(),"
6004 "\nAriaFloatAttribute().",
6005 problems,
6006 )
6007 ]
6008 return []
6009
Daniel Cheng6303eed2025-05-03 00:12:336010
seanmccullough4a9356252021-04-08 19:54:096011# string pattern, sequence of strings to show when pattern matches,
6012# error flag. True if match is a presubmit error, otherwise it's a warning.
6013_NON_INCLUSIVE_TERMS = (
6014 (
6015 # Note that \b pattern in python re is pretty particular. In this
6016 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
6017 # ...' will not. This may require some tweaking to catch these cases
6018 # without triggering a lot of false positives. Leaving it naive and
6019 # less matchy for now.
Josip Sokcevic9d2806a02023-12-13 03:04:026020 r'/(?i)\b((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:096021 (
6022 'Please don\'t use blacklist, whitelist, ' # nocheck
6023 'or slave in your', # nocheck
6024 'code and make every effort to use other terms. Using "// nocheck"',
6025 '"# nocheck" or "<!-- nocheck -->"',
6026 'at the end of the offending line will bypass this PRESUBMIT error',
6027 'but avoid using this whenever possible. Reach out to',
6028 '[email protected] if you have questions'),
Daniel Cheng6303eed2025-05-03 00:12:336029 True), )
6030
seanmccullough4a9356252021-04-08 19:54:096031
Saagar Sanghavifceeaae2020-08-12 16:40:366032def ChecksCommon(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506033 """Checks common to both upload and commit."""
6034 results = []
Eric Boren6fd2b932018-01-25 15:05:086035 results.extend(
Sam Maiera6e76d72022-02-11 21:43:506036 input_api.canned_checks.PanProjectChecks(
6037 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:086038
Sam Maiera6e76d72022-02-11 21:43:506039 author = input_api.change.author_email
6040 if author and author not in _KNOWN_ROBOTS:
6041 results.extend(
6042 input_api.canned_checks.CheckAuthorizedAuthor(
6043 input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:246044
Sam Maiera6e76d72022-02-11 21:43:506045 results.extend(
6046 input_api.canned_checks.CheckChangeHasNoTabs(
6047 input_api,
6048 output_api,
6049 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
6050 results.extend(
6051 input_api.RunTests(
6052 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Edward Lesmesce51df52020-08-04 22:10:176053
Ben Pastene30dc57082025-06-02 22:19:206054 dirmd = 'dirmd.bat' if input_api.is_windows else 'dirmd'
6055 dirmd_bin = input_api.os_path.join(input_api.PresubmitLocalPath(),
6056 'third_party', 'depot_tools', dirmd)
Sam Maiera6e76d72022-02-11 21:43:506057 results.extend(
6058 input_api.RunTests(
6059 input_api.canned_checks.CheckDirMetadataFormat(
Ben Pastene30dc57082025-06-02 22:19:206060 input_api, output_api, dirmd_bin)))
Sam Maiera6e76d72022-02-11 21:43:506061 results.extend(
6062 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
6063 input_api, output_api))
6064 results.extend(
6065 input_api.canned_checks.CheckNoNewMetadataInOwners(
6066 input_api, output_api))
6067 results.extend(
6068 input_api.canned_checks.CheckInclusiveLanguage(
6069 input_api,
6070 output_api,
6071 excluded_directories_relative_path=[
6072 'infra', 'inclusive_language_presubmit_exempt_dirs.txt'
6073 ],
6074 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Yiwei Zhang5341bf02025-03-20 16:34:136075 results.extend(
6076 input_api.canned_checks.CheckNewDEPSHooksHasRequiredReviewers(
6077 input_api, output_api))
Jie Shengb0c86f02025-06-12 21:36:146078 results.extend(
6079 input_api.canned_checks.CheckValidHostsInDEPSOnUpload(
6080 input_api, output_api))
Dirk Prankee3c9c62d2021-05-18 18:35:596081
Aleksey Khoroshilov2978c942022-06-13 16:14:126082 presubmit_py_filter = lambda f: input_api.FilterSourceFile(
Daniel Cheng6f3d1ae12025-04-07 17:11:276083 f, files_to_check=[r'.*PRESUBMIT(?:_test)?\.py$'])
6084 potential_paths = set(
6085 map(
6086 lambda f: input_api.os_path.dirname(f.AbsoluteLocalPath()),
6087 input_api.AffectedFiles(include_deletes=False,
6088 file_filter=presubmit_py_filter)))
6089 for full_path in potential_paths:
Aleksey Khoroshilov2978c942022-06-13 16:14:126090 test_file = input_api.os_path.join(full_path, 'PRESUBMIT_test.py')
6091 # The PRESUBMIT.py file (and the directory containing it) might have
6092 # been affected by being moved or removed, so only try to run the tests
6093 # if they still exist.
6094 if not input_api.os_path.exists(test_file):
6095 continue
Sam Maiera6e76d72022-02-11 21:43:506096
Aleksey Khoroshilov2978c942022-06-13 16:14:126097 results.extend(
6098 input_api.canned_checks.RunUnitTestsInDirectory(
6099 input_api,
6100 output_api,
6101 full_path,
Takuto Ikuta40def482023-06-02 02:23:496102 files_to_check=[r'^PRESUBMIT_test\.py$']))
Sam Maiera6e76d72022-02-11 21:43:506103 return results
[email protected]1f7b4172010-01-28 01:17:346104
[email protected]b337cb5b2011-01-23 21:24:056105
Saagar Sanghavifceeaae2020-08-12 16:40:366106def CheckPatchFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506107 problems = [
6108 f.LocalPath() for f in input_api.AffectedFiles()
6109 if f.LocalPath().endswith(('.orig', '.rej'))
6110 ]
6111 # Cargo.toml.orig files are part of third-party crates downloaded from
6112 # crates.io and should be included.
6113 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
6114 if problems:
6115 return [
6116 output_api.PresubmitError("Don't commit .rej and .orig files.",
6117 problems)
6118 ]
6119 else:
6120 return []
[email protected]b8079ae4a2012-12-05 19:56:496121
6122
Saagar Sanghavifceeaae2020-08-12 16:40:366123def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506124 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
6125 macro_re = input_api.re.compile(
6126 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
6127 include_re = input_api.re.compile(r'^#include\s+"build/build_config.h"',
6128 input_api.re.MULTILINE)
6129 extension_re = input_api.re.compile(r'\.[a-z]+$')
6130 errors = []
Bruce Dawsonf7679202022-08-09 20:24:006131 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:506132 for f in input_api.AffectedFiles(include_deletes=False):
Bruce Dawsonf7679202022-08-09 20:24:006133 # The build-config macros are allowed to be used in build_config.h
6134 # without including itself.
6135 if f.LocalPath() == config_h_file:
6136 continue
Sam Maiera6e76d72022-02-11 21:43:506137 if not f.LocalPath().endswith(
6138 ('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
6139 continue
Arthur Sonzognia3dec412024-04-29 12:05:376140
Sam Maiera6e76d72022-02-11 21:43:506141 found_line_number = None
6142 found_macro = None
6143 all_lines = input_api.ReadFile(f, 'r').splitlines()
6144 for line_num, line in enumerate(all_lines):
6145 match = macro_re.search(line)
6146 if match:
6147 found_line_number = line_num
6148 found_macro = match.group(2)
6149 break
6150 if not found_line_number:
6151 continue
Kent Tamura5a8755d2017-06-29 23:37:076152
Sam Maiera6e76d72022-02-11 21:43:506153 found_include_line = -1
6154 for line_num, line in enumerate(all_lines):
6155 if include_re.search(line):
6156 found_include_line = line_num
6157 break
6158 if found_include_line >= 0 and found_include_line < found_line_number:
6159 continue
Kent Tamura5a8755d2017-06-29 23:37:076160
Sam Maiera6e76d72022-02-11 21:43:506161 if not f.LocalPath().endswith('.h'):
6162 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
6163 try:
6164 content = input_api.ReadFile(primary_header_path, 'r')
6165 if include_re.search(content):
6166 continue
6167 except IOError:
6168 pass
6169 errors.append('%s:%d %s macro is used without first including build/'
6170 'build_config.h.' %
6171 (f.LocalPath(), found_line_number, found_macro))
6172 if errors:
6173 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
6174 return []
Kent Tamura5a8755d2017-06-29 23:37:076175
6176
Lei Zhang1c12a22f2021-05-12 11:28:456177def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506178 stl_include_re = input_api.re.compile(r'^#include\s+<('
6179 r'algorithm|'
6180 r'array|'
6181 r'limits|'
6182 r'list|'
6183 r'map|'
6184 r'memory|'
6185 r'queue|'
6186 r'set|'
6187 r'string|'
6188 r'unordered_map|'
6189 r'unordered_set|'
6190 r'utility|'
6191 r'vector)>')
6192 std_namespace_re = input_api.re.compile(r'std::')
6193 errors = []
6194 for f in input_api.AffectedFiles():
6195 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
6196 continue
Lei Zhang1c12a22f2021-05-12 11:28:456197
Sam Maiera6e76d72022-02-11 21:43:506198 uses_std_namespace = False
6199 has_stl_include = False
6200 for line in f.NewContents():
6201 if has_stl_include and uses_std_namespace:
6202 break
Lei Zhang1c12a22f2021-05-12 11:28:456203
Sam Maiera6e76d72022-02-11 21:43:506204 if not has_stl_include and stl_include_re.search(line):
6205 has_stl_include = True
6206 continue
Lei Zhang1c12a22f2021-05-12 11:28:456207
Bruce Dawson4a5579a2022-04-08 17:11:366208 if not uses_std_namespace and (std_namespace_re.search(line)
Daniel Cheng6303eed2025-05-03 00:12:336209 or 'no-std-usage-because-pch-file'
6210 in line):
Sam Maiera6e76d72022-02-11 21:43:506211 uses_std_namespace = True
6212 continue
Lei Zhang1c12a22f2021-05-12 11:28:456213
Sam Maiera6e76d72022-02-11 21:43:506214 if has_stl_include and not uses_std_namespace:
6215 errors.append(
6216 '%s: Includes STL header(s) but does not reference std::' %
6217 f.LocalPath())
6218 if errors:
6219 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
6220 return []
Lei Zhang1c12a22f2021-05-12 11:28:456221
6222
Xiaohan Wang42d96c22022-01-20 17:23:116223def _CheckForDeprecatedOSMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:506224 """Check for sensible looking, totally invalid OS macros."""
6225 preprocessor_statement = input_api.re.compile(r'^\s*#')
6226 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
6227 results = []
6228 for lnum, line in f.ChangedContents():
6229 if preprocessor_statement.search(line):
6230 for match in os_macro.finditer(line):
6231 results.append(
6232 ' %s:%d: %s' %
6233 (f.LocalPath(), lnum, 'defined(OS_' + match.group(1) +
6234 ') -> BUILDFLAG(IS_' + match.group(1) + ')'))
6235 return results
[email protected]b00342e7f2013-03-26 16:21:546236
6237
Xiaohan Wang42d96c22022-01-20 17:23:116238def CheckForDeprecatedOSMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506239 """Check all affected files for invalid OS macros."""
6240 bad_macros = []
Bruce Dawsonf7679202022-08-09 20:24:006241 # The OS_ macros are allowed to be used in build/build_config.h.
6242 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:506243 for f in input_api.AffectedSourceFiles(None):
Bruce Dawsonf7679202022-08-09 20:24:006244 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')) \
6245 and f.LocalPath() != config_h_file:
Sam Maiera6e76d72022-02-11 21:43:506246 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
[email protected]b00342e7f2013-03-26 16:21:546247
Sam Maiera6e76d72022-02-11 21:43:506248 if not bad_macros:
6249 return []
[email protected]b00342e7f2013-03-26 16:21:546250
Sam Maiera6e76d72022-02-11 21:43:506251 return [
6252 output_api.PresubmitError(
6253 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
6254 'defined in build_config.h):', bad_macros)
6255 ]
[email protected]b00342e7f2013-03-26 16:21:546256
lliabraa35bab3932014-10-01 12:16:446257
6258def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:506259 """Check all affected files for invalid "if defined" macros."""
6260 ALWAYS_DEFINED_MACROS = (
6261 "TARGET_CPU_PPC",
6262 "TARGET_CPU_PPC64",
6263 "TARGET_CPU_68K",
6264 "TARGET_CPU_X86",
6265 "TARGET_CPU_ARM",
6266 "TARGET_CPU_MIPS",
6267 "TARGET_CPU_SPARC",
6268 "TARGET_CPU_ALPHA",
6269 "TARGET_IPHONE_SIMULATOR",
6270 "TARGET_OS_EMBEDDED",
6271 "TARGET_OS_IPHONE",
6272 "TARGET_OS_MAC",
6273 "TARGET_OS_UNIX",
6274 "TARGET_OS_WIN32",
6275 )
6276 ifdef_macro = input_api.re.compile(
6277 r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
6278 results = []
6279 for lnum, line in f.ChangedContents():
6280 for match in ifdef_macro.finditer(line):
6281 if match.group(1) in ALWAYS_DEFINED_MACROS:
6282 always_defined = ' %s is always defined. ' % match.group(1)
6283 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
6284 results.append(
6285 ' %s:%d %s\n\t%s' %
6286 (f.LocalPath(), lnum, always_defined, did_you_mean))
6287 return results
lliabraa35bab3932014-10-01 12:16:446288
6289
Saagar Sanghavifceeaae2020-08-12 16:40:366290def CheckForInvalidIfDefinedMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506291 """Check all affected files for invalid "if defined" macros."""
Arthur Sonzogni4fd14fd2024-06-02 18:42:526292 SKIPPED_PATHS = [
6293 'base/allocator/partition_allocator/src/partition_alloc/build_config.h',
6294 'build/build_config.h',
6295 'third_party/abseil-cpp/',
6296 'third_party/sqlite/',
6297 ]
Daniel Cheng6303eed2025-05-03 00:12:336298
Arthur Sonzogni4fd14fd2024-06-02 18:42:526299 def affected_files_filter(f):
6300 # Normalize the local path to Linux-style path separators so that the
6301 # path comparisons work on Windows as well.
Anton Bershanskyi4253349482025-02-11 21:01:276302 path = f.UnixLocalPath()
Arthur Sonzogni4fd14fd2024-06-02 18:42:526303
6304 for skipped_path in SKIPPED_PATHS:
6305 if path.startswith(skipped_path):
6306 return False
6307
6308 return path.endswith(('.h', '.c', '.cc', '.m', '.mm'))
6309
Sam Maiera6e76d72022-02-11 21:43:506310 bad_macros = []
Arthur Sonzogni4fd14fd2024-06-02 18:42:526311 for f in input_api.AffectedSourceFiles(affected_files_filter):
6312 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
lliabraa35bab3932014-10-01 12:16:446313
Sam Maiera6e76d72022-02-11 21:43:506314 if not bad_macros:
6315 return []
lliabraa35bab3932014-10-01 12:16:446316
Sam Maiera6e76d72022-02-11 21:43:506317 return [
6318 output_api.PresubmitError(
6319 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
6320 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
6321 bad_macros)
6322 ]
lliabraa35bab3932014-10-01 12:16:446323
Daniel Cheng6303eed2025-05-03 00:12:336324
Saagar Sanghavifceeaae2020-08-12 16:40:366325def CheckForIPCRules(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506326 """Check for same IPC rules described in
6327 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
6328 """
6329 base_pattern = r'IPC_ENUM_TRAITS\('
6330 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
6331 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
mlamouria82272622014-09-16 18:45:046332
Sam Maiera6e76d72022-02-11 21:43:506333 problems = []
6334 for f in input_api.AffectedSourceFiles(None):
6335 local_path = f.LocalPath()
6336 if not local_path.endswith('.h'):
6337 continue
6338 for line_number, line in f.ChangedContents():
6339 if inclusion_pattern.search(
6340 line) and not comment_pattern.search(line):
6341 problems.append('%s:%d\n %s' %
6342 (local_path, line_number, line.strip()))
mlamouria82272622014-09-16 18:45:046343
Sam Maiera6e76d72022-02-11 21:43:506344 if problems:
6345 return [
6346 output_api.PresubmitPromptWarning(_IPC_ENUM_TRAITS_DEPRECATED,
6347 problems)
6348 ]
6349 else:
6350 return []
mlamouria82272622014-09-16 18:45:046351
[email protected]b00342e7f2013-03-26 16:21:546352
Saagar Sanghavifceeaae2020-08-12 16:40:366353def CheckForLongPathnames(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506354 """Check to make sure no files being submitted have long paths.
6355 This causes issues on Windows.
6356 """
6357 problems = []
6358 for f in input_api.AffectedTestableFiles():
6359 local_path = f.LocalPath()
6360 # Windows has a path limit of 260 characters. Limit path length to 200 so
6361 # that we have some extra for the prefix on dev machines and the bots.
Daniel Cheng6303eed2025-05-03 00:12:336362 if (local_path.startswith('third_party/blink/web_tests/platform/')
6363 and not local_path.startswith(
6364 'third_party/blink/web_tests/platform/win')):
Weizhong Xia8b461f12024-06-21 21:46:336365 # Do not check length of the path for files not used by Windows
6366 continue
Sam Maiera6e76d72022-02-11 21:43:506367 if len(local_path) > 200:
6368 problems.append(local_path)
Stephen Martinis97a394142018-06-07 23:06:056369
Sam Maiera6e76d72022-02-11 21:43:506370 if problems:
6371 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
6372 else:
6373 return []
Stephen Martinis97a394142018-06-07 23:06:056374
6375
Saagar Sanghavifceeaae2020-08-12 16:40:366376def CheckForIncludeGuards(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506377 """Check that header files have proper guards against multiple inclusion.
6378 If a file should not have such guards (and it probably should) then it
Bruce Dawson4a5579a2022-04-08 17:11:366379 should include the string "no-include-guard-because-multiply-included" or
6380 "no-include-guard-because-pch-file".
Sam Maiera6e76d72022-02-11 21:43:506381 """
Daniel Bratell8ba52722018-03-02 16:06:146382
Sam Maiera6e76d72022-02-11 21:43:506383 def is_chromium_header_file(f):
6384 # We only check header files under the control of the Chromium
mikt84d6c712024-03-27 13:29:036385 # project. This excludes:
6386 # - third_party/*, except blink.
6387 # - base/allocator/partition_allocator/: PartitionAlloc is a standalone
6388 # library used outside of Chrome. Includes are referenced from its
6389 # own base directory. It has its own `CheckForIncludeGuards`
6390 # PRESUBMIT.py check.
6391 # - *_message_generator.h: They use include guards in a special,
6392 # non-typical way.
Sam Maiera6e76d72022-02-11 21:43:506393 file_with_path = input_api.os_path.normpath(f.LocalPath())
6394 return (file_with_path.endswith('.h')
6395 and not file_with_path.endswith('_message_generator.h')
Bruce Dawson4c4c2922022-05-02 18:07:336396 and not file_with_path.endswith('com_imported_mstscax.h')
Peter Kasting66c1f752024-12-02 15:28:376397 and not file_with_path.startswith(
6398 input_api.os_path.join('base', 'allocator',
6399 'partition_allocator'))
Sam Maiera6e76d72022-02-11 21:43:506400 and (not file_with_path.startswith('third_party')
6401 or file_with_path.startswith(
6402 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:146403
Sam Maiera6e76d72022-02-11 21:43:506404 def replace_special_with_underscore(string):
6405 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:146406
Sam Maiera6e76d72022-02-11 21:43:506407 errors = []
Daniel Bratell8ba52722018-03-02 16:06:146408
Sam Maiera6e76d72022-02-11 21:43:506409 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
6410 guard_name = None
6411 guard_line_number = None
6412 seen_guard_end = False
Lei Zhangd84f9512024-05-28 19:43:306413 bypass_checks_at_end_of_file = False
Daniel Bratell8ba52722018-03-02 16:06:146414
Sam Maiera6e76d72022-02-11 21:43:506415 file_with_path = input_api.os_path.normpath(f.LocalPath())
6416 base_file_name = input_api.os_path.splitext(
6417 input_api.os_path.basename(file_with_path))[0]
6418 upper_base_file_name = base_file_name.upper()
Daniel Bratell8ba52722018-03-02 16:06:146419
Sam Maiera6e76d72022-02-11 21:43:506420 expected_guard = replace_special_with_underscore(
6421 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:146422
Sam Maiera6e76d72022-02-11 21:43:506423 # For "path/elem/file_name.h" we should really only accept
6424 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
6425 # are too many (1000+) files with slight deviations from the
6426 # coding style. The most important part is that the include guard
6427 # is there, and that it's unique, not the name so this check is
6428 # forgiving for existing files.
6429 #
6430 # As code becomes more uniform, this could be made stricter.
Daniel Bratell8ba52722018-03-02 16:06:146431
Sam Maiera6e76d72022-02-11 21:43:506432 guard_name_pattern_list = [
6433 # Anything with the right suffix (maybe with an extra _).
6434 r'\w+_H__?',
Daniel Bratell8ba52722018-03-02 16:06:146435
Sam Maiera6e76d72022-02-11 21:43:506436 # To cover include guards with old Blink style.
6437 r'\w+_h',
Daniel Bratell8ba52722018-03-02 16:06:146438
Sam Maiera6e76d72022-02-11 21:43:506439 # Anything including the uppercase name of the file.
6440 r'\w*' + input_api.re.escape(
6441 replace_special_with_underscore(upper_base_file_name)) +
6442 r'\w*',
6443 ]
6444 guard_name_pattern = '|'.join(guard_name_pattern_list)
6445 guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
6446 guard_name_pattern + ')')
Daniel Bratell8ba52722018-03-02 16:06:146447
Sam Maiera6e76d72022-02-11 21:43:506448 for line_number, line in enumerate(f.NewContents()):
Bruce Dawson4a5579a2022-04-08 17:11:366449 if ('no-include-guard-because-multiply-included' in line
6450 or 'no-include-guard-because-pch-file' in line):
Lei Zhangd84f9512024-05-28 19:43:306451 bypass_checks_at_end_of_file = True
Sam Maiera6e76d72022-02-11 21:43:506452 break
Daniel Bratell8ba52722018-03-02 16:06:146453
Sam Maiera6e76d72022-02-11 21:43:506454 if guard_name is None:
6455 match = guard_pattern.match(line)
6456 if match:
6457 guard_name = match.group(1)
6458 guard_line_number = line_number
Daniel Bratell8ba52722018-03-02 16:06:146459
Sam Maiera6e76d72022-02-11 21:43:506460 # We allow existing files to use include guards whose names
6461 # don't match the chromium style guide, but new files should
6462 # get it right.
Bruce Dawson6cc154e2022-04-12 20:39:496463 if guard_name != expected_guard:
Bruce Dawson95eb7562022-09-14 15:27:166464 if f.Action() == 'A': # If file was just 'A'dded
Sam Maiera6e76d72022-02-11 21:43:506465 errors.append(
6466 output_api.PresubmitPromptWarning(
6467 'Header using the wrong include guard name %s'
6468 % guard_name, [
6469 '%s:%d' %
6470 (f.LocalPath(), line_number + 1)
6471 ], 'Expected: %r\nFound: %r' %
6472 (expected_guard, guard_name)))
6473 else:
6474 # The line after #ifndef should have a #define of the same name.
6475 if line_number == guard_line_number + 1:
6476 expected_line = '#define %s' % guard_name
6477 if line != expected_line:
6478 errors.append(
6479 output_api.PresubmitPromptWarning(
6480 'Missing "%s" for include guard' %
6481 expected_line,
6482 ['%s:%d' % (f.LocalPath(), line_number + 1)],
6483 'Expected: %r\nGot: %r' %
6484 (expected_line, line)))
Daniel Bratell8ba52722018-03-02 16:06:146485
Sam Maiera6e76d72022-02-11 21:43:506486 if not seen_guard_end and line == '#endif // %s' % guard_name:
6487 seen_guard_end = True
6488 elif seen_guard_end:
6489 if line.strip() != '':
6490 errors.append(
6491 output_api.PresubmitPromptWarning(
6492 'Include guard %s not covering the whole file'
6493 % (guard_name), [f.LocalPath()]))
6494 break # Nothing else to check and enough to warn once.
Daniel Bratell8ba52722018-03-02 16:06:146495
Lei Zhangd84f9512024-05-28 19:43:306496 if bypass_checks_at_end_of_file:
6497 continue
6498
Sam Maiera6e76d72022-02-11 21:43:506499 if guard_name is None:
6500 errors.append(
6501 output_api.PresubmitPromptWarning(
Bruce Dawson32114b62022-04-11 16:45:496502 'Missing include guard in %s\n'
Sam Maiera6e76d72022-02-11 21:43:506503 'Recommended name: %s\n'
6504 'This check can be disabled by having the string\n'
Bruce Dawson4a5579a2022-04-08 17:11:366505 '"no-include-guard-because-multiply-included" or\n'
Daniel Cheng6303eed2025-05-03 00:12:336506 '"no-include-guard-because-pch-file" in the header.' %
6507 (f.LocalPath(), expected_guard)))
Lei Zhangd84f9512024-05-28 19:43:306508 elif not seen_guard_end:
6509 errors.append(
6510 output_api.PresubmitPromptWarning(
6511 'Incorrect or missing include guard #endif in %s\n'
Daniel Cheng6303eed2025-05-03 00:12:336512 'Recommended #endif comment: // %s' %
6513 (f.LocalPath(), expected_guard)))
Sam Maiera6e76d72022-02-11 21:43:506514
6515 return errors
Daniel Bratell8ba52722018-03-02 16:06:146516
6517
Saagar Sanghavifceeaae2020-08-12 16:40:366518def CheckForWindowsLineEndings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506519 """Check source code and known ascii text files for Windows style line
6520 endings.
6521 """
Bruce Dawson5efbdc652022-04-11 19:29:516522 known_text_files = r'.*\.(txt|html|htm|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:236523
dpapadfd421fb2025-02-13 00:47:326524 _WEBUI_FILES_EXTENSIONS = r'\.(css|html|js|ts|svg)$'
6525
Sam Maiera6e76d72022-02-11 21:43:506526 file_inclusion_pattern = (known_text_files,
6527 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
dpapadfd421fb2025-02-13 00:47:326528 r'.+%s' % _HEADER_EXTENSIONS,
6529 r'.+%s' % _WEBUI_FILES_EXTENSIONS)
6530
6531 # Exclude folder that contains .ts files that are actually binary video
6532 # format and not TypeScript.
6533 file_exclusion_pattern = (r'media/test/data/')
mostynbb639aca52015-01-07 20:31:236534
Sam Maiera6e76d72022-02-11 21:43:506535 problems = []
6536 source_file_filter = lambda f: input_api.FilterSourceFile(
Daniel Cheng6303eed2025-05-03 00:12:336537 f,
6538 files_to_check=file_inclusion_pattern,
dpapadfd421fb2025-02-13 00:47:326539 files_to_skip=file_exclusion_pattern)
Sam Maiera6e76d72022-02-11 21:43:506540 for f in input_api.AffectedSourceFiles(source_file_filter):
Bruce Dawson5efbdc652022-04-11 19:29:516541 # Ignore test files that contain crlf intentionally.
6542 if f.LocalPath().endswith('crlf.txt'):
Daniel Chenga37c03db2022-05-12 17:20:346543 continue
Sam Maiera6e76d72022-02-11 21:43:506544 include_file = False
6545 for line in input_api.ReadFile(f, 'r').splitlines(True):
6546 if line.endswith('\r\n'):
6547 include_file = True
6548 if include_file:
6549 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:236550
Sam Maiera6e76d72022-02-11 21:43:506551 if problems:
6552 return [
6553 output_api.PresubmitPromptWarning(
6554 'Are you sure that you want '
6555 'these files to contain Windows style line endings?\n' +
6556 '\n'.join(problems))
6557 ]
mostynbb639aca52015-01-07 20:31:236558
Sam Maiera6e76d72022-02-11 21:43:506559 return []
6560
mostynbb639aca52015-01-07 20:31:236561
Evan Stade6cfc964c12021-05-18 20:21:166562def CheckIconFilesForLicenseHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506563 """Check that .icon files (which are fragments of C++) have license headers.
6564 """
Evan Stade6cfc964c12021-05-18 20:21:166565
Sam Maiera6e76d72022-02-11 21:43:506566 icon_files = (r'.*\.icon$', )
Evan Stade6cfc964c12021-05-18 20:21:166567
Sam Maiera6e76d72022-02-11 21:43:506568 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
6569 return input_api.canned_checks.CheckLicense(input_api,
6570 output_api,
6571 source_file_filter=icons)
6572
Evan Stade6cfc964c12021-05-18 20:21:166573
Jose Magana2b456f22021-03-09 23:26:406574def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506575 """Check source code for use of Chrome App technologies being
6576 deprecated.
6577 """
Jose Magana2b456f22021-03-09 23:26:406578
Sam Maiera6e76d72022-02-11 21:43:506579 def _CheckForDeprecatedTech(input_api,
6580 output_api,
6581 detection_list,
6582 files_to_check=None,
6583 files_to_skip=None):
Jose Magana2b456f22021-03-09 23:26:406584
Sam Maiera6e76d72022-02-11 21:43:506585 if (files_to_check or files_to_skip):
6586 source_file_filter = lambda f: input_api.FilterSourceFile(
6587 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
6588 else:
6589 source_file_filter = None
6590
6591 problems = []
6592
6593 for f in input_api.AffectedSourceFiles(source_file_filter):
6594 if f.Action() == 'D':
6595 continue
6596 for _, line in f.ChangedContents():
6597 if any(detect in line for detect in detection_list):
6598 problems.append(f.LocalPath())
6599
6600 return problems
6601
6602 # to avoid this presubmit script triggering warnings
6603 files_to_skip = ['PRESUBMIT.py', 'PRESUBMIT_test.py']
Jose Magana2b456f22021-03-09 23:26:406604
6605 problems = []
6606
Sam Maiera6e76d72022-02-11 21:43:506607 # NMF: any files with extensions .nmf or NMF
6608 _NMF_FILES = r'\.(nmf|NMF)$'
6609 problems += _CheckForDeprecatedTech(
6610 input_api,
6611 output_api,
6612 detection_list=[''], # any change to the file will trigger warning
6613 files_to_check=[r'.+%s' % _NMF_FILES])
Jose Magana2b456f22021-03-09 23:26:406614
Sam Maiera6e76d72022-02-11 21:43:506615 # MANIFEST: any manifest.json that in its diff includes "app":
6616 _MANIFEST_FILES = r'(manifest\.json)$'
6617 problems += _CheckForDeprecatedTech(
6618 input_api,
6619 output_api,
6620 detection_list=['"app":'],
6621 files_to_check=[r'.*%s' % _MANIFEST_FILES])
Jose Magana2b456f22021-03-09 23:26:406622
Sam Maiera6e76d72022-02-11 21:43:506623 if problems:
6624 return [
6625 output_api.PresubmitPromptWarning(
6626 'You are adding/modifying code'
Fabian Sommera32b77a2025-07-23 12:41:206627 'related to technologies which will soon be deprecated (Chrome Apps'
6628 '). See this blog post for more details:\n'
Sam Maiera6e76d72022-02-11 21:43:506629 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
6630 'and this documentation for options to replace these technologies:\n'
6631 'https://developer.chrome.com/docs/apps/migration/\n' +
6632 '\n'.join(problems))
6633 ]
Jose Magana2b456f22021-03-09 23:26:406634
Sam Maiera6e76d72022-02-11 21:43:506635 return []
Jose Magana2b456f22021-03-09 23:26:406636
mostynbb639aca52015-01-07 20:31:236637
Saagar Sanghavifceeaae2020-08-12 16:40:366638def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
Sam Maiera6e76d72022-02-11 21:43:506639 """Checks that all source files use SYSLOG properly."""
6640 syslog_files = []
6641 for f in input_api.AffectedSourceFiles(src_file_filter):
6642 for line_number, line in f.ChangedContents():
6643 if 'SYSLOG' in line:
6644 syslog_files.append(f.LocalPath() + ':' + str(line_number))
pastarmovj032ba5bc2017-01-12 10:41:566645
Sam Maiera6e76d72022-02-11 21:43:506646 if syslog_files:
6647 return [
6648 output_api.PresubmitPromptWarning(
6649 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
6650 ' calls.\nFiles to check:\n',
6651 items=syslog_files)
6652 ]
6653 return []
pastarmovj89f7ee12016-09-20 14:58:136654
6655
[email protected]1f7b4172010-01-28 01:17:346656def CheckChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506657 if input_api.version < [2, 0, 0]:
6658 return [
6659 output_api.PresubmitError(
6660 "Your depot_tools is out of date. "
6661 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
6662 "but your version is %d.%d.%d" % tuple(input_api.version))
6663 ]
6664 results = []
6665 results.extend(
6666 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
6667 return results
[email protected]ca8d19842009-02-19 16:33:126668
6669
6670def CheckChangeOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506671 if input_api.version < [2, 0, 0]:
6672 return [
6673 output_api.PresubmitError(
6674 "Your depot_tools is out of date. "
6675 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
6676 "but your version is %d.%d.%d" % tuple(input_api.version))
6677 ]
Saagar Sanghavifceeaae2020-08-12 16:40:366678
Sam Maiera6e76d72022-02-11 21:43:506679 results = []
6680 # Make sure the tree is 'open'.
6681 results.extend(
6682 input_api.canned_checks.CheckTreeIsOpen(
6683 input_api,
6684 output_api,
6685 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:276686
Sam Maiera6e76d72022-02-11 21:43:506687 results.extend(
6688 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
6689 results.extend(
6690 input_api.canned_checks.CheckChangeHasBugField(input_api, output_api))
6691 results.extend(
6692 input_api.canned_checks.CheckChangeHasNoUnwantedTags(
6693 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:506694 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146695
6696
Saagar Sanghavifceeaae2020-08-12 16:40:366697def CheckStrings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506698 """Check string ICU syntax validity and if translation screenshots exist."""
6699 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
6700 # footer is set to true.
6701 git_footers = input_api.change.GitFootersFromDescription()
6702 skip_screenshot_check_footer = [
6703 footer.lower() for footer in git_footers.get(
6704 u'Skip-Translation-Screenshots-Check', [])
6705 ]
6706 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:026707
Sam Maiera6e76d72022-02-11 21:43:506708 import os
6709 import re
6710 import sys
6711 from io import StringIO
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146712
Sam Maiera6e76d72022-02-11 21:43:506713 new_or_added_paths = set(f.LocalPath() for f in input_api.AffectedFiles()
6714 if (f.Action() == 'A' or f.Action() == 'M'))
6715 removed_paths = set(f.LocalPath()
6716 for f in input_api.AffectedFiles(include_deletes=True)
6717 if f.Action() == 'D')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146718
Sam Maiera6e76d72022-02-11 21:43:506719 affected_grds = [
6720 f for f in input_api.AffectedFiles()
6721 if f.LocalPath().endswith(('.grd', '.grdp'))
6722 ]
6723 affected_grds = [
6724 f for f in affected_grds if not 'testdata' in f.LocalPath()
6725 ]
6726 if not affected_grds:
6727 return []
meacer8c0d3832019-12-26 21:46:166728
Sam Maiera6e76d72022-02-11 21:43:506729 affected_png_paths = [
Andrew Grieve713b89b2024-10-15 20:20:086730 f.LocalPath() for f in input_api.AffectedFiles()
6731 if f.LocalPath().endswith('.png')
Sam Maiera6e76d72022-02-11 21:43:506732 ]
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146733
Sam Maiera6e76d72022-02-11 21:43:506734 # Check for screenshots. Developers can upload screenshots using
6735 # tools/translation/upload_screenshots.py which finds and uploads
6736 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
6737 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
6738 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
6739 #
6740 # The logic here is as follows:
6741 #
6742 # - If the CL has a .png file under the screenshots directory for a grd
6743 # file, warn the developer. Actual images should never be checked into the
6744 # Chrome repo.
6745 #
6746 # - If the CL contains modified or new messages in grd files and doesn't
6747 # contain the corresponding .sha1 files, warn the developer to add images
6748 # and upload them via tools/translation/upload_screenshots.py.
6749 #
6750 # - If the CL contains modified or new messages in grd files and the
6751 # corresponding .sha1 files, everything looks good.
6752 #
6753 # - If the CL contains removed messages in grd files but the corresponding
6754 # .sha1 files aren't removed, warn the developer to remove them.
6755 unnecessary_screenshots = []
Jens Mueller054652c2023-05-10 15:12:306756 invalid_sha1 = []
Sam Maiera6e76d72022-02-11 21:43:506757 missing_sha1 = []
Bruce Dawson55776c42022-12-09 17:23:476758 missing_sha1_modified = []
Sam Maiera6e76d72022-02-11 21:43:506759 unnecessary_sha1_files = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146760
Sam Maiera6e76d72022-02-11 21:43:506761 # This checks verifies that the ICU syntax of messages this CL touched is
6762 # valid, and reports any found syntax errors.
6763 # Without this presubmit check, ICU syntax errors in Chromium strings can land
6764 # without developers being aware of them. Later on, such ICU syntax errors
6765 # break message extraction for translation, hence would block Chromium
6766 # translations until they are fixed.
6767 icu_syntax_errors = []
Jens Mueller054652c2023-05-10 15:12:306768 sha1_pattern = input_api.re.compile(r'^[a-fA-F0-9]{40}$',
6769 input_api.re.MULTILINE)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146770
Sam Maiera6e76d72022-02-11 21:43:506771 def _CheckScreenshotAdded(screenshots_dir, message_id):
6772 sha1_path = input_api.os_path.join(screenshots_dir,
6773 message_id + '.png.sha1')
6774 if sha1_path not in new_or_added_paths:
6775 missing_sha1.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306776 elif not _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256777 invalid_sha1.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146778
Bruce Dawson55776c42022-12-09 17:23:476779 def _CheckScreenshotModified(screenshots_dir, message_id):
6780 sha1_path = input_api.os_path.join(screenshots_dir,
6781 message_id + '.png.sha1')
6782 if sha1_path not in new_or_added_paths:
6783 missing_sha1_modified.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306784 elif not _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256785 invalid_sha1.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306786
6787 def _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256788 return sha1_pattern.search(
6789 next("\n".join(f.NewContents()) for f in input_api.AffectedFiles()
6790 if f.LocalPath() == sha1_path))
Bruce Dawson55776c42022-12-09 17:23:476791
Sam Maiera6e76d72022-02-11 21:43:506792 def _CheckScreenshotRemoved(screenshots_dir, message_id):
6793 sha1_path = input_api.os_path.join(screenshots_dir,
6794 message_id + '.png.sha1')
6795 if input_api.os_path.exists(
6796 sha1_path) and sha1_path not in removed_paths:
6797 unnecessary_sha1_files.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146798
Sam Maiera6e76d72022-02-11 21:43:506799 def _ValidateIcuSyntax(text, level, signatures):
6800 """Validates ICU syntax of a text string.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146801
Sam Maiera6e76d72022-02-11 21:43:506802 Check if text looks similar to ICU and checks for ICU syntax correctness
6803 in this case. Reports various issues with ICU syntax and values of
6804 variants. Supports checking of nested messages. Accumulate information of
6805 each ICU messages found in the text for further checking.
Rainhard Findlingfc31844c52020-05-15 09:58:266806
Sam Maiera6e76d72022-02-11 21:43:506807 Args:
6808 text: a string to check.
6809 level: a number of current nesting level.
6810 signatures: an accumulator, a list of tuple of (level, variable,
6811 kind, variants).
Rainhard Findlingfc31844c52020-05-15 09:58:266812
Sam Maiera6e76d72022-02-11 21:43:506813 Returns:
6814 None if a string is not ICU or no issue detected.
6815 A tuple of (message, start index, end index) if an issue detected.
6816 """
6817 valid_types = {
Daniel Cheng6303eed2025-05-03 00:12:336818 'plural': (frozenset([
6819 '=0', '=1', '=2', '=3', 'zero', 'one', 'two', 'few', 'many',
6820 'other'
6821 ]), frozenset(['=1', 'other'])),
6822 'selectordinal': (frozenset([
6823 '=0', '=1', '=2', '=3', 'zero', 'one', 'two', 'few', 'many',
6824 'other'
6825 ]), frozenset(['one', 'other'])),
Sam Maiera6e76d72022-02-11 21:43:506826 'select': (frozenset(), frozenset(['other'])),
6827 }
Rainhard Findlingfc31844c52020-05-15 09:58:266828
Sam Maiera6e76d72022-02-11 21:43:506829 # Check if the message looks like an attempt to use ICU
6830 # plural. If yes - check if its syntax strictly matches ICU format.
6831 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b',
6832 text)
6833 if not like:
6834 signatures.append((level, None, None, None))
6835 return
Rainhard Findlingfc31844c52020-05-15 09:58:266836
Sam Maiera6e76d72022-02-11 21:43:506837 # Check for valid prefix and suffix
6838 m = re.match(
6839 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
6840 r'(plural|selectordinal|select),\s*'
6841 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
6842 if not m:
6843 return (('This message looks like an ICU plural, '
6844 'but does not follow ICU syntax.'), like.start(),
6845 like.end())
6846 starting, variable, kind, variant_pairs = m.groups()
6847 variants, depth, last_pos = _ParseIcuVariants(variant_pairs,
6848 m.start(4))
6849 if depth:
6850 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
6851 len(text))
6852 first = text[0]
6853 ending = text[last_pos:]
6854 if not starting:
6855 return ('Invalid ICU format. No initial opening bracket',
6856 last_pos - 1, last_pos)
6857 if not ending or '}' not in ending:
6858 return ('Invalid ICU format. No final closing bracket',
6859 last_pos - 1, last_pos)
6860 elif first != '{':
6861 return ((
6862 'Invalid ICU format. Extra characters at the start of a complex '
6863 'message (go/icu-message-migration): "%s"') % starting, 0,
6864 len(starting))
6865 elif ending != '}':
6866 return ((
6867 'Invalid ICU format. Extra characters at the end of a complex '
6868 'message (go/icu-message-migration): "%s"') % ending,
6869 last_pos - 1, len(text) - 1)
6870 if kind not in valid_types:
6871 return (('Unknown ICU message type %s. '
6872 'Valid types are: plural, select, selectordinal') % kind,
6873 0, 0)
6874 known, required = valid_types[kind]
6875 defined_variants = set()
6876 for variant, variant_range, value, value_range in variants:
6877 start, end = variant_range
6878 if variant in defined_variants:
6879 return ('Variant "%s" is defined more than once' % variant,
6880 start, end)
6881 elif known and variant not in known:
6882 return ('Variant "%s" is not valid for %s message' %
6883 (variant, kind), start, end)
6884 defined_variants.add(variant)
6885 # Check for nested structure
6886 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
6887 if res:
6888 return (res[0], res[1] + value_range[0] + 1,
6889 res[2] + value_range[0] + 1)
6890 missing = required - defined_variants
6891 if missing:
6892 return ('Required variants missing: %s' % ', '.join(missing), 0,
6893 len(text))
6894 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:266895
Sam Maiera6e76d72022-02-11 21:43:506896 def _ParseIcuVariants(text, offset=0):
6897 """Parse variants part of ICU complex message.
Rainhard Findlingfc31844c52020-05-15 09:58:266898
Sam Maiera6e76d72022-02-11 21:43:506899 Builds a tuple of variant names and values, as well as
6900 their offsets in the input string.
Rainhard Findlingfc31844c52020-05-15 09:58:266901
Sam Maiera6e76d72022-02-11 21:43:506902 Args:
6903 text: a string to parse
6904 offset: additional offset to add to positions in the text to get correct
6905 position in the complete ICU string.
Rainhard Findlingfc31844c52020-05-15 09:58:266906
Sam Maiera6e76d72022-02-11 21:43:506907 Returns:
6908 List of tuples, each tuple consist of four fields: variant name,
6909 variant name span (tuple of two integers), variant value, value
6910 span (tuple of two integers).
6911 """
6912 depth, start, end = 0, -1, -1
6913 variants = []
6914 key = None
6915 for idx, char in enumerate(text):
6916 if char == '{':
6917 if not depth:
6918 start = idx
6919 chunk = text[end + 1:start]
6920 key = chunk.strip()
6921 pos = offset + end + 1 + chunk.find(key)
6922 span = (pos, pos + len(key))
6923 depth += 1
6924 elif char == '}':
6925 if not depth:
6926 return variants, depth, offset + idx
6927 depth -= 1
6928 if not depth:
6929 end = idx
6930 variants.append((key, span, text[start:end + 1],
6931 (offset + start, offset + end + 1)))
6932 return variants, depth, offset + end + 1
Rainhard Findlingfc31844c52020-05-15 09:58:266933
Terrence Reilly313f44ff2025-01-22 15:10:146934 old_sys_path = sys.path
Sam Maiera6e76d72022-02-11 21:43:506935 try:
Sam Maiera6e76d72022-02-11 21:43:506936 sys.path = sys.path + [
6937 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
6938 'translation')
6939 ]
6940 from helper import grd_helper
6941 finally:
6942 sys.path = old_sys_path
Rainhard Findlingfc31844c52020-05-15 09:58:266943
Sam Maiera6e76d72022-02-11 21:43:506944 for f in affected_grds:
6945 file_path = f.LocalPath()
6946 old_id_to_msg_map = {}
6947 new_id_to_msg_map = {}
6948 # Note that this code doesn't check if the file has been deleted. This is
6949 # OK because it only uses the old and new file contents and doesn't load
6950 # the file via its path.
6951 # It's also possible that a file's content refers to a renamed or deleted
6952 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
6953 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
6954 # .grdp files.
6955 if file_path.endswith('.grdp'):
6956 if f.OldContents():
6957 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6958 '\n'.join(f.OldContents()))
6959 if f.NewContents():
6960 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6961 '\n'.join(f.NewContents()))
6962 else:
6963 file_dir = input_api.os_path.dirname(file_path) or '.'
6964 if f.OldContents():
6965 old_id_to_msg_map = grd_helper.GetGrdMessages(
6966 StringIO('\n'.join(f.OldContents())), file_dir)
6967 if f.NewContents():
6968 new_id_to_msg_map = grd_helper.GetGrdMessages(
6969 StringIO('\n'.join(f.NewContents())), file_dir)
Rainhard Findlingfc31844c52020-05-15 09:58:266970
Sam Maiera6e76d72022-02-11 21:43:506971 grd_name, ext = input_api.os_path.splitext(
6972 input_api.os_path.basename(file_path))
6973 screenshots_dir = input_api.os_path.join(
6974 input_api.os_path.dirname(file_path),
6975 grd_name + ext.replace('.', '_'))
Rainhard Findlingfc31844c52020-05-15 09:58:266976
Sam Maiera6e76d72022-02-11 21:43:506977 # Compute added, removed and modified message IDs.
6978 old_ids = set(old_id_to_msg_map)
6979 new_ids = set(new_id_to_msg_map)
6980 added_ids = new_ids - old_ids
6981 removed_ids = old_ids - new_ids
6982 modified_ids = set([])
6983 for key in old_ids.intersection(new_ids):
Daniel Cheng6303eed2025-05-03 00:12:336984 if (old_id_to_msg_map[key].ContentsAsXml('', True)
6985 != new_id_to_msg_map[key].ContentsAsXml('', True)):
Sam Maiera6e76d72022-02-11 21:43:506986 # The message content itself changed. Require an updated screenshot.
6987 modified_ids.add(key)
6988 elif old_id_to_msg_map[key].attrs['meaning'] != \
6989 new_id_to_msg_map[key].attrs['meaning']:
Jens Mueller054652c2023-05-10 15:12:306990 # The message meaning changed. We later check for a screenshot.
6991 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146992
Sam Maiera6e76d72022-02-11 21:43:506993 if run_screenshot_check:
6994 # Check the screenshot directory for .png files. Warn if there is any.
6995 for png_path in affected_png_paths:
6996 if png_path.startswith(screenshots_dir):
6997 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146998
Sam Maiera6e76d72022-02-11 21:43:506999 for added_id in added_ids:
7000 _CheckScreenshotAdded(screenshots_dir, added_id)
Rainhard Findlingd8d04372020-08-13 13:30:097001
Sam Maiera6e76d72022-02-11 21:43:507002 for modified_id in modified_ids:
Bruce Dawson55776c42022-12-09 17:23:477003 _CheckScreenshotModified(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147004
Sam Maiera6e76d72022-02-11 21:43:507005 for removed_id in removed_ids:
7006 _CheckScreenshotRemoved(screenshots_dir, removed_id)
7007
7008 # Check new and changed strings for ICU syntax errors.
7009 for key in added_ids.union(modified_ids):
7010 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
7011 err = _ValidateIcuSyntax(msg, 0, [])
7012 if err is not None:
7013 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
7014
7015 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:267016 if run_screenshot_check:
Sam Maiera6e76d72022-02-11 21:43:507017 if unnecessary_screenshots:
7018 results.append(
7019 output_api.PresubmitError(
7020 'Do not include actual screenshots in the changelist. Run '
7021 'tools/translate/upload_screenshots.py to upload them instead:',
7022 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147023
Sam Maiera6e76d72022-02-11 21:43:507024 if missing_sha1:
7025 results.append(
7026 output_api.PresubmitError(
Bruce Dawson55776c42022-12-09 17:23:477027 'You are adding UI strings.\n'
Sam Maiera6e76d72022-02-11 21:43:507028 'To ensure the best translations, take screenshots of the relevant UI '
7029 '(https://g.co/chrome/translation) and add these files to your '
7030 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147031
Jens Mueller054652c2023-05-10 15:12:307032 if invalid_sha1:
7033 results.append(
7034 output_api.PresubmitError(
7035 'The following files do not seem to contain valid sha1 hashes. '
7036 'Make sure they contain hashes created by '
Daniel Cheng6303eed2025-05-03 00:12:337037 'tools/translate/upload_screenshots.py:',
7038 sorted(invalid_sha1)))
Jens Mueller054652c2023-05-10 15:12:307039
Bruce Dawson55776c42022-12-09 17:23:477040 if missing_sha1_modified:
7041 results.append(
7042 output_api.PresubmitError(
7043 'You are modifying UI strings or their meanings.\n'
7044 'To ensure the best translations, take screenshots of the relevant UI '
7045 '(https://g.co/chrome/translation) and add these files to your '
7046 'changelist:', sorted(missing_sha1_modified)))
7047
Sam Maiera6e76d72022-02-11 21:43:507048 if unnecessary_sha1_files:
7049 results.append(
7050 output_api.PresubmitError(
7051 'You removed strings associated with these files. Remove:',
7052 sorted(unnecessary_sha1_files)))
7053 else:
7054 results.append(
7055 output_api.PresubmitPromptOrNotify('Skipping translation '
7056 'screenshots check.'))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147057
Sam Maiera6e76d72022-02-11 21:43:507058 if icu_syntax_errors:
7059 results.append(
7060 output_api.PresubmitPromptWarning(
7061 'ICU syntax errors were found in the following strings (problems or '
7062 'feedback? Contact [email protected]):',
7063 items=icu_syntax_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:267064
Sam Maiera6e76d72022-02-11 21:43:507065 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:127066
7067
Daniel Cheng6303eed2025-05-03 00:12:337068def CheckTranslationExpectations(input_api,
7069 output_api,
7070 repo_root=None,
7071 translation_expectations_path=None,
7072 grd_files=None):
Sam Maiera6e76d72022-02-11 21:43:507073 import sys
7074 affected_grds = [
7075 f for f in input_api.AffectedFiles()
7076 if (f.LocalPath().endswith('.grd') or f.LocalPath().endswith('.grdp'))
7077 ]
7078 if not affected_grds:
7079 return []
7080
Terrence Reilly313f44ff2025-01-22 15:10:147081 old_sys_path = sys.path
Sam Maiera6e76d72022-02-11 21:43:507082 try:
Sam Maiera6e76d72022-02-11 21:43:507083 sys.path = sys.path + [
7084 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
7085 'translation')
7086 ]
Terrence Reilly313f44ff2025-01-22 15:10:147087 sys.path = sys.path + [
7088 input_api.os_path.join(input_api.PresubmitLocalPath(),
7089 'third_party', 'depot_tools')
7090 ]
Sam Maiera6e76d72022-02-11 21:43:507091 from helper import git_helper
7092 from helper import translation_helper
Terrence Reilly313f44ff2025-01-22 15:10:147093 import gclient_utils
Sam Maiera6e76d72022-02-11 21:43:507094 finally:
7095 sys.path = old_sys_path
7096
7097 # Check that translation expectations can be parsed and we can get a list of
7098 # translatable grd files. |repo_root| and |translation_expectations_path| are
7099 # only passed by tests.
7100 if not repo_root:
7101 repo_root = input_api.PresubmitLocalPath()
7102 if not translation_expectations_path:
7103 translation_expectations_path = input_api.os_path.join(
7104 repo_root, 'tools', 'gritsettings', 'translation_expectations.pyl')
Terrence Reilly313f44ff2025-01-22 15:10:147105 is_cog = gclient_utils.IsEnvCog()
7106 # Git is not available in cog workspaces.
7107 if not grd_files and not is_cog:
Sam Maiera6e76d72022-02-11 21:43:507108 grd_files = git_helper.list_grds_in_repository(repo_root)
Terrence Reilly313f44ff2025-01-22 15:10:147109 if not grd_files:
7110 grd_files = []
Sam Maiera6e76d72022-02-11 21:43:507111
7112 # Ignore bogus grd files used only for testing
Gao Shenga79ebd42022-08-08 17:25:597113 # ui/webui/resources/tools/generate_grd.py.
Sam Maiera6e76d72022-02-11 21:43:507114 ignore_path = input_api.os_path.join('ui', 'webui', 'resources', 'tools',
7115 'tests')
7116 grd_files = [p for p in grd_files if ignore_path not in p]
7117
Ben Mason5d4c3242025-04-15 20:28:377118 # Ensure no duplicate basenames.
7119 basename_to_src_paths = {}
7120 for grd_path in grd_files:
7121 basename = input_api.os_path.basename(grd_path)
7122 basename_to_src_paths.setdefault(basename, [])
7123 basename_to_src_paths[basename].append(grd_path)
7124 for src_paths in basename_to_src_paths.values():
7125 if len(src_paths) > 1:
7126 return [
7127 output_api.PresubmitNotifyResult(
7128 'Multiple string files have the same basename. This will result in '
Daniel Cheng6303eed2025-05-03 00:12:337129 'missing translations. Files: %s' % ', '.join(src_paths))
Ben Mason5d4c3242025-04-15 20:28:377130 ]
7131
Sam Maiera6e76d72022-02-11 21:43:507132 try:
7133 translation_helper.get_translatable_grds(
Terrence Reilly313f44ff2025-01-22 15:10:147134 repo_root, grd_files, translation_expectations_path, is_cog)
Sam Maiera6e76d72022-02-11 21:43:507135 except Exception as e:
7136 return [
7137 output_api.PresubmitNotifyResult(
7138 'Failed to get a list of translatable grd files. This happens when:\n'
7139 ' - One of the modified grd or grdp files cannot be parsed or\n'
7140 ' - %s is not updated.\n'
7141 'Stack:\n%s' % (translation_expectations_path, str(e)))
7142 ]
Mustafa Emre Acer51f2f742020-03-09 19:41:127143 return []
7144
Ken Rockotc31f4832020-05-29 18:58:517145
Saagar Sanghavifceeaae2020-08-12 16:40:367146def CheckStableMojomChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507147 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Daniel Cheng32bde7d2025-07-31 00:25:347148 no_stable_mojom_checks = input_api.change.GitFootersFromDescription().get(
Daniel Chengbdb67a22025-07-30 16:30:237149 'No-Stable-Mojom-Checks', None)
Erik Staabc734cd7a2021-11-23 03:11:527150
Daniel Chengbdb67a22025-07-30 16:30:237151 expect_stable_mojom_failures = False
Daniel Cheng32bde7d2025-07-31 00:25:347152 if no_stable_mojom_checks:
7153 if no_stable_mojom_checks == ['true']:
Daniel Chengbdb67a22025-07-30 16:30:237154 expect_stable_mojom_failures = True
7155 else:
7156 return [
7157 output_api.PresubmitError(
Daniel Cheng32bde7d2025-07-31 00:25:347158 f'If present, No-Stable-Mojom-Checks only accepts the value '
7159 f'"true", but got "{no_stable_mojom_checks}" instead.'
Daniel Chengbdb67a22025-07-30 16:30:237160 )
7161 ]
7162
7163 def CheckMojomsIfNeeded():
7164 changed_mojoms = input_api.AffectedFiles(
7165 include_deletes=True,
7166 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
7167
7168 if not changed_mojoms or input_api.no_diffs:
7169 return []
7170
7171 delta = []
7172 for mojom in changed_mojoms:
7173 delta.append({
7174 'filename': mojom.LocalPath(),
7175 'old': '\n'.join(mojom.OldContents()) or None,
7176 'new': '\n'.join(mojom.NewContents()) or None,
7177 })
7178
7179 process = input_api.subprocess.Popen([
7180 input_api.python3_executable,
7181 input_api.os_path.join(
7182 input_api.PresubmitLocalPath(), 'mojo', 'public', 'tools',
7183 'mojom', 'check_stable_mojom_compatibility.py'), '--src-root',
7184 input_api.PresubmitLocalPath()
7185 ],
7186 stdin=input_api.subprocess.PIPE,
7187 stdout=input_api.subprocess.PIPE,
7188 stderr=input_api.subprocess.PIPE,
7189 universal_newlines=True)
7190 (x, error) = process.communicate(input=input_api.json.dumps(delta))
7191 if process.returncode:
7192 return [
7193 output_api.PresubmitError(
7194 'One or more [Stable] mojom definitions changed in a way '
7195 'that breaks backward compatibility. See '
7196 'https://chromium.googlesource.com/chromium/src/+/HEAD/mojo/public/tools/bindings/README.md#versioning'
7197 ' for details.\n\n'
7198 'If you are confident this is a false positive, add '
7199 '`No-Stable-Mojom-Checks: true` to the git footers to suppress '
7200 'this check.',
7201 long_text=error)
7202 ]
Sam Maiera6e76d72022-02-11 21:43:507203 return []
7204
Daniel Chengbdb67a22025-07-30 16:30:237205 results = CheckMojomsIfNeeded()
7206 if bool(results) != expect_stable_mojom_failures:
7207 if expect_stable_mojom_failures:
7208 return [
7209 output_api.PresubmitError(
7210 'No [Stable] mojom definitions changed in a way breaks '
7211 'backward compatibility.\n\n'
7212 'Please remove the unnecessary git footer '
7213 '`No-Stable-Mojom-Checks: true`.')
7214 ]
7215 else:
7216 return results
Erik Staabc734cd7a2021-11-23 03:11:527217 return []
7218
Daniel Cheng6303eed2025-05-03 00:12:337219
Dominic Battre645d42342020-12-04 16:14:107220def CheckDeprecationOfPreferences(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507221 """Removing a preference should come with a deprecation."""
Dominic Battre645d42342020-12-04 16:14:107222
Sam Maiera6e76d72022-02-11 21:43:507223 def FilterFile(affected_file):
7224 """Accept only .cc files and the like."""
7225 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
7226 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
7227 input_api.DEFAULT_FILES_TO_SKIP)
7228 return input_api.FilterSourceFile(
7229 affected_file,
7230 files_to_check=file_inclusion_pattern,
7231 files_to_skip=files_to_skip)
Dominic Battre645d42342020-12-04 16:14:107232
Sam Maiera6e76d72022-02-11 21:43:507233 def ModifiedLines(affected_file):
7234 """Returns a list of tuples (line number, line text) of added and removed
7235 lines.
Dominic Battre645d42342020-12-04 16:14:107236
Sam Maiera6e76d72022-02-11 21:43:507237 Deleted lines share the same line number as the previous line.
Dominic Battre645d42342020-12-04 16:14:107238
Sam Maiera6e76d72022-02-11 21:43:507239 This relies on the scm diff output describing each changed code section
7240 with a line of the form
Dominic Battre645d42342020-12-04 16:14:107241
Sam Maiera6e76d72022-02-11 21:43:507242 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
7243 """
7244 line_num = 0
7245 modified_lines = []
7246 for line in affected_file.GenerateScmDiff().splitlines():
7247 # Extract <new line num> of the patch fragment (see format above).
7248 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@',
7249 line)
7250 if m:
7251 line_num = int(m.groups(1)[0])
7252 continue
7253 if ((line.startswith('+') and not line.startswith('++'))
7254 or (line.startswith('-') and not line.startswith('--'))):
7255 modified_lines.append((line_num, line))
Dominic Battre645d42342020-12-04 16:14:107256
Sam Maiera6e76d72022-02-11 21:43:507257 if not line.startswith('-'):
7258 line_num += 1
7259 return modified_lines
Dominic Battre645d42342020-12-04 16:14:107260
Sam Maiera6e76d72022-02-11 21:43:507261 def FindLineWith(lines, needle):
7262 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
Dominic Battre645d42342020-12-04 16:14:107263
Sam Maiera6e76d72022-02-11 21:43:507264 If 0 or >1 lines contain `needle`, -1 is returned.
7265 """
7266 matching_line_numbers = [
7267 # + 1 for 1-based counting of line numbers.
7268 i + 1 for i, line in enumerate(lines) if needle in line
7269 ]
7270 return matching_line_numbers[0] if len(
7271 matching_line_numbers) == 1 else -1
Dominic Battre645d42342020-12-04 16:14:107272
Sam Maiera6e76d72022-02-11 21:43:507273 def ModifiedPrefMigration(affected_file):
7274 """Returns whether the MigrateObsolete.*Pref functions were modified."""
7275 # Determine first and last lines of MigrateObsolete.*Pref functions.
7276 new_contents = affected_file.NewContents()
7277 range_1 = (FindLineWith(new_contents,
7278 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
7279 FindLineWith(new_contents,
7280 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
7281 range_2 = (FindLineWith(new_contents,
7282 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
7283 FindLineWith(new_contents,
7284 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
7285 if (-1 in range_1 + range_2):
7286 raise Exception(
7287 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.'
7288 )
Dominic Battre645d42342020-12-04 16:14:107289
Sam Maiera6e76d72022-02-11 21:43:507290 # Check whether any of the modified lines are part of the
7291 # MigrateObsolete.*Pref functions.
7292 for line_nr, line in ModifiedLines(affected_file):
7293 if (range_1[0] <= line_nr <= range_1[1]
7294 or range_2[0] <= line_nr <= range_2[1]):
7295 return True
7296 return False
Dominic Battre645d42342020-12-04 16:14:107297
Sam Maiera6e76d72022-02-11 21:43:507298 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
7299 browser_prefs_file_pattern = input_api.re.compile(
7300 r'chrome/browser/prefs/browser_prefs.cc')
Dominic Battre645d42342020-12-04 16:14:107301
Sam Maiera6e76d72022-02-11 21:43:507302 changes = input_api.AffectedFiles(include_deletes=True,
7303 file_filter=FilterFile)
7304 potential_problems = []
7305 for f in changes:
7306 for line in f.GenerateScmDiff().splitlines():
7307 # Check deleted lines for pref registrations.
7308 if (line.startswith('-') and not line.startswith('--')
7309 and register_pref_pattern.search(line)):
7310 potential_problems.append('%s: %s' % (f.LocalPath(), line))
Dominic Battre645d42342020-12-04 16:14:107311
Sam Maiera6e76d72022-02-11 21:43:507312 if browser_prefs_file_pattern.search(f.LocalPath()):
7313 # If the developer modified the MigrateObsolete.*Prefs() functions, we
7314 # assume that they knew that they have to deprecate preferences and don't
7315 # warn.
7316 try:
7317 if ModifiedPrefMigration(f):
7318 return []
7319 except Exception as e:
7320 return [output_api.PresubmitError(str(e))]
Dominic Battre645d42342020-12-04 16:14:107321
Sam Maiera6e76d72022-02-11 21:43:507322 if potential_problems:
7323 return [
7324 output_api.PresubmitPromptWarning(
7325 'Discovered possible removal of preference registrations.\n\n'
7326 'Please make sure to properly deprecate preferences by clearing their\n'
7327 'value for a couple of milestones before finally removing the code.\n'
7328 'Otherwise data may stay in the preferences files forever. See\n'
7329 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
7330 'chrome/browser/prefs/README.md for examples.\n'
7331 'This may be a false positive warning (e.g. if you move preference\n'
Alexander Hendrich465aed22025-07-25 11:42:177332 'registrations to a different place or if the preference was only\n'
7333 'written to by the policy stack).\n', potential_problems)
Sam Maiera6e76d72022-02-11 21:43:507334 ]
7335 return []
7336
Matt Stark6ef08872021-07-29 01:21:467337
7338def CheckConsistentGrdChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507339 """Changes to GRD files must be consistent for tools to read them."""
7340 changed_grds = input_api.AffectedFiles(
7341 include_deletes=False,
7342 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
7343 errors = []
7344 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
7345 for matcher, msg in _INVALID_GRD_FILE_LINE]
7346 for grd in changed_grds:
7347 for i, line in enumerate(grd.NewContents()):
7348 for matcher, msg in invalid_file_regexes:
7349 if matcher.search(line):
7350 errors.append(
7351 output_api.PresubmitError(
7352 'Problem on {grd}:{i} - {msg}'.format(
7353 grd=grd.LocalPath(), i=i + 1, msg=msg)))
7354 return errors
7355
Kevin McNee967dd2d22021-11-15 16:09:297356
Henrique Ferreiro2a4b55942021-11-29 23:45:367357def CheckAssertAshOnlyCode(input_api, output_api):
7358 """Errors if a BUILD.gn file in an ash/ directory doesn't include
Georg Neis94f87f02024-10-22 08:20:137359 assert(is_chromeos).
7360 For a transition period, assert(is_chromeos_ash) is also accepted.
Henrique Ferreiro2a4b55942021-11-29 23:45:367361 """
7362
7363 def FileFilter(affected_file):
7364 """Includes directories known to be Ash only."""
7365 return input_api.FilterSourceFile(
7366 affected_file,
7367 files_to_check=(
7368 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
7369 r'.*/ash/.*BUILD\.gn'), # Any path component.
7370 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
7371
7372 errors = []
Georg Neis94f87f02024-10-22 08:20:137373 pattern = input_api.re.compile(r'assert\(is_chromeos(_ash)?\b')
Jameson Thies0ce669f2021-12-09 15:56:567374 for f in input_api.AffectedFiles(include_deletes=False,
7375 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:367376 if (not pattern.search(input_api.ReadFile(f))):
7377 errors.append(
7378 output_api.PresubmitError(
Georg Neis94f87f02024-10-22 08:20:137379 'Please add assert(is_chromeos) to %s. If that\'s not '
7380 'possible, please create an issue and add a comment such '
Alison Galed6b25fe2024-04-17 13:59:047381 'as:\n # TODO(crbug.com/XXX): add '
Georg Neis94f87f02024-10-22 08:20:137382 'assert(is_chromeos) when ...' % f.LocalPath()))
Henrique Ferreiro2a4b55942021-11-29 23:45:367383 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:277384
7385
Kalvin Lee84ad17a2023-09-25 11:14:417386def _IsMiraclePtrDisallowed(input_api, affected_file):
Anton Bershanskyi4253349482025-02-11 21:01:277387 path = affected_file.UnixLocalPath()
Sam Maiera6e76d72022-02-11 21:43:507388 if not _IsCPlusPlusFile(input_api, path):
7389 return False
7390
Bartek Nowierski49b1a452024-06-08 00:24:357391 # Renderer-only code is generally allowed to use MiraclePtr. These
7392 # directories, however, are specifically disallowed, for perf reasons.
Kalvin Lee84ad17a2023-09-25 11:14:417393 if ("third_party/blink/renderer/core/" in path
7394 or "third_party/blink/renderer/platform/heap/" in path
Bartek Nowierski49b1a452024-06-08 00:24:357395 or "third_party/blink/renderer/platform/wtf/" in path
7396 or "third_party/blink/renderer/platform/fonts/" in path):
7397 return True
7398
7399 # The below paths are an explicitly listed subset of Renderer-only code,
7400 # because the plan is to Oilpanize it.
7401 # TODO(crbug.com/330759291): Remove once Oilpanization is completed or
7402 # abandoned.
Daniel Cheng6303eed2025-05-03 00:12:337403 if ("third_party/blink/renderer/core/paint/" in path or
7404 "third_party/blink/renderer/platform/graphics/compositing/" in path
Bartek Nowierski49b1a452024-06-08 00:24:357405 or "third_party/blink/renderer/platform/graphics/paint/" in path):
Sam Maiera6e76d72022-02-11 21:43:507406 return True
7407
Sam Maiera6e76d72022-02-11 21:43:507408 # We assume that everything else may be used outside of Renderer processes.
Lukasz Anforowicz7016d05e2021-11-30 03:56:277409 return False
7410
Daniel Cheng6303eed2025-05-03 00:12:337411
Alison Galed6b25fe2024-04-17 13:59:047412# TODO(crbug.com/40206238): Remove these checks, once they are replaced
Lukasz Anforowicz7016d05e2021-11-30 03:56:277413# by the Chromium Clang Plugin (which will be preferable because it will
7414# 1) report errors earlier - at compile-time and 2) cover more rules).
7415def CheckRawPtrUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507416 """Rough checks that raw_ptr<T> usage guidelines are followed."""
7417 errors = []
7418 # The regex below matches "raw_ptr<" following a word boundary, but not in a
7419 # C++ comment.
7420 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
Kalvin Lee84ad17a2023-09-25 11:14:417421 file_filter = lambda f: _IsMiraclePtrDisallowed(input_api, f)
Sam Maiera6e76d72022-02-11 21:43:507422 for f, line_num, line in input_api.RightHandSideLines(file_filter):
7423 if raw_ptr_matcher.search(line):
7424 errors.append(
7425 output_api.PresubmitError(
7426 'Problem on {path}:{line} - '\
Kalvin Lee84ad17a2023-09-25 11:14:417427 'raw_ptr<T> should not be used in this renderer code '\
Sam Maiera6e76d72022-02-11 21:43:507428 '(as documented in the "Pointers to unprotected memory" '\
7429 'section in //base/memory/raw_ptr.md)'.format(
7430 path=f.LocalPath(), line=line_num)))
7431 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:567432
Daniel Cheng6303eed2025-05-03 00:12:337433
mikt9337567c2023-09-08 18:38:177434def CheckAdvancedMemorySafetyChecksUsage(input_api, output_api):
7435 """Checks that ADVANCED_MEMORY_SAFETY_CHECKS() macro is neither added nor
7436 removed as it is managed by the memory safety team internally.
7437 Do not add / remove it manually."""
7438 paths = set([])
7439 # The regex below matches "ADVANCED_MEMORY_SAFETY_CHECKS(" following a word
7440 # boundary, but not in a C++ comment.
7441 macro_matcher = input_api.re.compile(
Daniel Cheng6303eed2025-05-03 00:12:337442 r'^((?!//).)*\bADVANCED_MEMORY_SAFETY_CHECKS\(',
7443 input_api.re.MULTILINE)
mikt9337567c2023-09-08 18:38:177444 for f in input_api.AffectedFiles():
7445 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
7446 continue
7447 if macro_matcher.search(f.GenerateScmDiff()):
7448 paths.add(f.LocalPath())
7449 if not paths:
7450 return []
7451 return [output_api.PresubmitPromptWarning(
7452 'ADVANCED_MEMORY_SAFETY_CHECKS() macro is managed by ' \
7453 'the memory safety team (chrome-memory-safety@). ' \
7454 'Please contact us to add/delete the uses of the macro.',
7455 paths)]
Henrique Ferreirof9819f2e32021-11-30 13:31:567456
Daniel Cheng6303eed2025-05-03 00:12:337457
Henrique Ferreirof9819f2e32021-11-30 13:31:567458def CheckPythonShebang(input_api, output_api):
7459 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
7460 system-wide python.
7461 """
7462 errors = []
7463 sources = lambda affected_file: input_api.FilterSourceFile(
7464 affected_file,
7465 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
7466 r'third_party/blink/web_tests/external/') + input_api.
7467 DEFAULT_FILES_TO_SKIP),
7468 files_to_check=[r'.*\.py$'])
7469 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:277470 for line_num, line in f.ChangedContents():
7471 if line_num == 1 and line.startswith('#!/usr/bin/python'):
7472 errors.append(f.LocalPath())
7473 break
Henrique Ferreirof9819f2e32021-11-30 13:31:567474
7475 result = []
7476 for file in errors:
7477 result.append(
7478 output_api.PresubmitError(
7479 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
7480 file))
7481 return result
James Shen81cc0e22022-06-15 21:10:457482
7483
Andrew Grieve5a66ae72024-12-13 15:21:537484def CheckAndroidTestAnnotations(input_api, output_api):
James Shen81cc0e22022-06-15 21:10:457485 """Checks that tests have either @Batch or @DoNotBatch annotation. If this
7486 is not an instrumentation test, disregard."""
7487
7488 batch_annotation = input_api.re.compile(r'^\s*@Batch')
7489 do_not_batch_annotation = input_api.re.compile(r'^\s*@DoNotBatch')
Daniel Cheng6303eed2025-05-03 00:12:337490 robolectric_test = input_api.re.compile(
7491 r'@RunWith\((.*?)RobolectricTestRunner')
James Shen81cc0e22022-06-15 21:10:457492 test_class_declaration = input_api.re.compile(r'^\s*public\sclass.*Test')
7493 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
Daniel Cheng6303eed2025-05-03 00:12:337494 test_annotation_declaration = input_api.re.compile(
7495 r'^\s*public\s@interface\s.*{')
James Shen81cc0e22022-06-15 21:10:457496
ckitagawae8fd23b2022-06-17 15:29:387497 missing_annotation_errors = []
7498 extra_annotation_errors = []
Andrew Grieve5a66ae72024-12-13 15:21:537499 wrong_robolectric_test_runner_errors = []
James Shen81cc0e22022-06-15 21:10:457500
7501 def _FilterFile(affected_file):
7502 return input_api.FilterSourceFile(
7503 affected_file,
7504 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
7505 files_to_check=[r'.*Test\.java$'])
7506
7507 for f in input_api.AffectedSourceFiles(_FilterFile):
7508 batch_matched = None
7509 do_not_batch_matched = None
7510 is_instrumentation_test = True
Mark Schillaci8ef0d872023-07-18 22:07:597511 test_annotation_declaration_matched = None
Andrew Grieve5a66ae72024-12-13 15:21:537512 has_base_robolectric_rule = False
James Shen81cc0e22022-06-15 21:10:457513 for line in f.NewContents():
Andrew Grieve5a66ae72024-12-13 15:21:537514 if 'BaseRobolectricTestRule' in line:
7515 has_base_robolectric_rule = True
7516 continue
7517 if m := robolectric_test.search(line):
7518 is_instrumentation_test = False
7519 if m.group(1) == '' and not has_base_robolectric_rule:
Yiwei Zhang5341bf02025-03-20 16:34:137520 path = str(f.LocalPath())
7521 # These two spots cannot use it.
7522 if 'webapk' not in path and 'build' not in path:
7523 wrong_robolectric_test_runner_errors.append(path)
Andrew Grieve5a66ae72024-12-13 15:21:537524 break
7525 if uiautomator_test.search(line):
James Shen81cc0e22022-06-15 21:10:457526 is_instrumentation_test = False
7527 break
7528 if not batch_matched:
7529 batch_matched = batch_annotation.search(line)
7530 if not do_not_batch_matched:
7531 do_not_batch_matched = do_not_batch_annotation.search(line)
7532 test_class_declaration_matched = test_class_declaration.search(
7533 line)
Daniel Cheng6303eed2025-05-03 00:12:337534 test_annotation_declaration_matched = test_annotation_declaration.search(
7535 line)
Mark Schillaci8ef0d872023-07-18 22:07:597536 if test_class_declaration_matched or test_annotation_declaration_matched:
James Shen81cc0e22022-06-15 21:10:457537 break
Mark Schillaci8ef0d872023-07-18 22:07:597538 if test_annotation_declaration_matched:
7539 continue
Daniel Cheng6303eed2025-05-03 00:12:337540 if (is_instrumentation_test and not batch_matched
7541 and not do_not_batch_matched):
Sam Maier4cef9242022-10-03 14:21:247542 missing_annotation_errors.append(str(f.LocalPath()))
Daniel Cheng6303eed2025-05-03 00:12:337543 if (not is_instrumentation_test
7544 and (batch_matched or do_not_batch_matched)):
Sam Maier4cef9242022-10-03 14:21:247545 extra_annotation_errors.append(str(f.LocalPath()))
James Shen81cc0e22022-06-15 21:10:457546
7547 results = []
7548
ckitagawae8fd23b2022-06-17 15:29:387549 if missing_annotation_errors:
James Shen81cc0e22022-06-15 21:10:457550 results.append(
7551 output_api.PresubmitPromptWarning(
7552 """
Andrew Grieve43a5cf82023-09-08 15:09:467553A change was made to an on-device test that has neither been annotated with
7554@Batch nor @DoNotBatch. If this is a new test, please add the annotation. If
7555this is an existing test, please consider adding it if you are sufficiently
7556familiar with the test (but do so as a separate change).
7557
Jens Mueller2085ff82023-02-27 11:54:497558See https://source.chromium.org/chromium/chromium/src/+/main:docs/testing/batching_instrumentation_tests.md
ckitagawae8fd23b2022-06-17 15:29:387559""", missing_annotation_errors))
7560 if extra_annotation_errors:
7561 results.append(
7562 output_api.PresubmitPromptWarning(
7563 """
7564Robolectric tests do not need a @Batch or @DoNotBatch annotations.
7565""", extra_annotation_errors))
Andrew Grieve5a66ae72024-12-13 15:21:537566 if wrong_robolectric_test_runner_errors:
7567 results.append(
7568 output_api.PresubmitPromptWarning(
7569 """
Wenyu Fu0005ab82025-01-03 18:13:267570Robolectric tests should use either @RunWith(BaseRobolectricTestRunner.class) (or
Andrew Grieve5a66ae72024-12-13 15:21:537571a subclass of it), or use "@Rule BaseRobolectricTestRule".
7572""", wrong_robolectric_test_runner_errors))
James Shen81cc0e22022-06-15 21:10:457573
7574 return results
Sam Maier4cef9242022-10-03 14:21:247575
7576
Henrique Nakashima224ee2482025-03-21 18:35:027577def _CheckAndroidNullAwayAnnotatedClasses(input_api, output_api):
7578 """Checks that Java classes/interfaces/annotations are null-annotated."""
7579
Henrique Nakashima2bdd8ad2025-04-08 18:24:577580 # Temporary, crbug.com/389129271
7581 if input_api.change.RepositoryRoot().endswith('clank'):
7582 return []
7583
Daniel Cheng6303eed2025-05-03 00:12:337584 nullmarked_annotation = input_api.re.compile(
7585 r'^\s*@(NullMarked|NullUnmarked)')
Henrique Nakashima224ee2482025-03-21 18:35:027586
7587 missing_annotation_errors = []
7588
7589 def _FilterFile(affected_file):
7590 return input_api.FilterSourceFile(
7591 affected_file,
Daniel Cheng6303eed2025-05-03 00:12:337592 files_to_skip=(
7593 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
7594 input_api.DEFAULT_FILES_TO_SKIP + (
7595 r'.*Test.*\.java',
7596 r'^android_webview/.*', # Temporary, crbug.com/389129271
7597 r'^build/.*',
Daniel Cheng6303eed2025-05-03 00:12:337598 r'^chromecast/.*',
7599 r'^components/cronet/.*',
7600 r'^tools/.*',
7601 )),
7602 files_to_check=[r'.*\.java$'])
Henrique Nakashima224ee2482025-03-21 18:35:027603
7604 for f in input_api.AffectedSourceFiles(_FilterFile):
Henrique Nakashimac6605432025-04-24 18:11:597605 if f.Action() != 'A':
7606 continue
Henrique Nakashima224ee2482025-03-21 18:35:027607 for line in f.NewContents():
7608 if nullmarked_annotation.search(line):
7609 break
7610 else:
7611 missing_annotation_errors.append(str(f.LocalPath()))
7612
7613 results = []
7614
7615 if missing_annotation_errors:
7616 results.append(
Henrique Nakashima8bafbc52025-04-22 19:38:427617 output_api.PresubmitError(
Henrique Nakashima224ee2482025-03-21 18:35:027618 """
7619Please add @NullMarked and fix the NullAway warnings in the following files
7620(see https://chromium.googlesource.com/chromium/src/+/main/styleguide/java/nullaway.md):
7621""", missing_annotation_errors))
7622
7623 return results
7624
7625
Mike Dougherty1b8be712022-10-20 00:15:137626def CheckNoJsInIos(input_api, output_api):
7627 """Checks to make sure that JavaScript files are not used on iOS."""
7628
7629 def _FilterFile(affected_file):
7630 return input_api.FilterSourceFile(
7631 affected_file,
7632 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP +
Daniel Cheng6303eed2025-05-03 00:12:337633 (r'^ios/third_party/*', r'^ios/tools/*', r'^third_party/*',
7634 r'^components/autofill/ios/form_util/resources/*'),
Mike Dougherty1b8be712022-10-20 00:15:137635 files_to_check=[r'^ios/.*\.js$', r'.*/ios/.*\.js$'])
7636
Mike Dougherty4d1050b2023-03-14 15:59:537637 deleted_files = []
7638
7639 # Collect filenames of all removed JS files.
Arthur Sonzognic66e9c82024-04-23 07:53:047640 for f in input_api.AffectedFiles(file_filter=_FilterFile):
Mike Dougherty4d1050b2023-03-14 15:59:537641 local_path = f.LocalPath()
7642
Daniel Cheng6303eed2025-05-03 00:12:337643 if input_api.os_path.splitext(
7644 local_path)[1] == '.js' and f.Action() == 'D':
Mike Dougherty4d1050b2023-03-14 15:59:537645 deleted_files.append(input_api.os_path.basename(local_path))
7646
Mike Dougherty1b8be712022-10-20 00:15:137647 error_paths = []
Mike Dougherty4d1050b2023-03-14 15:59:537648 moved_paths = []
Mike Dougherty1b8be712022-10-20 00:15:137649 warning_paths = []
7650
7651 for f in input_api.AffectedSourceFiles(_FilterFile):
7652 local_path = f.LocalPath()
7653
7654 if input_api.os_path.splitext(local_path)[1] == '.js':
7655 if f.Action() == 'A':
Mike Dougherty4d1050b2023-03-14 15:59:537656 if input_api.os_path.basename(local_path) in deleted_files:
7657 # This script was probably moved rather than newly created.
7658 # Present a warning instead of an error for these cases.
7659 moved_paths.append(local_path)
7660 else:
7661 error_paths.append(local_path)
Mike Dougherty1b8be712022-10-20 00:15:137662 elif f.Action() != 'D':
7663 warning_paths.append(local_path)
7664
7665 results = []
7666
7667 if warning_paths:
Daniel Cheng6303eed2025-05-03 00:12:337668 results.append(
7669 output_api.PresubmitPromptWarning(
7670 'TypeScript is now fully supported for iOS feature scripts. '
7671 'Consider converting JavaScript files to TypeScript. See '
7672 '//ios/web/public/js_messaging/README.md for more details.',
7673 warning_paths))
Mike Dougherty1b8be712022-10-20 00:15:137674
Mike Dougherty4d1050b2023-03-14 15:59:537675 if moved_paths:
Daniel Cheng6303eed2025-05-03 00:12:337676 results.append(
7677 output_api.PresubmitPromptWarning(
7678 'Do not use JavaScript on iOS for new files as TypeScript is '
7679 'fully supported. (If this is a moved file, you may leave the '
7680 'script unconverted.) See //ios/web/public/js_messaging/README.md '
7681 'for help using scripts on iOS.', moved_paths))
Mike Dougherty4d1050b2023-03-14 15:59:537682
Mike Dougherty1b8be712022-10-20 00:15:137683 if error_paths:
Daniel Cheng6303eed2025-05-03 00:12:337684 results.append(
7685 output_api.PresubmitError(
7686 'Do not use JavaScript on iOS as TypeScript is fully supported. '
7687 'See //ios/web/public/js_messaging/README.md for help using '
7688 'scripts on iOS.', error_paths))
Mike Dougherty1b8be712022-10-20 00:15:137689
7690 return results
Hans Wennborg23a81d52023-03-24 16:38:137691
Daniel Cheng6303eed2025-05-03 00:12:337692
Hans Wennborg23a81d52023-03-24 16:38:137693def CheckLibcxxRevisionsMatch(input_api, output_api):
7694 """Check to make sure the libc++ version matches across deps files."""
Andrew Grieve21bb6792023-03-27 19:06:487695 # Disable check for changes to sub-repositories.
7696 if input_api.PresubmitLocalPath() != input_api.change.RepositoryRoot():
Sam Maierb926c58c2023-08-08 19:58:257697 return []
Hans Wennborg23a81d52023-03-24 16:38:137698
Daniel Cheng6303eed2025-05-03 00:12:337699 DEPS_FILES = ['DEPS', 'buildtools/deps_revisions.gni']
Hans Wennborg23a81d52023-03-24 16:38:137700
Anton Bershanskyi4253349482025-02-11 21:01:277701 file_filter = lambda f: f.UnixLocalPath() in DEPS_FILES
Hans Wennborg23a81d52023-03-24 16:38:137702 changed_deps_files = input_api.AffectedFiles(file_filter=file_filter)
7703 if not changed_deps_files:
7704 return []
7705
7706 def LibcxxRevision(file):
7707 file = input_api.os_path.join(input_api.PresubmitLocalPath(),
7708 *file.split('/'))
Daniel Cheng6303eed2025-05-03 00:12:337709 return input_api.re.search(r'libcxx_revision.*[:=].*[\'"](\w+)[\'"]',
7710 input_api.ReadFile(file)).group(1)
Hans Wennborg23a81d52023-03-24 16:38:137711
7712 if len(set([LibcxxRevision(f) for f in DEPS_FILES])) == 1:
7713 return []
7714
Daniel Cheng6303eed2025-05-03 00:12:337715 return [
7716 output_api.PresubmitError(
7717 'libcxx_revision not equal across %s' % ', '.join(DEPS_FILES),
7718 changed_deps_files)
7719 ]
Arthur Sonzogni7109bd32023-10-03 10:34:427720
7721
7722def CheckDanglingUntriaged(input_api, output_api):
7723 """Warn developers adding DanglingUntriaged raw_ptr."""
7724
7725 # Ignore during git presubmit --all.
7726 #
7727 # This would be too costly, because this would check every lines of every
7728 # C++ files. Check from _BANNED_CPP_FUNCTIONS are also reading the whole
7729 # source code, but only once to apply every checks. It seems the bots like
7730 # `win-presubmit` are particularly sensitive to reading the files. Adding
7731 # this check caused the bot to run 2x longer. See https://crbug.com/1486612.
7732 if input_api.no_diffs:
Arthur Sonzogni9eafd222023-11-10 08:50:397733 return []
Arthur Sonzogni7109bd32023-10-03 10:34:427734
7735 def FilterFile(file):
7736 return input_api.FilterSourceFile(
7737 file,
7738 files_to_check=[r".*\.(h|cc|cpp|cxx|m|mm)$"],
7739 files_to_skip=[r"^base/allocator.*"],
7740 )
7741
7742 count = 0
Arthur Sonzognic66e9c82024-04-23 07:53:047743 for f in input_api.AffectedFiles(file_filter=FilterFile):
Arthur Sonzogni9eafd222023-11-10 08:50:397744 count -= sum([l.count("DanglingUntriaged") for l in f.OldContents()])
7745 count += sum([l.count("DanglingUntriaged") for l in f.NewContents()])
Arthur Sonzogni7109bd32023-10-03 10:34:427746
7747 # Most likely, nothing changed:
7748 if count == 0:
7749 return []
7750
7751 # Congrats developers for improving it:
7752 if count < 0:
Arthur Sonzogni9eafd222023-11-10 08:50:397753 message = f"DanglingUntriaged pointers removed: {-count}\nThank you!"
Arthur Sonzogni7109bd32023-10-03 10:34:427754 return [output_api.PresubmitNotifyResult(message)]
7755
7756 # Check for 'DanglingUntriaged-notes' in the description:
7757 notes_regex = input_api.re.compile("DanglingUntriaged-notes[:=]")
7758 if any(
7759 notes_regex.match(line)
7760 for line in input_api.change.DescriptionText().splitlines()):
7761 return []
7762
7763 # Check for DanglingUntriaged-notes in the git footer:
7764 if input_api.change.GitFootersFromDescription().get(
7765 "DanglingUntriaged-notes", []):
7766 return []
7767
7768 message = (
Daniel Cheng6303eed2025-05-03 00:12:337769 "Unexpected new occurrences of `DanglingUntriaged` detected. Please\n"
7770 + "avoid adding new ones\n" + "\n" + "See documentation:\n" +
7771 "https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr.md\n"
7772 + "\n" + "See also the guide to fix dangling pointers:\n" +
7773 "https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr_guide.md\n"
7774 + "\n" +
Arthur Sonzogni9eafd222023-11-10 08:50:397775 "To disable this warning, please add in the commit description:\n" +
Alex Gough26dcd852023-12-22 16:47:197776 "DanglingUntriaged-notes: <rationale for new untriaged dangling " +
Daniel Cheng6303eed2025-05-03 00:12:337777 "pointers>")
Arthur Sonzogni7109bd32023-10-03 10:34:427778 return [output_api.PresubmitPromptWarning(message)]
Jan Keitel77be7522023-10-12 20:40:497779
Daniel Cheng6303eed2025-05-03 00:12:337780
Jan Keitel77be7522023-10-12 20:40:497781def CheckInlineConstexprDefinitionsInHeaders(input_api, output_api):
7782 """Checks that non-static constexpr definitions in headers are inline."""
7783 # In a properly formatted file, constexpr definitions inside classes or
7784 # structs will have additional whitespace at the beginning of the line.
7785 # The pattern looks for variables initialized as constexpr kVar = ...; or
7786 # constexpr kVar{...};
7787 # The pattern does not match expressions that have braces in kVar to avoid
7788 # matching constexpr functions.
7789 pattern = input_api.re.compile(r'^constexpr (?!inline )[^\(\)]*[={]')
Daniel Cheng6303eed2025-05-03 00:12:337790 attribute_pattern = input_api.re.compile(
7791 r'(\[\[[a-zA-Z_:]+\]\]|[A-Z]+[A-Z_]+) ')
Jan Keitel77be7522023-10-12 20:40:497792 problems = []
7793 for f in input_api.AffectedFiles():
7794 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
7795 continue
7796
7797 for line_number, line in f.ChangedContents():
7798 line = attribute_pattern.sub('', line)
7799 if pattern.search(line):
Daniel Cheng6303eed2025-05-03 00:12:337800 problems.append(f"{f.LocalPath()}: {line_number}\n {line}")
Jan Keitel77be7522023-10-12 20:40:497801
7802 if problems:
7803 return [
7804 output_api.PresubmitPromptWarning(
7805 'Consider inlining constexpr variable definitions in headers '
7806 'outside of classes to avoid unnecessary copies of the '
7807 'constant. See https://abseil.io/tips/168 for more details.',
7808 problems)
7809 ]
7810 else:
7811 return []
Alison Galed6b25fe2024-04-17 13:59:047812
Daniel Cheng6303eed2025-05-03 00:12:337813
Alison Galed6b25fe2024-04-17 13:59:047814def CheckTodoBugReferences(input_api, output_api):
7815 """Checks that bugs in TODOs use updated issue tracker IDs."""
7816
Daniel Cheng6303eed2025-05-03 00:12:337817 files_to_skip = [
7818 'PRESUBMIT_test.py', r"^third_party/rust/chromium_crates_io/vendor/.*"
7819 ]
Alison Galed6b25fe2024-04-17 13:59:047820
7821 def _FilterFile(affected_file):
Daniel Cheng6303eed2025-05-03 00:12:337822 return input_api.FilterSourceFile(affected_file,
7823 files_to_skip=files_to_skip)
Alison Galed6b25fe2024-04-17 13:59:047824
7825 # Monorail bug IDs are all less than or equal to 1524553 so check that all
7826 # bugs in TODOs are greater than that value.
Tom Sepez8e628582025-02-14 02:18:557827 pattern = input_api.re.compile(r'.*\bTODO\([^\)0-9]*([0-9]+)\).*')
Alison Galed6b25fe2024-04-17 13:59:047828 problems = []
7829 for f in input_api.AffectedSourceFiles(_FilterFile):
7830 for line_number, line in f.ChangedContents():
7831 match = pattern.match(line)
7832 if match and int(match.group(1)) <= 1524553:
Daniel Cheng6303eed2025-05-03 00:12:337833 problems.append(f"{f.LocalPath()}: {line_number}\n {line}")
Alison Galed6b25fe2024-04-17 13:59:047834
7835 if problems:
7836 return [
7837 output_api.PresubmitPromptWarning(
Alison Galecb598de52024-04-26 17:03:257838 'TODOs should use the new Chromium Issue Tracker IDs which can '
7839 'be found by navigating to the bug. See '
Daniel Cheng6303eed2025-05-03 00:12:337840 'https://crbug.com/336778624 for more details.', problems)
Alison Galed6b25fe2024-04-17 13:59:047841 ]
7842 else:
7843 return []
Mikita Kuchyne9cd0e29f2025-05-26 11:47:257844
7845def CheckNoBrowserStarInUnittests(input_api, output_api):
7846 """Checks that unit-tests don't contain Browser* variables.
7847 """
7848 problems = []
7849
7850 def FileFilter(affected_file):
7851 """Check unit-tests only"""
7852 return input_api.FilterSourceFile(
7853 affected_file,
7854 files_to_check=(
7855 r'.*unittest\.cc$',
7856 r'.*unittest\.h$'
7857 ),
7858 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
7859 )
7860
7861 browser_star_pattern = input_api.re.compile(r'\bBrowser\s*\*')
7862
7863 for f in input_api.AffectedFiles(include_deletes=False,
7864 file_filter=FileFilter):
7865 for line_num, line in f.ChangedContents():
7866 match = browser_star_pattern.search(line)
7867 if match:
7868 problems.append(' %s:%d:%s' %
7869 (f.LocalPath(), line_num, match.group(0)))
7870
7871 if not problems:
7872 return []
7873
7874 WARNING_MSG="""Do not use "Browser*" type in unittest files (e.g.,
7875 "*unittest.cc" or "*unittest.h"). Unit tests should generally
7876 not depend on the full Browser class or related components. Consider
7877 refactoring to mock dependencies, use test-specific fakes,
7878 or determine if a browser_test is more appropriate.
7879 """
7880 return [output_api.PresubmitPromptWarning(WARNING_MSG, items=problems)]