blob: b95248a7380fa5ccb315fba43a164736f890dffc [file] [log] [blame]
Avi Drissman24976592022-09-12 15:24:311# Copyright 2012 The Chromium Authors
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
Daniel Chengd88244472022-05-16 09:08:477See https://www.chromium.org/developers/how-tos/depottools/presubmit-scripts/
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d1982009-02-19 16:33:129"""
Daniel Chenga44a1bcd2022-03-15 20:00:1510
Daniel Chenga37c03db2022-05-12 17:20:3411from typing import Callable
Daniel Chenga44a1bcd2022-03-15 20:00:1512from typing import Optional
13from typing import Sequence
mikt19226ff22024-08-27 05:28:2114from typing import Tuple
Daniel Chenga44a1bcd2022-03-15 20:00:1515from dataclasses import dataclass
16
Saagar Sanghavifceeaae2020-08-12 16:40:3617PRESUBMIT_VERSION = '2.0.0'
[email protected]eea609a2011-11-18 13:10:1218
Dirk Prankee3c9c62d2021-05-18 18:35:5919
[email protected]379e7dd2010-01-28 17:39:2120_EXCLUDED_PATHS = (
Bruce Dawson7f8566b2022-05-06 16:22:1821 # Generated file
Bruce Dawson40fece62022-09-16 19:58:3122 (r"chrome/android/webapk/shell_apk/src/org/chromium"
23 r"/webapk/lib/runtime_library/IWebApkApi.java"),
Mila Greene3aa7222021-09-07 16:34:0824 # File needs to write to stdout to emulate a tool it's replacing.
Bruce Dawson40fece62022-09-16 19:58:3125 r"chrome/updater/mac/keystone/ksadmin.mm",
Ilya Shermane8a7d2d2020-07-25 04:33:4726 # Generated file.
Bruce Dawson40fece62022-09-16 19:58:3127 (r"^components/variations/proto/devtools/"
Ilya Shermanc167a962020-08-18 18:40:2628 r"client_variations.js"),
Bruce Dawson3bd976c2022-05-06 22:47:5229 # These are video files, not typescript.
Bruce Dawson40fece62022-09-16 19:58:3130 r"^media/test/data/.*.ts",
31 r"^native_client_sdksrc/build_tools/make_rules.py",
32 r"^native_client_sdk/src/build_tools/make_simple.py",
33 r"^native_client_sdk/src/tools/.*.mk",
34 r"^net/tools/spdyshark/.*",
35 r"^skia/.*",
36 r"^third_party/blink/.*",
37 r"^third_party/breakpad/.*",
Darwin Huangd74a9d32019-07-17 17:58:4638 # sqlite is an imported third party dependency.
Bruce Dawson40fece62022-09-16 19:58:3139 r"^third_party/sqlite/.*",
40 r"^v8/.*",
[email protected]3e4eb112011-01-18 03:29:5441 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5342 r".+_autogen\.h$",
Yue Shecf1380552022-08-23 20:59:2043 r".+_pb2(_grpc)?\.py$",
Bruce Dawson40fece62022-09-16 19:58:3144 r".+/pnacl_shim\.c$",
45 r"^gpu/config/.*_list_json\.cc$",
46 r"tools/md_browser/.*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1447 # Test pages for Maps telemetry tests.
Bruce Dawson40fece62022-09-16 19:58:3148 r"tools/perf/page_sets/maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5449 # Test pages for WebRTC telemetry tests.
Bruce Dawson40fece62022-09-16 19:58:3150 r"tools/perf/page_sets/webrtc_cases.*",
dpapad2efd4452023-04-06 01:43:4551 # Test file compared with generated output.
52 r"tools/polymer/tests/html_to_wrapper/.*.html.ts$",
dpapada45be36c2024-08-07 20:19:3553 # Third-party dependency frozen at a fixed version.
54 r"chrome/test/data/webui/chromeos/chai_v4.js$",
[email protected]4306417642009-06-11 00:33:4055)
[email protected]ca8d1982009-02-19 16:33:1256
John Abd-El-Malek759fea62021-03-13 03:41:1457_EXCLUDED_SET_NO_PARENT_PATHS = (
58 # It's for historical reasons that blink isn't a top level directory, where
59 # it would be allowed to have "set noparent" to avoid top level owners
60 # accidentally +1ing changes.
61 'third_party/blink/OWNERS',
62)
63
wnwenbdc444e2016-05-25 13:44:1564
[email protected]06e6d0ff2012-12-11 01:36:4465# Fragment of a regular expression that matches C++ and Objective-C++
66# implementation files.
67_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
68
wnwenbdc444e2016-05-25 13:44:1569
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1970# Fragment of a regular expression that matches C++ and Objective-C++
71# header files.
72_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
73
74
Aleksey Khoroshilov9b28c032022-06-03 16:35:3275# Paths with sources that don't use //base.
76_NON_BASE_DEPENDENT_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:3177 r"^chrome/browser/browser_switcher/bho/",
78 r"^tools/win/",
Aleksey Khoroshilov9b28c032022-06-03 16:35:3279)
80
81
[email protected]06e6d0ff2012-12-11 01:36:4482# Regular expression that matches code only used for test binaries
83# (best effort).
84_TEST_CODE_EXCLUDED_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:3185 r'.*/(fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
Marijn Kruisselbrink2a2d5fc2024-05-15 15:23:4986 # Test support files, like:
87 # foo_test_support.cc
88 # bar_test_util_linux.cc (suffix)
89 # baz_test_base.cc
90 r'.+_test_(base|support|util)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
James Cook1b4dc132021-03-09 22:45:1391 # Test suite files, like:
92 # foo_browsertest.cc
93 # bar_unittest_mac.cc (suffix)
94 # baz_unittests.cc (plural)
95 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(s)?(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1296 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1897 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
Victor Hugo Vianna Silvac22e0202021-06-09 19:46:2198 r'.+sync_service_impl_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Bruce Dawson40fece62022-09-16 19:58:3199 r'.*/(test|tool(s)?)/.*',
danakj89f47082020-09-02 17:53:43100 # content_shell is used for running content_browsertests.
Bruce Dawson40fece62022-09-16 19:58:31101 r'content/shell/.*',
danakj89f47082020-09-02 17:53:43102 # Web test harness.
Bruce Dawson40fece62022-09-16 19:58:31103 r'content/web_test/.*',
[email protected]7b054982013-11-27 00:44:47104 # Non-production example code.
Bruce Dawson40fece62022-09-16 19:58:31105 r'mojo/examples/.*',
[email protected]8176de12014-06-20 19:07:08106 # Launcher for running iOS tests on the simulator.
Bruce Dawson40fece62022-09-16 19:58:31107 r'testing/iossim/iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:41108 # EarlGrey app side code for tests.
Bruce Dawson40fece62022-09-16 19:58:31109 r'ios/.*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:17110 # Views Examples code
Bruce Dawson40fece62022-09-16 19:58:31111 r'ui/views/examples/.*',
Austin Sullivan33da70a2020-10-07 15:39:41112 # Chromium Codelab
Bruce Dawson40fece62022-09-16 19:58:31113 r'codelabs/*'
[email protected]06e6d0ff2012-12-11 01:36:44114)
[email protected]ca8d1982009-02-19 16:33:12115
Daniel Bratell609102be2019-03-27 20:53:21116_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:15117
[email protected]eea609a2011-11-18 13:10:12118_TEST_ONLY_WARNING = (
119 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:55120 'production code. If you are doing this from inside another method\n'
121 'named as *ForTesting(), then consider exposing things to have tests\n'
122 'make that same call directly.\n'
123 'If that is not possible, you may put a comment on the same line with\n'
124 ' // IN-TEST \n'
125 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
126 'method and can be ignored. Do not do this inside production code.\n'
127 'The android-binary-size trybot will block if the method exists in the\n'
Yulun Zeng08d7d8c2024-02-01 18:46:54128 'release apk.\n'
129 'Note: this warning might be a false positive (crbug.com/1196548).')
[email protected]eea609a2011-11-18 13:10:12130
131
Daniel Chenga44a1bcd2022-03-15 20:00:15132@dataclass
133class BanRule:
Daniel Chenga37c03db2022-05-12 17:20:34134 # String pattern. If the pattern begins with a slash, the pattern will be
135 # treated as a regular expression instead.
136 pattern: str
137 # Explanation as a sequence of strings. Each string in the sequence will be
138 # printed on its own line.
mikt19226ff22024-08-27 05:28:21139 explanation: Tuple[str, ...]
Daniel Chenga37c03db2022-05-12 17:20:34140 # Whether or not to treat this ban as a fatal error. If unspecified,
141 # defaults to true.
142 treat_as_error: Optional[bool] = None
143 # Paths that should be excluded from the ban check. Each string is a regular
144 # expression that will be matched against the path of the file being checked
145 # relative to the root of the source tree.
146 excluded_paths: Optional[Sequence[str]] = None
[email protected]cf9b78f2012-11-14 11:40:28147
Daniel Chenga44a1bcd2022-03-15 20:00:15148
Daniel Cheng917ce542022-03-15 20:46:57149_BANNED_JAVA_IMPORTS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15150 BanRule(
151 'import java.net.URI;',
152 (
153 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
154 ),
155 excluded_paths=(
156 (r'net/android/javatests/src/org/chromium/net/'
Dirk Prankee4df27972025-02-26 18:39:35157 r'AndroidProxySelectorTest\.java'),
Daniel Chenga44a1bcd2022-03-15 20:00:15158 r'components/cronet/',
159 r'third_party/robolectric/local/',
160 ),
Michael Thiessen44457642020-02-06 00:24:15161 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15162 BanRule(
163 'import android.annotation.TargetApi;',
164 (
165 'Do not use TargetApi, use @androidx.annotation.RequiresApi instead. '
166 'RequiresApi ensures that any calls are guarded by the appropriate '
167 'SDK_INT check. See https://crbug.com/1116486.',
168 ),
169 ),
170 BanRule(
Mohamed Heikal3d7a94c2023-03-28 16:55:24171 'import androidx.test.rule.ActivityTestRule;',
Daniel Chenga44a1bcd2022-03-15 20:00:15172 (
173 'Do not use ActivityTestRule, use '
174 'org.chromium.base.test.BaseActivityTestRule instead.',
175 ),
176 excluded_paths=(
177 'components/cronet/',
178 ),
179 ),
Min Qinbc44383c2023-02-22 17:25:26180 BanRule(
181 'import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;',
182 (
183 'Do not use VectorDrawableCompat, use getResources().getDrawable() to '
184 'avoid extra indirections. Please also add trace event as the call '
185 'might take more than 20 ms to complete.',
186 ),
187 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15188)
wnwenbdc444e2016-05-25 13:44:15189
Daniel Cheng917ce542022-03-15 20:46:57190_BANNED_JAVA_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15191 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41192 'StrictMode.allowThreadDiskReads()',
193 (
194 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
195 'directly.',
196 ),
197 False,
198 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15199 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41200 'StrictMode.allowThreadDiskWrites()',
201 (
202 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
203 'directly.',
204 ),
205 False,
206 ),
Daniel Cheng917ce542022-03-15 20:46:57207 BanRule(
Michael Thiessen0f2547e2020-07-27 21:55:36208 '.waitForIdleSync()',
209 (
210 'Do not use waitForIdleSync as it masks underlying issues. There is '
211 'almost always something else you should wait on instead.',
212 ),
213 False,
214 ),
Ashley Newson09cbd602022-10-26 11:40:14215 BanRule(
Ashley Newsoneb6f5ce2022-10-26 14:45:42216 r'/(?<!\bsuper\.)(?<!\bIntent )\bregisterReceiver\(',
Ashley Newson09cbd602022-10-26 11:40:14217 (
218 'Do not call android.content.Context.registerReceiver (or an override) '
219 'directly. Use one of the wrapper methods defined in '
220 'org.chromium.base.ContextUtils, such as '
221 'registerProtectedBroadcastReceiver, '
222 'registerExportedBroadcastReceiver, or '
223 'registerNonExportedBroadcastReceiver. See their documentation for '
224 'which one to use.',
225 ),
226 True,
227 excluded_paths=(
Ashley Newson22bc26d2022-11-01 20:30:57228 r'.*Test[^a-z]',
229 r'third_party/',
Ashley Newson09cbd602022-10-26 11:40:14230 'base/android/java/src/org/chromium/base/ContextUtils.java',
Brandon Mousseau7e76a9c2022-12-08 22:08:38231 'chromecast/browser/android/apk/src/org/chromium/chromecast/shell/BroadcastReceiverScope.java',
Ashley Newson09cbd602022-10-26 11:40:14232 ),
233 ),
Ted Chocd5b327b12022-11-05 02:13:22234 BanRule(
235 r'/(?:extends|new)\s*(?:android.util.)?Property<[A-Za-z.]+,\s*(?:Integer|Float)>',
236 (
237 'Do not use Property<..., Integer|Float>, but use FloatProperty or '
238 'IntProperty because it will avoid unnecessary autoboxing of '
239 'primitives.',
240 ),
241 ),
Peilin Wangbba4a8652022-11-10 16:33:57242 BanRule(
243 'requestLayout()',
244 (
245 'Layouts can be expensive. Prefer using ViewUtils.requestLayout(), '
246 'which emits a trace event with additional information to help with '
247 'scroll jank investigations. See http://crbug.com/1354176.',
248 ),
249 False,
250 excluded_paths=(
251 'ui/android/java/src/org/chromium/ui/base/ViewUtils.java',
252 ),
253 ),
Ted Chocf40ea9152023-02-14 19:02:39254 BanRule(
Ted Chocf486e3f2024-02-17 05:37:03255 'ProfileManager.getLastUsedRegularProfile()',
Ted Chocf40ea9152023-02-14 19:02:39256 (
257 'Prefer passing in the Profile reference instead of relying on the '
258 'static getLastUsedRegularProfile() call. Only top level entry points '
259 '(e.g. Activities) should call this method. Otherwise, the Profile '
260 'should either be passed in explicitly or retreived from an existing '
261 'entity with a reference to the Profile (e.g. WebContents).',
262 ),
263 False,
264 excluded_paths=(
265 r'.*Test[A-Z]?.*\.java',
266 ),
267 ),
Min Qinbc44383c2023-02-22 17:25:26268 BanRule(
269 r'/(ResourcesCompat|getResources\(\))\.getDrawable\(\)',
270 (
271 'getDrawable() can be expensive. If you have a lot of calls to '
272 'GetDrawable() or your code may introduce janks, please put your calls '
273 'inside a trace().',
274 ),
275 False,
276 excluded_paths=(
277 r'.*Test[A-Z]?.*\.java',
278 ),
279 ),
Henrique Nakashimabbf2b262023-03-10 17:21:39280 BanRule(
281 r'/RecordHistogram\.getHistogram(ValueCount|TotalCount|Samples)ForTesting\(',
282 (
283 'Raw histogram counts are easy to misuse; for example they don\'t reset '
Thiago Perrotta099034f2023-06-05 18:10:20284 'between batched tests. Use HistogramWatcher to check histogram records '
285 'instead.',
Henrique Nakashimabbf2b262023-03-10 17:21:39286 ),
287 False,
288 excluded_paths=(
289 'base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java',
290 'base/test/android/javatests/src/org/chromium/base/test/util/HistogramWatcher.java',
291 ),
292 ),
Jenna Himawan859865d2025-02-25 22:22:31293 BanRule(
294 r'/((announceForAccessibility\()|TYPE_ANNOUNCEMENT)',
295 ('Android 16 deprecates accessibility announcements, characterized by '
296 'the use of announceForAccessibility or the dispatch of '
297 'TYPE_ANNOUNCEMENT accessibility events. See '
298 'https://developer.android.com/about/versions/16/behavior-changes-all#disruptive-a11y'
299 ' for more details and suggested replacements.', ),
300 False,
301 ),
Nate Fischerd541ff82025-03-11 21:34:19302 BanRule(
303 pattern=(r'IS_DESKTOP_ANDROID'),
304 explanation=(
305 'Features which depend on IS_DESKTOP_ANDROID should only exist in '
306 'chrome/ layer and similar layers. Lower layers such as content/ '
307 'should not have features which are only designed for '
308 'desktop-android builds. See https://crbug.com/401628399.', ),
309 treat_as_error=False,
310 excluded_paths=[
311 _THIRD_PARTY_EXCEPT_BLINK, # Don't warn in third_party folders.
312 r'^build/', # This is permitted in build/ folder.
313 r'^chrome/', # This is permitted in chrome/ folder.
314 r'^components/', # This is permitted only for components/ that are not shared by WebView.
315 r'^extensions/', # This is permitted in chrome/ folder.
316 r'^infra/', # This is permitted in infra/ folder.
317 r'^tools/', # This is permitted in tools/ folder.
318 ],
319 ),
Eric Stevensona9a980972017-09-23 00:04:41320)
321
Clement Yan9b330cb2022-11-17 05:25:29322_BANNED_JAVASCRIPT_FUNCTIONS : Sequence [BanRule] = (
323 BanRule(
324 r'/\bchrome\.send\b',
325 (
326 '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).',
327 'Please use mojo instead for new webuis. https://docs.google.com/document/d/1RF-GSUoveYa37eoyZ9EhwMtaIwoW7Z88pIgNZ9YzQi4/edit#heading=h.gkk22wgk6wff',
328 ),
329 True,
330 (
331 r'^(?!ash\/webui).+',
332 # TODO(crbug.com/1385601): pre-existing violations still need to be
333 # cleaned up.
Rebekah Potter57aa94df2022-12-13 20:30:58334 'ash/webui/common/resources/cr.m.js',
Clement Yan9b330cb2022-11-17 05:25:29335 'ash/webui/common/resources/multidevice_setup/multidevice_setup_browser_proxy.js',
Martin Bidlingmaiera921fee72023-06-03 07:52:22336 'ash/webui/common/resources/quick_unlock/lock_screen_constants.ts',
Clement Yan9b330cb2022-11-17 05:25:29337 'ash/webui/common/resources/smb_shares/smb_browser_proxy.js',
Chad Duffin06e47de2023-12-14 18:04:13338 'ash/webui/connectivity_diagnostics/resources/connectivity_diagnostics.ts',
Clement Yan9b330cb2022-11-17 05:25:29339 'ash/webui/diagnostics_ui/resources/diagnostics_browser_proxy.ts',
340 'ash/webui/multidevice_debug/resources/logs.js',
341 'ash/webui/multidevice_debug/resources/webui.js',
342 'ash/webui/projector_app/resources/annotator/trusted/annotator_browser_proxy.js',
343 'ash/webui/projector_app/resources/app/trusted/projector_browser_proxy.js',
Ashley Prasad71f9024e2023-09-25 22:33:55344 # TODO(b/301634378): Remove violation exception once Scanning App
345 # migrated off usage of `chrome.send`.
346 'ash/webui/scanning/resources/scanning_browser_proxy.ts',
Clement Yan9b330cb2022-11-17 05:25:29347 ),
348 ),
349)
350
Daniel Cheng917ce542022-03-15 20:46:57351_BANNED_OBJC_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15352 BanRule(
[email protected]127f18ec2012-06-16 05:05:59353 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20354 (
355 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59356 'prohibited. Please use CrTrackingArea instead.',
357 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
358 ),
359 False,
360 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15361 BanRule(
[email protected]eaae1972014-04-16 04:17:26362 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20363 (
364 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59365 'instead.',
366 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
367 ),
368 False,
369 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15370 BanRule(
[email protected]127f18ec2012-06-16 05:05:59371 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20372 (
373 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59374 'Please use |convertPoint:(point) fromView:nil| instead.',
375 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
376 ),
377 True,
378 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15379 BanRule(
[email protected]127f18ec2012-06-16 05:05:59380 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20381 (
382 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59383 'Please use |convertPoint:(point) toView:nil| instead.',
384 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
385 ),
386 True,
387 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15388 BanRule(
[email protected]127f18ec2012-06-16 05:05:59389 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20390 (
391 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59392 'Please use |convertRect:(point) fromView:nil| instead.',
393 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
394 ),
395 True,
396 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15397 BanRule(
[email protected]127f18ec2012-06-16 05:05:59398 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20399 (
400 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59401 'Please use |convertRect:(point) toView:nil| instead.',
402 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
403 ),
404 True,
405 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15406 BanRule(
[email protected]127f18ec2012-06-16 05:05:59407 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20408 (
409 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59410 'Please use |convertSize:(point) fromView:nil| instead.',
411 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
412 ),
413 True,
414 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15415 BanRule(
[email protected]127f18ec2012-06-16 05:05:59416 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20417 (
418 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59419 'Please use |convertSize:(point) toView:nil| instead.',
420 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
421 ),
422 True,
423 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15424 BanRule(
jif65398702016-10-27 10:19:48425 r"/\s+UTF8String\s*]",
426 (
427 'The use of -[NSString UTF8String] is dangerous as it can return null',
428 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
429 'Please use |SysNSStringToUTF8| instead.',
430 ),
431 True,
Marijn Kruisselbrink1b7c48952023-08-31 16:58:34432 excluded_paths = (
433 '^third_party/ocmock/OCMock/',
434 ),
jif65398702016-10-27 10:19:48435 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15436 BanRule(
Sylvain Defresne4cf1d182017-09-18 14:16:34437 r'__unsafe_unretained',
438 (
439 'The use of __unsafe_unretained is almost certainly wrong, unless',
440 'when interacting with NSFastEnumeration or NSInvocation.',
441 'Please use __weak in files build with ARC, nothing otherwise.',
442 ),
443 False,
444 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15445 BanRule(
Avi Drissman7382afa02019-04-29 23:27:13446 'freeWhenDone:NO',
447 (
448 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
449 'Foundation types is prohibited.',
450 ),
451 True,
452 ),
Avi Drissman3d243a42023-08-01 16:53:59453 BanRule(
454 'This file requires ARC support.',
455 (
456 'ARC compilation is default in Chromium; do not add boilerplate to ',
457 'files that require ARC.',
458 ),
459 True,
460 ),
[email protected]127f18ec2012-06-16 05:05:59461)
462
Sylvain Defresnea8b73d252018-02-28 15:45:54463_BANNED_IOS_OBJC_FUNCTIONS = (
Daniel Chenga44a1bcd2022-03-15 20:00:15464 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54465 r'/\bTEST[(]',
466 (
467 'TEST() macro should not be used in Objective-C++ code as it does not ',
468 'drain the autorelease pool at the end of the test. Use TEST_F() ',
469 'macro instead with a fixture inheriting from PlatformTest (or a ',
470 'typedef).'
471 ),
472 True,
473 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15474 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54475 r'/\btesting::Test\b',
476 (
477 'testing::Test should not be used in Objective-C++ code as it does ',
478 'not drain the autorelease pool at the end of the test. Use ',
479 'PlatformTest instead.'
480 ),
481 True,
482 ),
Ewann2ecc8d72022-07-18 07:41:23483 BanRule(
484 ' systemImageNamed:',
485 (
486 '+[UIImage systemImageNamed:] should not be used to create symbols.',
487 'Instead use a wrapper defined in:',
Slobodan Pejic8ef56c702024-07-12 18:21:26488 'ios/chrome/browser/shared/ui/symbols/symbol_helpers.h'
Ewann2ecc8d72022-07-18 07:41:23489 ),
490 True,
Ewann450a2ef2022-07-19 14:38:23491 excluded_paths=(
Gauthier Ambard4d8756b2023-04-07 17:26:41492 'ios/chrome/browser/shared/ui/symbols/symbol_helpers.mm',
Slobodan Pejic8ef56c702024-07-12 18:21:26493 'ios/chrome/common',
Tommy Martino2a1182dc2024-11-20 19:34:42494 # App extensions have restricted dependencies and thus can't use the
495 # wrappers.
Riley Wong49be8a882025-02-27 00:38:23496 r'^ios/chrome/\w+_extension/',
Ewann450a2ef2022-07-19 14:38:23497 ),
Ewann2ecc8d72022-07-18 07:41:23498 ),
Sylvain Defresne781b9f92024-12-11 09:36:18499 BanRule(
500 r'public (RefCounted)?BrowserStateKeyedServiceFactory',
501 (
502 'KeyedService factories in //ios/chrome/browser should inherit from',
503 '(Refcounted)?ProfileKeyedServieFactoryIOS, not directory from',
504 '(Refcounted)?BrowserStateKeyedServiceFactory.'
505 ),
506 treat_as_error=True,
507 excluded_paths=(
508 'ios/components',
509 'ios/web_view',
510 ),
511 ),
Sylvain Defresnea8b73d252018-02-28 15:45:54512)
513
Daniel Cheng917ce542022-03-15 20:46:57514_BANNED_IOS_EGTEST_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15515 BanRule(
Peter K. Lee6c03ccff2019-07-15 14:40:05516 r'/\bEXPECT_OCMOCK_VERIFY\b',
517 (
518 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
519 'it is meant for GTests. Use [mock verify] instead.'
520 ),
521 True,
522 ),
523)
524
Daniel Cheng566634ff2024-06-29 14:56:53525_BANNED_CPP_FUNCTIONS: Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15526 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53527 '%#0',
528 (
529 'Zero-padded values that use "#" to add prefixes don\'t exhibit ',
530 'consistent behavior, since the prefix is not prepended for zero ',
531 'values. Use "0x%0..." instead.',
532 ),
533 False,
534 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting7c0d98a2023-10-06 15:42:39535 ),
536 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53537 r'/\busing namespace ',
538 (
539 'Using directives ("using namespace x") are banned by the Google Style',
540 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
541 'Explicitly qualify symbols or use using declarations ("using x::foo").',
542 ),
543 True,
544 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting94a56c42019-10-25 21:54:04545 ),
Antonio Gomes07300d02019-03-13 20:59:57546 # Make sure that gtest's FRIEND_TEST() macro is not used; the
547 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
548 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
Daniel Chenga44a1bcd2022-03-15 20:00:15549 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53550 'FRIEND_TEST(',
551 (
552 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
553 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
554 ),
555 False,
556 excluded_paths=(
557 "base/gtest_prod_util.h",
558 "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/gtest_prod_util.h",
559 ),
[email protected]23e6cbc2012-06-16 18:51:20560 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15561 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53562 'setMatrixClip',
563 (
564 'Overriding setMatrixClip() is prohibited; ',
565 'the base function is deprecated. ',
566 ),
567 True,
568 (),
tomhudsone2c14d552016-05-26 17:07:46569 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15570 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53571 'SkRefPtr',
572 ('The use of SkRefPtr is prohibited. ', 'Please use sk_sp<> instead.'),
573 True,
574 (),
[email protected]52657f62013-05-20 05:30:31575 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15576 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53577 'SkAutoRef',
578 ('The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
579 'Please use sk_sp<> instead.'),
580 True,
581 (),
[email protected]52657f62013-05-20 05:30:31582 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15583 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53584 'SkAutoTUnref',
585 ('The use of SkAutoTUnref is dangerous because it implicitly ',
586 'converts to a raw pointer. Please use sk_sp<> instead.'),
587 True,
588 (),
[email protected]52657f62013-05-20 05:30:31589 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15590 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53591 'SkAutoUnref',
592 ('The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
593 'because it implicitly converts to a raw pointer. ',
594 'Please use sk_sp<> instead.'),
595 True,
596 (),
[email protected]52657f62013-05-20 05:30:31597 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15598 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53599 r'/HANDLE_EINTR\(.*close',
600 ('HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
601 'descriptor will be closed, and it is incorrect to retry the close.',
602 'Either call close directly and ignore its return value, or wrap close',
603 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
604 ),
605 True,
606 (),
[email protected]d89eec82013-12-03 14:10:59607 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15608 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53609 r'/IGNORE_EINTR\((?!.*close)',
610 (
611 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
612 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
613 ),
614 True,
615 (
616 # Files that #define IGNORE_EINTR.
617 r'^base/posix/eintr_wrapper\.h$',
618 r'^ppapi/tests/test_broker\.cc$',
619 ),
[email protected]d89eec82013-12-03 14:10:59620 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15621 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53622 r'/v8::Extension\(',
623 (
624 'Do not introduce new v8::Extensions into the code base, use',
625 'gin::Wrappable instead. See http://crbug.com/334679',
626 ),
627 True,
628 (r'extensions/renderer/safe_builtins\.*', ),
[email protected]ec5b3f02014-04-04 18:43:43629 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15630 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53631 '#pragma comment(lib,',
632 ('Specify libraries to link with in build files and not in the source.',
633 ),
634 True,
635 (
636 r'^base/third_party/symbolize/.*',
637 r'^third_party/abseil-cpp/.*',
Victor Hugo Vianna Silvac86846c02025-03-07 06:56:37638 r'^third_party/grpc/source/.*',
Daniel Cheng566634ff2024-06-29 14:56:53639 ),
jame2d1a952016-04-02 00:27:10640 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15641 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53642 r'/base::SequenceChecker\b',
643 ('Consider using SEQUENCE_CHECKER macros instead of the class directly.',
644 ),
645 False,
646 (),
gabd52c912a2017-05-11 04:15:59647 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15648 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53649 r'/base::ThreadChecker\b',
650 ('Consider using THREAD_CHECKER macros instead of the class directly.',
651 ),
652 False,
653 (),
gabd52c912a2017-05-11 04:15:59654 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15655 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53656 r'/\b(?!(Sequenced|SingleThread))\w*TaskRunner::(GetCurrentDefault|CurrentDefaultHandle)',
657 (
658 'It is not allowed to call these methods from the subclasses ',
659 'of Sequenced or SingleThread task runners.',
660 ),
661 True,
662 (),
Sean Maher03efef12022-09-23 22:43:13663 ),
664 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53665 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
666 (
667 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
668 'deprecated (http://crbug.com/634507). Please avoid converting away',
669 'from the Time types in Chromium code, especially if any math is',
670 'being done on time values. For interfacing with platform/library',
671 'APIs, use base::Time::(From,To)DeltaSinceWindowsEpoch() or',
672 'base::{TimeDelta::In}Microseconds(), or one of the other type',
673 'converter methods instead. For faking TimeXXX values (for unit',
674 'testing only), use TimeXXX() + Microseconds(N). For',
675 'other use cases, please contact base/time/OWNERS.',
676 ),
677 False,
678 excluded_paths=(
679 "base/time/time.h",
680 "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/time/time.h",
681 ),
Yuri Wiitala2f8de5c2017-07-21 00:11:06682 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15683 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53684 'CallJavascriptFunctionUnsafe',
685 (
686 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
687 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
688 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
689 ),
690 False,
691 (
692 r'^content/browser/webui/web_ui_impl\.(cc|h)$',
693 r'^content/public/browser/web_ui\.h$',
694 r'^content/public/test/test_web_ui\.(cc|h)$',
695 ),
dbeamb6f4fde2017-06-15 04:03:06696 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15697 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53698 'leveldb::DB::Open',
699 (
700 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
701 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
702 "Chrome's tracing, making their memory usage visible.",
703 ),
704 True,
705 (r'^third_party/leveldatabase/.*\.(cc|h)$', ),
Gabriel Charette0592c3a2017-07-26 12:02:04706 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15707 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53708 'leveldb::NewMemEnv',
709 (
710 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
711 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
712 "to Chrome's tracing, making their memory usage visible.",
713 ),
714 True,
715 (r'^third_party/leveldatabase/.*\.(cc|h)$', ),
Chris Mumfordc38afb62017-10-09 17:55:08716 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15717 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53718 'base::ScopedMockTimeMessageLoopTaskRunner',
719 (
720 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
721 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
722 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
723 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
724 'with gab@ first if you think you need it)',
725 ),
726 False,
727 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57728 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15729 BanRule(
Peter Kasting5fdcd782025-01-13 14:57:07730 '\bstd::aligned_(storage|union)\b',
731 (
732 'std::aligned_storage and std::aligned_union are deprecated in',
733 'C++23. Use an aligned char array instead.'
734 ),
735 True,
736 (),
737 ),
738 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53739 'std::regex',
740 (
741 'Using std::regex adds unnecessary binary size to Chrome. Please use',
742 're2::RE2 instead (crbug.com/755321)',
743 ),
744 True,
745 [
746 # Abseil's benchmarks never linked into chrome.
747 'third_party/abseil-cpp/.*_benchmark.cc',
748 ],
Francois Doray43670e32017-09-27 12:40:38749 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15750 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53751 r'/\bstd::sto(i|l|ul|ll|ull)\b',
752 (
753 'std::sto{i,l,ul,ll,ull}() use exceptions to communicate results. ',
754 'Use base::StringTo[U]Int[64]() instead.',
755 ),
756 True,
757 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting991618a62019-06-17 22:00:09758 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15759 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53760 r'/\bstd::sto(f|d|ld)\b',
761 (
762 'std::sto{f,d,ld}() use exceptions to communicate results. ',
763 'For locale-independent values, e.g. reading numbers from disk',
764 'profiles, use base::StringToDouble().',
765 'For user-visible values, parse using ICU.',
766 ),
767 True,
768 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting991618a62019-06-17 22:00:09769 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15770 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53771 r'/\bstd::to_string\b',
772 (
773 'std::to_string() is locale dependent and slower than alternatives.',
774 'For locale-independent strings, e.g. writing numbers to disk',
775 'profiles, use base::NumberToString().',
776 'For user-visible strings, use base::FormatNumber() and',
777 'the related functions in base/i18n/number_formatting.h.',
778 ),
779 True,
780 [
781 # TODO(crbug.com/335672557): Please do not add to this list. Existing
782 # uses should removed.
Daniel Cheng566634ff2024-06-29 14:56:53783 "third_party/blink/renderer/core/css/parser/css_proto_converter.cc",
784 "third_party/blink/renderer/core/editing/ime/edit_context.cc",
785 "third_party/blink/renderer/platform/graphics/bitmap_image_test.cc",
Daniel Cheng566634ff2024-06-29 14:56:53786 _THIRD_PARTY_EXCEPT_BLINK
787 ],
Daniel Bratell69334cc2019-03-26 11:07:45788 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15789 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53790 r'/#include <(cctype|ctype\.h|cwctype|wctype.h)>',
791 (
792 '<cctype>/<ctype.h>/<cwctype>/<wctype.h> are banned. Use',
793 '"third_party/abseil-cpp/absl/strings/ascii.h" instead.',
794 ),
795 True,
796 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting6f79b202023-08-09 21:25:41797 ),
798 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53799 r'/\bstd::shared_ptr\b',
800 ('std::shared_ptr is banned. Use scoped_refptr instead.', ),
801 True,
802 [
803 # Needed for interop with third-party library.
Dirk Prankee4df27972025-02-26 18:39:35804 r'^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
805 r'array_buffer_contents\.(cc|h)',
806 r'^third_party/blink/renderer/core/typed_arrays/dom_array_buffer\.cc',
Daniel Cheng566634ff2024-06-29 14:56:53807 '^third_party/blink/renderer/bindings/core/v8/' +
808 'v8_wasm_response_extensions.cc',
Dirk Prankee4df27972025-02-26 18:39:35809 r'^gin/array_buffer\.(cc|h)',
810 r'^gin/per_isolate_data\.(cc|h)',
Daniel Cheng566634ff2024-06-29 14:56:53811 '^chrome/services/sharing/nearby/',
812 # Needed for interop with third-party library libunwindstack.
Dirk Prankee4df27972025-02-26 18:39:35813 r'^base/profiler/libunwindstack_unwinder_android\.(cc|h)',
814 r'^base/profiler/native_unwinder_android_memory_regions_map_impl.(cc|h)',
Daniel Cheng566634ff2024-06-29 14:56:53815 # Needed for interop with third-party boringssl cert verifier
816 '^third_party/boringssl/',
817 '^net/cert/',
818 '^net/tools/cert_verify_tool/',
819 '^services/cert_verifier/',
820 '^components/certificate_transparency/',
821 '^components/media_router/common/providers/cast/certificate/',
822 # gRPC provides some C++ libraries that use std::shared_ptr<>.
823 '^chromeos/ash/services/libassistant/grpc/',
824 '^chromecast/cast_core/grpc',
825 '^chromecast/cast_core/runtime/browser',
Dirk Prankee4df27972025-02-26 18:39:35826 r'^ios/chrome/test/earl_grey/chrome_egtest_plugin_client\.(mm|h)',
Daniel Cheng566634ff2024-06-29 14:56:53827 # Fuchsia provides C++ libraries that use std::shared_ptr<>.
Dirk Prankee4df27972025-02-26 18:39:35828 r'^base/fuchsia/.*\.(cc|h)',
829 r'.*fuchsia.*test\.(cc|h)',
Daniel Cheng566634ff2024-06-29 14:56:53830 # Clang plugins have different build config.
831 '^tools/clang/plugins/',
832 _THIRD_PARTY_EXCEPT_BLINK
833 ], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21834 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15835 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53836 r'/\bstd::weak_ptr\b',
837 ('std::weak_ptr is banned. Use base::WeakPtr instead.', ),
838 True,
839 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting991618a62019-06-17 22:00:09840 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15841 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53842 r'/\blong long\b',
843 ('long long is banned. Use [u]int64_t instead.', ),
844 False, # Only a warning since it is already used.
845 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21846 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15847 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53848 r'/\b(absl|std)::any\b',
849 (
850 '{absl,std}::any are banned due to incompatibility with the component ',
851 'build.',
852 ),
853 True,
854 # Not an error in third party folders, though it probably should be :)
855 [_THIRD_PARTY_EXCEPT_BLINK],
Daniel Chengc05fcc62022-01-12 16:54:29856 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15857 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53858 r'/\bstd::bind\b',
859 (
860 'std::bind() is banned because of lifetime risks. Use ',
861 'base::Bind{Once,Repeating}() instead.',
862 ),
863 True,
864 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21865 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15866 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53867 (r'/\bstd::(?:'
868 r'linear_congruential_engine|mersenne_twister_engine|'
869 r'subtract_with_carry_engine|discard_block_engine|'
870 r'independent_bits_engine|shuffle_order_engine|'
871 r'minstd_rand0?|mt19937(_64)?|ranlux(24|48)(_base)?|knuth_b|'
872 r'default_random_engine|'
873 r'random_device|'
874 r'seed_seq'
875 r')\b'),
876 (
877 'STL random number engines and generators are banned. Use the ',
878 'helpers in base/rand_util.h instead, e.g. base::RandBytes() or ',
879 'base::RandomBitGenerator.'
880 '',
881 'Please reach out to [email protected] if the base APIs are ',
882 'insufficient for your needs.',
883 ),
884 True,
885 [
886 # Not an error in third_party folders.
887 _THIRD_PARTY_EXCEPT_BLINK,
888 # Various tools which build outside of Chrome.
889 r'testing/libfuzzer',
Steinar H. Gundersone5689e42024-08-07 18:17:19890 r'testing/perf/confidence',
Daniel Cheng566634ff2024-06-29 14:56:53891 r'tools/android/io_benchmark/',
892 # Fuzzers are allowed to use standard library random number generators
893 # since fuzzing speed + reproducibility is important.
894 r'tools/ipc_fuzzer/',
895 r'.+_fuzzer\.cc$',
896 r'.+_fuzzertest\.cc$',
897 # TODO(https://crbug.com/1380528): These are all unsanctioned uses of
898 # the standard library's random number generators, and should be
899 # migrated to the //base equivalent.
900 r'ash/ambient/model/ambient_topic_queue\.cc',
901 r'base/allocator/partition_allocator/src/partition_alloc/partition_alloc_unittest\.cc',
Daniel Cheng566634ff2024-06-29 14:56:53902 r'base/test/launcher/test_launcher\.cc',
903 r'cc/metrics/video_playback_roughness_reporter_unittest\.cc',
904 r'chrome/browser/apps/app_service/metrics/website_metrics\.cc',
905 r'chrome/browser/ash/power/auto_screen_brightness/monotone_cubic_spline_unittest\.cc',
906 r'chrome/browser/ash/printing/zeroconf_printer_detector_unittest\.cc',
907 r'chrome/browser/nearby_sharing/contacts/nearby_share_contact_manager_impl_unittest\.cc',
908 r'chrome/browser/nearby_sharing/contacts/nearby_share_contacts_sorter_unittest\.cc',
909 r'chrome/browser/privacy_budget/mesa_distribution_unittest\.cc',
910 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
911 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
912 r'chrome/browser/win/conflicts/module_blocklist_cache_util_unittest\.cc',
913 r'chromeos/ash/components/memory/userspace_swap/swap_storage_unittest\.cc',
914 r'chromeos/ash/components/memory/userspace_swap/userspace_swap\.cc',
915 r'components/metrics/metrics_state_manager\.cc',
916 r'components/omnibox/browser/history_quick_provider_performance_unittest\.cc',
917 r'components/zucchini/disassembler_elf_unittest\.cc',
918 r'content/browser/webid/federated_auth_request_impl\.cc',
919 r'content/browser/webid/federated_auth_request_impl\.cc',
920 r'media/cast/test/utility/udp_proxy\.h',
921 r'sql/recover_module/module_unittest\.cc',
Nicolas Dossou-Gbeteaf9023d2025-04-07 17:44:38922 r'components/regional_capabilities/regional_capabilities_utils.cc',
Daniel Cheng566634ff2024-06-29 14:56:53923 # Do not add new entries to this list. If you have a use case which is
924 # not satisfied by the current APIs (i.e. you need an explicitly-seeded
925 # sequence, or stability of some sort is required), please contact
926 # [email protected].
927 ],
Daniel Cheng192683f2022-11-01 20:52:44928 ),
929 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53930 r'/\b(absl,std)::bind_front\b',
931 ('{absl,std}::bind_front() are banned. Use base::Bind{Once,Repeating}() '
932 'instead.', ),
933 True,
934 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12935 ),
936 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53937 r'/\bABSL_FLAG\b',
938 ('ABSL_FLAG is banned. Use base::CommandLine instead.', ),
939 True,
940 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12941 ),
942 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53943 r'/\babsl::c_',
944 (
Peter Kasting3b811ffd2025-01-29 22:20:16945 'Abseil container utilities are banned. Use std::ranges:: instead.',
Daniel Cheng566634ff2024-06-29 14:56:53946 ),
947 True,
948 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12949 ),
950 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53951 r'/\babsl::FixedArray\b',
952 ('absl::FixedArray is banned. Use base::FixedArray instead.', ),
953 True,
954 [
955 # base::FixedArray provides canonical access.
956 r'^base/types/fixed_array.h',
957 # Not an error in third_party folders.
958 _THIRD_PARTY_EXCEPT_BLINK,
959 ],
Peter Kasting431239a2023-09-29 03:11:44960 ),
961 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53962 r'/\babsl::FunctionRef\b',
963 ('absl::FunctionRef is banned. Use base::FunctionRef instead.', ),
964 True,
965 [
966 # base::Bind{Once,Repeating} references absl::FunctionRef to disallow
967 # interoperability.
968 r'^base/functional/bind_internal\.h',
969 # base::FunctionRef is implemented on top of absl::FunctionRef.
970 r'^base/functional/function_ref.*\..+',
971 # Not an error in third_party folders.
972 _THIRD_PARTY_EXCEPT_BLINK,
973 ],
Peter Kasting4f35bfc2022-10-18 18:39:12974 ),
975 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53976 r'/\babsl::(Insecure)?BitGen\b',
977 ('absl random number generators are banned. Use the helpers in '
978 'base/rand_util.h instead, e.g. base::RandBytes() or ',
979 'base::RandomBitGenerator.'),
980 True,
981 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12982 ),
983 BanRule(
Peter Kasting3b77a0c2024-08-22 00:22:26984 pattern=
985 r'/\babsl::(optional|nullopt|make_optional)\b',
986 explanation=('absl::optional is banned. Use std::optional instead.', ),
987 treat_as_error=True,
988 excluded_paths=[
989 _THIRD_PARTY_EXCEPT_BLINK,
990 ]),
991 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53992 r'/(\babsl::Span\b|#include <span>|\bstd::span\b)',
993 (
Peter Kastinge73b89d2024-11-26 19:35:52994 'absl::Span and std::span are banned. Use base::span instead.',
Daniel Cheng566634ff2024-06-29 14:56:53995 ),
996 True,
997 [
998 # Included for conversions between base and std.
999 r'base/containers/span.h',
1000 # Test base::span<> compatibility against std::span<>.
1001 r'base/containers/span_unittest.cc',
1002 # //base/numerics can't use base or absl. So it uses std.
1003 r'base/numerics/.*'
Lei Zhang1f9d9ec42024-06-20 18:42:271004
Daniel Cheng566634ff2024-06-29 14:56:531005 # Needed to use QUICHE API.
Ciara McMullinc029c8e2024-08-21 14:22:321006 r'android_webview/browser/ip_protection/.*',
Daniel Cheng566634ff2024-06-29 14:56:531007 r'chrome/browser/ip_protection/.*',
1008 r'components/ip_protection/.*',
1009 r'net/third_party/quiche/overrides/quiche_platform_impl/quiche_stack_trace_impl\.*',
1010 r'services/network/web_transport\.cc',
Lei Zhang1f9d9ec42024-06-20 18:42:271011
Daniel Cheng566634ff2024-06-29 14:56:531012 # Not an error in third_party folders.
1013 _THIRD_PARTY_EXCEPT_BLINK,
1014 ],
Peter Kasting4f35bfc2022-10-18 18:39:121015 ),
1016 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531017 r'/\babsl::StatusOr\b',
1018 ('absl::StatusOr is banned. Use base::expected instead.', ),
1019 True,
1020 [
1021 # Needed to use liburlpattern API.
1022 r'components/url_pattern/.*',
1023 r'services/network/shared_dictionary/simple_url_pattern_matcher\.cc',
1024 r'third_party/blink/renderer/core/url_pattern/.*',
1025 r'third_party/blink/renderer/modules/manifest/manifest_parser\.cc',
Lei Zhang1f9d9ec42024-06-20 18:42:271026
Daniel Cheng566634ff2024-06-29 14:56:531027 # Needed to use QUICHE API.
Ciara McMullinc029c8e2024-08-21 14:22:321028 r'android_webview/browser/ip_protection/.*',
Daniel Cheng566634ff2024-06-29 14:56:531029 r'chrome/browser/ip_protection/.*',
1030 r'components/ip_protection/.*',
Lei Zhang1f9d9ec42024-06-20 18:42:271031
Daniel Cheng566634ff2024-06-29 14:56:531032 # Needed to use MediaPipe API.
1033 r'components/media_effects/.*\.cc',
1034 # Not an error in third_party folders.
1035 _THIRD_PARTY_EXCEPT_BLINK
1036 ],
Peter Kasting4f35bfc2022-10-18 18:39:121037 ),
1038 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531039 r'/\babsl::(StrSplit|StrJoin|StrCat|StrAppend|Substitute|StrContains)\b',
1040 ('Abseil string utilities are banned. Use base/strings instead.', ),
1041 True,
1042 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:121043 ),
1044 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531045 r'/\babsl::(Mutex|CondVar|Notification|Barrier|BlockingCounter)\b',
1046 (
1047 'Abseil synchronization primitives are banned. Use',
1048 'base/synchronization instead.',
1049 ),
1050 True,
1051 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:121052 ),
1053 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531054 r'/\babsl::(Duration|Time|TimeZone|CivilDay)\b',
1055 ('Abseil\'s time library is banned. Use base/time instead.', ),
1056 True,
1057 [
1058 # Needed to use QUICHE API.
Ciara McMullinc029c8e2024-08-21 14:22:321059 r'android_webview/browser/ip_protection/.*',
Daniel Cheng566634ff2024-06-29 14:56:531060 r'chrome/browser/ip_protection/.*',
1061 r'components/ip_protection/.*',
Lei Zhang1f9d9ec42024-06-20 18:42:271062
Daniel Cheng566634ff2024-06-29 14:56:531063 # Needed to integrate with //third_party/nearby
1064 r'components/cross_device/nearby/system_clock.cc',
1065 _THIRD_PARTY_EXCEPT_BLINK # Not an error in third_party folders.
1066 ],
1067 ),
1068 BanRule(
Victor Hugo Vianna Silva6e84e8d42025-03-19 00:32:001069 r'/absl::(bad_variant_access|get|holds_alternative|monostate|variant|'
1070 r'visit)',
1071 ('Abseil\'s variant library is banned, use std.', ),
Victor Hugo Vianna Silvad9139fbe2025-03-19 20:59:081072 True,
Victor Hugo Vianna Silva6e84e8d42025-03-19 00:32:001073 [
1074 _THIRD_PARTY_EXCEPT_BLINK
1075 ],
1076 ),
1077 BanRule(
1078 r'/absl::(apply|exchange|forward|in_place|index_sequence|'
1079 r'integer_sequence|make_from_tuple|make_index_sequence|'
1080 r'make_integer_sequence|move)',
1081 ('Abseil\'s util library is banned, use std.', ),
Victor Hugo Vianna Silvad9139fbe2025-03-19 20:59:081082 True,
Victor Hugo Vianna Silva6e84e8d42025-03-19 00:32:001083 [
1084 _THIRD_PARTY_EXCEPT_BLINK
1085 ],
1086 ),
1087 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531088 r'/#include <chrono>',
1089 ('<chrono> is banned. Use base/time instead.', ),
1090 True,
1091 [
1092 # Not an error in third_party folders:
1093 _THIRD_PARTY_EXCEPT_BLINK,
Daniel Cheng566634ff2024-06-29 14:56:531094 # This uses openscreen API depending on std::chrono.
1095 "components/openscreen_platform/task_runner.cc",
1096 ]),
1097 BanRule(
1098 r'/#include <exception>',
1099 ('Exceptions are banned and disabled in Chromium.', ),
1100 True,
1101 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1102 ),
1103 BanRule(
1104 r'/\bstd::function\b',
1105 ('std::function is banned. Use base::{Once,Repeating}Callback instead.',
1106 ),
1107 True,
1108 [
1109 # Has tests that template trait helpers don't unintentionally match
1110 # std::function.
1111 r'base/functional/callback_helpers_unittest\.cc',
1112 # Required to implement interfaces from the third-party perfetto
1113 # library.
1114 r'base/tracing/perfetto_task_runner\.cc',
1115 r'base/tracing/perfetto_task_runner\.h',
1116 # Needed for interop with the third-party nearby library type
1117 # location::nearby::connections::ResultCallback.
Dirk Prankee4df27972025-02-26 18:39:351118 r'chrome/services/sharing/nearby/nearby_connections_conversions\.cc'
Daniel Cheng566634ff2024-06-29 14:56:531119 # Needed for interop with the internal libassistant library.
Dirk Prankee4df27972025-02-26 18:39:351120 r'chromeos/ash/services/libassistant/callback_utils\.h',
Daniel Cheng566634ff2024-06-29 14:56:531121 # Needed for interop with Fuchsia fidl APIs.
Dirk Prankee4df27972025-02-26 18:39:351122 r'fuchsia_web/webengine/browser/context_impl_browsertest\.cc',
1123 r'fuchsia_web/webengine/browser/cookie_manager_impl_unittest\.cc',
1124 r'fuchsia_web/webengine/browser/media_player_impl_unittest\.cc',
Daniel Cheng566634ff2024-06-29 14:56:531125 # Required to interop with interfaces from the third-party ChromeML
1126 # library API.
Dirk Prankee4df27972025-02-26 18:39:351127 r'services/on_device_model/ml/chrome_ml_api\.h',
1128 r'services/on_device_model/ml/on_device_model_executor\.cc',
1129 r'services/on_device_model/ml/on_device_model_executor\.h',
Daniel Cheng566634ff2024-06-29 14:56:531130 # Required to interop with interfaces from the third-party perfetto
1131 # library.
Dirk Prankee4df27972025-02-26 18:39:351132 r'components/tracing/common/etw_consumer_win_unittest\.cc',
1133 r'services/tracing/public/cpp/perfetto/custom_event_recorder\.cc',
1134 r'services/tracing/public/cpp/perfetto/perfetto_traced_process\.cc',
1135 r'services/tracing/public/cpp/perfetto/perfetto_traced_process\.h',
1136 r'services/tracing/public/cpp/perfetto/perfetto_tracing_backend\.cc',
1137 r'services/tracing/public/cpp/perfetto/producer_client\.cc',
1138 r'services/tracing/public/cpp/perfetto/producer_client\.h',
1139 r'services/tracing/public/cpp/perfetto/producer_test_utils\.cc',
1140 r'services/tracing/public/cpp/perfetto/producer_test_utils\.h',
Daniel Cheng566634ff2024-06-29 14:56:531141 # Required for interop with the third-party webrtc library.
Dirk Prankee4df27972025-02-26 18:39:351142 r'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.cc',
1143 r'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.h',
Daniel Cheng566634ff2024-06-29 14:56:531144 # TODO(https://crbug.com/1364577): Various uses that should be
1145 # migrated to something else.
1146 # Should use base::OnceCallback or base::RepeatingCallback.
Dirk Prankee4df27972025-02-26 18:39:351147 r'base/allocator/dispatcher/initializer_unittest\.cc',
1148 r'chrome/browser/ash/accessibility/speech_monitor\.cc',
1149 r'chrome/browser/ash/accessibility/speech_monitor\.h',
1150 r'chrome/browser/ash/login/ash_hud_login_browsertest\.cc',
1151 r'chromecast/base/observer_unittest\.cc',
1152 r'chromecast/browser/cast_web_view\.h',
1153 r'chromecast/public/cast_media_shlib\.h',
1154 r'device/bluetooth/floss/exported_callback_manager\.h',
1155 r'device/bluetooth/floss/floss_dbus_client\.h',
1156 r'device/fido/cable/v2_handshake_unittest\.cc',
1157 r'device/fido/pin\.cc',
1158 r'services/tracing/perfetto/test_utils\.h',
Daniel Cheng566634ff2024-06-29 14:56:531159 # Should use base::FunctionRef.
Dirk Prankee4df27972025-02-26 18:39:351160 r'chrome/browser/media/webrtc/test_stats_dictionary\.cc',
1161 r'chrome/browser/media/webrtc/test_stats_dictionary\.h',
1162 r'chromeos/ash/services/libassistant/device_settings_controller\.cc',
1163 r'components/browser_ui/client_certificate/android/ssl_client_certificate_request\.cc',
1164 r'components/gwp_asan/client/sampling_malloc_shims_unittest\.cc',
1165 r'content/browser/font_unique_name_lookup/font_unique_name_lookup_unittest\.cc',
Daniel Cheng566634ff2024-06-29 14:56:531166 # Does not need std::function at all.
Dirk Prankee4df27972025-02-26 18:39:351167 r'components/omnibox/browser/autocomplete_result\.cc',
1168 r'device/fido/win/webauthn_api\.cc',
1169 r'media/audio/alsa/alsa_util\.cc',
1170 r'media/remoting/stream_provider\.h',
1171 r'sql/vfs_wrapper\.cc',
Daniel Cheng566634ff2024-06-29 14:56:531172 # TODO(https://crbug.com/1364585): Remove usage and exception list
1173 # entries.
Dirk Prankee4df27972025-02-26 18:39:351174 r'extensions/renderer/api/automation/automation_internal_custom_bindings\.cc',
1175 r'extensions/renderer/api/automation/automation_internal_custom_bindings\.h',
Daniel Cheng566634ff2024-06-29 14:56:531176 # TODO(https://crbug.com/1364579): Remove usage and exception list
1177 # entry.
Dirk Prankee4df27972025-02-26 18:39:351178 r'ui/views/controls/focus_ring\.h',
Lei Zhang1f9d9ec42024-06-20 18:42:271179
Daniel Cheng566634ff2024-06-29 14:56:531180 # Various pre-existing uses in //tools that is low-priority to fix.
Dirk Prankee4df27972025-02-26 18:39:351181 r'tools/binary_size/libsupersize/viewer/caspian/diff\.cc',
1182 r'tools/binary_size/libsupersize/viewer/caspian/model\.cc',
1183 r'tools/binary_size/libsupersize/viewer/caspian/model\.h',
1184 r'tools/binary_size/libsupersize/viewer/caspian/tree_builder\.h',
1185 r'tools/clang/base_bind_rewriters/BaseBindRewriters\.cpp',
Daniel Chenge5583e3c2022-09-22 00:19:411186
Daniel Cheng566634ff2024-06-29 14:56:531187 # Not an error in third_party folders.
1188 _THIRD_PARTY_EXCEPT_BLINK
1189 ],
Daniel Bratell609102be2019-03-27 20:53:211190 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151191 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531192 r'/#include <X11/',
1193 ('Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.', ),
1194 True,
1195 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Tom Andersona95e12042020-09-09 23:08:001196 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151197 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531198 r'/\bstd::ratio\b',
1199 ('std::ratio is banned by the Google Style Guide.', ),
1200 True,
1201 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:451202 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151203 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531204 r'/\bstd::aligned_alloc\b',
1205 (
1206 'std::aligned_alloc() is not yet allowed (crbug.com/1412818). Use ',
1207 'base::AlignedAlloc() instead.',
1208 ),
1209 True,
1210 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181211 ),
1212 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531213 r'/#include <(barrier|latch|semaphore|stop_token)>',
1214 ('The thread support library is banned. Use base/synchronization '
1215 'instead.', ),
1216 True,
1217 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181218 ),
1219 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531220 r'/\bstd::execution::(par|seq)\b',
1221 ('std::execution::(par|seq) is banned; they do not fit into '
1222 ' Chrome\'s threading model, and libc++ doesn\'t have full '
mikt19226ff22024-08-27 05:28:211223 'support.', ),
Daniel Cheng566634ff2024-06-29 14:56:531224 True,
1225 [_THIRD_PARTY_EXCEPT_BLINK],
Helmut Januschka7cc8a84f2024-02-07 22:50:411226 ),
1227 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531228 r'/\bstd::bit_cast\b',
1229 ('std::bit_cast is banned; use base::bit_cast instead for values and '
1230 'standard C++ casting when pointers are involved.', ),
1231 True,
1232 [
1233 # Don't warn in third_party folders.
1234 _THIRD_PARTY_EXCEPT_BLINK,
1235 # //base/numerics can't use base or absl.
1236 r'base/numerics/.*'
1237 ],
Avi Drissman70cb7f72023-12-12 17:44:371238 ),
1239 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531240 r'/\bstd::(c8rtomb|mbrtoc8)\b',
1241 ('std::c8rtomb() and std::mbrtoc8() are banned.', ),
1242 True,
1243 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181244 ),
1245 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531246 r'/\bchar8_t|std::u8string\b',
1247 (
1248 'char8_t and std::u8string are not yet allowed. Can you use [unsigned]',
1249 ' char and std::string instead?',
1250 ),
1251 True,
1252 [
1253 # The demangler does not use this type but needs to know about it.
Dirk Prankee4df27972025-02-26 18:39:351254 r'base/third_party/symbolize/demangle\.cc',
Daniel Cheng566634ff2024-06-29 14:56:531255 # Don't warn in third_party folders.
1256 _THIRD_PARTY_EXCEPT_BLINK
1257 ],
Peter Kastinge2c5ee82023-02-15 17:23:081258 ),
1259 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531260 r'/(\b(co_await|co_return|co_yield)\b|#include <coroutine>)',
1261 ('Coroutines are not yet allowed (https://crbug.com/1403840).', ),
1262 True,
1263 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081264 ),
1265 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531266 r'/^\s*(export\s|import\s+["<:\w]|module(;|\s+[:\w]))',
1267 ('Modules are disallowed for now due to lack of toolchain support.', ),
1268 True,
1269 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting69357dc2023-03-14 01:34:291270 ),
1271 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531272 r'/\[\[(\w*::)?no_unique_address\]\]',
1273 (
1274 '[[no_unique_address]] does not work as expected on Windows ',
1275 '(https://crbug.com/1414621). Use NO_UNIQUE_ADDRESS instead.',
1276 ),
1277 True,
1278 [
1279 # NO_UNIQUE_ADDRESS / PA_NO_UNIQUE_ADDRESS provide canonical access.
1280 r'^base/compiler_specific\.h',
1281 r'^base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/compiler_specific\.h',
1282 # Not an error in third_party folders.
1283 _THIRD_PARTY_EXCEPT_BLINK,
1284 ],
Peter Kasting8bc046d22023-11-14 00:38:031285 ),
1286 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531287 r'/#include <format>',
1288 ('<format> is not yet allowed. Use base::StringPrintf() instead.', ),
1289 True,
1290 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081291 ),
1292 BanRule(
Daniel Cheng89719222024-07-04 04:59:291293 pattern='std::views',
1294 explanation=(
1295 'Use of std::views is banned in Chrome. If you need this '
1296 'functionality, please contact [email protected].',
1297 ),
1298 treat_as_error=True,
1299 excluded_paths=[
1300 # Don't warn in third_party folders.
1301 _THIRD_PARTY_EXCEPT_BLINK
1302 ],
1303 ),
1304 BanRule(
1305 # Ban everything except specifically allowlisted constructs.
1306 pattern=r'/std::ranges::(?!' + '|'.join((
1307 # From https://en.cppreference.com/w/cpp/ranges:
1308 # Range access
1309 'begin',
1310 'end',
1311 'cbegin',
1312 'cend',
1313 'rbegin',
1314 'rend',
1315 'crbegin',
1316 'crend',
1317 'size',
1318 'ssize',
1319 'empty',
1320 'data',
1321 'cdata',
1322 # Range primitives
1323 'iterator_t',
1324 'const_iterator_t',
1325 'sentinel_t',
1326 'const_sentinel_t',
1327 'range_difference_t',
1328 'range_size_t',
1329 'range_value_t',
1330 'range_reference_t',
1331 'range_const_reference_t',
1332 'range_rvalue_reference_t',
1333 'range_common_reference_t',
1334 # Dangling iterator handling
1335 'dangling',
1336 'borrowed_iterator_t',
1337 # Banned: borrowed_subrange_t
1338 # Range concepts
1339 'range',
1340 'borrowed_range',
1341 'sized_range',
1342 'view',
1343 'input_range',
1344 'output_range',
1345 'forward_range',
1346 'bidirectional_range',
1347 'random_access_range',
1348 'contiguous_range',
1349 'common_range',
1350 'viewable_range',
1351 'constant_range',
1352 # Banned: Views
1353 # Banned: Range factories
1354 # Banned: Range adaptors
Peter Kastinga7f93752024-10-24 22:15:401355 # Incidentally listed on
1356 # https://en.cppreference.com/w/cpp/header/ranges:
1357 'enable_borrowed_range',
1358 'enable_view',
Daniel Cheng89719222024-07-04 04:59:291359 # From https://en.cppreference.com/w/cpp/algorithm/ranges:
1360 # Constrained algorithms: non-modifying sequence operations
1361 'all_of',
1362 'any_of',
1363 'none_of',
1364 'for_each',
1365 'for_each_n',
1366 'count',
1367 'count_if',
1368 'mismatch',
1369 'equal',
1370 'lexicographical_compare',
1371 'find',
1372 'find_if',
1373 'find_if_not',
1374 'find_end',
1375 'find_first_of',
1376 'adjacent_find',
1377 'search',
1378 'search_n',
1379 # Constrained algorithms: modifying sequence operations
1380 'copy',
1381 'copy_if',
1382 'copy_n',
1383 'copy_backward',
1384 'move',
1385 'move_backward',
1386 'fill',
1387 'fill_n',
1388 'transform',
1389 'generate',
1390 'generate_n',
1391 'remove',
1392 'remove_if',
1393 'remove_copy',
1394 'remove_copy_if',
1395 'replace',
1396 'replace_if',
1397 'replace_copy',
1398 'replace_copy_if',
1399 'swap_ranges',
1400 'reverse',
1401 'reverse_copy',
1402 'rotate',
1403 'rotate_copy',
1404 'shuffle',
1405 'sample',
1406 'unique',
1407 'unique_copy',
1408 # Constrained algorithms: partitioning operations
1409 'is_partitioned',
1410 'partition',
1411 'partition_copy',
1412 'stable_partition',
1413 'partition_point',
1414 # Constrained algorithms: sorting operations
1415 'is_sorted',
1416 'is_sorted_until',
1417 'sort',
1418 'partial_sort',
1419 'partial_sort_copy',
1420 'stable_sort',
1421 'nth_element',
1422 # Constrained algorithms: binary search operations (on sorted ranges)
1423 'lower_bound',
1424 'upper_bound',
1425 'binary_search',
1426 'equal_range',
1427 # Constrained algorithms: set operations (on sorted ranges)
1428 'merge',
1429 'inplace_merge',
1430 'includes',
1431 'set_difference',
1432 'set_intersection',
1433 'set_symmetric_difference',
1434 'set_union',
1435 # Constrained algorithms: heap operations
1436 'is_heap',
1437 'is_heap_until',
1438 'make_heap',
1439 'push_heap',
1440 'pop_heap',
1441 'sort_heap',
1442 # Constrained algorithms: minimum/maximum operations
1443 'max',
1444 'max_element',
1445 'min',
1446 'min_element',
1447 'minmax',
1448 'minmax_element',
1449 'clamp',
1450 # Constrained algorithms: permutation operations
1451 'is_permutation',
1452 'next_permutation',
1453 'prev_premutation',
1454 # Constrained uninitialized memory algorithms
1455 'uninitialized_copy',
1456 'uninitialized_copy_n',
1457 'uninitialized_fill',
1458 'uninitialized_fill_n',
1459 'uninitialized_move',
1460 'uninitialized_move_n',
1461 'uninitialized_default_construct',
1462 'uninitialized_default_construct_n',
1463 'uninitialized_value_construct',
1464 'uninitialized_value_construct_n',
1465 'destroy',
1466 'destroy_n',
1467 'destroy_at',
1468 'construct_at',
1469 # Return types
1470 'in_fun_result',
1471 'in_in_result',
1472 'in_out_result',
1473 'in_in_out_result',
1474 'in_out_out_result',
1475 'min_max_result',
1476 'in_found_result',
Peter Kastingf379c022025-01-13 14:01:001477 # From https://en.cppreference.com/w/cpp/header/functional
1478 'equal_to',
1479 'not_equal_to',
1480 'greater',
1481 'less',
1482 'greater_equal',
1483 'less_equal',
danakj91c715b2024-07-10 13:24:261484 # From https://en.cppreference.com/w/cpp/iterator
1485 'advance',
1486 'distance',
1487 'next',
1488 'prev',
Daniel Cheng89719222024-07-04 04:59:291489 )) + r')\w+',
1490 explanation=(
1491 'Use of range views and associated helpers is banned in Chrome. '
1492 'If you need this functionality, please contact [email protected].',
1493 ),
1494 treat_as_error=True,
1495 excluded_paths=[
1496 # Don't warn in third_party folders.
1497 _THIRD_PARTY_EXCEPT_BLINK
1498 ],
Peter Kastinge2c5ee82023-02-15 17:23:081499 ),
1500 BanRule(
Peter Kasting31879d82024-10-07 20:18:391501 r'/#include <regex>',
1502 ('<regex> is not allowed. Use third_party/re2 instead.',
1503 ),
1504 True,
1505 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1506 ),
1507 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531508 r'/#include <source_location>',
1509 ('<source_location> is not yet allowed. Use base/location.h instead.',
1510 ),
1511 True,
1512 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081513 ),
1514 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531515 r'/\bstd::to_address\b',
1516 (
1517 'std::to_address is banned because it is not guaranteed to be',
1518 'SFINAE-compatible. Use base::to_address from base/types/to_address.h',
1519 'instead.',
1520 ),
1521 True,
1522 [
1523 # Needed in base::to_address implementation.
1524 r'base/types/to_address.h',
1525 _THIRD_PARTY_EXCEPT_BLINK
1526 ], # Not an error in third_party folders.
Nick Diego Yamanee522ae82024-02-27 04:23:221527 ),
1528 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531529 r'/#include <syncstream>',
1530 ('<syncstream> is banned.', ),
1531 True,
1532 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181533 ),
1534 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531535 r'/\bRunMessageLoop\b',
1536 ('RunMessageLoop is deprecated, use RunLoop instead.', ),
1537 False,
1538 (),
Gabriel Charette147335ea2018-03-22 15:59:191539 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151540 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531541 'RunAllPendingInMessageLoop()',
1542 (
1543 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
1544 "if you're convinced you need this.",
1545 ),
1546 False,
1547 (),
Gabriel Charette147335ea2018-03-22 15:59:191548 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151549 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531550 'RunAllPendingInMessageLoop(BrowserThread',
1551 (
1552 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
1553 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
1554 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
1555 'async events instead of flushing threads.',
1556 ),
1557 False,
1558 (),
Gabriel Charette147335ea2018-03-22 15:59:191559 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151560 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531561 r'MessageLoopRunner',
1562 ('MessageLoopRunner is deprecated, use RunLoop instead.', ),
1563 False,
1564 (),
Gabriel Charette147335ea2018-03-22 15:59:191565 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151566 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531567 'GetDeferredQuitTaskForRunLoop',
1568 (
1569 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
1570 "gab@ if you found a use case where this is the only solution.",
1571 ),
1572 False,
1573 (),
Gabriel Charette147335ea2018-03-22 15:59:191574 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151575 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531576 'sqlite3_initialize(',
1577 (
1578 'Instead of calling sqlite3_initialize(), depend on //sql, ',
1579 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
1580 ),
1581 True,
1582 (
1583 r'^sql/initialization\.(cc|h)$',
1584 r'^third_party/sqlite/.*\.(c|cc|h)$',
1585 ),
Victor Costan3653df62018-02-08 21:38:161586 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151587 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531588 'CREATE VIEW',
1589 (
1590 'SQL views are disabled in Chromium feature code',
1591 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-views',
1592 ),
1593 True,
1594 (
1595 _THIRD_PARTY_EXCEPT_BLINK,
1596 # sql/ itself uses views when using memory-mapped IO.
1597 r'^sql/.*',
1598 # Various performance tools that do not build as part of Chrome.
1599 r'^infra/.*',
1600 r'^tools/perf.*',
1601 r'.*perfetto.*',
1602 ),
Austin Sullivand661ab52022-11-16 08:55:151603 ),
1604 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531605 'CREATE VIRTUAL TABLE',
1606 (
1607 'SQL virtual tables are disabled in Chromium feature code',
1608 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-virtual-tables',
1609 ),
1610 True,
1611 (
1612 _THIRD_PARTY_EXCEPT_BLINK,
1613 # sql/ itself uses virtual tables in the recovery module and tests.
1614 r'^sql/.*',
1615 # TODO(https://crbug.com/695592): Remove once WebSQL is deprecated.
1616 r'third_party/blink/web_tests/storage/websql/.*'
1617 # Various performance tools that do not build as part of Chrome.
1618 r'^tools/perf.*',
1619 r'.*perfetto.*',
1620 ),
Austin Sullivand661ab52022-11-16 08:55:151621 ),
1622 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531623 'std::random_shuffle',
1624 ('std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
1625 'base::RandomShuffle instead.'),
1626 True,
1627 (),
tzik5de2157f2018-05-08 03:42:471628 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151629 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531630 'ios/web/public/test/http_server',
1631 ('web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
1632 ),
1633 False,
1634 (),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:241635 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151636 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531637 'GetAddressOf',
1638 ('Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
1639 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
1640 'operator& is generally recommended. So always use operator& instead. ',
1641 'See http://crbug.com/914910 for more conversion guidance.'),
1642 True,
1643 (),
Robert Liao764c9492019-01-24 18:46:281644 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151645 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531646 'SHFileOperation',
1647 ('SHFileOperation was deprecated in Windows Vista, and there are less ',
1648 'complex functions to achieve the same goals. Use IFileOperation for ',
1649 'any esoteric actions instead.'),
1650 True,
1651 (),
Ben Lewisa9514602019-04-29 17:53:051652 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151653 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531654 'StringFromGUID2',
1655 ('StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
1656 'Use base::win::WStringFromGUID instead.'),
1657 True,
1658 (r'/base/win/win_util_unittest.cc', ),
Cliff Smolinsky81951642019-04-30 21:39:511659 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151660 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531661 'StringFromCLSID',
1662 ('StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
1663 'Use base::win::WStringFromGUID instead.'),
1664 True,
1665 (r'/base/win/win_util_unittest.cc', ),
Cliff Smolinsky81951642019-04-30 21:39:511666 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151667 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531668 'kCFAllocatorNull',
1669 (
1670 'The use of kCFAllocatorNull with the NoCopy creation of ',
1671 'CoreFoundation types is prohibited.',
1672 ),
1673 True,
1674 (),
Avi Drissman7382afa02019-04-29 23:27:131675 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151676 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531677 'mojo::ConvertTo',
1678 ('mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1679 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1680 'StringTraits if you would like to convert between custom types and',
1681 'the wire format of mojom types.'),
1682 False,
1683 (
1684 r'^fuchsia_web/webengine/browser/url_request_rewrite_rules_manager\.cc$',
1685 r'^fuchsia_web/webengine/url_request_rewrite_type_converters\.cc$',
1686 r'^third_party/blink/.*\.(cc|h)$',
1687 r'^content/renderer/.*\.(cc|h)$',
1688 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291689 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151690 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531691 'GetInterfaceProvider',
1692 ('InterfaceProvider is deprecated.',
1693 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1694 'or Platform::GetBrowserInterfaceBroker.'),
1695 False,
1696 (),
Oksana Zhuravlovac8222d22019-12-19 19:21:161697 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151698 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531699 'CComPtr',
1700 ('New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1701 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1702 'details.'),
1703 False,
1704 (),
Robert Liao1d78df52019-11-11 20:02:011705 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151706 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531707 r'/\b(IFACE|STD)METHOD_?\(',
1708 ('IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1709 'Instead, always use IFACEMETHODIMP in the declaration.'),
1710 False,
1711 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Xiaohan Wang72bd2ba2020-02-18 21:38:201712 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151713 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531714 'RemoveAllChildViewsWithoutDeleting',
1715 ('RemoveAllChildViewsWithoutDeleting is deprecated.',
1716 'This method is deemed dangerous as, unless raw pointers are re-added,',
1717 'calls to this method introduce memory leaks.'),
1718 False,
1719 (),
Peter Boström7ff41522021-07-29 03:43:271720 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151721 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531722 r'/\bTRACE_EVENT_ASYNC_',
1723 (
1724 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1725 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1726 ),
1727 False,
1728 (
1729 r'^base/trace_event/.*',
1730 r'^base/tracing/.*',
1731 ),
Eric Secklerbe6f48d2020-05-06 18:09:121732 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151733 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531734 'RoInitialize',
1735 ('Improper use of [base::win]::RoInitialize() has been implicated in a ',
1736 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
1737 'instead. See http://crbug.com/1197722 for more information.'),
1738 True,
1739 (
1740 r'^base/win/scoped_winrt_initializer\.cc$',
1741 r'^third_party/abseil-cpp/absl/.*',
1742 ),
Robert Liao22f66a52021-04-10 00:57:521743 ),
Patrick Monettec343bb982022-06-01 17:18:451744 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531745 r'base::Watchdog',
1746 (
1747 'base::Watchdog is deprecated because it creates its own thread.',
1748 'Instead, manually start a timer on a SequencedTaskRunner.',
1749 ),
1750 False,
1751 (),
Patrick Monettec343bb982022-06-01 17:18:451752 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091753 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531754 'base::Passed',
1755 ('Do not use base::Passed. It is a legacy helper for capturing ',
1756 'move-only types with base::BindRepeating, but invoking the ',
1757 'resulting RepeatingCallback moves the captured value out of ',
1758 'the callback storage, and subsequent invocations may pass the ',
1759 'value in a valid but undefined state. Prefer base::BindOnce().',
1760 'See http://crbug.com/1326449 for context.'),
1761 False,
1762 (
1763 # False positive, but it is also fine to let bind internals reference
1764 # base::Passed.
1765 r'^base[\\/]functional[\\/]bind\.h',
1766 r'^base[\\/]functional[\\/]bind_internal\.h',
1767 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091768 ),
Daniel Cheng2248b332022-07-27 06:16:591769 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531770 r'base::Feature k',
1771 ('Please use BASE_DECLARE_FEATURE() or BASE_FEATURE() instead of ',
1772 'directly declaring/defining features.'),
1773 True,
1774 [
1775 # Implements BASE_DECLARE_FEATURE().
1776 r'^base/feature_list\.h',
1777 ],
Daniel Chengba3bc2e2022-10-03 02:45:431778 ),
Robert Ogden92101dcb2022-10-19 23:49:361779 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531780 r'/\bchartorune\b',
1781 ('chartorune is not memory-safe, unless you can guarantee the input ',
1782 'string is always null-terminated. Otherwise, please use charntorune ',
1783 'from libphonenumber instead.'),
1784 True,
1785 [
1786 _THIRD_PARTY_EXCEPT_BLINK,
1787 # Exceptions to this rule should have a fuzzer.
1788 ],
Robert Ogden92101dcb2022-10-19 23:49:361789 ),
Arthur Sonzogni1da65fa2023-03-27 16:01:521790 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531791 r'/\b#include "base/atomicops\.h"\b',
1792 ('Do not use base::subtle atomics, but std::atomic, which are simpler '
1793 'to use, have better understood, clearer and richer semantics, and are '
1794 'harder to mis-use. See details in base/atomicops.h.', ),
1795 False,
1796 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Benoit Lize79cf0592023-01-27 10:01:571797 ),
Daniel Cheng566634ff2024-06-29 14:56:531798 BanRule(r'CrossThreadPersistent<', (
Arthur Sonzogni60348572e2023-04-07 10:22:521799 'Do not use blink::CrossThreadPersistent, but '
Daniel Cheng566634ff2024-06-29 14:56:531800 'blink::CrossThreadHandle. It is harder to mis-use.', 'More info: '
Arthur Sonzogni60348572e2023-04-07 10:22:521801 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1802 'Please contact platform-architecture-dev@ before adding new instances.'
Daniel Cheng566634ff2024-06-29 14:56:531803 ), False, []),
1804 BanRule(r'CrossThreadWeakPersistent<', (
Arthur Sonzogni60348572e2023-04-07 10:22:521805 'Do not use blink::CrossThreadWeakPersistent, but '
Daniel Cheng566634ff2024-06-29 14:56:531806 'blink::CrossThreadWeakHandle. It is harder to mis-use.', 'More info: '
Arthur Sonzogni60348572e2023-04-07 10:22:521807 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1808 'Please contact platform-architecture-dev@ before adding new instances.'
Daniel Cheng566634ff2024-06-29 14:56:531809 ), False, []),
1810 BanRule(r'objc/objc.h', (
Avi Drissman491617c2023-04-13 17:33:151811 'Do not include <objc/objc.h>. It defines away ARC lifetime '
1812 'annotations, and is thus dangerous.',
1813 'Please use the pimpl pattern; search for `ObjCStorage` for examples.',
1814 'For further reading on how to safely mix C++ and Obj-C, see',
1815 'https://chromium.googlesource.com/chromium/src/+/main/docs/mac/mixing_cpp_and_objc.md'
Daniel Cheng566634ff2024-06-29 14:56:531816 ), True, []),
1817 BanRule(
1818 r'/#include <filesystem>',
1819 ('libc++ <filesystem> is banned per the Google C++ styleguide.', ),
1820 True,
1821 # This fuzzing framework is a standalone open source project and
1822 # cannot rely on Chromium base.
1823 (r'third_party/centipede'),
Avi Drissman491617c2023-04-13 17:33:151824 ),
Grace Park8d59b54b2023-04-26 17:53:351825 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531826 r'TopDocument()',
1827 ('TopDocument() does not work correctly with out-of-process iframes. '
1828 'Please do not introduce new uses.', ),
1829 True,
1830 (
1831 # TODO(crbug.com/617677): Remove all remaining uses.
1832 r'^third_party/blink/renderer/core/dom/document\.cc',
1833 r'^third_party/blink/renderer/core/dom/document\.h',
1834 r'^third_party/blink/renderer/core/dom/element\.cc',
1835 r'^third_party/blink/renderer/core/exported/web_disallow_transition_scope_test\.cc',
1836 r'^third_party/blink/renderer/core/exported/web_document_test\.cc',
1837 r'^third_party/blink/renderer/core/html/html_anchor_element\.cc',
1838 r'^third_party/blink/renderer/core/html/html_dialog_element\.cc',
1839 r'^third_party/blink/renderer/core/html/html_element\.cc',
1840 r'^third_party/blink/renderer/core/html/html_frame_owner_element\.cc',
1841 r'^third_party/blink/renderer/core/html/media/video_wake_lock\.cc',
1842 r'^third_party/blink/renderer/core/loader/anchor_element_interaction_tracker\.cc',
1843 r'^third_party/blink/renderer/core/page/scrolling/root_scroller_controller\.cc',
1844 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.cc',
1845 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.h',
1846 r'^third_party/blink/renderer/core/script/classic_pending_script\.cc',
1847 r'^third_party/blink/renderer/core/script/script_loader\.cc',
1848 ),
Grace Park8d59b54b2023-04-26 17:53:351849 ),
Daniel Cheng72153e02023-05-18 21:18:141850 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531851 pattern=r'base::raw_ptr<',
1852 explanation=('Do not use base::raw_ptr, use raw_ptr.', ),
1853 treat_as_error=True,
1854 excluded_paths=(
1855 '^base/',
1856 '^tools/',
1857 ),
Daniel Cheng72153e02023-05-18 21:18:141858 ),
Arthur Sonzognif0eea302023-08-18 19:20:311859 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531860 pattern=r'base:raw_ref<',
1861 explanation=('Do not use base::raw_ref, use raw_ref.', ),
1862 treat_as_error=True,
1863 excluded_paths=(
1864 '^base/',
1865 '^tools/',
1866 ),
Arthur Sonzognif0eea302023-08-18 19:20:311867 ),
1868 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531869 pattern=r'/raw_ptr<[^;}]*\w{};',
1870 explanation=(
1871 'Do not use {} for raw_ptr initialization, use = nullptr instead.',
1872 ),
1873 treat_as_error=True,
1874 excluded_paths=(
1875 '^base/',
1876 '^tools/',
1877 ),
Arthur Sonzognif0eea302023-08-18 19:20:311878 ),
Anton Maliev66751812023-08-24 16:28:131879 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531880 pattern=r'/#include "base/allocator/.*/raw_'
1881 r'(ptr|ptr_cast|ptr_exclusion|ref).h"',
1882 explanation=(
1883 'Please include the corresponding facade headers:',
1884 '- #include "base/memory/raw_ptr.h"',
1885 '- #include "base/memory/raw_ptr_cast.h"',
1886 '- #include "base/memory/raw_ptr_exclusion.h"',
1887 '- #include "base/memory/raw_ref.h"',
1888 ),
1889 treat_as_error=True,
1890 excluded_paths=(
1891 '^base/',
1892 '^tools/',
1893 ),
Tom Sepez41eb158d2023-09-12 16:16:221894 ),
1895 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531896 pattern=r'ContentSettingsType::COOKIES',
1897 explanation=
1898 ('Do not use ContentSettingsType::COOKIES to check whether cookies are '
1899 'supported in the provided context. Instead rely on the '
1900 'content_settings::CookieSettings API. If you are using '
1901 'ContentSettingsType::COOKIES to check the user preference setting '
1902 'specifically, disregard this warning.', ),
1903 treat_as_error=False,
1904 excluded_paths=(
1905 '^chrome/browser/ui/content_settings/',
1906 '^components/content_settings/',
1907 '^services/network/cookie_settings.cc',
1908 '.*test.cc',
1909 ),
Arthur Sonzogni48c6aea22023-09-04 22:25:201910 ),
1911 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531912 pattern=r'ContentSettingsType::TRACKING_PROTECTION',
1913 explanation=
1914 ('Do not directly use ContentSettingsType::TRACKING_PROTECTION to check '
1915 'for tracking protection exceptions. Instead rely on the '
1916 'privacy_sandbox::TrackingProtectionSettings API.', ),
1917 treat_as_error=False,
1918 excluded_paths=(
1919 '^chrome/browser/ui/content_settings/',
1920 '^components/content_settings/',
1921 '^components/privacy_sandbox/tracking_protection_settings.cc',
1922 '.*test.cc',
1923 ),
Anton Maliev66751812023-08-24 16:28:131924 ),
Tom Andersoncd522072023-10-03 00:52:351925 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531926 pattern=r'/\bg_signal_connect',
1927 explanation=('Use ScopedGSignal instead of g_signal_connect*()', ),
1928 treat_as_error=True,
1929 excluded_paths=('^ui/base/glib/scoped_gsignal.h', ),
Michelle Abreo6b7437822024-04-26 17:29:041930 ),
1931 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531932 pattern=r'features::kIsolatedWebApps',
1933 explanation=(
1934 'Do not use `features::kIsolatedWebApps` directly to guard Isolated ',
1935 'Web App code. ',
Andrew Rayskiy7ae2b5d2025-02-28 16:59:381936 'Use `content::AreIsolatedWebAppsEnabled()` in the browser process '
1937 'or check the `kEnableIsolatedWebAppsInRenderer` command line flag '
1938 'in the renderer process.',
Daniel Cheng566634ff2024-06-29 14:56:531939 ),
1940 treat_as_error=True,
Andrew Rayskiy7ae2b5d2025-02-28 16:59:381941 excluded_paths=_TEST_CODE_EXCLUDED_PATHS + (
1942 '^chrome/browser/about_flags.cc',
1943 '^chrome/browser/component_updater/iwa_key_distribution_component_installer.cc',
1944 '^chrome/browser/web_applications/isolated_web_apps/chrome_content_browser_client_isolated_web_apps_part.cc',
1945 '^chrome/browser/ui/startup/bad_flags_prompt.cc',
1946 '^content/shell/browser/shell_content_browser_client.cc',
1947 )),
Daniel Cheng566634ff2024-06-29 14:56:531948 BanRule(
1949 pattern=r'features::kIsolatedWebAppDevMode',
1950 explanation=(
1951 'Do not use `features::kIsolatedWebAppDevMode` directly to guard code ',
1952 'related to Isolated Web App Developer Mode. ',
1953 'Use `web_app::IsIwaDevModeEnabled()` instead.',
1954 ),
1955 treat_as_error=True,
1956 excluded_paths=_TEST_CODE_EXCLUDED_PATHS + (
1957 '^chrome/browser/about_flags.cc',
1958 '^chrome/browser/web_applications/isolated_web_apps/isolated_web_app_features.cc',
1959 '^chrome/browser/ui/startup/bad_flags_prompt.cc',
1960 )),
1961 BanRule(
1962 pattern=r'features::kIsolatedWebAppUnmanagedInstall',
1963 explanation=(
1964 'Do not use `features::kIsolatedWebAppUnmanagedInstall` directly to ',
1965 'guard code related to unmanaged install flow for Isolated Web Apps. ',
1966 'Use `web_app::IsIwaUnmanagedInstallEnabled()` instead.',
1967 ),
1968 treat_as_error=True,
1969 excluded_paths=_TEST_CODE_EXCLUDED_PATHS + (
1970 '^chrome/browser/about_flags.cc',
1971 '^chrome/browser/web_applications/isolated_web_apps/isolated_web_app_features.cc',
1972 )),
1973 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531974 pattern='/(CUIAutomation|AccessibleObjectFromWindow)',
1975 explanation=
1976 ('Direct usage of UIAutomation or IAccessible2 in client code is '
1977 'discouraged in Chromium, as it is not an assistive technology and '
1978 'should not rely on accessibility APIs directly. These APIs can '
1979 'introduce significant performance overhead. However, if you believe '
1980 'your use case warrants an exception, please discuss it with an '
1981 'accessibility owner before proceeding. For more information on the '
1982 'performance implications, see https://docs.google.com/document/d/1jN4itpCe_bDXF0BhFaYwv4xVLsCWkL9eULdzjmLzkuk/edit#heading=h.pwth3nbwdub0.',
1983 ),
1984 treat_as_error=False,
Andrew Rayskiycdd45e732024-03-20 14:32:391985 ),
1986 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531987 pattern=r'/WIDGET_OWNS_NATIVE_WIDGET|'
1988 r'NATIVE_WIDGET_OWNS_WIDGET',
1989 explanation=
1990 ('WIDGET_OWNS_NATIVE_WIDGET and NATIVE_WIDGET_OWNS_WIDGET are in the '
1991 'process of being deprecated. Consider using the new '
1992 'CLIENT_OWNS_WIDGET ownership model. Eventually, this will be the only '
1993 'available ownership model available and the associated enumeration'
1994 'will be removed.', ),
1995 treat_as_error=False,
Andrew Rayskiycdd45e732024-03-20 14:32:391996 ),
1997 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531998 pattern='ProfileManager::GetLastUsedProfile',
1999 explanation=
2000 ('Most code should already be scoped to a Profile. Pass in a Profile* '
2001 'or retreive from an existing entity with a reference to the Profile '
2002 '(e.g. WebContents).', ),
2003 treat_as_error=False,
Arthur Sonzogni5cbd3e32024-02-08 17:51:322004 ),
Helmut Januschkab3f71ab52024-03-12 02:48:052005 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:532006 pattern=(r'/FindBrowserWithUiElementContext|'
2007 r'FindBrowserWithTab|'
2008 r'FindBrowserWithGroup|'
2009 r'FindTabbedBrowser|'
2010 r'FindAnyBrowser|'
2011 r'FindBrowserWithProfile|'
Erik Chen5f02eb4c2024-08-23 06:30:442012 r'FindLastActive|'
Daniel Cheng566634ff2024-06-29 14:56:532013 r'FindBrowserWithActiveWindow'),
2014 explanation=
2015 ('Most code should already be scoped to a Browser. Pass in a Browser* '
2016 'or retreive from an existing entity with a reference to the Browser.',
2017 ),
2018 treat_as_error=False,
Helmut Januschkab3f71ab52024-03-12 02:48:052019 ),
2020 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:532021 pattern='BrowserUserData',
2022 explanation=
2023 ('Do not use BrowserUserData to store state on a Browser instance. '
2024 'Instead use BrowserWindowFeatures. BrowserWindowFeatures is '
2025 'functionally identical but has two benefits: it does not force a '
2026 'dependency onto class Browser, and lifetime semantics are explicit '
2027 'rather than implicit. See BrowserUserData header file for more '
2028 'details.', ),
2029 treat_as_error=False,
Mike Doughertyab1bdec2024-08-06 16:39:012030 excluded_paths=(
2031 # Exclude iOS as the iOS implementation of BrowserUserData is separate
2032 # and still in use.
2033 '^ios/',
2034 ),
Erik Chen87358e82024-06-04 02:13:122035 ),
Tom Sepezea67b6e2024-08-08 18:17:272036 BanRule(
Tom Sepezd3272cd2025-02-21 19:11:312037 pattern=r'subspan(0u,',
2038 explanation=
2039 ('Prefer first(n) over subspan(0u, n) as it is shorter, and the '
2040 'compiler may have to emit a branch for the n == dynamic_extent '
2041 'case of subspan().',
2042 ),
2043 treat_as_error=False,
2044 ),
2045 BanRule(
Tom Sepezea67b6e2024-08-08 18:17:272046 pattern=r'UNSAFE_TODO(',
2047 explanation=
2048 ('Do not use UNSAFE_TODO() to write new unsafe code. Use only when '
Tom Sepeza90f92b2024-08-15 16:01:352049 'removing a pre-existing file-wide allow_unsafe_buffers pragma, or '
2050 'when incrementally converting code off of unsafe interfaces',
Tom Sepezea67b6e2024-08-08 18:17:272051 ),
2052 treat_as_error=False,
2053 ),
2054 BanRule(
Claudio DeSouzaad1d1f252025-04-22 23:38:582055 pattern='#pragma allow_unsafe_buffers',
2056 explanation=
2057 ('Do not use allow_unsafe_buffers to write new unsafe code. Use only '
2058 'when enabling unsafe buffers checks under a new uncovered path.',
2059 ),
2060 treat_as_error=False,
2061 ),
2062 BanRule(
Tom Sepezea67b6e2024-08-08 18:17:272063 pattern=r'UNSAFE_BUFFERS(',
2064 explanation=
Tom Sepeza90f92b2024-08-15 16:01:352065 ('Try to avoid using UNSAFE_BUFFERS() if at all possible. Otherwise, '
2066 'be sure to justify in a // SAFETY comment why other options are not '
2067 'available, and why the code is safe.',
Tom Sepezea67b6e2024-08-08 18:17:272068 ),
2069 treat_as_error=False,
2070 ),
Erik Chend086ae02024-08-20 22:53:332071 BanRule(
2072 pattern='BrowserWithTestWindowTest',
2073 explanation=
2074 ('Do not use BrowserWithTestWindowTest. By instantiating an instance '
2075 'of class Browser, the test is no longer a unit test but is instead a '
2076 'browser test. The class BrowserWithTestWindowTest forces production '
2077 'logic to take on test-only conditionals, which is an anti-pattern. '
2078 'Features should be performing dependency injection rather than '
2079 'directly using class Browser. See '
mikt19226ff22024-08-27 05:28:212080 'docs/chrome_browser_design_principles.md for more details.',
Erik Chend086ae02024-08-20 22:53:332081 ),
2082 treat_as_error=False,
2083 ),
Erik Chen8cf3a652024-08-23 17:13:302084 BanRule(
Erik Chen959cdd72024-08-29 02:11:212085 pattern='TestWithBrowserView',
2086 explanation=
2087 ('Do not use TestWithBrowserView. See '
2088 'docs/chrome_browser_design_principles.md for details. If you want '
2089 'to write a test that has both a Browser and a BrowserView, create '
2090 'a browser_test. If you want to write a unit_test, your code must '
Erik Chendba23692024-09-26 06:43:362091 'not reference Browser*.',
Erik Chen959cdd72024-08-29 02:11:212092 ),
2093 treat_as_error=False,
2094 ),
2095 BanRule(
Erik Chene89ebe32025-02-22 02:46:492096 pattern='CreateBrowserWithTestWindow',
2097 explanation=
2098 ('Do not use CreateBrowserWithTestWindow. See '
2099 'docs/chrome_browser_design_principles.md for details. If you want '
2100 'to write a test that has a Browser, create a browser_test. If you '
2101 'want to write a unit_test, your code must not reference Browser*.',
2102 ),
2103 treat_as_error=False,
2104 ),
2105 BanRule(
Erik Chenf12a06642025-03-13 23:30:342106 pattern='CreateBrowserWithTestWindowForParams',
2107 explanation=
2108 ('Do not use CreateBrowserWithTestWindowForParams. See '
2109 'docs/chrome_browser_design_principles.md for details. If you want '
2110 'to write a test that has a Browser, create a browser_test and use '
2111 'Browser::Browser. If you want to write a unit_test, your code must '
2112 'not reference Browser*.',
2113 ),
2114 treat_as_error=False,
2115 ),
2116 BanRule(
Erik Chen8cf3a652024-08-23 17:13:302117 pattern='RunUntilIdle',
2118 explanation=
2119 ('Do not RunUntilIdle. If possible, explicitly quit the run loop using '
2120 'run_loop.Quit() or run_loop.QuitClosure() if completion can be '
2121 'observed using a lambda or callback. Otherwise, wait for the '
mikt19226ff22024-08-27 05:28:212122 'condition to be true via base::test::RunUntil().',
Erik Chen8cf3a652024-08-23 17:13:302123 ),
2124 treat_as_error=False,
2125 ),
Daniel Chengddde13a2024-09-05 21:39:282126 BanRule(
2127 pattern=r'/\bstd::(literals|string_literals|string_view_literals)\b',
2128 explanation = (
2129 'User-defined literals are banned by the Google C++ style guide. '
2130 'Exceptions are provided in Chrome for string and string_view '
2131 'literals that embed \\0.',
2132 ),
2133 treat_as_error=True,
2134 excluded_paths=(
2135 # Various tests or test helpers that embed NUL in strings or
2136 # string_views.
Daniel Chengddde13a2024-09-05 21:39:282137 r'^base/strings/string_util_unittest\.cc',
2138 r'^base/strings/utf_string_conversions_unittest\.cc',
2139 r'^chrome/browser/ash/crosapi/browser_data_back_migrator_unittest\.cc',
2140 r'^chrome/browser/ash/crosapi/browser_data_migrator_util_unittest\.cc',
2141 r'^chrome/browser/ash/crosapi/move_migrator_unittest\.cc',
Hidehiko Abe51601812025-01-12 16:17:352142 r'^chromeos/ash/experiences/arc/session/serial_number_util_unittest\.cc',
Daniel Chengddde13a2024-09-05 21:39:282143 r'^components/history/core/browser/visit_annotations_database\.cc',
2144 r'^components/history/core/browser/visit_annotations_database_unittest\.cc',
2145 r'^components/os_crypt/sync/os_crypt_unittest\.cc',
2146 r'^components/password_manager/core/browser/credentials_cleaner_unittest\.cc',
2147 r'^content/browser/file_system_access/file_system_access_file_writer_impl_unittest\.cc',
2148 r'^net/cookies/parsed_cookie_unittest\.cc',
2149 r'^third_party/blink/renderer/modules/webcodecs/test_helpers\.cc',
2150 r'^third_party/blink/renderer/modules/websockets/websocket_channel_impl_test\.cc',
2151 ),
Erik Chenba8b0cd32024-10-01 08:36:362152 ),
2153 BanRule(
2154 pattern='BUILDFLAG(GOOGLE_CHROME_BRANDING)',
2155 explanation=
2156 ('Code gated by GOOGLE_CHROME_BRANDING is effectively untested. This '
2157 'is typically wrong. Valid use cases are glue for private modules '
2158 'shipped alongside Chrome, and installation-related logic.',
2159 ),
2160 treat_as_error=False,
2161 ),
2162 BanRule(
2163 pattern='defined(OFFICIAL_BUILD)',
2164 explanation=
2165 ('Code gated by OFFICIAL_BUILD is effectively untested. This '
2166 'is typically wrong. One valid use case is low-level code that '
2167 'handles subtleties related to high-levels of optimizations that come '
2168 'with OFFICIAL_BUILD.',
2169 ),
2170 treat_as_error=False,
2171 ),
Erik Chen95b9c782024-11-08 03:26:272172 BanRule(
2173 pattern='WebContentsDestroyed',
2174 explanation=
2175 ('Do not use this method. It is invoked half-way through the '
2176 'destructor of WebContentsImpl and using it often results in crashes '
2177 'or surprising behavior. Conceptually, this is only necessary by '
2178 'objects that depend on, but outlive the WebContents. These objects '
2179 'should instead coordinate with the owner of the WebContents which is '
2180 'responsible for destroying the WebContents.',
2181 ),
2182 treat_as_error=False,
2183 ),
Maksim Sisovc98fdfa2024-11-16 20:12:272184 BanRule(
Georg Neisa7f94e62025-02-28 07:01:482185 pattern='IS_CHROMEOS_ASH',
Maksim Sisovc98fdfa2024-11-16 20:12:272186 explanation=
Georg Neisa7f94e62025-02-28 07:01:482187 ('IS_CHROMEOS_ASH is deprecated. Please use the equivalent IS_CHROMEOS '
2188 'instead (Lacros is gone).',
Maksim Sisovc98fdfa2024-11-16 20:12:272189 ),
2190 treat_as_error=False,
2191 ),
Erik Chen1396bbe2025-01-27 23:39:362192 BanRule(
2193 pattern=(r'namespace {'),
2194 explanation=
2195 ('Anonymous namespaces are disallowed in C++ header files. See '
2196 'https://google.github.io/styleguide/cppguide.html#Internal_Linkage '
2197 ' for details.',
2198 ),
2199 treat_as_error=False,
2200 excluded_paths=[
2201 _THIRD_PARTY_EXCEPT_BLINK, # Don't warn in third_party folders.
2202 r'^(?!.*\.h$).*$', # Exclude all files except those that end in .h
2203 ],
2204 ),
Keren Zhuf06d757d2025-03-04 05:32:362205 BanRule(
2206 pattern=('AddChildViewRaw'),
2207 explanation=(
2208 'Do not use AddChildViewRaw. It is prone to memory leaks and '
2209 'use-after-free bugs. Instead, use AddChildView(std::unique_ptr). '
2210 'See https://crbug.com/40485510 for more details.', ),
2211 treat_as_error=False,
2212 ),
Nate Fischerd541ff82025-03-11 21:34:192213 BanRule(
2214 pattern=(r'IS_DESKTOP_ANDROID'),
2215 explanation=(
2216 'Features which depend on IS_DESKTOP_ANDROID should only exist in '
2217 'chrome/ layer and similar layers. Lower layers such as content/ '
2218 'should not have features which are only designed for '
2219 'desktop-android builds. See https://crbug.com/401628399.', ),
2220 treat_as_error=False,
2221 excluded_paths=[
2222 _THIRD_PARTY_EXCEPT_BLINK, # Don't warn in third_party folders.
2223 r'^build/', # This is permitted in build/ folder.
2224 r'^chrome/', # This is permitted in chrome/ folder.
2225 r'^components/', # This is permitted only for components/ that are not shared by WebView.
2226 r'^extensions/', # This is permitted in chrome/ folder.
2227 r'^infra/', # This is permitted in infra/ folder.
2228 r'^tools/', # This is permitted in tools/ folder.
2229 ],
2230 ),
[email protected]127f18ec2012-06-16 05:05:592231)
2232
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152233_DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING = (
2234 'Used a predicate related to signin::ConsentLevel::kSync which will always '
2235 'return false in the future (crbug.com/40066949). Prefer using a predicate '
2236 'that also supports signin::ConsentLevel::kSignin when appropriate. It is '
2237 'safe to ignore this warning if you are just moving an existing call, or if '
2238 'you want special handling for users in the legacy state. In doubt, reach '
Victor Hugo Vianna Silvae2292972024-06-04 17:11:552239 'out to //components/sync/OWNERS.',
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152240)
2241
2242# C++ functions related to signin::ConsentLevel::kSync which are deprecated.
2243_DEPRECATED_SYNC_CONSENT_CPP_FUNCTIONS : Sequence[BanRule] = (
2244 BanRule(
2245 'HasSyncConsent',
2246 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2247 False,
2248 ),
2249 BanRule(
2250 'CanSyncFeatureStart',
2251 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2252 False,
2253 ),
2254 BanRule(
2255 'IsSyncFeatureEnabled',
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152256 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152257 False,
2258 ),
2259 BanRule(
2260 'IsSyncFeatureActive',
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152261 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152262 False,
2263 ),
2264)
2265
2266# Java functions related to signin::ConsentLevel::kSync which are deprecated.
2267_DEPRECATED_SYNC_CONSENT_JAVA_FUNCTIONS : Sequence[BanRule] = (
2268 BanRule(
2269 'hasSyncConsent',
2270 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2271 False,
2272 ),
2273 BanRule(
2274 'canSyncFeatureStart',
2275 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2276 False,
2277 ),
2278 BanRule(
2279 'isSyncFeatureEnabled',
2280 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2281 False,
2282 ),
2283 BanRule(
2284 'isSyncFeatureActive',
2285 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2286 False,
2287 ),
2288)
2289
Justin Lulejian09fd06872025-04-01 22:03:282290_BANNED_MOJOM_PATTERNS: Sequence[BanRule] = (
Daniel Cheng92c15e32022-03-16 17:48:222291 BanRule(
2292 'handle<shared_buffer>',
2293 (
Justin Lulejian09fd06872025-04-01 22:03:282294 'Please use one of the more specific shared memory types instead:',
2295 ' mojo_base.mojom.ReadOnlySharedMemoryRegion',
2296 ' mojo_base.mojom.WritableSharedMemoryRegion',
2297 ' mojo_base.mojom.UnsafeSharedMemoryRegion',
Daniel Cheng92c15e32022-03-16 17:48:222298 ),
2299 True,
2300 ),
Justin Lulejian09fd06872025-04-01 22:03:282301 BanRule(
2302 'string extension_id',
2303 (
2304 'Please use the extensions::mojom::ExtensionId struct when '
2305 'passing extensions::ExtensionIds as mojom messages in order to ',
2306 'provide message validation.',
2307 ),
2308 True,
2309 # Only apply this to (mojom) files in a subdirectory of extensions.
2310 excluded_paths=(r'^((?!extensions/).)*$', ),
2311 ),
Daniel Cheng92c15e32022-03-16 17:48:222312)
2313
mlamouria82272622014-09-16 18:45:042314_IPC_ENUM_TRAITS_DEPRECATED = (
2315 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:502316 'See http://www.chromium.org/Home/chromium-security/education/'
2317 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:042318
Stephen Martinis97a394142018-06-07 23:06:052319_LONG_PATH_ERROR = (
2320 'Some files included in this CL have file names that are too long (> 200'
2321 ' characters). If committed, these files will cause issues on Windows. See'
2322 ' https://crbug.com/612667 for more details.'
2323)
2324
Shenghua Zhangbfaa38b82017-11-16 21:58:022325_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Bruce Dawson40fece62022-09-16 19:58:312326 r".*/BuildHooksAndroidImpl\.java",
2327 r".*/LicenseContentProvider\.java",
2328 r".*/PlatformServiceBridgeImpl.java",
2329 r".*chrome/android/feed/dummy/.*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:022330]
[email protected]127f18ec2012-06-16 05:05:592331
Mohamed Heikald048240a2019-11-12 16:57:372332# List of image extensions that are used as resources in chromium.
2333_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
2334
Sean Kau46e29bc2017-08-28 16:31:162335# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:402336_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Bruce Dawson40fece62022-09-16 19:58:312337 r'test/data/',
2338 r'testing/buildbot/',
2339 r'^components/policy/resources/policy_templates\.json$',
2340 r'^third_party/protobuf/',
Camillo Bruni1411a352023-05-24 12:39:032341 r'^third_party/blink/perf_tests/speedometer.*/resources/todomvc/learn\.json',
Bruce Dawson40fece62022-09-16 19:58:312342 r'^third_party/blink/renderer/devtools/protocol\.json$',
2343 r'^third_party/blink/web_tests/external/wpt/',
2344 r'^tools/perf/',
2345 r'^tools/traceline/svgui/startup-release.json',
Daniel Cheng2d4c2d192022-07-01 01:38:312346 # vscode configuration files allow comments
Bruce Dawson40fece62022-09-16 19:58:312347 r'^tools/vscode/',
Sean Kau46e29bc2017-08-28 16:31:162348]
2349
Andrew Grieveb773bad2020-06-05 18:00:382350# These are not checked on the public chromium-presubmit trybot.
2351# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:042352# checkouts.
agrievef32bcc72016-04-04 14:57:402353_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:382354 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382355]
2356
2357
2358_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:042359 'android_webview/tools/run_cts.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:362360 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042361 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362362 'build/android/gyp/aar.pydeps',
2363 'build/android/gyp/aidl.pydeps',
2364 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:382365 'build/android/gyp/assert_static_initializers.pydeps',
Mohamed Heikal133e1f22023-04-18 20:04:372366 'build/android/gyp/binary_baseline_profile.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:022367 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:222368 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieveacac4242024-12-20 19:39:422369 'build/android/gyp/check_for_missing_direct_deps.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:112370 'build/android/gyp/compile_java.pydeps',
Peter Weneaa963f2023-01-20 19:40:302371 'build/android/gyp/compile_kt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362372 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362373 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362374 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:112375 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042376 'build/android/gyp/create_app_bundle_apks.pydeps',
2377 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362378 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:122379 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:092380 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:222381 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve2d972e5f2025-01-28 18:28:142382 'build/android/gyp/create_stub_manifest.pydeps',
Peter Wene6e017e2022-07-27 21:40:402383 'build/android/gyp/create_test_apk_wrapper_script.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002384 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362385 'build/android/gyp/dex.pydeps',
2386 'build/android/gyp/dist_aar.pydeps',
Andrew Grieve651ddb32025-01-23 03:27:342387 'build/android/gyp/errorprone.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362388 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:212389 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362390 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:362391 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362392 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:582393 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362394 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:142395 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:262396 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:472397 'build/android/gyp/java_google_api_keys.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042398 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362399 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362400 'build/android/gyp/merge_manifest.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:102401 'build/android/gyp/optimize_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362402 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:222403 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362404 'build/android/gyp/proguard.pydeps',
Mohamed Heikaldd52b452024-09-10 17:10:502405 'build/android/gyp/rename_java_classes.pydeps',
Andrew Grievee3a775ab2022-05-16 15:59:222406 'build/android/gyp/system_image_apks.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:102407 'build/android/gyp/trace_event_bytecode_rewriter.pydeps',
Andrew Grieve170b9782025-02-03 15:54:532408 'build/android/gyp/tracereferences.pydeps',
Peter Wen578730b2020-03-19 19:55:462409 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:302410 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:242411 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362412 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:462413 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:562414 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362415 'build/android/incremental_install/generate_android_manifest.pydeps',
2416 'build/android/incremental_install/write_installer_json.pydeps',
Stephanie Kim392913b452022-06-15 17:25:322417 'build/android/pylib/results/presentation/test_results_presentation.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042418 'build/android/resource_sizes.pydeps',
2419 'build/android/test_runner.pydeps',
2420 'build/android/test_wrapper/logdog_wrapper.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362421 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:322422 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:272423 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
2424 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Bailey Myers-Morganbd122132025-03-26 23:09:162425 'chrome/test/media_router/performance/performance_test.pydeps',
Junbo Kedcd3a452021-03-19 17:55:042426 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Mohannad Farrag19102742023-12-01 01:16:302427 'components/cronet/tools/check_combined_proguard_file.pydeps',
2428 'components/cronet/tools/generate_proguard_file.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002429 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382430 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002431 'content/public/android/generate_child_service.pydeps',
Hzj_jie77bdb802024-07-22 18:14:512432 'fuchsia_web/av_testing/av_sync_tests.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382433 'net/tools/testserver/testserver.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:182434 'testing/scripts/run_isolated_script_test.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:412435 'testing/merge_scripts/standard_isolated_script_merge.pydeps',
2436 'testing/merge_scripts/standard_gtest_merge.pydeps',
2437 'testing/merge_scripts/code_coverage/merge_results.pydeps',
2438 'testing/merge_scripts/code_coverage/merge_steps.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042439 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:422440 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
Yuki Shiino38eeaad12022-08-11 06:40:252441 'third_party/blink/renderer/bindings/scripts/check_generated_file_list.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:422442 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:132443 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Yuki Shiinoea477d32023-08-21 06:24:342444 'third_party/blink/renderer/bindings/scripts/generate_event_interface_names.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:502445 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:412446 'third_party/blink/tools/blinkpy/web_tests/merge_results.pydeps',
2447 'third_party/blink/tools/merge_web_test_results.pydeps',
John Budorickbc3571aa2019-04-25 02:20:062448 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:222449 'tools/binary_size/supersize.pydeps',
Peter Wen2dcfa6e2025-03-04 22:42:522450 'tools/cygprofile/generate_orderfile.pydeps',
Ben Pastene028104a2022-08-10 19:17:452451 'tools/perf/process_perf_results.pydeps',
Peter Wence103e12024-10-09 19:23:512452 'tools/pgo/generate_profile.pydeps',
agrievef32bcc72016-04-04 14:57:402453]
2454
wnwenbdc444e2016-05-25 13:44:152455
agrievef32bcc72016-04-04 14:57:402456_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
2457
2458
Eric Boren6fd2b932018-01-25 15:05:082459# Bypass the AUTHORS check for these accounts.
2460_KNOWN_ROBOTS = set(
Shuai Xia0d99ebf2025-02-11 23:47:592461 ) | set('%[email protected]' % s for s in ('findit-for-me',
2462 'luci-bisection',
2463 'predator-for-me-staging',
2464 'predator-for-me')
Achuith Bhandarkar35905562018-07-25 19:28:452465 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:592466 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:522467 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:232468 'wpt-autoroller', 'chrome-weblayer-builder',
Georg Neise5817eb2025-02-06 03:47:312469 'skylab-test-cros-roller', 'infra-try-recipes-tester',
2470 'chrome-automated-expectation',
Stephanie Kimb49bdd242023-04-28 16:46:042471 'chromium-automated-expectation', 'chrome-branch-day',
Gennady Tsitovich554fd422025-04-02 21:03:182472 'chrome-cherry-picker', 'chromium-autosharder')
Eric Boren835d71f2018-09-07 21:09:042473 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:272474 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:042475 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:162476 for s in ('chromium-internal-autoroll',)
Kyungjun Lee3b7c9352024-04-02 23:59:142477 ) | set('%[email protected]' % s
Shuai Xia174d35c2025-04-15 17:10:312478 for s in ('chrome-screen-ai-releaser', 'crash-eng', 'crash')
Yulan Lineb0cfba2021-04-09 18:43:162479 ) | set('%[email protected]' % s
Chong Gub277e342022-10-15 03:30:552480 for s in ('swarming-tasks',)
2481 ) | set('%[email protected]' % s
2482 for s in ('global-integration-try-builder',
Joey Scarr1103c5d2023-09-14 01:17:552483 'global-integration-ci-builder')
Suma Kasa3b9cf7a2023-09-21 22:05:542484 ) | set('%[email protected]' % s
2485 for s in ('chops-security-borg',
2486 'chops-security-cronjobs-cpesuggest'))
Eric Boren6fd2b932018-01-25 15:05:082487
Matt Stark6ef08872021-07-29 01:21:462488_INVALID_GRD_FILE_LINE = [
2489 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
2490]
Eric Boren6fd2b932018-01-25 15:05:082491
Daniel Bratell65b033262019-04-23 08:17:062492def _IsCPlusPlusFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502493 """Returns True if this file contains C++-like code (and not Python,
2494 Go, Java, MarkDown, ...)"""
Daniel Bratell65b033262019-04-23 08:17:062495
Sam Maiera6e76d72022-02-11 21:43:502496 ext = input_api.os_path.splitext(file_path)[1]
2497 # This list is compatible with CppChecker.IsCppFile but we should
2498 # consider adding ".c" to it. If we do that we can use this function
2499 # at more places in the code.
2500 return ext in (
2501 '.h',
2502 '.cc',
2503 '.cpp',
2504 '.m',
2505 '.mm',
2506 )
2507
Daniel Bratell65b033262019-04-23 08:17:062508
2509def _IsCPlusPlusHeaderFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502510 return input_api.os_path.splitext(file_path)[1] == ".h"
Daniel Bratell65b033262019-04-23 08:17:062511
2512
2513def _IsJavaFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502514 return input_api.os_path.splitext(file_path)[1] == ".java"
Daniel Bratell65b033262019-04-23 08:17:062515
2516
2517def _IsProtoFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502518 return input_api.os_path.splitext(file_path)[1] == ".proto"
Daniel Bratell65b033262019-04-23 08:17:062519
Mohamed Heikal5e5b7922020-10-29 18:57:592520
Erik Staabc734cd7a2021-11-23 03:11:522521def _IsXmlOrGrdFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502522 ext = input_api.os_path.splitext(file_path)[1]
2523 return ext in ('.grd', '.xml')
Erik Staabc734cd7a2021-11-23 03:11:522524
2525
Sven Zheng76a79ea2022-12-21 21:25:242526def _IsMojomFile(input_api, file_path):
2527 return input_api.os_path.splitext(file_path)[1] == ".mojom"
2528
2529
Mohamed Heikal5e5b7922020-10-29 18:57:592530def CheckNoUpstreamDepsOnClank(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502531 """Prevent additions of dependencies from the upstream repo on //clank."""
2532 # clank can depend on clank
2533 if input_api.change.RepositoryRoot().endswith('clank'):
2534 return []
2535 build_file_patterns = [
2536 r'(.+/)?BUILD\.gn',
2537 r'.+\.gni',
2538 ]
2539 excluded_files = [r'build[/\\]config[/\\]android[/\\]config\.gni']
2540 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
Mohamed Heikal5e5b7922020-10-29 18:57:592541
Sam Maiera6e76d72022-02-11 21:43:502542 error_message = 'Disallowed import on //clank in an upstream build file:'
Mohamed Heikal5e5b7922020-10-29 18:57:592543
Sam Maiera6e76d72022-02-11 21:43:502544 def FilterFile(affected_file):
2545 return input_api.FilterSourceFile(affected_file,
2546 files_to_check=build_file_patterns,
2547 files_to_skip=excluded_files)
Mohamed Heikal5e5b7922020-10-29 18:57:592548
Sam Maiera6e76d72022-02-11 21:43:502549 problems = []
2550 for f in input_api.AffectedSourceFiles(FilterFile):
2551 local_path = f.LocalPath()
2552 for line_number, line in f.ChangedContents():
2553 if (bad_pattern.search(line)):
2554 problems.append('%s:%d\n %s' %
2555 (local_path, line_number, line.strip()))
2556 if problems:
2557 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
2558 else:
2559 return []
Mohamed Heikal5e5b7922020-10-29 18:57:592560
2561
Saagar Sanghavifceeaae2020-08-12 16:40:362562def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502563 """Attempts to prevent use of functions intended only for testing in
2564 non-testing code. For now this is just a best-effort implementation
2565 that ignores header files and may have some false positives. A
2566 better implementation would probably need a proper C++ parser.
2567 """
2568 # We only scan .cc files and the like, as the declaration of
2569 # for-testing functions in header files are hard to distinguish from
2570 # calls to such functions without a proper C++ parser.
2571 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:192572
Sam Maiera6e76d72022-02-11 21:43:502573 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
2574 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' %
2575 base_function_pattern)
2576 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
2577 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
2578 exclusion_pattern = input_api.re.compile(
2579 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' %
2580 (base_function_pattern, base_function_pattern))
2581 # Avoid a false positive in this case, where the method name, the ::, and
2582 # the closing { are all on different lines due to line wrapping.
2583 # HelperClassForTesting::
2584 # HelperClassForTesting(
2585 # args)
2586 # : member(0) {}
2587 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:192588
Sam Maiera6e76d72022-02-11 21:43:502589 def FilterFile(affected_file):
2590 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2591 input_api.DEFAULT_FILES_TO_SKIP)
2592 return input_api.FilterSourceFile(
2593 affected_file,
2594 files_to_check=file_inclusion_pattern,
2595 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:192596
Sam Maiera6e76d72022-02-11 21:43:502597 problems = []
2598 for f in input_api.AffectedSourceFiles(FilterFile):
2599 local_path = f.LocalPath()
2600 in_method_defn = False
2601 for line_number, line in f.ChangedContents():
2602 if (inclusion_pattern.search(line)
2603 and not comment_pattern.search(line)
2604 and not exclusion_pattern.search(line)
2605 and not allowlist_pattern.search(line)
2606 and not in_method_defn):
2607 problems.append('%s:%d\n %s' %
2608 (local_path, line_number, line.strip()))
2609 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:192610
Sam Maiera6e76d72022-02-11 21:43:502611 if problems:
2612 return [
2613 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
2614 ]
2615 else:
2616 return []
[email protected]55459852011-08-10 15:17:192617
2618
Saagar Sanghavifceeaae2020-08-12 16:40:362619def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502620 """This is a simplified version of
2621 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
2622 """
2623 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
2624 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
2625 name_pattern = r'ForTest(s|ing)?'
2626 # Describes an occurrence of "ForTest*" inside a // comment.
2627 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
2628 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
2629 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
2630 # Catch calls.
2631 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
2632 # Ignore definitions. (Comments are ignored separately.)
2633 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
Andrew Grieve40f451d2023-07-06 19:46:512634 allowlist_re = input_api.re.compile(r'// IN-TEST$')
Vaclav Brozek7dbc28c2018-03-27 08:35:232635
Sam Maiera6e76d72022-02-11 21:43:502636 problems = []
2637 sources = lambda x: input_api.FilterSourceFile(
2638 x,
2639 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
2640 DEFAULT_FILES_TO_SKIP),
2641 files_to_check=[r'.*\.java$'])
2642 for f in input_api.AffectedFiles(include_deletes=False,
2643 file_filter=sources):
2644 local_path = f.LocalPath()
Vaclav Brozek7dbc28c2018-03-27 08:35:232645 is_inside_javadoc = False
Sam Maiera6e76d72022-02-11 21:43:502646 for line_number, line in f.ChangedContents():
2647 if is_inside_javadoc and javadoc_end_re.search(line):
2648 is_inside_javadoc = False
2649 if not is_inside_javadoc and javadoc_start_re.search(line):
2650 is_inside_javadoc = True
2651 if is_inside_javadoc:
2652 continue
2653 if (inclusion_re.search(line) and not comment_re.search(line)
2654 and not annotation_re.search(line)
Andrew Grieve40f451d2023-07-06 19:46:512655 and not allowlist_re.search(line)
Sam Maiera6e76d72022-02-11 21:43:502656 and not exclusion_re.search(line)):
2657 problems.append('%s:%d\n %s' %
2658 (local_path, line_number, line.strip()))
Vaclav Brozek7dbc28c2018-03-27 08:35:232659
Sam Maiera6e76d72022-02-11 21:43:502660 if problems:
2661 return [
2662 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
2663 ]
2664 else:
2665 return []
Vaclav Brozek7dbc28c2018-03-27 08:35:232666
2667
Saagar Sanghavifceeaae2020-08-12 16:40:362668def CheckNoIOStreamInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502669 """Checks to make sure no .h files include <iostream>."""
2670 files = []
2671 pattern = input_api.re.compile(r'^#include\s*<iostream>',
2672 input_api.re.MULTILINE)
2673 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2674 if not f.LocalPath().endswith('.h'):
2675 continue
2676 contents = input_api.ReadFile(f)
2677 if pattern.search(contents):
2678 files.append(f)
[email protected]10689ca2011-09-02 02:31:542679
Sam Maiera6e76d72022-02-11 21:43:502680 if len(files):
2681 return [
2682 output_api.PresubmitError(
2683 'Do not #include <iostream> in header files, since it inserts static '
2684 'initialization into every file including the header. Instead, '
2685 '#include <ostream>. See http://crbug.com/94794', files)
2686 ]
2687 return []
2688
[email protected]10689ca2011-09-02 02:31:542689
Aleksey Khoroshilov9b28c032022-06-03 16:35:322690def CheckNoStrCatRedefines(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502691 """Checks no windows headers with StrCat redefined are included directly."""
2692 files = []
Aleksey Khoroshilov9b28c032022-06-03 16:35:322693 files_to_check = (r'.+%s' % _HEADER_EXTENSIONS,
2694 r'.+%s' % _IMPLEMENTATION_EXTENSIONS)
2695 files_to_skip = (input_api.DEFAULT_FILES_TO_SKIP +
2696 _NON_BASE_DEPENDENT_PATHS)
2697 sources_filter = lambda f: input_api.FilterSourceFile(
2698 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
2699
Sam Maiera6e76d72022-02-11 21:43:502700 pattern_deny = input_api.re.compile(
2701 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
2702 input_api.re.MULTILINE)
2703 pattern_allow = input_api.re.compile(
2704 r'^#include\s"base/win/windows_defines.inc"', input_api.re.MULTILINE)
Aleksey Khoroshilov9b28c032022-06-03 16:35:322705 for f in input_api.AffectedSourceFiles(sources_filter):
Sam Maiera6e76d72022-02-11 21:43:502706 contents = input_api.ReadFile(f)
2707 if pattern_deny.search(
2708 contents) and not pattern_allow.search(contents):
2709 files.append(f.LocalPath())
Danil Chapovalov3518f362018-08-11 16:13:432710
Sam Maiera6e76d72022-02-11 21:43:502711 if len(files):
2712 return [
2713 output_api.PresubmitError(
2714 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
2715 'directly since they pollute code with StrCat macro. Instead, '
2716 'include matching header from base/win. See http://crbug.com/856536',
2717 files)
2718 ]
2719 return []
Danil Chapovalov3518f362018-08-11 16:13:432720
[email protected]10689ca2011-09-02 02:31:542721
Andrew Williamsc9f69b482023-07-10 16:07:362722def _CheckNoUNIT_TESTInSourceFiles(input_api, f):
2723 problems = []
2724
2725 unit_test_macro = input_api.re.compile(
Riley Wong49be8a882025-02-27 00:38:232726 r'^\s*#.*(?:ifn?def\s+UNIT_TEST|defined\s*\(?\s*UNIT_TEST\s*\)?)(?:$|\s+)')
Andrew Williamsc9f69b482023-07-10 16:07:362727 for line_num, line in f.ChangedContents():
2728 if unit_test_macro.match(line):
2729 problems.append(' %s:%d' % (f.LocalPath(), line_num))
2730
2731 return problems
2732
2733
Saagar Sanghavifceeaae2020-08-12 16:40:362734def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502735 """Checks to make sure no source files use UNIT_TEST."""
2736 problems = []
2737 for f in input_api.AffectedFiles():
2738 if (not f.LocalPath().endswith(('.cc', '.mm'))):
2739 continue
Andrew Williamsc9f69b482023-07-10 16:07:362740 problems.extend(
2741 _CheckNoUNIT_TESTInSourceFiles(input_api, f))
[email protected]72df4e782012-06-21 16:28:182742
Sam Maiera6e76d72022-02-11 21:43:502743 if not problems:
2744 return []
2745 return [
2746 output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
2747 '\n'.join(problems))
2748 ]
2749
[email protected]72df4e782012-06-21 16:28:182750
Saagar Sanghavifceeaae2020-08-12 16:40:362751def CheckNoDISABLETypoInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502752 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
Dominic Battre033531052018-09-24 15:45:342753
Sam Maiera6e76d72022-02-11 21:43:502754 This test warns if somebody tries to disable a test with the DISABLE_ prefix
2755 instead of DISABLED_. To filter false positives, reports are only generated
2756 if a corresponding MAYBE_ line exists.
2757 """
2758 problems = []
Dominic Battre033531052018-09-24 15:45:342759
Sam Maiera6e76d72022-02-11 21:43:502760 # The following two patterns are looked for in tandem - is a test labeled
2761 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
2762 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
2763 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
Dominic Battre033531052018-09-24 15:45:342764
Sam Maiera6e76d72022-02-11 21:43:502765 # This is for the case that a test is disabled on all platforms.
2766 full_disable_pattern = input_api.re.compile(
2767 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
2768 input_api.re.MULTILINE)
Dominic Battre033531052018-09-24 15:45:342769
Arthur Sonzognic66e9c82024-04-23 07:53:042770 for f in input_api.AffectedFiles(include_deletes=False):
Sam Maiera6e76d72022-02-11 21:43:502771 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2772 continue
Dominic Battre033531052018-09-24 15:45:342773
Arthur Sonzognic66e9c82024-04-23 07:53:042774 # Search for MAYBE_, DISABLE_ pairs.
Sam Maiera6e76d72022-02-11 21:43:502775 disable_lines = {} # Maps of test name to line number.
2776 maybe_lines = {}
2777 for line_num, line in f.ChangedContents():
2778 disable_match = disable_pattern.search(line)
2779 if disable_match:
2780 disable_lines[disable_match.group(1)] = line_num
2781 maybe_match = maybe_pattern.search(line)
2782 if maybe_match:
2783 maybe_lines[maybe_match.group(1)] = line_num
Dominic Battre033531052018-09-24 15:45:342784
Sam Maiera6e76d72022-02-11 21:43:502785 # Search for DISABLE_ occurrences within a TEST() macro.
2786 disable_tests = set(disable_lines.keys())
2787 maybe_tests = set(maybe_lines.keys())
2788 for test in disable_tests.intersection(maybe_tests):
2789 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
Dominic Battre033531052018-09-24 15:45:342790
Sam Maiera6e76d72022-02-11 21:43:502791 contents = input_api.ReadFile(f)
2792 full_disable_match = full_disable_pattern.search(contents)
2793 if full_disable_match:
2794 problems.append(' %s' % f.LocalPath())
Dominic Battre033531052018-09-24 15:45:342795
Sam Maiera6e76d72022-02-11 21:43:502796 if not problems:
2797 return []
2798 return [
2799 output_api.PresubmitPromptWarning(
2800 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
2801 '\n'.join(problems))
2802 ]
2803
Dominic Battre033531052018-09-24 15:45:342804
Nina Satragnof7660532021-09-20 18:03:352805def CheckForgettingMAYBEInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502806 """Checks to make sure tests disabled conditionally are not missing a
2807 corresponding MAYBE_ prefix.
2808 """
2809 # Expect at least a lowercase character in the test name. This helps rule out
2810 # false positives with macros wrapping the actual tests name.
2811 define_maybe_pattern = input_api.re.compile(
2812 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
Bruce Dawsonffc55292022-04-20 04:18:192813 # The test_maybe_pattern needs to handle all of these forms. The standard:
2814 # IN_PROC_TEST_F(SyncTest, MAYBE_Start) {
2815 # With a wrapper macro around the test name:
2816 # IN_PROC_TEST_F(SyncTest, E2E_ENABLED(MAYBE_Start)) {
2817 # And the odd-ball NACL_BROWSER_TEST_f format:
2818 # NACL_BROWSER_TEST_F(NaClBrowserTest, SimpleLoad, {
2819 # The optional E2E_ENABLED-style is handled with (\w*\()?
2820 # The NACL_BROWSER_TEST_F pattern is handled by allowing a trailing comma or
2821 # trailing ')'.
2822 test_maybe_pattern = (
2823 r'^\s*\w*TEST[^(]*\(\s*\w+,\s*(\w*\()?MAYBE_{test_name}[\),]')
Sam Maiera6e76d72022-02-11 21:43:502824 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
2825 warnings = []
Nina Satragnof7660532021-09-20 18:03:352826
Sam Maiera6e76d72022-02-11 21:43:502827 # Read the entire files. We can't just read the affected lines, forgetting to
2828 # add MAYBE_ on a change would not show up otherwise.
Arthur Sonzognic66e9c82024-04-23 07:53:042829 for f in input_api.AffectedFiles(include_deletes=False):
Sam Maiera6e76d72022-02-11 21:43:502830 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2831 continue
2832 contents = input_api.ReadFile(f)
2833 lines = contents.splitlines(True)
2834 current_position = 0
2835 warning_test_names = set()
2836 for line_num, line in enumerate(lines, start=1):
2837 current_position += len(line)
2838 maybe_match = define_maybe_pattern.search(line)
2839 if maybe_match:
2840 test_name = maybe_match.group('test_name')
2841 # Do not warn twice for the same test.
2842 if (test_name in warning_test_names):
2843 continue
2844 warning_test_names.add(test_name)
Nina Satragnof7660532021-09-20 18:03:352845
Sam Maiera6e76d72022-02-11 21:43:502846 # Attempt to find the corresponding MAYBE_ test or suite, starting from
2847 # the current position.
2848 test_match = input_api.re.compile(
2849 test_maybe_pattern.format(test_name=test_name),
2850 input_api.re.MULTILINE).search(contents, current_position)
2851 suite_match = input_api.re.compile(
2852 suite_maybe_pattern.format(test_name=test_name),
2853 input_api.re.MULTILINE).search(contents, current_position)
2854 if not test_match and not suite_match:
2855 warnings.append(
2856 output_api.PresubmitPromptWarning(
2857 '%s:%d found MAYBE_ defined without corresponding test %s'
2858 % (f.LocalPath(), line_num, test_name)))
2859 return warnings
2860
[email protected]72df4e782012-06-21 16:28:182861
Saagar Sanghavifceeaae2020-08-12 16:40:362862def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502863 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
2864 errors = []
Kalvin Lee4a3b79de2022-05-26 16:00:162865 pattern = input_api.re.compile(r'\bDCHECK_IS_ON\b(?!\(\))',
Sam Maiera6e76d72022-02-11 21:43:502866 input_api.re.MULTILINE)
2867 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2868 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
2869 continue
2870 for lnum, line in f.ChangedContents():
2871 if input_api.re.search(pattern, line):
2872 errors.append(
2873 output_api.PresubmitError((
2874 '%s:%d: Use of DCHECK_IS_ON() must be written as "#if '
2875 + 'DCHECK_IS_ON()", not forgetting the parentheses.') %
2876 (f.LocalPath(), lnum)))
2877 return errors
danakj61c1aa22015-10-26 19:55:522878
2879
Weilun Shia487fad2020-10-28 00:10:342880# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
2881# more reliable way. See
2882# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:192883
wnwenbdc444e2016-05-25 13:44:152884
Saagar Sanghavifceeaae2020-08-12 16:40:362885def CheckFlakyTestUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502886 """Check that FlakyTest annotation is our own instead of the android one"""
2887 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
2888 files = []
2889 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2890 if f.LocalPath().endswith('Test.java'):
2891 if pattern.search(input_api.ReadFile(f)):
2892 files.append(f)
2893 if len(files):
2894 return [
2895 output_api.PresubmitError(
2896 'Use org.chromium.base.test.util.FlakyTest instead of '
2897 'android.test.FlakyTest', files)
2898 ]
2899 return []
mcasasb7440c282015-02-04 14:52:192900
wnwenbdc444e2016-05-25 13:44:152901
Saagar Sanghavifceeaae2020-08-12 16:40:362902def CheckNoDEPSGIT(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502903 """Make sure .DEPS.git is never modified manually."""
2904 if any(f.LocalPath().endswith('.DEPS.git')
2905 for f in input_api.AffectedFiles()):
2906 return [
2907 output_api.PresubmitError(
2908 'Never commit changes to .DEPS.git. This file is maintained by an\n'
2909 'automated system based on what\'s in DEPS and your changes will be\n'
2910 'overwritten.\n'
2911 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
2912 'get-the-code#Rolling_DEPS\n'
2913 'for more information')
2914 ]
2915 return []
[email protected]2a8ac9c2011-10-19 17:20:442916
2917
Sven Zheng76a79ea2022-12-21 21:25:242918def CheckCrosApiNeedBrowserTest(input_api, output_api):
2919 """Check new crosapi should add browser test."""
2920 has_new_crosapi = False
2921 has_browser_test = False
2922 for f in input_api.AffectedFiles():
Anton Bershanskyi4253349482025-02-11 21:01:272923 path = f.UnixLocalPath()
Sven Zheng76a79ea2022-12-21 21:25:242924 if (path.startswith('chromeos/crosapi/mojom') and
2925 _IsMojomFile(input_api, path) and f.Action() == 'A'):
2926 has_new_crosapi = True
2927 if path.endswith('browsertest.cc') or path.endswith('browser_test.cc'):
2928 has_browser_test = True
2929 if has_new_crosapi and not has_browser_test:
2930 return [
2931 output_api.PresubmitPromptWarning(
2932 'You are adding a new crosapi, but there is no file ends with '
2933 'browsertest.cc file being added or modified. It is important '
2934 'to add crosapi browser test coverage to avoid version '
2935 ' skew issues.\n'
2936 'Check //docs/lacros/test_instructions.md for more information.'
2937 )
2938 ]
2939 return []
2940
2941
Saagar Sanghavifceeaae2020-08-12 16:40:362942def CheckValidHostsInDEPSOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502943 """Checks that DEPS file deps are from allowed_hosts."""
2944 # Run only if DEPS file has been modified to annoy fewer bystanders.
2945 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
2946 return []
2947 # Outsource work to gclient verify
2948 try:
2949 gclient_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
2950 'third_party', 'depot_tools',
2951 'gclient.py')
2952 input_api.subprocess.check_output(
Bruce Dawson8a43cf72022-05-13 17:10:322953 [input_api.python3_executable, gclient_path, 'verify'],
Sam Maiera6e76d72022-02-11 21:43:502954 stderr=input_api.subprocess.STDOUT)
2955 return []
2956 except input_api.subprocess.CalledProcessError as error:
2957 return [
2958 output_api.PresubmitError(
2959 'DEPS file must have only git dependencies.',
2960 long_text=error.output)
2961 ]
tandriief664692014-09-23 14:51:472962
2963
Mario Sanchez Prada2472cab2019-09-18 10:58:312964def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152965 ban_rule):
Allen Bauer84778682022-09-22 16:28:562966 """Helper method for checking for banned constructs.
Mario Sanchez Prada2472cab2019-09-18 10:58:312967
Sam Maiera6e76d72022-02-11 21:43:502968 Returns an string composed of the name of the file, the line number where the
2969 match has been found and the additional text passed as |message| in case the
2970 target type name matches the text inside the line passed as parameter.
2971 """
2972 result = []
Peng Huang9c5949a02020-06-11 19:20:542973
Daniel Chenga44a1bcd2022-03-15 20:00:152974 # Ignore comments about banned types.
2975 if input_api.re.search(r"^ *//", line):
Sam Maiera6e76d72022-02-11 21:43:502976 return result
Daniel Chenga44a1bcd2022-03-15 20:00:152977 # A // nocheck comment will bypass this error.
2978 if line.endswith(" nocheck"):
Sam Maiera6e76d72022-02-11 21:43:502979 return result
2980
2981 matched = False
Daniel Chenga44a1bcd2022-03-15 20:00:152982 if ban_rule.pattern[0:1] == '/':
2983 regex = ban_rule.pattern[1:]
Sam Maiera6e76d72022-02-11 21:43:502984 if input_api.re.search(regex, line):
2985 matched = True
Daniel Chenga44a1bcd2022-03-15 20:00:152986 elif ban_rule.pattern in line:
Sam Maiera6e76d72022-02-11 21:43:502987 matched = True
2988
2989 if matched:
2990 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
Daniel Chenga44a1bcd2022-03-15 20:00:152991 for line in ban_rule.explanation:
2992 result.append(' %s' % line)
Sam Maiera6e76d72022-02-11 21:43:502993
danakjd18e8892020-12-17 17:42:012994 return result
Mario Sanchez Prada2472cab2019-09-18 10:58:312995
2996
Saagar Sanghavifceeaae2020-08-12 16:40:362997def CheckNoBannedFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502998 """Make sure that banned functions are not used."""
2999 warnings = []
3000 errors = []
[email protected]127f18ec2012-06-16 05:05:593001
Sam Maiera6e76d72022-02-11 21:43:503002 def IsExcludedFile(affected_file, excluded_paths):
Daniel Chenga44a1bcd2022-03-15 20:00:153003 if not excluded_paths:
3004 return False
3005
Anton Bershanskyi4253349482025-02-11 21:01:273006 local_path = affected_file.UnixLocalPath()
Sam Maiera6e76d72022-02-11 21:43:503007 for item in excluded_paths:
3008 if input_api.re.match(item, local_path):
3009 return True
3010 return False
wnwenbdc444e2016-05-25 13:44:153011
Sam Maiera6e76d72022-02-11 21:43:503012 def IsIosObjcFile(affected_file):
3013 local_path = affected_file.LocalPath()
3014 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m',
3015 '.h'):
3016 return False
3017 basename = input_api.os_path.basename(local_path)
3018 if 'ios' in basename.split('_'):
3019 return True
3020 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
3021 if sep and 'ios' in local_path.split(sep):
3022 return True
3023 return False
Sylvain Defresnea8b73d252018-02-28 15:45:543024
Daniel Chenga44a1bcd2022-03-15 20:00:153025 def CheckForMatch(affected_file, line_num: int, line: str,
3026 ban_rule: BanRule):
3027 if IsExcludedFile(affected_file, ban_rule.excluded_paths):
3028 return
3029
Sam Maiera6e76d72022-02-11 21:43:503030 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
Daniel Chenga44a1bcd2022-03-15 20:00:153031 ban_rule)
Sam Maiera6e76d72022-02-11 21:43:503032 if problems:
Daniel Chenga44a1bcd2022-03-15 20:00:153033 if ban_rule.treat_as_error is not None and ban_rule.treat_as_error:
Sam Maiera6e76d72022-02-11 21:43:503034 errors.extend(problems)
3035 else:
3036 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:153037
Sam Maiera6e76d72022-02-11 21:43:503038 file_filter = lambda f: f.LocalPath().endswith(('.java'))
3039 for f in input_api.AffectedFiles(file_filter=file_filter):
3040 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:153041 for ban_rule in _BANNED_JAVA_FUNCTIONS:
3042 CheckForMatch(f, line_num, line, ban_rule)
Eric Stevensona9a980972017-09-23 00:04:413043
Clement Yan9b330cb2022-11-17 05:25:293044 file_filter = lambda f: f.LocalPath().endswith(('.js', '.ts'))
3045 for f in input_api.AffectedFiles(file_filter=file_filter):
3046 for line_num, line in f.ChangedContents():
3047 for ban_rule in _BANNED_JAVASCRIPT_FUNCTIONS:
3048 CheckForMatch(f, line_num, line, ban_rule)
3049
Sam Maiera6e76d72022-02-11 21:43:503050 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
3051 for f in input_api.AffectedFiles(file_filter=file_filter):
3052 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:153053 for ban_rule in _BANNED_OBJC_FUNCTIONS:
3054 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:593055
Sam Maiera6e76d72022-02-11 21:43:503056 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
3057 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:153058 for ban_rule in _BANNED_IOS_OBJC_FUNCTIONS:
3059 CheckForMatch(f, line_num, line, ban_rule)
Sylvain Defresnea8b73d252018-02-28 15:45:543060
Sam Maiera6e76d72022-02-11 21:43:503061 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
3062 for f in input_api.AffectedFiles(file_filter=egtest_filter):
3063 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:153064 for ban_rule in _BANNED_IOS_EGTEST_FUNCTIONS:
3065 CheckForMatch(f, line_num, line, ban_rule)
Peter K. Lee6c03ccff2019-07-15 14:40:053066
Sam Maiera6e76d72022-02-11 21:43:503067 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
3068 for f in input_api.AffectedFiles(file_filter=file_filter):
3069 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:153070 for ban_rule in _BANNED_CPP_FUNCTIONS:
3071 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:593072
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:153073 # As of 05/2024, iOS fully migrated ConsentLevel::kSync to kSignin, and
3074 # Android is in the process of preventing new users from entering kSync.
3075 # So the warning is restricted to those platforms.
Riley Wong49be8a882025-02-27 00:38:233076 ios_pattern = input_api.re.compile(r'(^|[\W_])ios[\W_]')
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:153077 file_filter = lambda f: (f.LocalPath().endswith(('.cc', '.mm', '.h')) and
3078 ('android' in f.LocalPath() or
3079 # Simply checking for an 'ios' substring would
3080 # catch unrelated cases, use a regex.
3081 ios_pattern.search(f.LocalPath())))
3082 for f in input_api.AffectedFiles(file_filter=file_filter):
3083 for line_num, line in f.ChangedContents():
3084 for ban_rule in _DEPRECATED_SYNC_CONSENT_CPP_FUNCTIONS:
3085 CheckForMatch(f, line_num, line, ban_rule)
3086
3087 file_filter = lambda f: f.LocalPath().endswith(('.java'))
3088 for f in input_api.AffectedFiles(file_filter=file_filter):
3089 for line_num, line in f.ChangedContents():
3090 for ban_rule in _DEPRECATED_SYNC_CONSENT_JAVA_FUNCTIONS:
3091 CheckForMatch(f, line_num, line, ban_rule)
3092
Daniel Cheng92c15e32022-03-16 17:48:223093 file_filter = lambda f: f.LocalPath().endswith(('.mojom'))
3094 for f in input_api.AffectedFiles(file_filter=file_filter):
3095 for line_num, line in f.ChangedContents():
3096 for ban_rule in _BANNED_MOJOM_PATTERNS:
3097 CheckForMatch(f, line_num, line, ban_rule)
3098
3099
Sam Maiera6e76d72022-02-11 21:43:503100 result = []
3101 if (warnings):
3102 result.append(
3103 output_api.PresubmitPromptWarning('Banned functions were used.\n' +
3104 '\n'.join(warnings)))
3105 if (errors):
3106 result.append(
3107 output_api.PresubmitError('Banned functions were used.\n' +
3108 '\n'.join(errors)))
3109 return result
[email protected]127f18ec2012-06-16 05:05:593110
Michael Thiessen44457642020-02-06 00:24:153111def _CheckAndroidNoBannedImports(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503112 """Make sure that banned java imports are not used."""
3113 errors = []
Michael Thiessen44457642020-02-06 00:24:153114
Sam Maiera6e76d72022-02-11 21:43:503115 file_filter = lambda f: f.LocalPath().endswith(('.java'))
3116 for f in input_api.AffectedFiles(file_filter=file_filter):
3117 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:153118 for ban_rule in _BANNED_JAVA_IMPORTS:
3119 # Consider merging this into the above function. There is no
3120 # real difference anymore other than helping with a little
3121 # bit of boilerplate text. Doing so means things like
3122 # `treat_as_error` will also be uniformly handled.
Sam Maiera6e76d72022-02-11 21:43:503123 problems = _GetMessageForMatchingType(input_api, f, line_num,
Daniel Chenga44a1bcd2022-03-15 20:00:153124 line, ban_rule)
Sam Maiera6e76d72022-02-11 21:43:503125 if problems:
3126 errors.extend(problems)
3127 result = []
3128 if (errors):
3129 result.append(
3130 output_api.PresubmitError('Banned imports were used.\n' +
3131 '\n'.join(errors)))
3132 return result
Michael Thiessen44457642020-02-06 00:24:153133
3134
Saagar Sanghavifceeaae2020-08-12 16:40:363135def CheckNoPragmaOnce(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503136 """Make sure that banned functions are not used."""
3137 files = []
3138 pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
3139 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
3140 if not f.LocalPath().endswith('.h'):
3141 continue
Bruce Dawson4c4c2922022-05-02 18:07:333142 if f.LocalPath().endswith('com_imported_mstscax.h'):
3143 continue
Sam Maiera6e76d72022-02-11 21:43:503144 contents = input_api.ReadFile(f)
3145 if pattern.search(contents):
3146 files.append(f)
[email protected]6c063c62012-07-11 19:11:063147
Sam Maiera6e76d72022-02-11 21:43:503148 if files:
3149 return [
3150 output_api.PresubmitError(
3151 'Do not use #pragma once in header files.\n'
3152 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
3153 files)
3154 ]
3155 return []
[email protected]6c063c62012-07-11 19:11:063156
[email protected]127f18ec2012-06-16 05:05:593157
Saagar Sanghavifceeaae2020-08-12 16:40:363158def CheckNoTrinaryTrueFalse(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503159 """Checks to make sure we don't introduce use of foo ? true : false."""
3160 problems = []
3161 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
3162 for f in input_api.AffectedFiles():
3163 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
3164 continue
[email protected]e7479052012-09-19 00:26:123165
Sam Maiera6e76d72022-02-11 21:43:503166 for line_num, line in f.ChangedContents():
3167 if pattern.match(line):
3168 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]e7479052012-09-19 00:26:123169
Sam Maiera6e76d72022-02-11 21:43:503170 if not problems:
3171 return []
3172 return [
3173 output_api.PresubmitPromptWarning(
3174 'Please consider avoiding the "? true : false" pattern if possible.\n'
3175 + '\n'.join(problems))
3176 ]
[email protected]e7479052012-09-19 00:26:123177
3178
Saagar Sanghavifceeaae2020-08-12 16:40:363179def CheckUnwantedDependencies(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503180 """Runs checkdeps on #include and import statements added in this
3181 change. Breaking - rules is an error, breaking ! rules is a
3182 warning.
3183 """
3184 # Return early if no relevant file types were modified.
3185 for f in input_api.AffectedFiles():
3186 path = f.LocalPath()
3187 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path)
3188 or _IsJavaFile(input_api, path)):
3189 break
[email protected]55f9f382012-07-31 11:02:183190 else:
Sam Maiera6e76d72022-02-11 21:43:503191 return []
rhalavati08acd232017-04-03 07:23:283192
Sam Maiera6e76d72022-02-11 21:43:503193 import sys
3194 # We need to wait until we have an input_api object and use this
3195 # roundabout construct to import checkdeps because this file is
3196 # eval-ed and thus doesn't have __file__.
3197 original_sys_path = sys.path
3198 try:
3199 sys.path = sys.path + [
3200 input_api.os_path.join(input_api.PresubmitLocalPath(),
3201 'buildtools', 'checkdeps')
3202 ]
3203 import checkdeps
3204 from rules import Rule
3205 finally:
3206 # Restore sys.path to what it was before.
3207 sys.path = original_sys_path
[email protected]55f9f382012-07-31 11:02:183208
Sam Maiera6e76d72022-02-11 21:43:503209 added_includes = []
3210 added_imports = []
3211 added_java_imports = []
3212 for f in input_api.AffectedFiles():
3213 if _IsCPlusPlusFile(input_api, f.LocalPath()):
3214 changed_lines = [line for _, line in f.ChangedContents()]
3215 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
3216 elif _IsProtoFile(input_api, f.LocalPath()):
3217 changed_lines = [line for _, line in f.ChangedContents()]
3218 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
3219 elif _IsJavaFile(input_api, f.LocalPath()):
3220 changed_lines = [line for _, line in f.ChangedContents()]
3221 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:243222
Sam Maiera6e76d72022-02-11 21:43:503223 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
3224
3225 error_descriptions = []
3226 warning_descriptions = []
3227 error_subjects = set()
3228 warning_subjects = set()
3229
3230 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
3231 added_includes):
3232 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3233 description_with_path = '%s\n %s' % (path, rule_description)
3234 if rule_type == Rule.DISALLOW:
3235 error_descriptions.append(description_with_path)
3236 error_subjects.add("#includes")
3237 else:
3238 warning_descriptions.append(description_with_path)
3239 warning_subjects.add("#includes")
3240
3241 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
3242 added_imports):
3243 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3244 description_with_path = '%s\n %s' % (path, rule_description)
3245 if rule_type == Rule.DISALLOW:
3246 error_descriptions.append(description_with_path)
3247 error_subjects.add("imports")
3248 else:
3249 warning_descriptions.append(description_with_path)
3250 warning_subjects.add("imports")
3251
3252 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
3253 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
3254 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3255 description_with_path = '%s\n %s' % (path, rule_description)
3256 if rule_type == Rule.DISALLOW:
3257 error_descriptions.append(description_with_path)
3258 error_subjects.add("imports")
3259 else:
3260 warning_descriptions.append(description_with_path)
3261 warning_subjects.add("imports")
3262
3263 results = []
3264 if error_descriptions:
3265 results.append(
3266 output_api.PresubmitError(
3267 'You added one or more %s that violate checkdeps rules.' %
3268 " and ".join(error_subjects), error_descriptions))
3269 if warning_descriptions:
3270 results.append(
3271 output_api.PresubmitPromptOrNotify(
3272 'You added one or more %s of files that are temporarily\n'
3273 'allowed but being removed. Can you avoid introducing the\n'
3274 '%s? See relevant DEPS file(s) for details and contacts.' %
3275 (" and ".join(warning_subjects), "/".join(warning_subjects)),
3276 warning_descriptions))
3277 return results
[email protected]55f9f382012-07-31 11:02:183278
3279
Saagar Sanghavifceeaae2020-08-12 16:40:363280def CheckFilePermissions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503281 """Check that all files have their permissions properly set."""
3282 if input_api.platform == 'win32':
3283 return []
3284 checkperms_tool = input_api.os_path.join(input_api.PresubmitLocalPath(),
3285 'tools', 'checkperms',
3286 'checkperms.py')
3287 args = [
Bruce Dawson8a43cf72022-05-13 17:10:323288 input_api.python3_executable, checkperms_tool, '--root',
Sam Maiera6e76d72022-02-11 21:43:503289 input_api.change.RepositoryRoot()
3290 ]
3291 with input_api.CreateTemporaryFile() as file_list:
3292 for f in input_api.AffectedFiles():
3293 # checkperms.py file/directory arguments must be relative to the
3294 # repository.
3295 file_list.write((f.LocalPath() + '\n').encode('utf8'))
3296 file_list.close()
3297 args += ['--file-list', file_list.name]
3298 try:
3299 input_api.subprocess.check_output(args)
3300 return []
3301 except input_api.subprocess.CalledProcessError as error:
3302 return [
3303 output_api.PresubmitError('checkperms.py failed:',
3304 long_text=error.output.decode(
3305 'utf-8', 'ignore'))
3306 ]
[email protected]fbcafe5a2012-08-08 15:31:223307
3308
Saagar Sanghavifceeaae2020-08-12 16:40:363309def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503310 """Makes sure we don't include ui/aura/window_property.h
3311 in header files.
3312 """
3313 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
3314 errors = []
3315 for f in input_api.AffectedFiles():
3316 if not f.LocalPath().endswith('.h'):
3317 continue
3318 for line_num, line in f.ChangedContents():
3319 if pattern.match(line):
3320 errors.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]c8278b32012-10-30 20:35:493321
Sam Maiera6e76d72022-02-11 21:43:503322 results = []
3323 if errors:
3324 results.append(
3325 output_api.PresubmitError(
3326 'Header files should not include ui/aura/window_property.h',
3327 errors))
3328 return results
[email protected]c8278b32012-10-30 20:35:493329
3330
Omer Katzcc77ea92021-04-26 10:23:283331def CheckNoInternalHeapIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503332 """Makes sure we don't include any headers from
3333 third_party/blink/renderer/platform/heap/impl or
3334 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
3335 third_party/blink/renderer/platform/heap
3336 """
3337 impl_pattern = input_api.re.compile(
3338 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
3339 v8_wrapper_pattern = input_api.re.compile(
3340 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"'
3341 )
3342 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:313343 r"^third_party/blink/renderer/platform/heap/.*",
Anton Bershanskyi4253349482025-02-11 21:01:273344 f.UnixLocalPath())
Sam Maiera6e76d72022-02-11 21:43:503345 errors = []
Omer Katzcc77ea92021-04-26 10:23:283346
Sam Maiera6e76d72022-02-11 21:43:503347 for f in input_api.AffectedFiles(file_filter=file_filter):
3348 for line_num, line in f.ChangedContents():
3349 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
3350 errors.append(' %s:%d' % (f.LocalPath(), line_num))
Omer Katzcc77ea92021-04-26 10:23:283351
Sam Maiera6e76d72022-02-11 21:43:503352 results = []
3353 if errors:
3354 results.append(
3355 output_api.PresubmitError(
3356 'Do not include files from third_party/blink/renderer/platform/heap/impl'
3357 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
3358 'relevant counterparts from third_party/blink/renderer/platform/heap',
3359 errors))
3360 return results
Omer Katzcc77ea92021-04-26 10:23:283361
3362
[email protected]70ca77752012-11-20 03:45:033363def _CheckForVersionControlConflictsInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:503364 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
3365 errors = []
3366 for line_num, line in f.ChangedContents():
3367 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
3368 # First-level headers in markdown look a lot like version control
3369 # conflict markers. http://daringfireball.net/projects/markdown/basics
3370 continue
3371 if pattern.match(line):
3372 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
3373 return errors
[email protected]70ca77752012-11-20 03:45:033374
3375
Saagar Sanghavifceeaae2020-08-12 16:40:363376def CheckForVersionControlConflicts(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503377 """Usually this is not intentional and will cause a compile failure."""
3378 errors = []
3379 for f in input_api.AffectedFiles():
3380 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
[email protected]70ca77752012-11-20 03:45:033381
Sam Maiera6e76d72022-02-11 21:43:503382 results = []
3383 if errors:
3384 results.append(
3385 output_api.PresubmitError(
3386 'Version control conflict markers found, please resolve.',
3387 errors))
3388 return results
[email protected]70ca77752012-11-20 03:45:033389
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203390
Saagar Sanghavifceeaae2020-08-12 16:40:363391def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
Dirk Prankee4df27972025-02-26 18:39:353392 pattern = input_api.re.compile(r'support\.google\.com\/chrome.*/answer')
Sam Maiera6e76d72022-02-11 21:43:503393 errors = []
3394 for f in input_api.AffectedFiles():
3395 for line_num, line in f.ChangedContents():
3396 if pattern.search(line):
3397 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
estadee17314a02017-01-12 16:22:163398
Sam Maiera6e76d72022-02-11 21:43:503399 results = []
3400 if errors:
3401 results.append(
3402 output_api.PresubmitPromptWarning(
3403 'Found Google support URL addressed by answer number. Please replace '
3404 'with a p= identifier instead. See crbug.com/679462\n',
3405 errors))
3406 return results
estadee17314a02017-01-12 16:22:163407
[email protected]70ca77752012-11-20 03:45:033408
Saagar Sanghavifceeaae2020-08-12 16:40:363409def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503410 def FilterFile(affected_file):
3411 """Filter function for use with input_api.AffectedSourceFiles,
3412 below. This filters out everything except non-test files from
3413 top-level directories that generally speaking should not hard-code
3414 service URLs (e.g. src/android_webview/, src/content/ and others).
3415 """
3416 return input_api.FilterSourceFile(
3417 affected_file,
Bruce Dawson40fece62022-09-16 19:58:313418 files_to_check=[r'^(android_webview|base|content|net)/.*'],
Sam Maiera6e76d72022-02-11 21:43:503419 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3420 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:443421
Dirk Prankee4df27972025-02-26 18:39:353422 base_pattern = (r'"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
3423 r'\.(com|net)[^"]*"')
Sam Maiera6e76d72022-02-11 21:43:503424 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
3425 pattern = input_api.re.compile(base_pattern)
3426 problems = [] # items are (filename, line_number, line)
3427 for f in input_api.AffectedSourceFiles(FilterFile):
3428 for line_num, line in f.ChangedContents():
3429 if not comment_pattern.search(line) and pattern.search(line):
3430 problems.append((f.LocalPath(), line_num, line))
[email protected]06e6d0ff2012-12-11 01:36:443431
Sam Maiera6e76d72022-02-11 21:43:503432 if problems:
3433 return [
3434 output_api.PresubmitPromptOrNotify(
3435 'Most layers below src/chrome/ should not hardcode service URLs.\n'
3436 'Are you sure this is correct?', [
3437 ' %s:%d: %s' % (problem[0], problem[1], problem[2])
3438 for problem in problems
3439 ])
3440 ]
3441 else:
3442 return []
[email protected]06e6d0ff2012-12-11 01:36:443443
3444
Saagar Sanghavifceeaae2020-08-12 16:40:363445def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503446 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
James Cook6b6597c2019-11-06 22:05:293447
Sam Maiera6e76d72022-02-11 21:43:503448 def FileFilter(affected_file):
3449 """Includes directories known to be Chrome OS only."""
3450 return input_api.FilterSourceFile(
3451 affected_file,
3452 files_to_check=(
3453 '^ash/',
3454 '^chromeos/', # Top-level src/chromeos.
3455 '.*/chromeos/', # Any path component.
3456 '^components/arc',
3457 '^components/exo'),
3458 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:293459
Sam Maiera6e76d72022-02-11 21:43:503460 prefs = []
3461 priority_prefs = []
3462 for f in input_api.AffectedFiles(file_filter=FileFilter):
3463 for line_num, line in f.ChangedContents():
3464 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF',
3465 line):
3466 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
3467 prefs.append(' %s' % line)
3468 if input_api.re.search(
3469 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
3470 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
3471 priority_prefs.append(' %s' % line)
3472
3473 results = []
3474 if (prefs):
3475 results.append(
3476 output_api.PresubmitPromptWarning(
3477 'Preferences were registered as SYNCABLE_PREF and will be controlled '
3478 'by browser sync settings. If these prefs should be controlled by OS '
3479 'sync settings use SYNCABLE_OS_PREF instead.\n' +
3480 '\n'.join(prefs)))
3481 if (priority_prefs):
3482 results.append(
3483 output_api.PresubmitPromptWarning(
3484 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
3485 'controlled by browser sync settings. If these prefs should be '
3486 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
3487 'instead.\n' + '\n'.join(prefs)))
3488 return results
James Cook6b6597c2019-11-06 22:05:293489
3490
Saagar Sanghavifceeaae2020-08-12 16:40:363491def CheckNoAbbreviationInPngFileName(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503492 """Makes sure there are no abbreviations in the name of PNG files.
3493 The native_client_sdk directory is excluded because it has auto-generated PNG
3494 files for documentation.
3495 """
3496 errors = []
Yuanqing Zhu9eef02832022-12-04 14:42:173497 files_to_check = [r'.*\.png$']
Bruce Dawson40fece62022-09-16 19:58:313498 files_to_skip = [r'^native_client_sdk/',
3499 r'^services/test/',
3500 r'^third_party/blink/web_tests/',
Bruce Dawson3db456212022-05-02 05:34:183501 ]
Sam Maiera6e76d72022-02-11 21:43:503502 file_filter = lambda f: input_api.FilterSourceFile(
3503 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Dirk Prankee4df27972025-02-26 18:39:353504 abbreviation = input_api.re.compile(r'.+_[a-z]\.png|.+_[a-z]_.*\.png')
Sam Maiera6e76d72022-02-11 21:43:503505 for f in input_api.AffectedFiles(include_deletes=False,
3506 file_filter=file_filter):
Yuanqing Zhu9eef02832022-12-04 14:42:173507 file_name = input_api.os_path.split(f.LocalPath())[1]
3508 if abbreviation.search(file_name):
3509 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:273510
Sam Maiera6e76d72022-02-11 21:43:503511 results = []
3512 if errors:
3513 results.append(
3514 output_api.PresubmitError(
3515 'The name of PNG files should not have abbreviations. \n'
3516 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
3517 'Contact [email protected] if you have questions.', errors))
3518 return results
[email protected]d2530012013-01-25 16:39:273519
Evan Stade7cd4a2c2022-08-04 23:37:253520def CheckNoProductIconsAddedToPublicRepo(input_api, output_api):
3521 """Heuristically identifies product icons based on their file name and reminds
3522 contributors not to add them to the Chromium repository.
3523 """
3524 errors = []
3525 files_to_check = [r'.*google.*\.png$|.*google.*\.svg$|.*google.*\.icon$']
3526 file_filter = lambda f: input_api.FilterSourceFile(
3527 f, files_to_check=files_to_check)
3528 for f in input_api.AffectedFiles(include_deletes=False,
3529 file_filter=file_filter):
3530 errors.append(' %s' % f.LocalPath())
3531
3532 results = []
3533 if errors:
Bruce Dawson3bcf0c92022-08-12 00:03:083534 # Give warnings instead of errors on presubmit --all and presubmit
3535 # --files.
3536 message_type = (output_api.PresubmitNotifyResult if input_api.no_diffs
3537 else output_api.PresubmitError)
Evan Stade7cd4a2c2022-08-04 23:37:253538 results.append(
Bruce Dawson3bcf0c92022-08-12 00:03:083539 message_type(
Evan Stade7cd4a2c2022-08-04 23:37:253540 'Trademarked images should not be added to the public repo. '
3541 'See crbug.com/944754', errors))
3542 return results
3543
[email protected]d2530012013-01-25 16:39:273544
Daniel Cheng4dcdb6b2017-04-13 08:30:173545def _ExtractAddRulesFromParsedDeps(parsed_deps):
Sam Maiera6e76d72022-02-11 21:43:503546 """Extract the rules that add dependencies from a parsed DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:173547
Sam Maiera6e76d72022-02-11 21:43:503548 Args:
3549 parsed_deps: the locals dictionary from evaluating the DEPS file."""
3550 add_rules = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:173551 add_rules.update([
Sam Maiera6e76d72022-02-11 21:43:503552 rule[1:] for rule in parsed_deps.get('include_rules', [])
Daniel Cheng4dcdb6b2017-04-13 08:30:173553 if rule.startswith('+') or rule.startswith('!')
3554 ])
Sam Maiera6e76d72022-02-11 21:43:503555 for _, rules in parsed_deps.get('specific_include_rules', {}).items():
3556 add_rules.update([
3557 rule[1:] for rule in rules
3558 if rule.startswith('+') or rule.startswith('!')
3559 ])
3560 return add_rules
Daniel Cheng4dcdb6b2017-04-13 08:30:173561
3562
3563def _ParseDeps(contents):
Sam Maiera6e76d72022-02-11 21:43:503564 """Simple helper for parsing DEPS files."""
Daniel Cheng4dcdb6b2017-04-13 08:30:173565
Sam Maiera6e76d72022-02-11 21:43:503566 # Stubs for handling special syntax in the root DEPS file.
3567 class _VarImpl:
3568 def __init__(self, local_scope):
3569 self._local_scope = local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:173570
Sam Maiera6e76d72022-02-11 21:43:503571 def Lookup(self, var_name):
3572 """Implements the Var syntax."""
3573 try:
3574 return self._local_scope['vars'][var_name]
3575 except KeyError:
3576 raise Exception('Var is not defined: %s' % var_name)
Daniel Cheng4dcdb6b2017-04-13 08:30:173577
Sam Maiera6e76d72022-02-11 21:43:503578 local_scope = {}
3579 global_scope = {
3580 'Var': _VarImpl(local_scope).Lookup,
3581 'Str': str,
3582 }
Dirk Pranke1b9e06382021-05-14 01:16:223583
Sam Maiera6e76d72022-02-11 21:43:503584 exec(contents, global_scope, local_scope)
3585 return local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:173586
3587
Andrew Grieveb77ac762024-11-29 15:01:483588def _FindAllDepsFilesForSubpath(input_api, subpath):
3589 ret = []
3590 while subpath:
3591 cur = input_api.os_path.join(input_api.change.RepositoryRoot(), subpath, 'DEPS')
Joanna Wang130e7bdd2024-12-10 17:39:033592 if input_api.os_path.isfile(cur):
Andrew Grieveb77ac762024-11-29 15:01:483593 ret.append(cur)
3594 subpath = input_api.os_path.dirname(subpath)
3595 return ret
3596
3597
3598def _FindAddedDepsThatRequireReview(input_api, depended_on_paths):
3599 """Filters to those whose DEPS set new_usages_require_review=True"""
3600 ret = set()
3601 cache = {}
3602 for target_path in depended_on_paths:
3603 for subpath in _FindAllDepsFilesForSubpath(input_api, target_path):
3604 config = cache.get(subpath)
3605 if config is None:
3606 config = _ParseDeps(input_api.ReadFile(subpath))
3607 cache[subpath] = config
3608 if config.get('new_usages_require_review'):
3609 ret.add(target_path)
3610 break
3611 return ret
3612
3613
Daniel Cheng4dcdb6b2017-04-13 08:30:173614def _CalculateAddedDeps(os_path, old_contents, new_contents):
Sam Maiera6e76d72022-02-11 21:43:503615 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
3616 a set of DEPS entries that we should look up.
[email protected]14a6131c2014-01-08 01:15:413617
Sam Maiera6e76d72022-02-11 21:43:503618 For a directory (rather than a specific filename) we fake a path to
3619 a specific filename by adding /DEPS. This is chosen as a file that
3620 will seldom or never be subject to per-file include_rules.
3621 """
3622 # We ignore deps entries on auto-generated directories.
3623 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:083624
Sam Maiera6e76d72022-02-11 21:43:503625 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
3626 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
Daniel Cheng4dcdb6b2017-04-13 08:30:173627
Sam Maiera6e76d72022-02-11 21:43:503628 added_deps = new_deps.difference(old_deps)
Daniel Cheng4dcdb6b2017-04-13 08:30:173629
Sam Maiera6e76d72022-02-11 21:43:503630 results = set()
3631 for added_dep in added_deps:
3632 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
3633 continue
3634 # Assume that a rule that ends in .h is a rule for a specific file.
3635 if added_dep.endswith('.h'):
3636 results.add(added_dep)
3637 else:
3638 results.add(os_path.join(added_dep, 'DEPS'))
3639 return results
[email protected]f32e2d1e2013-07-26 21:39:083640
Stephanie Kimec4f55a2024-04-24 16:54:023641def CheckForNewDEPSDownloadFromGoogleStorageHooks(input_api, output_api):
3642 """Checks that there are no new download_from_google_storage hooks"""
3643 for f in input_api.AffectedFiles(include_deletes=False):
3644 if f.LocalPath() == 'DEPS':
3645 old_hooks = _ParseDeps('\n'.join(f.OldContents()))['hooks']
3646 new_hooks = _ParseDeps('\n'.join(f.NewContents()))['hooks']
3647 old_name_to_hook = {hook['name']: hook for hook in old_hooks}
3648 new_name_to_hook = {hook['name']: hook for hook in new_hooks}
3649 added_hook_names = set(new_name_to_hook.keys()) - set(
3650 old_name_to_hook.keys())
3651 if not added_hook_names:
3652 return []
3653 new_download_from_google_storage_hooks = []
3654 for new_hook in added_hook_names:
3655 hook = new_name_to_hook[new_hook]
3656 action_cmd = hook['action']
3657 if any('download_from_google_storage' in arg
3658 for arg in action_cmd):
3659 new_download_from_google_storage_hooks.append(new_hook)
3660 if new_download_from_google_storage_hooks:
3661 return [
3662 output_api.PresubmitError(
3663 'Please do not add new download_from_google_storage '
3664 'hooks. Instead, add a `gcs` dep_type entry to `deps`. '
3665 'See https://chromium.googlesource.com/chromium/src.git'
3666 '/+/refs/heads/main/docs/gcs_dependencies.md for more '
3667 'info. Added hooks:',
3668 items=new_download_from_google_storage_hooks)
3669 ]
3670 return []
3671
[email protected]f32e2d1e2013-07-26 21:39:083672
Rasika Navarangec2d33d22024-05-23 15:19:023673def CheckEachPerfettoTestDataFileHasDepsEntry(input_api, output_api):
3674 test_data_filter = lambda f: input_api.FilterSourceFile(
Rasika Navarange08e542162024-05-31 13:31:263675 f, files_to_check=[r'^base/tracing/test/data_sha256/.*\.sha256'])
Rasika Navarangec2d33d22024-05-23 15:19:023676 if not any(input_api.AffectedFiles(file_filter=test_data_filter)):
3677 return []
3678
3679 # Find DEPS entry
3680 deps_entry = []
Rasika Navarange277cd662024-06-04 10:14:593681 old_deps_entry = []
Rasika Navarangec2d33d22024-05-23 15:19:023682 for f in input_api.AffectedFiles(include_deletes=False):
3683 if f.LocalPath() == 'DEPS':
3684 new_deps = _ParseDeps('\n'.join(f.NewContents()))['deps']
3685 deps_entry = new_deps['src/base/tracing/test/data']
Rasika Navarange277cd662024-06-04 10:14:593686 old_deps = _ParseDeps('\n'.join(f.OldContents()))['deps']
3687 old_deps_entry = old_deps['src/base/tracing/test/data']
Rasika Navarangec2d33d22024-05-23 15:19:023688 if not deps_entry:
Rasika Navarange08e542162024-05-31 13:31:263689 # TODO(312895063):Add back error when .sha256 files have been moved.
Rasika Navaranged977df342024-06-05 10:01:273690 return [output_api.PresubmitError(
Rasika Navarangec2d33d22024-05-23 15:19:023691 'You must update the DEPS file when you update a '
Rasika Navarange08e542162024-05-31 13:31:263692 '.sha256 file in base/tracing/test/data_sha256'
Rasika Navarangec2d33d22024-05-23 15:19:023693 )]
3694
3695 output = []
3696 for f in input_api.AffectedFiles(file_filter=test_data_filter):
3697 objects = deps_entry['objects']
3698 if not f.NewContents():
3699 # Deleted file so check that DEPS entry removed
3700 sha256_from_file = f.OldContents()[0]
3701 object_entry = next(
3702 (item for item in objects if item["sha256sum"] == sha256_from_file),
3703 None)
Rasika Navarange277cd662024-06-04 10:14:593704 old_entry = next(
3705 (item for item in old_deps_entry['objects'] if item["sha256sum"] == sha256_from_file),
3706 None)
Rasika Navarangec2d33d22024-05-23 15:19:023707 if object_entry:
Rasika Navarange277cd662024-06-04 10:14:593708 # Allow renaming of objects with the same hash
3709 if object_entry['object_name'] != old_entry['object_name']:
3710 continue
Rasika Navarangec2d33d22024-05-23 15:19:023711 output.append(output_api.PresubmitError(
3712 'You deleted %s so you must also remove the corresponding DEPS entry.'
3713 % f.LocalPath()
3714 ))
3715 continue
3716
3717 sha256_from_file = f.NewContents()[0]
3718 object_entry = next(
3719 (item for item in objects if item["sha256sum"] == sha256_from_file),
3720 None)
3721 if not object_entry:
3722 output.append(output_api.PresubmitError(
3723 'No corresponding DEPS entry found for %s. '
3724 'Run `base/tracing/test/test_data.py get_deps --filepath %s` '
3725 'to generate the DEPS entry.'
3726 % (f.LocalPath(), f.LocalPath())
3727 ))
3728
3729 if output:
3730 output.append(output_api.PresubmitError(
3731 'The DEPS entry for `src/base/tracing/test/data` in the DEPS file has not been '
3732 'updated properly. Run `base/tracing/test/test_data.py get_all_deps` to see what '
3733 'the DEPS entry should look like.'
3734 ))
3735 return output
3736
3737
Saagar Sanghavifceeaae2020-08-12 16:40:363738def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503739 """When a dependency prefixed with + is added to a DEPS file, we
3740 want to make sure that the change is reviewed by an OWNER of the
3741 target file or directory, to avoid layering violations from being
3742 introduced. This check verifies that this happens.
3743 """
3744 # We rely on Gerrit's code-owners to check approvals.
3745 # input_api.gerrit is always set for Chromium, but other projects
3746 # might not use Gerrit.
Bruce Dawson344ab262022-06-04 11:35:103747 if not input_api.gerrit or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:503748 return []
Bruce Dawsonb357aeb2022-08-09 15:38:303749 if 'PRESUBMIT_SKIP_NETWORK' in input_api.environ:
Sam Maiera6e76d72022-02-11 21:43:503750 return []
Bruce Dawsonb357aeb2022-08-09 15:38:303751 try:
3752 if (input_api.change.issue and
3753 input_api.gerrit.IsOwnersOverrideApproved(
3754 input_api.change.issue)):
3755 # Skip OWNERS check when Owners-Override label is approved. This is
3756 # intended for global owners, trusted bots, and on-call sheriffs.
3757 # Review is still required for these changes.
3758 return []
3759 except Exception as e:
Sam Maier4cef9242022-10-03 14:21:243760 return [output_api.PresubmitPromptWarning(
3761 'Failed to retrieve owner override status - %s' % str(e))]
Edward Lesmes6fba51082021-01-20 04:20:233762
Andrew Grieveb77ac762024-11-29 15:01:483763 # A set of paths (that might not exist) that are being added as DEPS
3764 # (via lines like "+foo/bar/baz").
3765 depended_on_paths = set()
jochen53efcdd2016-01-29 05:09:243766
Sam Maiera6e76d72022-02-11 21:43:503767 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:313768 r"^third_party/blink/.*",
Anton Bershanskyi4253349482025-02-11 21:01:273769 f.UnixLocalPath())
Sam Maiera6e76d72022-02-11 21:43:503770 for f in input_api.AffectedFiles(include_deletes=False,
3771 file_filter=file_filter):
3772 filename = input_api.os_path.basename(f.LocalPath())
3773 if filename == 'DEPS':
Andrew Grieveb77ac762024-11-29 15:01:483774 depended_on_paths.update(
Sam Maiera6e76d72022-02-11 21:43:503775 _CalculateAddedDeps(input_api.os_path,
3776 '\n'.join(f.OldContents()),
3777 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:553778
Andrew Grieveb77ac762024-11-29 15:01:483779 # Requiring reviews is opt-in as of https://crbug.com/365797506
3780 depended_on_paths = _FindAddedDepsThatRequireReview(input_api, depended_on_paths)
3781 if not depended_on_paths:
Sam Maiera6e76d72022-02-11 21:43:503782 return []
[email protected]e871964c2013-05-13 14:14:553783
Sam Maiera6e76d72022-02-11 21:43:503784 if input_api.is_committing:
3785 if input_api.tbr:
3786 return [
3787 output_api.PresubmitNotifyResult(
3788 '--tbr was specified, skipping OWNERS check for DEPS additions'
3789 )
3790 ]
Daniel Cheng3008dc12022-05-13 04:02:113791 # TODO(dcheng): Make this generate an error on dry runs if the reviewer
3792 # is not added, to prevent review serialization.
Sam Maiera6e76d72022-02-11 21:43:503793 if input_api.dry_run:
3794 return [
3795 output_api.PresubmitNotifyResult(
3796 'This is a dry run, skipping OWNERS check for DEPS additions'
3797 )
3798 ]
3799 if not input_api.change.issue:
3800 return [
3801 output_api.PresubmitError(
3802 "DEPS approval by OWNERS check failed: this change has "
3803 "no change number, so we can't check it for approvals.")
3804 ]
3805 output = output_api.PresubmitError
[email protected]14a6131c2014-01-08 01:15:413806 else:
Sam Maiera6e76d72022-02-11 21:43:503807 output = output_api.PresubmitNotifyResult
[email protected]e871964c2013-05-13 14:14:553808
Sam Maiera6e76d72022-02-11 21:43:503809 owner_email, reviewers = (
3810 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3811 input_api, None, approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:553812
Sam Maiera6e76d72022-02-11 21:43:503813 owner_email = owner_email or input_api.change.author_email
3814
3815 approval_status = input_api.owners_client.GetFilesApprovalStatus(
Andrew Grieveb77ac762024-11-29 15:01:483816 depended_on_paths, reviewers.union([owner_email]), [])
Sam Maiera6e76d72022-02-11 21:43:503817 missing_files = [
Andrew Grieveb77ac762024-11-29 15:01:483818 p for p in depended_on_paths
3819 if approval_status[p] != input_api.owners_client.APPROVED
Sam Maiera6e76d72022-02-11 21:43:503820 ]
3821
3822 # We strip the /DEPS part that was added by
3823 # _FilesToCheckForIncomingDeps to fake a path to a file in a
3824 # directory.
3825 def StripDeps(path):
3826 start_deps = path.rfind('/DEPS')
3827 if start_deps != -1:
3828 return path[:start_deps]
3829 else:
3830 return path
3831
Scott Leebf6a0942024-06-26 22:59:393832 submodule_paths = set(input_api.ListSubmodules())
3833 def is_from_submodules(path, submodule_paths):
3834 path = input_api.os_path.normpath(path)
3835 while path:
3836 if path in submodule_paths:
3837 return True
3838
3839 # All deps should be a relative path from the checkout.
3840 # i.e., shouldn't start with "/" or "c:\", for example.
3841 #
3842 # That said, this is to prevent an infinite loop, just in case
3843 # an input dep path starts with "/", because
3844 # os.path.dirname("/") => "/"
3845 parent = input_api.os_path.dirname(path)
3846 if parent == path:
3847 break
3848 path = parent
3849
3850 return False
3851
Sam Maiera6e76d72022-02-11 21:43:503852 unapproved_dependencies = [
3853 "'+%s'," % StripDeps(path) for path in missing_files
Scott Leebf6a0942024-06-26 22:59:393854 # if a newly added dep is from a submodule, it becomes trickier
3855 # to get suggested owners, especially it is from a different host.
3856 #
3857 # skip the review enforcement for cross-repo deps.
3858 if not is_from_submodules(path, submodule_paths)
Sam Maiera6e76d72022-02-11 21:43:503859 ]
3860
3861 if unapproved_dependencies:
3862 output_list = [
3863 output(
3864 'You need LGTM from owners of depends-on paths in DEPS that were '
3865 'modified in this CL:\n %s' %
3866 '\n '.join(sorted(unapproved_dependencies)))
3867 ]
3868 suggested_owners = input_api.owners_client.SuggestOwners(
3869 missing_files, exclude=[owner_email])
3870 output_list.append(
3871 output('Suggested missing target path OWNERS:\n %s' %
3872 '\n '.join(suggested_owners or [])))
3873 return output_list
3874
3875 return []
[email protected]e871964c2013-05-13 14:14:553876
3877
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493878# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:363879def CheckSpamLogging(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503880 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3881 files_to_skip = (
3882 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3883 input_api.DEFAULT_FILES_TO_SKIP + (
Jaewon Jung2f323bb2022-12-07 23:55:013884 r"^base/fuchsia/scoped_fx_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313885 r"^base/logging\.h$",
3886 r"^base/logging\.cc$",
3887 r"^base/task/thread_pool/task_tracker\.cc$",
3888 r"^chrome/app/chrome_main_delegate\.cc$",
Yao Li359937b2023-02-15 23:43:033889 r"^chrome/browser/ash/arc/enterprise/cert_store/arc_cert_installer\.cc$",
3890 r"^chrome/browser/ash/policy/remote_commands/user_command_arc_job\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313891 r"^chrome/browser/chrome_browser_main\.cc$",
3892 r"^chrome/browser/ui/startup/startup_browser_creator\.cc$",
3893 r"^chrome/browser/browser_switcher/bho/.*",
3894 r"^chrome/browser/diagnostics/diagnostics_writer\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313895 r"^chrome/chrome_elf/dll_hash/dll_hash_main\.cc$",
3896 r"^chrome/installer/setup/.*",
Daniel Ruberyad36eea2024-08-01 01:38:323897 # crdmg runs as a separate binary which intentionally does
3898 # not depend on base logging.
3899 r"^chrome/utility/safe_browsing/mac/crdmg\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313900 r"^chromecast/",
Vigen Issahhanjane2d93822023-06-30 15:57:203901 r"^components/cast",
Bruce Dawson40fece62022-09-16 19:58:313902 r"^components/media_control/renderer/media_playback_options\.cc$",
Salma Elmahallawy52976452023-01-27 17:04:493903 r"^components/policy/core/common/policy_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313904 r"^components/viz/service/display/"
Sam Maiera6e76d72022-02-11 21:43:503905 r"overlay_strategy_underlay_cast\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313906 r"^components/zucchini/.*",
Sam Maiera6e76d72022-02-11 21:43:503907 # TODO(peter): Remove exception. https://crbug.com/534537
Bruce Dawson40fece62022-09-16 19:58:313908 r"^content/browser/notifications/"
Sam Maiera6e76d72022-02-11 21:43:503909 r"notification_event_dispatcher_impl\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313910 r"^content/common/gpu/client/gl_helper_benchmark\.cc$",
3911 r"^courgette/courgette_minimal_tool\.cc$",
3912 r"^courgette/courgette_tool\.cc$",
3913 r"^extensions/renderer/logging_native_handler\.cc$",
3914 r"^fuchsia_web/common/init_logging\.cc$",
3915 r"^fuchsia_web/runners/common/web_component\.cc$",
Caroline Liua7050132023-02-13 22:23:153916 r"^fuchsia_web/shell/.*\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313917 r"^headless/app/headless_shell\.cc$",
3918 r"^ipc/ipc_logging\.cc$",
3919 r"^native_client_sdk/",
3920 r"^remoting/base/logging\.h$",
3921 r"^remoting/host/.*",
3922 r"^sandbox/linux/.*",
Austin Sullivana6054e02024-05-20 16:31:293923 r"^services/webnn/tflite/graph_impl_tflite\.cc$",
3924 r"^services/webnn/coreml/graph_impl_coreml\.mm$",
Bruce Dawson40fece62022-09-16 19:58:313925 r"^storage/browser/file_system/dump_file_system\.cc$",
Steinar H. Gundersone5689e42024-08-07 18:17:193926 r"^testing/perf/",
Bruce Dawson40fece62022-09-16 19:58:313927 r"^tools/",
3928 r"^ui/base/resource/data_pack\.cc$",
3929 r"^ui/aura/bench/bench_main\.cc$",
3930 r"^ui/ozone/platform/cast/",
3931 r"^ui/base/x/xwmstartupcheck/"
Sam Maiera6e76d72022-02-11 21:43:503932 r"xwmstartupcheck\.cc$"))
3933 source_file_filter = lambda x: input_api.FilterSourceFile(
3934 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:403935
Sam Maiera6e76d72022-02-11 21:43:503936 log_info = set([])
3937 printf = set([])
[email protected]85218562013-11-22 07:41:403938
Sam Maiera6e76d72022-02-11 21:43:503939 for f in input_api.AffectedSourceFiles(source_file_filter):
3940 for _, line in f.ChangedContents():
3941 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
3942 log_info.add(f.LocalPath())
3943 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
3944 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:373945
Sam Maiera6e76d72022-02-11 21:43:503946 if input_api.re.search(r"\bprintf\(", line):
3947 printf.add(f.LocalPath())
3948 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
3949 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:403950
Sam Maiera6e76d72022-02-11 21:43:503951 if log_info:
3952 return [
3953 output_api.PresubmitError(
3954 'These files spam the console log with LOG(INFO):',
3955 items=log_info)
3956 ]
3957 if printf:
3958 return [
3959 output_api.PresubmitError(
3960 'These files spam the console log with printf/fprintf:',
3961 items=printf)
3962 ]
3963 return []
[email protected]85218562013-11-22 07:41:403964
3965
Saagar Sanghavifceeaae2020-08-12 16:40:363966def CheckForAnonymousVariables(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503967 """These types are all expected to hold locks while in scope and
3968 so should never be anonymous (which causes them to be immediately
3969 destroyed)."""
3970 they_who_must_be_named = [
3971 'base::AutoLock',
3972 'base::AutoReset',
3973 'base::AutoUnlock',
3974 'SkAutoAlphaRestore',
3975 'SkAutoBitmapShaderInstall',
3976 'SkAutoBlitterChoose',
3977 'SkAutoBounderCommit',
3978 'SkAutoCallProc',
3979 'SkAutoCanvasRestore',
3980 'SkAutoCommentBlock',
3981 'SkAutoDescriptor',
3982 'SkAutoDisableDirectionCheck',
3983 'SkAutoDisableOvalCheck',
3984 'SkAutoFree',
3985 'SkAutoGlyphCache',
3986 'SkAutoHDC',
3987 'SkAutoLockColors',
3988 'SkAutoLockPixels',
3989 'SkAutoMalloc',
3990 'SkAutoMaskFreeImage',
3991 'SkAutoMutexAcquire',
3992 'SkAutoPathBoundsUpdate',
3993 'SkAutoPDFRelease',
3994 'SkAutoRasterClipValidate',
3995 'SkAutoRef',
3996 'SkAutoTime',
3997 'SkAutoTrace',
3998 'SkAutoUnref',
3999 ]
4000 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
4001 # bad: base::AutoLock(lock.get());
4002 # not bad: base::AutoLock lock(lock.get());
4003 bad_pattern = input_api.re.compile(anonymous)
4004 # good: new base::AutoLock(lock.get())
4005 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
4006 errors = []
[email protected]49aa76a2013-12-04 06:59:164007
Sam Maiera6e76d72022-02-11 21:43:504008 for f in input_api.AffectedFiles():
4009 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
4010 continue
4011 for linenum, line in f.ChangedContents():
4012 if bad_pattern.search(line) and not good_pattern.search(line):
4013 errors.append('%s:%d' % (f.LocalPath(), linenum))
[email protected]49aa76a2013-12-04 06:59:164014
Sam Maiera6e76d72022-02-11 21:43:504015 if errors:
4016 return [
4017 output_api.PresubmitError(
4018 'These lines create anonymous variables that need to be named:',
4019 items=errors)
4020 ]
4021 return []
[email protected]49aa76a2013-12-04 06:59:164022
4023
Saagar Sanghavifceeaae2020-08-12 16:40:364024def CheckUniquePtrOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504025 # Returns whether |template_str| is of the form <T, U...> for some types T
Glen Robertson9142ffd72024-05-16 01:37:474026 # and U, or is invalid due to mismatched angle bracket pairs. Assumes that
4027 # |template_str| is already in the form <...>.
4028 def HasMoreThanOneArgOrInvalid(template_str):
Sam Maiera6e76d72022-02-11 21:43:504029 # Level of <...> nesting.
4030 nesting = 0
4031 for c in template_str:
4032 if c == '<':
4033 nesting += 1
4034 elif c == '>':
4035 nesting -= 1
4036 elif c == ',' and nesting == 1:
4037 return True
Glen Robertson9142ffd72024-05-16 01:37:474038 if nesting != 0:
Daniel Cheng566634ff2024-06-29 14:56:534039 # Invalid.
4040 return True
Sam Maiera6e76d72022-02-11 21:43:504041 return False
Vaclav Brozekb7fadb692018-08-30 06:39:534042
Sam Maiera6e76d72022-02-11 21:43:504043 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
4044 sources = lambda affected_file: input_api.FilterSourceFile(
4045 affected_file,
4046 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4047 DEFAULT_FILES_TO_SKIP),
4048 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:554049
Sam Maiera6e76d72022-02-11 21:43:504050 # Pattern to capture a single "<...>" block of template arguments. It can
4051 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
4052 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
4053 # latter would likely require counting that < and > match, which is not
4054 # expressible in regular languages. Should the need arise, one can introduce
4055 # limited counting (matching up to a total number of nesting depth), which
4056 # should cover all practical cases for already a low nesting limit.
4057 template_arg_pattern = (
4058 r'<[^>]*' # Opening block of <.
4059 r'>([^<]*>)?') # Closing block of >.
4060 # Prefix expressing that whatever follows is not already inside a <...>
4061 # block.
4062 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
4063 null_construct_pattern = input_api.re.compile(
4064 not_inside_template_arg_pattern + r'\bstd::unique_ptr' +
4065 template_arg_pattern + r'\(\)')
Vaclav Brozeka54c528b2018-04-06 19:23:554066
Sam Maiera6e76d72022-02-11 21:43:504067 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
4068 template_arg_no_array_pattern = (
4069 r'<[^>]*[^]]' # Opening block of <.
4070 r'>([^(<]*[^]]>)?') # Closing block of >.
4071 # Prefix saying that what follows is the start of an expression.
4072 start_of_expr_pattern = r'(=|\breturn|^)\s*'
4073 # Suffix saying that what follows are call parentheses with a non-empty list
4074 # of arguments.
4075 nonempty_arg_list_pattern = r'\(([^)]|$)'
4076 # Put the template argument into a capture group for deeper examination later.
4077 return_construct_pattern = input_api.re.compile(
4078 start_of_expr_pattern + r'std::unique_ptr' + '(?P<template_arg>' +
4079 template_arg_no_array_pattern + ')' + nonempty_arg_list_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:554080
Sam Maiera6e76d72022-02-11 21:43:504081 problems_constructor = []
4082 problems_nullptr = []
4083 for f in input_api.AffectedSourceFiles(sources):
4084 for line_number, line in f.ChangedContents():
4085 # Disallow:
4086 # return std::unique_ptr<T>(foo);
4087 # bar = std::unique_ptr<T>(foo);
4088 # But allow:
4089 # return std::unique_ptr<T[]>(foo);
4090 # bar = std::unique_ptr<T[]>(foo);
4091 # And also allow cases when the second template argument is present. Those
4092 # cases cannot be handled by std::make_unique:
4093 # return std::unique_ptr<T, U>(foo);
4094 # bar = std::unique_ptr<T, U>(foo);
4095 local_path = f.LocalPath()
4096 return_construct_result = return_construct_pattern.search(line)
Glen Robertson9142ffd72024-05-16 01:37:474097 if return_construct_result and not HasMoreThanOneArgOrInvalid(
Sam Maiera6e76d72022-02-11 21:43:504098 return_construct_result.group('template_arg')):
4099 problems_constructor.append(
4100 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4101 # Disallow:
4102 # std::unique_ptr<T>()
4103 if null_construct_pattern.search(line):
4104 problems_nullptr.append(
4105 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Vaclav Brozek851d9602018-04-04 16:13:054106
Sam Maiera6e76d72022-02-11 21:43:504107 errors = []
4108 if problems_nullptr:
4109 errors.append(
4110 output_api.PresubmitPromptWarning(
4111 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
4112 problems_nullptr))
4113 if problems_constructor:
4114 errors.append(
4115 output_api.PresubmitError(
4116 'The following files use explicit std::unique_ptr constructor. '
4117 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
4118 'std::make_unique is not an option.', problems_constructor))
4119 return errors
Peter Kasting4844e46e2018-02-23 07:27:104120
4121
Saagar Sanghavifceeaae2020-08-12 16:40:364122def CheckUserActionUpdate(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504123 """Checks if any new user action has been added."""
4124 if any('actions.xml' == input_api.os_path.basename(f)
4125 for f in input_api.LocalPaths()):
4126 # If actions.xml is already included in the changelist, the PRESUBMIT
4127 # for actions.xml will do a more complete presubmit check.
4128 return []
4129
4130 file_inclusion_pattern = [r'.*\.(cc|mm)$']
4131 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
4132 input_api.DEFAULT_FILES_TO_SKIP)
4133 file_filter = lambda f: input_api.FilterSourceFile(
4134 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
4135
4136 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
4137 current_actions = None
4138 for f in input_api.AffectedFiles(file_filter=file_filter):
4139 for line_num, line in f.ChangedContents():
4140 match = input_api.re.search(action_re, line)
4141 if match:
4142 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
4143 # loaded only once.
4144 if not current_actions:
Bruce Dawson6cb2d4d2023-03-01 21:35:094145 with open('tools/metrics/actions/actions.xml',
4146 encoding='utf-8') as actions_f:
Sam Maiera6e76d72022-02-11 21:43:504147 current_actions = actions_f.read()
4148 # Search for the matched user action name in |current_actions|.
4149 for action_name in match.groups():
4150 action = 'name="{0}"'.format(action_name)
4151 if action not in current_actions:
4152 return [
4153 output_api.PresubmitPromptWarning(
4154 'File %s line %d: %s is missing in '
4155 'tools/metrics/actions/actions.xml. Please run '
4156 'tools/metrics/actions/extract_actions.py to update.'
4157 % (f.LocalPath(), line_num, action_name))
4158 ]
[email protected]999261d2014-03-03 20:08:084159 return []
4160
[email protected]999261d2014-03-03 20:08:084161
Daniel Cheng13ca61a882017-08-25 15:11:254162def _ImportJSONCommentEater(input_api):
Sam Maiera6e76d72022-02-11 21:43:504163 import sys
4164 sys.path = sys.path + [
4165 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4166 'json_comment_eater')
4167 ]
4168 import json_comment_eater
4169 return json_comment_eater
Daniel Cheng13ca61a882017-08-25 15:11:254170
4171
[email protected]99171a92014-06-03 08:44:474172def _GetJSONParseError(input_api, filename, eat_comments=True):
dchenge07de812016-06-20 19:27:174173 try:
Sam Maiera6e76d72022-02-11 21:43:504174 contents = input_api.ReadFile(filename)
4175 if eat_comments:
4176 json_comment_eater = _ImportJSONCommentEater(input_api)
4177 contents = json_comment_eater.Nom(contents)
dchenge07de812016-06-20 19:27:174178
Sam Maiera6e76d72022-02-11 21:43:504179 input_api.json.loads(contents)
4180 except ValueError as e:
4181 return e
Andrew Grieve4deedb12022-02-03 21:34:504182 return None
4183
4184
Sam Maiera6e76d72022-02-11 21:43:504185def _GetIDLParseError(input_api, filename):
4186 try:
4187 contents = input_api.ReadFile(filename)
Devlin Croninf7582a12022-04-21 21:14:284188 for i, char in enumerate(contents):
Daniel Chenga37c03db2022-05-12 17:20:344189 if not char.isascii():
4190 return (
4191 'Non-ascii character "%s" (ord %d) found at offset %d.' %
4192 (char, ord(char), i))
Sam Maiera6e76d72022-02-11 21:43:504193 idl_schema = input_api.os_path.join(input_api.PresubmitLocalPath(),
4194 'tools', 'json_schema_compiler',
4195 'idl_schema.py')
4196 process = input_api.subprocess.Popen(
Bruce Dawson679fb082022-04-14 00:47:284197 [input_api.python3_executable, idl_schema],
Sam Maiera6e76d72022-02-11 21:43:504198 stdin=input_api.subprocess.PIPE,
4199 stdout=input_api.subprocess.PIPE,
4200 stderr=input_api.subprocess.PIPE,
4201 universal_newlines=True)
4202 (_, error) = process.communicate(input=contents)
4203 return error or None
4204 except ValueError as e:
4205 return e
agrievef32bcc72016-04-04 14:57:404206
agrievef32bcc72016-04-04 14:57:404207
Sam Maiera6e76d72022-02-11 21:43:504208def CheckParseErrors(input_api, output_api):
4209 """Check that IDL and JSON files do not contain syntax errors."""
4210 actions = {
4211 '.idl': _GetIDLParseError,
4212 '.json': _GetJSONParseError,
4213 }
4214 # Most JSON files are preprocessed and support comments, but these do not.
4215 json_no_comments_patterns = [
Bruce Dawson40fece62022-09-16 19:58:314216 r'^testing/',
Sam Maiera6e76d72022-02-11 21:43:504217 ]
4218 # Only run IDL checker on files in these directories.
4219 idl_included_patterns = [
Bruce Dawson40fece62022-09-16 19:58:314220 r'^chrome/common/extensions/api/',
4221 r'^extensions/common/api/',
Sam Maiera6e76d72022-02-11 21:43:504222 ]
agrievef32bcc72016-04-04 14:57:404223
Sam Maiera6e76d72022-02-11 21:43:504224 def get_action(affected_file):
4225 filename = affected_file.LocalPath()
4226 return actions.get(input_api.os_path.splitext(filename)[1])
agrievef32bcc72016-04-04 14:57:404227
Sam Maiera6e76d72022-02-11 21:43:504228 def FilterFile(affected_file):
4229 action = get_action(affected_file)
4230 if not action:
4231 return False
Anton Bershanskyi4253349482025-02-11 21:01:274232 path = affected_file.UnixLocalPath()
agrievef32bcc72016-04-04 14:57:404233
Sam Maiera6e76d72022-02-11 21:43:504234 if _MatchesFile(input_api,
4235 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS, path):
4236 return False
4237
4238 if (action == _GetIDLParseError
4239 and not _MatchesFile(input_api, idl_included_patterns, path)):
4240 return False
4241 return True
4242
4243 results = []
4244 for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
4245 include_deletes=False):
4246 action = get_action(affected_file)
4247 kwargs = {}
4248 if (action == _GetJSONParseError
4249 and _MatchesFile(input_api, json_no_comments_patterns,
Anton Bershanskyi4253349482025-02-11 21:01:274250 affected_file.UnixLocalPath())):
Sam Maiera6e76d72022-02-11 21:43:504251 kwargs['eat_comments'] = False
4252 parse_error = action(input_api, affected_file.AbsoluteLocalPath(),
4253 **kwargs)
4254 if parse_error:
4255 results.append(
4256 output_api.PresubmitError(
4257 '%s could not be parsed: %s' %
4258 (affected_file.LocalPath(), parse_error)))
4259 return results
4260
4261
4262def CheckJavaStyle(input_api, output_api):
4263 """Runs checkstyle on changed java files and returns errors if any exist."""
4264
4265 # Return early if no java files were modified.
4266 if not any(
4267 _IsJavaFile(input_api, f.LocalPath())
4268 for f in input_api.AffectedFiles()):
4269 return []
4270
4271 import sys
4272 original_sys_path = sys.path
4273 try:
4274 sys.path = sys.path + [
4275 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4276 'android', 'checkstyle')
4277 ]
4278 import checkstyle
4279 finally:
4280 # Restore sys.path to what it was before.
4281 sys.path = original_sys_path
4282
Andrew Grieve4f88e3ca2022-11-22 19:09:204283 return checkstyle.run_presubmit(
Sam Maiera6e76d72022-02-11 21:43:504284 input_api,
4285 output_api,
Sam Maiera6e76d72022-02-11 21:43:504286 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
4287
4288
4289def CheckPythonDevilInit(input_api, output_api):
4290 """Checks to make sure devil is initialized correctly in python scripts."""
4291 script_common_initialize_pattern = input_api.re.compile(
4292 r'script_common\.InitializeEnvironment\(')
4293 devil_env_config_initialize = input_api.re.compile(
4294 r'devil_env\.config\.Initialize\(')
4295
4296 errors = []
4297
4298 sources = lambda affected_file: input_api.FilterSourceFile(
4299 affected_file,
4300 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314301 r'^build/android/devil_chromium\.py',
Sven Zheng8e079562024-05-10 20:11:064302 r'^tools/bisect-builds\.py',
Bruce Dawson40fece62022-09-16 19:58:314303 r'^third_party/.*',
Sam Maiera6e76d72022-02-11 21:43:504304 )),
4305 files_to_check=[r'.*\.py$'])
4306
4307 for f in input_api.AffectedSourceFiles(sources):
4308 for line_num, line in f.ChangedContents():
4309 if (script_common_initialize_pattern.search(line)
4310 or devil_env_config_initialize.search(line)):
4311 errors.append("%s:%d" % (f.LocalPath(), line_num))
4312
4313 results = []
4314
4315 if errors:
4316 results.append(
4317 output_api.PresubmitError(
4318 'Devil initialization should always be done using '
4319 'devil_chromium.Initialize() in the chromium project, to use better '
4320 'defaults for dependencies (ex. up-to-date version of adb).',
4321 errors))
4322
4323 return results
4324
4325
4326def _MatchesFile(input_api, patterns, path):
4327 for pattern in patterns:
4328 if input_api.re.search(pattern, path):
4329 return True
4330 return False
4331
4332
Daniel Chenga37c03db2022-05-12 17:20:344333def _ChangeHasSecurityReviewer(input_api, owners_file):
4334 """Returns True iff the CL has a reviewer from SECURITY_OWNERS.
Sam Maiera6e76d72022-02-11 21:43:504335
Daniel Chenga37c03db2022-05-12 17:20:344336 Args:
4337 input_api: The presubmit input API.
4338 owners_file: OWNERS file with required reviewers. Typically, this is
4339 something like ipc/SECURITY_OWNERS.
4340
4341 Note: if the presubmit is running for commit rather than for upload, this
4342 only returns True if a security reviewer has also approved the CL.
Sam Maiera6e76d72022-02-11 21:43:504343 """
Daniel Chengd88244472022-05-16 09:08:474344 # Owners-Override should bypass all additional OWNERS enforcement checks.
4345 # A CR+1 vote will still be required to land this change.
4346 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
4347 input_api.change.issue)):
4348 return True
4349
Daniel Chenga37c03db2022-05-12 17:20:344350 owner_email, reviewers = (
4351 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
Daniel Cheng3008dc12022-05-13 04:02:114352 input_api,
4353 None,
4354 approval_needed=input_api.is_committing and not input_api.dry_run))
Sam Maiera6e76d72022-02-11 21:43:504355
Daniel Chenga37c03db2022-05-12 17:20:344356 security_owners = input_api.owners_client.ListOwners(owners_file)
4357 return any(owner in reviewers for owner in security_owners)
Sam Maiera6e76d72022-02-11 21:43:504358
Daniel Chenga37c03db2022-05-12 17:20:344359
4360@dataclass
Daniel Cheng171dad8d2022-05-21 00:40:254361class _SecurityProblemWithItems:
4362 problem: str
4363 items: Sequence[str]
4364
4365
4366@dataclass
Daniel Chenga37c03db2022-05-12 17:20:344367class _MissingSecurityOwnersResult:
Daniel Cheng171dad8d2022-05-21 00:40:254368 owners_file_problems: Sequence[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:344369 has_security_sensitive_files: bool
Daniel Cheng171dad8d2022-05-21 00:40:254370 missing_reviewer_problem: Optional[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:344371
4372
4373def _FindMissingSecurityOwners(input_api,
4374 output_api,
4375 file_patterns: Sequence[str],
4376 excluded_patterns: Sequence[str],
4377 required_owners_file: str,
4378 custom_rule_function: Optional[Callable] = None
4379 ) -> _MissingSecurityOwnersResult:
4380 """Find OWNERS files missing per-file rules for security-sensitive files.
4381
4382 Args:
4383 input_api: the PRESUBMIT input API object.
4384 output_api: the PRESUBMIT output API object.
4385 file_patterns: basename patterns that require a corresponding per-file
4386 security restriction.
4387 excluded_patterns: path patterns that should be exempted from
4388 requiring a security restriction.
4389 required_owners_file: path to the required OWNERS file, e.g.
4390 ipc/SECURITY_OWNERS
4391 cc_alias: If not None, email that will be CCed automatically if the
4392 change contains security-sensitive files, as determined by
4393 `file_patterns` and `excluded_patterns`.
4394 custom_rule_function: If not None, will be called with `input_api` and
4395 the current file under consideration. Returning True will add an
4396 exact match per-file rule check for the current file.
4397 """
4398
4399 # `to_check` is a mapping of an OWNERS file path to Patterns.
4400 #
4401 # Patterns is a dictionary mapping glob patterns (suitable for use in
4402 # per-file rules) to a PatternEntry.
4403 #
Sam Maiera6e76d72022-02-11 21:43:504404 # PatternEntry is a dictionary with two keys:
4405 # - 'files': the files that are matched by this pattern
4406 # - 'rules': the per-file rules needed for this pattern
Daniel Chenga37c03db2022-05-12 17:20:344407 #
Sam Maiera6e76d72022-02-11 21:43:504408 # For example, if we expect OWNERS file to contain rules for *.mojom and
4409 # *_struct_traits*.*, Patterns might look like this:
4410 # {
4411 # '*.mojom': {
4412 # 'files': ...,
4413 # 'rules': [
4414 # 'per-file *.mojom=set noparent',
4415 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
4416 # ],
4417 # },
4418 # '*_struct_traits*.*': {
4419 # 'files': ...,
4420 # 'rules': [
4421 # 'per-file *_struct_traits*.*=set noparent',
4422 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
4423 # ],
4424 # },
4425 # }
4426 to_check = {}
Daniel Chenga37c03db2022-05-12 17:20:344427 files_to_review = []
Sam Maiera6e76d72022-02-11 21:43:504428
Daniel Chenga37c03db2022-05-12 17:20:344429 def AddPatternToCheck(file, pattern):
Sam Maiera6e76d72022-02-11 21:43:504430 owners_file = input_api.os_path.join(
Daniel Chengd88244472022-05-16 09:08:474431 input_api.os_path.dirname(file.LocalPath()), 'OWNERS')
Sam Maiera6e76d72022-02-11 21:43:504432 if owners_file not in to_check:
4433 to_check[owners_file] = {}
4434 if pattern not in to_check[owners_file]:
4435 to_check[owners_file][pattern] = {
4436 'files': [],
4437 'rules': [
Daniel Chenga37c03db2022-05-12 17:20:344438 f'per-file {pattern}=set noparent',
4439 f'per-file {pattern}=file://{required_owners_file}',
Sam Maiera6e76d72022-02-11 21:43:504440 ]
4441 }
Daniel Chenged57a162022-05-25 02:56:344442 to_check[owners_file][pattern]['files'].append(file.LocalPath())
Daniel Chenga37c03db2022-05-12 17:20:344443 files_to_review.append(file.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:504444
Daniel Chenga37c03db2022-05-12 17:20:344445 # Only enforce security OWNERS rules for a directory if that directory has a
4446 # file that matches `file_patterns`. For example, if a directory only
4447 # contains *.mojom files and no *_messages*.h files, the check should only
4448 # ensure that rules for *.mojom files are present.
4449 for file in input_api.AffectedFiles(include_deletes=False):
4450 file_basename = input_api.os_path.basename(file.LocalPath())
4451 if custom_rule_function is not None and custom_rule_function(
4452 input_api, file):
4453 AddPatternToCheck(file, file_basename)
4454 continue
Sam Maiera6e76d72022-02-11 21:43:504455
Daniel Chenga37c03db2022-05-12 17:20:344456 if any(
4457 input_api.fnmatch.fnmatch(file.LocalPath(), pattern)
4458 for pattern in excluded_patterns):
Sam Maiera6e76d72022-02-11 21:43:504459 continue
4460
4461 for pattern in file_patterns:
Daniel Chenga37c03db2022-05-12 17:20:344462 # Unlike `excluded_patterns`, `file_patterns` is checked only against the
4463 # file's basename.
4464 if input_api.fnmatch.fnmatch(file_basename, pattern):
4465 AddPatternToCheck(file, pattern)
Sam Maiera6e76d72022-02-11 21:43:504466 break
4467
Daniel Chenga37c03db2022-05-12 17:20:344468 has_security_sensitive_files = bool(to_check)
Daniel Cheng171dad8d2022-05-21 00:40:254469
4470 # Check if any newly added lines in OWNERS files intersect with required
4471 # per-file OWNERS lines. If so, ensure that a security reviewer is included.
4472 # This is a hack, but is needed because the OWNERS check (by design) ignores
4473 # new OWNERS entries; otherwise, a non-owner could add someone as a new
4474 # OWNER and have that newly-added OWNER self-approve their own addition.
4475 newly_covered_files = []
4476 for file in input_api.AffectedFiles(include_deletes=False):
4477 if not file.LocalPath() in to_check:
4478 continue
4479 for _, line in file.ChangedContents():
4480 for _, entry in to_check[file.LocalPath()].items():
4481 if line in entry['rules']:
4482 newly_covered_files.extend(entry['files'])
4483
4484 missing_reviewer_problems = None
4485 if newly_covered_files and not _ChangeHasSecurityReviewer(
Daniel Chenga37c03db2022-05-12 17:20:344486 input_api, required_owners_file):
Daniel Cheng171dad8d2022-05-21 00:40:254487 missing_reviewer_problems = _SecurityProblemWithItems(
4488 f'Review from an owner in {required_owners_file} is required for '
4489 'the following newly-added files:',
4490 [f'{file}' for file in sorted(set(newly_covered_files))])
Sam Maiera6e76d72022-02-11 21:43:504491
4492 # Go through the OWNERS files to check, filtering out rules that are already
4493 # present in that OWNERS file.
4494 for owners_file, patterns in to_check.items():
4495 try:
Daniel Cheng171dad8d2022-05-21 00:40:254496 lines = set(
4497 input_api.ReadFile(
4498 input_api.os_path.join(input_api.change.RepositoryRoot(),
4499 owners_file)).splitlines())
4500 for entry in patterns.values():
4501 entry['rules'] = [
4502 rule for rule in entry['rules'] if rule not in lines
4503 ]
Sam Maiera6e76d72022-02-11 21:43:504504 except IOError:
4505 # No OWNERS file, so all the rules are definitely missing.
4506 continue
4507
4508 # All the remaining lines weren't found in OWNERS files, so emit an error.
Daniel Cheng171dad8d2022-05-21 00:40:254509 owners_file_problems = []
Daniel Chenga37c03db2022-05-12 17:20:344510
Sam Maiera6e76d72022-02-11 21:43:504511 for owners_file, patterns in to_check.items():
4512 missing_lines = []
4513 files = []
4514 for _, entry in patterns.items():
Daniel Chenged57a162022-05-25 02:56:344515 files.extend(entry['files'])
Sam Maiera6e76d72022-02-11 21:43:504516 missing_lines.extend(entry['rules'])
Sam Maiera6e76d72022-02-11 21:43:504517 if missing_lines:
Daniel Cheng171dad8d2022-05-21 00:40:254518 joined_missing_lines = '\n'.join(line for line in missing_lines)
4519 owners_file_problems.append(
4520 _SecurityProblemWithItems(
4521 'Found missing OWNERS lines for security-sensitive files. '
4522 f'Please add the following lines to {owners_file}:\n'
4523 f'{joined_missing_lines}\n\nTo ensure security review for:',
4524 files))
Daniel Chenga37c03db2022-05-12 17:20:344525
Daniel Cheng171dad8d2022-05-21 00:40:254526 return _MissingSecurityOwnersResult(owners_file_problems,
Daniel Chenga37c03db2022-05-12 17:20:344527 has_security_sensitive_files,
Daniel Cheng171dad8d2022-05-21 00:40:254528 missing_reviewer_problems)
Daniel Chenga37c03db2022-05-12 17:20:344529
4530
4531def _CheckChangeForIpcSecurityOwners(input_api, output_api):
4532 # Whether or not a file affects IPC is (mostly) determined by a simple list
4533 # of filename patterns.
4534 file_patterns = [
4535 # Legacy IPC:
4536 '*_messages.cc',
4537 '*_messages*.h',
4538 '*_param_traits*.*',
4539 # Mojo IPC:
4540 '*.mojom',
4541 '*_mojom_traits*.*',
4542 '*_type_converter*.*',
4543 # Android native IPC:
4544 '*.aidl',
4545 ]
4546
Daniel Chenga37c03db2022-05-12 17:20:344547 excluded_patterns = [
Daniel Cheng518943f2022-05-12 22:15:464548 # These third_party directories do not contain IPCs, but contain files
4549 # matching the above patterns, which trigger false positives.
Daniel Chenga37c03db2022-05-12 17:20:344550 'third_party/crashpad/*',
4551 'third_party/blink/renderer/platform/bindings/*',
Evan Stade23a77da2025-02-06 21:15:314552 'third_party/protobuf/*',
Daniel Chenga37c03db2022-05-12 17:20:344553 'third_party/win_build_output/*',
Daniel Chengd88244472022-05-16 09:08:474554 # Enum-only mojoms used for web metrics, so no security review needed.
4555 'third_party/blink/public/mojom/use_counter/metrics/*',
Daniel Chenga37c03db2022-05-12 17:20:344556 # These files are just used to communicate between class loaders running
4557 # in the same process.
4558 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
4559 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
4560 ]
4561
4562 def IsMojoServiceManifestFile(input_api, file):
Dirk Prankee4df27972025-02-26 18:39:354563 manifest_pattern = input_api.re.compile(r'manifests?\.(cc|h)$')
4564 test_manifest_pattern = input_api.re.compile(r'test_manifests?\.(cc|h)')
Daniel Chenga37c03db2022-05-12 17:20:344565 if not manifest_pattern.search(file.LocalPath()):
4566 return False
4567
4568 if test_manifest_pattern.search(file.LocalPath()):
4569 return False
4570
4571 # All actual service manifest files should contain at least one
4572 # qualified reference to service_manager::Manifest.
4573 return any('service_manager::Manifest' in line
4574 for line in file.NewContents())
4575
4576 return _FindMissingSecurityOwners(
4577 input_api,
4578 output_api,
4579 file_patterns,
4580 excluded_patterns,
4581 'ipc/SECURITY_OWNERS',
4582 custom_rule_function=IsMojoServiceManifestFile)
4583
4584
4585def _CheckChangeForFuchsiaSecurityOwners(input_api, output_api):
4586 file_patterns = [
4587 # Component specifications.
4588 '*.cml', # Component Framework v2.
4589 '*.cmx', # Component Framework v1.
4590
4591 # Fuchsia IDL protocol specifications.
4592 '*.fidl',
4593 ]
4594
4595 # Don't check for owners files for changes in these directories.
4596 excluded_patterns = [
4597 'third_party/crashpad/*',
4598 ]
4599
4600 return _FindMissingSecurityOwners(input_api, output_api, file_patterns,
4601 excluded_patterns,
4602 'build/fuchsia/SECURITY_OWNERS')
4603
4604
4605def CheckSecurityOwners(input_api, output_api):
4606 """Checks that various security-sensitive files have an IPC OWNERS rule."""
4607 ipc_results = _CheckChangeForIpcSecurityOwners(input_api, output_api)
4608 fuchsia_results = _CheckChangeForFuchsiaSecurityOwners(
4609 input_api, output_api)
4610
4611 if ipc_results.has_security_sensitive_files:
4612 output_api.AppendCC('[email protected]')
Sam Maiera6e76d72022-02-11 21:43:504613
4614 results = []
Daniel Chenga37c03db2022-05-12 17:20:344615
Daniel Cheng171dad8d2022-05-21 00:40:254616 missing_reviewer_problems = []
4617 if ipc_results.missing_reviewer_problem:
4618 missing_reviewer_problems.append(ipc_results.missing_reviewer_problem)
4619 if fuchsia_results.missing_reviewer_problem:
4620 missing_reviewer_problems.append(
4621 fuchsia_results.missing_reviewer_problem)
Daniel Chenga37c03db2022-05-12 17:20:344622
Daniel Cheng171dad8d2022-05-21 00:40:254623 # Missing reviewers are an error unless there's no issue number
4624 # associated with this branch; in that case, the presubmit is being run
4625 # with --all or --files.
4626 #
4627 # Note that upload should never be an error; otherwise, it would be
4628 # impossible to upload changes at all.
4629 if input_api.is_committing and input_api.change.issue:
4630 make_presubmit_message = output_api.PresubmitError
4631 else:
4632 make_presubmit_message = output_api.PresubmitNotifyResult
4633 for problem in missing_reviewer_problems:
Sam Maiera6e76d72022-02-11 21:43:504634 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:254635 make_presubmit_message(problem.problem, items=problem.items))
Daniel Chenga37c03db2022-05-12 17:20:344636
Daniel Cheng171dad8d2022-05-21 00:40:254637 owners_file_problems = []
4638 owners_file_problems.extend(ipc_results.owners_file_problems)
4639 owners_file_problems.extend(fuchsia_results.owners_file_problems)
Daniel Chenga37c03db2022-05-12 17:20:344640
Daniel Cheng171dad8d2022-05-21 00:40:254641 for problem in owners_file_problems:
Daniel Cheng3008dc12022-05-13 04:02:114642 # Missing per-file rules are always an error. While swarming and caching
4643 # means that uploading a patchset with updated OWNERS files and sending
4644 # it to the CQ again should not have a large incremental cost, it is
4645 # still frustrating to discover the error only after the change has
4646 # already been uploaded.
Daniel Chenga37c03db2022-05-12 17:20:344647 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:254648 output_api.PresubmitError(problem.problem, items=problem.items))
Sam Maiera6e76d72022-02-11 21:43:504649
4650 return results
4651
4652
4653def _GetFilesUsingSecurityCriticalFunctions(input_api):
4654 """Checks affected files for changes to security-critical calls. This
4655 function checks the full change diff, to catch both additions/changes
4656 and removals.
4657
4658 Returns a dict keyed by file name, and the value is a set of detected
4659 functions.
4660 """
4661 # Map of function pretty name (displayed in an error) to the pattern to
4662 # match it with.
4663 _PATTERNS_TO_CHECK = {
4664 'content::GetServiceSandboxType<>()': 'GetServiceSandboxType\\<'
4665 }
4666 _PATTERNS_TO_CHECK = {
4667 k: input_api.re.compile(v)
4668 for k, v in _PATTERNS_TO_CHECK.items()
4669 }
4670
Sam Maiera6e76d72022-02-11 21:43:504671 # We don't want to trigger on strings within this file.
4672 def presubmit_file_filter(f):
Daniel Chenga37c03db2022-05-12 17:20:344673 return 'PRESUBMIT.py' != input_api.os_path.split(f.LocalPath())[1]
Sam Maiera6e76d72022-02-11 21:43:504674
4675 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
4676 files_to_functions = {}
4677 for f in input_api.AffectedFiles(file_filter=presubmit_file_filter):
4678 diff = f.GenerateScmDiff()
4679 for line in diff.split('\n'):
4680 # Not using just RightHandSideLines() because removing a
4681 # call to a security-critical function can be just as important
4682 # as adding or changing the arguments.
4683 if line.startswith('-') or (line.startswith('+')
4684 and not line.startswith('++')):
4685 for name, pattern in _PATTERNS_TO_CHECK.items():
4686 if pattern.search(line):
4687 path = f.LocalPath()
4688 if not path in files_to_functions:
4689 files_to_functions[path] = set()
4690 files_to_functions[path].add(name)
4691 return files_to_functions
4692
4693
4694def CheckSecurityChanges(input_api, output_api):
4695 """Checks that changes involving security-critical functions are reviewed
4696 by the security team.
4697 """
4698 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
4699 if not len(files_to_functions):
4700 return []
4701
Sam Maiera6e76d72022-02-11 21:43:504702 owners_file = 'ipc/SECURITY_OWNERS'
Daniel Chenga37c03db2022-05-12 17:20:344703 if _ChangeHasSecurityReviewer(input_api, owners_file):
Sam Maiera6e76d72022-02-11 21:43:504704 return []
4705
Daniel Chenga37c03db2022-05-12 17:20:344706 msg = 'The following files change calls to security-sensitive functions\n' \
Sam Maiera6e76d72022-02-11 21:43:504707 'that need to be reviewed by {}.\n'.format(owners_file)
4708 for path, names in files_to_functions.items():
4709 msg += ' {}\n'.format(path)
4710 for name in names:
4711 msg += ' {}\n'.format(name)
4712 msg += '\n'
4713
4714 if input_api.is_committing:
4715 output = output_api.PresubmitError
Mohamed Heikale217fc852020-07-06 19:44:034716 else:
Sam Maiera6e76d72022-02-11 21:43:504717 output = output_api.PresubmitNotifyResult
4718 return [output(msg)]
4719
4720
4721def CheckSetNoParent(input_api, output_api):
4722 """Checks that set noparent is only used together with an OWNERS file in
4723 //build/OWNERS.setnoparent (see also
4724 //docs/code_reviews.md#owners-files-details)
4725 """
4726 # Return early if no OWNERS files were modified.
4727 if not any(f.LocalPath().endswith('OWNERS')
4728 for f in input_api.AffectedFiles(include_deletes=False)):
4729 return []
4730
4731 errors = []
4732
4733 allowed_owners_files_file = 'build/OWNERS.setnoparent'
4734 allowed_owners_files = set()
Bruce Dawson58a45d22023-02-27 11:24:164735 with open(allowed_owners_files_file, 'r', encoding='utf-8') as f:
Sam Maiera6e76d72022-02-11 21:43:504736 for line in f:
4737 line = line.strip()
4738 if not line or line.startswith('#'):
4739 continue
4740 allowed_owners_files.add(line)
4741
4742 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
4743
4744 for f in input_api.AffectedFiles(include_deletes=False):
4745 if not f.LocalPath().endswith('OWNERS'):
4746 continue
4747
4748 found_owners_files = set()
4749 found_set_noparent_lines = dict()
4750
4751 # Parse the OWNERS file.
4752 for lineno, line in enumerate(f.NewContents(), 1):
4753 line = line.strip()
4754 if line.startswith('set noparent'):
4755 found_set_noparent_lines[''] = lineno
4756 if line.startswith('file://'):
4757 if line in allowed_owners_files:
4758 found_owners_files.add('')
4759 if line.startswith('per-file'):
4760 match = per_file_pattern.match(line)
4761 if match:
4762 glob = match.group(1).strip()
4763 directive = match.group(2).strip()
4764 if directive == 'set noparent':
4765 found_set_noparent_lines[glob] = lineno
4766 if directive.startswith('file://'):
4767 if directive in allowed_owners_files:
4768 found_owners_files.add(glob)
4769
4770 # Check that every set noparent line has a corresponding file:// line
4771 # listed in build/OWNERS.setnoparent. An exception is made for top level
4772 # directories since src/OWNERS shouldn't review them.
Anton Bershanskyi4253349482025-02-11 21:01:274773 linux_path = f.UnixLocalPath()
Bruce Dawson6bb0d672022-04-06 15:13:494774 if (linux_path.count('/') != 1
4775 and (not linux_path in _EXCLUDED_SET_NO_PARENT_PATHS)):
Sam Maiera6e76d72022-02-11 21:43:504776 for set_noparent_line in found_set_noparent_lines:
4777 if set_noparent_line in found_owners_files:
4778 continue
4779 errors.append(' %s:%d' %
Bruce Dawson6bb0d672022-04-06 15:13:494780 (linux_path,
Sam Maiera6e76d72022-02-11 21:43:504781 found_set_noparent_lines[set_noparent_line]))
4782
4783 results = []
4784 if errors:
4785 if input_api.is_committing:
4786 output = output_api.PresubmitError
4787 else:
4788 output = output_api.PresubmitPromptWarning
4789 results.append(
4790 output(
4791 'Found the following "set noparent" restrictions in OWNERS files that '
4792 'do not include owners from build/OWNERS.setnoparent:',
4793 long_text='\n\n'.join(errors)))
4794 return results
4795
4796
4797def CheckUselessForwardDeclarations(input_api, output_api):
4798 """Checks that added or removed lines in non third party affected
4799 header files do not lead to new useless class or struct forward
4800 declaration.
4801 """
4802 results = []
4803 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
4804 input_api.re.MULTILINE)
4805 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
4806 input_api.re.MULTILINE)
4807 for f in input_api.AffectedFiles(include_deletes=False):
Anton Bershanskyi4253349482025-02-11 21:01:274808 local_path = f.UnixLocalPath()
4809 if (local_path.startswith('third_party')
4810 and not local_path.startswith('third_party/blink')):
Sam Maiera6e76d72022-02-11 21:43:504811 continue
4812
Anton Bershanskyi4253349482025-02-11 21:01:274813 if not local_path.endswith('.h'):
Sam Maiera6e76d72022-02-11 21:43:504814 continue
4815
4816 contents = input_api.ReadFile(f)
4817 fwd_decls = input_api.re.findall(class_pattern, contents)
4818 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
4819
4820 useless_fwd_decls = []
4821 for decl in fwd_decls:
4822 count = sum(1 for _ in input_api.re.finditer(
4823 r'\b%s\b' % input_api.re.escape(decl), contents))
4824 if count == 1:
4825 useless_fwd_decls.append(decl)
4826
4827 if not useless_fwd_decls:
4828 continue
4829
4830 for line in f.GenerateScmDiff().splitlines():
4831 if (line.startswith('-') and not line.startswith('--')
4832 or line.startswith('+') and not line.startswith('++')):
4833 for decl in useless_fwd_decls:
4834 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
4835 results.append(
4836 output_api.PresubmitPromptWarning(
4837 '%s: %s forward declaration is no longer needed'
4838 % (f.LocalPath(), decl)))
4839 useless_fwd_decls.remove(decl)
4840
4841 return results
4842
4843
4844def _CheckAndroidDebuggableBuild(input_api, output_api):
4845 """Checks that code uses BuildInfo.isDebugAndroid() instead of
4846 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
4847 this is a debuggable build of Android.
4848 """
4849 build_type_check_pattern = input_api.re.compile(
4850 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
4851
4852 errors = []
4853
4854 sources = lambda affected_file: input_api.FilterSourceFile(
4855 affected_file,
4856 files_to_skip=(
4857 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4858 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314859 r"^android_webview/support_library/boundary_interfaces/",
4860 r"^chrome/android/webapk/.*",
4861 r'^third_party/.*',
4862 r"tools/android/customtabs_benchmark/.*",
4863 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504864 )),
4865 files_to_check=[r'.*\.java$'])
4866
4867 for f in input_api.AffectedSourceFiles(sources):
4868 for line_num, line in f.ChangedContents():
4869 if build_type_check_pattern.search(line):
4870 errors.append("%s:%d" % (f.LocalPath(), line_num))
4871
4872 results = []
4873
4874 if errors:
4875 results.append(
4876 output_api.PresubmitPromptWarning(
4877 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
4878 ' Please use BuildInfo.isDebugAndroid() instead.', errors))
4879
4880 return results
4881
4882# TODO: add unit tests
4883def _CheckAndroidToastUsage(input_api, output_api):
4884 """Checks that code uses org.chromium.ui.widget.Toast instead of
4885 android.widget.Toast (Chromium Toast doesn't force hardware
4886 acceleration on low-end devices, saving memory).
4887 """
4888 toast_import_pattern = input_api.re.compile(
4889 r'^import android\.widget\.Toast;$')
4890
4891 errors = []
4892
4893 sources = lambda affected_file: input_api.FilterSourceFile(
4894 affected_file,
4895 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
Bruce Dawson40fece62022-09-16 19:58:314896 DEFAULT_FILES_TO_SKIP + (r'^chromecast/.*',
4897 r'^remoting/.*')),
Sam Maiera6e76d72022-02-11 21:43:504898 files_to_check=[r'.*\.java$'])
4899
4900 for f in input_api.AffectedSourceFiles(sources):
4901 for line_num, line in f.ChangedContents():
4902 if toast_import_pattern.search(line):
4903 errors.append("%s:%d" % (f.LocalPath(), line_num))
4904
4905 results = []
4906
4907 if errors:
4908 results.append(
4909 output_api.PresubmitError(
4910 'android.widget.Toast usage is detected. Android toasts use hardware'
4911 ' acceleration, and can be\ncostly on low-end devices. Please use'
4912 ' org.chromium.ui.widget.Toast instead.\n'
4913 'Contact [email protected] if you have any questions.',
4914 errors))
4915
4916 return results
4917
4918
4919def _CheckAndroidCrLogUsage(input_api, output_api):
4920 """Checks that new logs using org.chromium.base.Log:
4921 - Are using 'TAG' as variable name for the tags (warn)
4922 - Are using a tag that is shorter than 20 characters (error)
4923 """
4924
4925 # Do not check format of logs in the given files
4926 cr_log_check_excluded_paths = [
4927 # //chrome/android/webapk cannot depend on //base
Bruce Dawson40fece62022-09-16 19:58:314928 r"^chrome/android/webapk/.*",
Sam Maiera6e76d72022-02-11 21:43:504929 # WebView license viewer code cannot depend on //base; used in stub APK.
Bruce Dawson40fece62022-09-16 19:58:314930 r"^android_webview/glue/java/src/com/android/"
4931 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504932 # The customtabs_benchmark is a small app that does not depend on Chromium
4933 # java pieces.
Bruce Dawson40fece62022-09-16 19:58:314934 r"tools/android/customtabs_benchmark/.*",
Sam Maiera6e76d72022-02-11 21:43:504935 ]
4936
4937 cr_log_import_pattern = input_api.re.compile(
4938 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
4939 class_in_base_pattern = input_api.re.compile(
4940 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
4941 has_some_log_import_pattern = input_api.re.compile(r'^import .*\.Log;$',
4942 input_api.re.MULTILINE)
4943 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
4944 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
4945 log_decl_pattern = input_api.re.compile(
4946 r'static final String TAG = "(?P<name>(.*))"')
4947 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
4948
4949 REF_MSG = ('See docs/android_logging.md for more info.')
4950 sources = lambda x: input_api.FilterSourceFile(
4951 x,
4952 files_to_check=[r'.*\.java$'],
4953 files_to_skip=cr_log_check_excluded_paths)
4954
4955 tag_decl_errors = []
Andrew Grieved3a35d82024-01-02 21:24:384956 tag_length_errors = []
Sam Maiera6e76d72022-02-11 21:43:504957 tag_errors = []
4958 tag_with_dot_errors = []
4959 util_log_errors = []
4960
4961 for f in input_api.AffectedSourceFiles(sources):
4962 file_content = input_api.ReadFile(f)
4963 has_modified_logs = False
4964 # Per line checks
4965 if (cr_log_import_pattern.search(file_content)
4966 or (class_in_base_pattern.search(file_content)
4967 and not has_some_log_import_pattern.search(file_content))):
4968 # Checks to run for files using cr log
4969 for line_num, line in f.ChangedContents():
4970 if rough_log_decl_pattern.search(line):
4971 has_modified_logs = True
4972
4973 # Check if the new line is doing some logging
4974 match = log_call_pattern.search(line)
4975 if match:
4976 has_modified_logs = True
4977
4978 # Make sure it uses "TAG"
4979 if not match.group('tag') == 'TAG':
4980 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
4981 else:
4982 # Report non cr Log function calls in changed lines
4983 for line_num, line in f.ChangedContents():
4984 if log_call_pattern.search(line):
4985 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
4986
4987 # Per file checks
4988 if has_modified_logs:
4989 # Make sure the tag is using the "cr" prefix and is not too long
4990 match = log_decl_pattern.search(file_content)
4991 tag_name = match.group('name') if match else None
4992 if not tag_name:
4993 tag_decl_errors.append(f.LocalPath())
Andrew Grieved3a35d82024-01-02 21:24:384994 elif len(tag_name) > 20:
4995 tag_length_errors.append(f.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:504996 elif '.' in tag_name:
4997 tag_with_dot_errors.append(f.LocalPath())
4998
4999 results = []
5000 if tag_decl_errors:
5001 results.append(
5002 output_api.PresubmitPromptWarning(
5003 'Please define your tags using the suggested format: .\n'
5004 '"private static final String TAG = "<package tag>".\n'
5005 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
5006 tag_decl_errors))
5007
Andrew Grieved3a35d82024-01-02 21:24:385008 if tag_length_errors:
5009 results.append(
5010 output_api.PresubmitError(
5011 'The tag length is restricted by the system to be at most '
5012 '20 characters.\n' + REF_MSG, tag_length_errors))
5013
Sam Maiera6e76d72022-02-11 21:43:505014 if tag_errors:
5015 results.append(
5016 output_api.PresubmitPromptWarning(
5017 'Please use a variable named "TAG" for your log tags.\n' +
5018 REF_MSG, tag_errors))
5019
5020 if util_log_errors:
5021 results.append(
5022 output_api.PresubmitPromptWarning(
5023 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
5024 util_log_errors))
5025
5026 if tag_with_dot_errors:
5027 results.append(
5028 output_api.PresubmitPromptWarning(
5029 'Dot in log tags cause them to be elided in crash reports.\n' +
5030 REF_MSG, tag_with_dot_errors))
5031
5032 return results
5033
5034
Sam Maiera6e76d72022-02-11 21:43:505035def _CheckAndroidTestAnnotationUsage(input_api, output_api):
5036 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
5037 deprecated_annotation_import_pattern = input_api.re.compile(
5038 r'^import android\.test\.suitebuilder\.annotation\..*;',
5039 input_api.re.MULTILINE)
5040 sources = lambda x: input_api.FilterSourceFile(
5041 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
5042 errors = []
5043 for f in input_api.AffectedFiles(file_filter=sources):
5044 for line_num, line in f.ChangedContents():
5045 if deprecated_annotation_import_pattern.search(line):
5046 errors.append("%s:%d" % (f.LocalPath(), line_num))
5047
5048 results = []
5049 if errors:
5050 results.append(
5051 output_api.PresubmitError(
5052 'Annotations in android.test.suitebuilder.annotation have been'
Mohamed Heikal3d7a94c2023-03-28 16:55:245053 ' deprecated since API level 24. Please use androidx.test.filters'
5054 ' from //third_party/androidx:androidx_test_runner_java instead.'
Sam Maiera6e76d72022-02-11 21:43:505055 ' Contact [email protected] if you have any questions.',
5056 errors))
5057 return results
5058
5059
5060def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
5061 """Checks if MDPI assets are placed in a correct directory."""
Anton Bershanskyi4253349482025-02-11 21:01:275062 file_filter = lambda f: (f.UnixLocalPath().endswith(
5063 '.png') and ('/res/drawable/' in f.
5064 UnixLocalPath() or '/res/drawable-ldrtl/' in f.UnixLocalPath()))
Sam Maiera6e76d72022-02-11 21:43:505065 errors = []
5066 for f in input_api.AffectedFiles(include_deletes=False,
5067 file_filter=file_filter):
5068 errors.append(' %s' % f.LocalPath())
5069
5070 results = []
5071 if errors:
5072 results.append(
5073 output_api.PresubmitError(
5074 'MDPI assets should be placed in /res/drawable-mdpi/ or '
5075 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
5076 '/res/drawable-ldrtl/.\n'
5077 'Contact [email protected] if you have questions.', errors))
5078 return results
5079
5080
5081def _CheckAndroidWebkitImports(input_api, output_api):
5082 """Checks that code uses org.chromium.base.Callback instead of
5083 android.webview.ValueCallback except in the WebView glue layer
5084 and WebLayer.
5085 """
5086 valuecallback_import_pattern = input_api.re.compile(
5087 r'^import android\.webkit\.ValueCallback;$')
5088
5089 errors = []
5090
5091 sources = lambda affected_file: input_api.FilterSourceFile(
5092 affected_file,
5093 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
5094 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:315095 r'^android_webview/glue/.*',
elabadysayedcbbaea72024-08-01 16:10:425096 r'^android_webview/support_library/.*',
Bruce Dawson40fece62022-09-16 19:58:315097 r'^weblayer/.*',
Sam Maiera6e76d72022-02-11 21:43:505098 )),
5099 files_to_check=[r'.*\.java$'])
5100
5101 for f in input_api.AffectedSourceFiles(sources):
5102 for line_num, line in f.ChangedContents():
5103 if valuecallback_import_pattern.search(line):
5104 errors.append("%s:%d" % (f.LocalPath(), line_num))
5105
5106 results = []
5107
5108 if errors:
5109 results.append(
5110 output_api.PresubmitError(
5111 'android.webkit.ValueCallback usage is detected outside of the glue'
5112 ' layer. To stay compatible with the support library, android.webkit.*'
5113 ' classes should only be used inside the glue layer and'
5114 ' org.chromium.base.Callback should be used instead.', errors))
5115
5116 return results
5117
5118
5119def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
5120 """Checks Android XML styles """
5121
5122 # Return early if no relevant files were modified.
5123 if not any(
5124 _IsXmlOrGrdFile(input_api, f.LocalPath())
5125 for f in input_api.AffectedFiles(include_deletes=False)):
5126 return []
5127
5128 import sys
5129 original_sys_path = sys.path
5130 try:
5131 sys.path = sys.path + [
5132 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5133 'android', 'checkxmlstyle')
5134 ]
5135 import checkxmlstyle
5136 finally:
5137 # Restore sys.path to what it was before.
5138 sys.path = original_sys_path
5139
5140 if is_check_on_upload:
5141 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
5142 else:
5143 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
5144
5145
5146def _CheckAndroidInfoBarDeprecation(input_api, output_api):
5147 """Checks Android Infobar Deprecation """
5148
5149 import sys
5150 original_sys_path = sys.path
5151 try:
5152 sys.path = sys.path + [
5153 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5154 'android', 'infobar_deprecation')
5155 ]
5156 import infobar_deprecation
5157 finally:
5158 # Restore sys.path to what it was before.
5159 sys.path = original_sys_path
5160
5161 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
5162
5163
5164class _PydepsCheckerResult:
5165 def __init__(self, cmd, pydeps_path, process, old_contents):
5166 self._cmd = cmd
5167 self._pydeps_path = pydeps_path
5168 self._process = process
5169 self._old_contents = old_contents
5170
5171 def GetError(self):
5172 """Returns an error message, or None."""
5173 import difflib
Andrew Grieved27620b62023-07-13 16:35:075174 new_contents = self._process.stdout.read().splitlines()[2:]
Sam Maiera6e76d72022-02-11 21:43:505175 if self._process.wait() != 0:
5176 # STDERR should already be printed.
5177 return 'Command failed: ' + self._cmd
Sam Maiera6e76d72022-02-11 21:43:505178 if self._old_contents != new_contents:
5179 diff = '\n'.join(
5180 difflib.context_diff(self._old_contents, new_contents))
5181 return ('File is stale: {}\n'
5182 'Diff (apply to fix):\n'
5183 '{}\n'
5184 'To regenerate, run:\n\n'
5185 ' {}').format(self._pydeps_path, diff, self._cmd)
5186 return None
5187
5188
5189class PydepsChecker:
5190 def __init__(self, input_api, pydeps_files):
5191 self._file_cache = {}
5192 self._input_api = input_api
5193 self._pydeps_files = pydeps_files
5194
5195 def _LoadFile(self, path):
5196 """Returns the list of paths within a .pydeps file relative to //."""
5197 if path not in self._file_cache:
5198 with open(path, encoding='utf-8') as f:
5199 self._file_cache[path] = f.read()
5200 return self._file_cache[path]
5201
5202 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
Gao Shenga79ebd42022-08-08 17:25:595203 """Returns an iterable of paths within the .pydep, relativized to //."""
Sam Maiera6e76d72022-02-11 21:43:505204 pydeps_data = self._LoadFile(pydeps_path)
5205 uses_gn_paths = '--gn-paths' in pydeps_data
5206 entries = (l for l in pydeps_data.splitlines()
5207 if not l.startswith('#'))
5208 if uses_gn_paths:
5209 # Paths look like: //foo/bar/baz
5210 return (e[2:] for e in entries)
5211 else:
5212 # Paths look like: path/relative/to/file.pydeps
5213 os_path = self._input_api.os_path
5214 pydeps_dir = os_path.dirname(pydeps_path)
5215 return (os_path.normpath(os_path.join(pydeps_dir, e))
5216 for e in entries)
5217
5218 def _CreateFilesToPydepsMap(self):
5219 """Returns a map of local_path -> list_of_pydeps."""
5220 ret = {}
5221 for pydep_local_path in self._pydeps_files:
5222 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
5223 ret.setdefault(path, []).append(pydep_local_path)
5224 return ret
5225
5226 def ComputeAffectedPydeps(self):
5227 """Returns an iterable of .pydeps files that might need regenerating."""
5228 affected_pydeps = set()
5229 file_to_pydeps_map = None
5230 for f in self._input_api.AffectedFiles(include_deletes=True):
5231 local_path = f.LocalPath()
5232 # Changes to DEPS can lead to .pydeps changes if any .py files are in
5233 # subrepositories. We can't figure out which files change, so re-check
5234 # all files.
5235 # Changes to print_python_deps.py affect all .pydeps.
5236 if local_path in ('DEPS', 'PRESUBMIT.py'
5237 ) or local_path.endswith('print_python_deps.py'):
5238 return self._pydeps_files
5239 elif local_path.endswith('.pydeps'):
5240 if local_path in self._pydeps_files:
5241 affected_pydeps.add(local_path)
5242 elif local_path.endswith('.py'):
5243 if file_to_pydeps_map is None:
5244 file_to_pydeps_map = self._CreateFilesToPydepsMap()
5245 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
5246 return affected_pydeps
5247
5248 def DetermineIfStaleAsync(self, pydeps_path):
5249 """Runs print_python_deps.py to see if the files is stale."""
5250 import os
5251
5252 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
5253 if old_pydeps_data:
5254 cmd = old_pydeps_data[1][1:].strip()
5255 if '--output' not in cmd:
5256 cmd += ' --output ' + pydeps_path
5257 old_contents = old_pydeps_data[2:]
5258 else:
5259 # A default cmd that should work in most cases (as long as pydeps filename
5260 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
5261 # file is empty/new.
5262 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
5263 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
5264 old_contents = []
5265 env = dict(os.environ)
5266 env['PYTHONDONTWRITEBYTECODE'] = '1'
5267 process = self._input_api.subprocess.Popen(
5268 cmd + ' --output ""',
5269 shell=True,
5270 env=env,
5271 stdout=self._input_api.subprocess.PIPE,
5272 encoding='utf-8')
5273 return _PydepsCheckerResult(cmd, pydeps_path, process, old_contents)
agrievef32bcc72016-04-04 14:57:405274
5275
Tibor Goldschwendt360793f72019-06-25 18:23:495276def _ParseGclientArgs():
Sam Maiera6e76d72022-02-11 21:43:505277 args = {}
5278 with open('build/config/gclient_args.gni', 'r') as f:
5279 for line in f:
5280 line = line.strip()
5281 if not line or line.startswith('#'):
5282 continue
5283 attribute, value = line.split('=')
5284 args[attribute.strip()] = value.strip()
5285 return args
Tibor Goldschwendt360793f72019-06-25 18:23:495286
5287
Saagar Sanghavifceeaae2020-08-12 16:40:365288def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
Sam Maiera6e76d72022-02-11 21:43:505289 """Checks if a .pydeps file needs to be regenerated."""
5290 # This check is for Python dependency lists (.pydeps files), and involves
5291 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
5292 # doesn't work on Windows and Mac, so skip it on other platforms.
5293 if not input_api.platform.startswith('linux'):
5294 return []
Erik Staabc734cd7a2021-11-23 03:11:525295
Sam Maiera6e76d72022-02-11 21:43:505296 results = []
5297 # First, check for new / deleted .pydeps.
5298 for f in input_api.AffectedFiles(include_deletes=True):
5299 # Check whether we are running the presubmit check for a file in src.
Sam Maiera6e76d72022-02-11 21:43:505300 if f.LocalPath().endswith('.pydeps'):
Andrew Grieve713b89b2024-10-15 20:20:085301 # f.LocalPath is relative to repo (src, or internal repo).
5302 # os_path.exists is relative to src repo.
5303 # Therefore if os_path.exists is true, it means f.LocalPath is relative
5304 # to src and we can conclude that the pydeps is in src.
5305 exists = input_api.os_path.exists(f.LocalPath())
5306 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
5307 results.append(
5308 output_api.PresubmitError(
5309 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
5310 'remove %s' % f.LocalPath()))
5311 elif (f.Action() != 'D' and exists
5312 and f.LocalPath() not in _ALL_PYDEPS_FILES):
5313 results.append(
5314 output_api.PresubmitError(
5315 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
5316 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:405317
Sam Maiera6e76d72022-02-11 21:43:505318 if results:
5319 return results
5320
Gavin Mak23884402024-07-25 20:39:265321 try:
5322 parsed_args = _ParseGclientArgs()
5323 except FileNotFoundError:
5324 message = (
5325 'build/config/gclient_args.gni not found. Please make sure your '
5326 'workspace has been initialized with gclient sync.'
5327 )
5328 import sys
5329 original_sys_path = sys.path
5330 try:
5331 sys.path = sys.path + [
5332 input_api.os_path.join(input_api.PresubmitLocalPath(),
5333 'third_party', 'depot_tools')
5334 ]
5335 import gclient_utils
5336 if gclient_utils.IsEnvCog():
5337 # Users will always hit this when they run presubmits before cog
5338 # workspace initialization finishes. The check shouldn't fail in
5339 # this case. This is an unavoidable workaround that's needed for
5340 # good presubmit UX for cog.
5341 results.append(output_api.PresubmitPromptWarning(message))
5342 else:
5343 results.append(output_api.PresubmitError(message))
5344 return results
5345 finally:
5346 # Restore sys.path to what it was before.
5347 sys.path = original_sys_path
5348
5349 is_android = parsed_args.get('checkout_android', 'false') == 'true'
Sam Maiera6e76d72022-02-11 21:43:505350 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
5351 affected_pydeps = set(checker.ComputeAffectedPydeps())
5352 affected_android_pydeps = affected_pydeps.intersection(
5353 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
5354 if affected_android_pydeps and not is_android:
5355 results.append(
5356 output_api.PresubmitPromptOrNotify(
5357 'You have changed python files that may affect pydeps for android\n'
Gao Shenga79ebd42022-08-08 17:25:595358 'specific scripts. However, the relevant presubmit check cannot be\n'
Sam Maiera6e76d72022-02-11 21:43:505359 'run because you are not using an Android checkout. To validate that\n'
5360 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
5361 'use the android-internal-presubmit optional trybot.\n'
5362 'Possibly stale pydeps files:\n{}'.format(
5363 '\n'.join(affected_android_pydeps))))
5364
5365 all_pydeps = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
5366 pydeps_to_check = affected_pydeps.intersection(all_pydeps)
5367 # Process these concurrently, as each one takes 1-2 seconds.
5368 pydep_results = [checker.DetermineIfStaleAsync(p) for p in pydeps_to_check]
5369 for result in pydep_results:
5370 error_msg = result.GetError()
5371 if error_msg:
5372 results.append(output_api.PresubmitError(error_msg))
5373
agrievef32bcc72016-04-04 14:57:405374 return results
5375
agrievef32bcc72016-04-04 14:57:405376
Saagar Sanghavifceeaae2020-08-12 16:40:365377def CheckSingletonInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505378 """Checks to make sure no header files have |Singleton<|."""
5379
5380 def FileFilter(affected_file):
5381 # It's ok for base/memory/singleton.h to have |Singleton<|.
5382 files_to_skip = (_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
Bruce Dawson40fece62022-09-16 19:58:315383 (r"^base/memory/singleton\.h$",
5384 r"^net/quic/platform/impl/quic_singleton_impl\.h$"))
Sam Maiera6e76d72022-02-11 21:43:505385 return input_api.FilterSourceFile(affected_file,
5386 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:435387
Sam Maiera6e76d72022-02-11 21:43:505388 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
5389 files = []
5390 for f in input_api.AffectedSourceFiles(FileFilter):
5391 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx')
5392 or f.LocalPath().endswith('.hpp')
5393 or f.LocalPath().endswith('.inl')):
5394 contents = input_api.ReadFile(f)
5395 for line in contents.splitlines(False):
5396 if (not line.lstrip().startswith('//')
5397 and # Strip C++ comment.
5398 pattern.search(line)):
5399 files.append(f)
5400 break
glidere61efad2015-02-18 17:39:435401
Sam Maiera6e76d72022-02-11 21:43:505402 if files:
5403 return [
5404 output_api.PresubmitError(
5405 'Found base::Singleton<T> in the following header files.\n' +
5406 'Please move them to an appropriate source file so that the ' +
5407 'template gets instantiated in a single compilation unit.',
5408 files)
5409 ]
5410 return []
glidere61efad2015-02-18 17:39:435411
5412
[email protected]fd20b902014-05-09 02:14:535413_DEPRECATED_CSS = [
5414 # Values
5415 ( "-webkit-box", "flex" ),
5416 ( "-webkit-inline-box", "inline-flex" ),
5417 ( "-webkit-flex", "flex" ),
5418 ( "-webkit-inline-flex", "inline-flex" ),
5419 ( "-webkit-min-content", "min-content" ),
5420 ( "-webkit-max-content", "max-content" ),
5421
5422 # Properties
5423 ( "-webkit-background-clip", "background-clip" ),
5424 ( "-webkit-background-origin", "background-origin" ),
5425 ( "-webkit-background-size", "background-size" ),
5426 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:445427 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:535428
5429 # Functions
5430 ( "-webkit-gradient", "gradient" ),
5431 ( "-webkit-repeating-gradient", "repeating-gradient" ),
5432 ( "-webkit-linear-gradient", "linear-gradient" ),
5433 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
5434 ( "-webkit-radial-gradient", "radial-gradient" ),
5435 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
5436]
5437
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:205438
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:495439# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:365440def CheckNoDeprecatedCss(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505441 """ Make sure that we don't use deprecated CSS
5442 properties, functions or values. Our external
5443 documentation and iOS CSS for dom distiller
5444 (reader mode) are ignored by the hooks as it
5445 needs to be consumed by WebKit. """
5446 results = []
5447 file_inclusion_pattern = [r".+\.css$"]
5448 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
5449 input_api.DEFAULT_FILES_TO_SKIP +
dpapad7fcdfc42024-12-06 01:21:385450 (# Legacy CSS file using deprecated CSS.
5451 r"^chrome/browser/resources/chromeos/arc_support/cr_overlay.css$",
5452 r"^chrome/common/extensions/docs", r"^chrome/docs",
Teresa Mao1d910882024-04-26 21:06:255453 r"^native_client_sdk",
5454 # The NTP team prefers reserving -webkit-line-clamp for
5455 # ellipsis effect which can only be used with -webkit-box.
5456 r"ui/webui/resources/cr_components/most_visited/.*\.css$"))
Sam Maiera6e76d72022-02-11 21:43:505457 file_filter = lambda f: input_api.FilterSourceFile(
5458 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
5459 for fpath in input_api.AffectedFiles(file_filter=file_filter):
5460 for line_num, line in fpath.ChangedContents():
5461 for (deprecated_value, value) in _DEPRECATED_CSS:
5462 if deprecated_value in line:
5463 results.append(
5464 output_api.PresubmitError(
5465 "%s:%d: Use of deprecated CSS %s, use %s instead" %
5466 (fpath.LocalPath(), line_num, deprecated_value,
5467 value)))
5468 return results
[email protected]fd20b902014-05-09 02:14:535469
mohan.reddyf21db962014-10-16 12:26:475470
Saagar Sanghavifceeaae2020-08-12 16:40:365471def CheckForRelativeIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505472 bad_files = {}
5473 for f in input_api.AffectedFiles(include_deletes=False):
Anton Bershanskyi4253349482025-02-11 21:01:275474 if (f.UnixLocalPath().startswith('third_party')
5475 and not f.LocalPath().startswith('third_party/blink')):
Sam Maiera6e76d72022-02-11 21:43:505476 continue
rlanday6802cf632017-05-30 17:48:365477
Sam Maiera6e76d72022-02-11 21:43:505478 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
5479 continue
rlanday6802cf632017-05-30 17:48:365480
Sam Maiera6e76d72022-02-11 21:43:505481 relative_includes = [
5482 line for _, line in f.ChangedContents()
5483 if "#include" in line and "../" in line
5484 ]
5485 if not relative_includes:
5486 continue
5487 bad_files[f.LocalPath()] = relative_includes
rlanday6802cf632017-05-30 17:48:365488
Sam Maiera6e76d72022-02-11 21:43:505489 if not bad_files:
5490 return []
rlanday6802cf632017-05-30 17:48:365491
Sam Maiera6e76d72022-02-11 21:43:505492 error_descriptions = []
5493 for file_path, bad_lines in bad_files.items():
5494 error_description = file_path
5495 for line in bad_lines:
5496 error_description += '\n ' + line
5497 error_descriptions.append(error_description)
rlanday6802cf632017-05-30 17:48:365498
Sam Maiera6e76d72022-02-11 21:43:505499 results = []
5500 results.append(
5501 output_api.PresubmitError(
5502 'You added one or more relative #include paths (including "../").\n'
5503 'These shouldn\'t be used because they can be used to include headers\n'
5504 'from code that\'s not correctly specified as a dependency in the\n'
5505 'relevant BUILD.gn file(s).', error_descriptions))
rlanday6802cf632017-05-30 17:48:365506
Sam Maiera6e76d72022-02-11 21:43:505507 return results
rlanday6802cf632017-05-30 17:48:365508
Takeshi Yoshinoe387aa32017-08-02 13:16:135509
Saagar Sanghavifceeaae2020-08-12 16:40:365510def CheckForCcIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505511 """Check that nobody tries to include a cc file. It's a relatively
5512 common error which results in duplicate symbols in object
5513 files. This may not always break the build until someone later gets
5514 very confusing linking errors."""
5515 results = []
5516 for f in input_api.AffectedFiles(include_deletes=False):
5517 # We let third_party code do whatever it wants
Anton Bershanskyi4253349482025-02-11 21:01:275518 if (f.UnixLocalPath().startswith('third_party')
5519 and not f.LocalPath().startswith('third_party/blink')):
Sam Maiera6e76d72022-02-11 21:43:505520 continue
Daniel Bratell65b033262019-04-23 08:17:065521
Sam Maiera6e76d72022-02-11 21:43:505522 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
5523 continue
Daniel Bratell65b033262019-04-23 08:17:065524
Sam Maiera6e76d72022-02-11 21:43:505525 for _, line in f.ChangedContents():
5526 if line.startswith('#include "'):
5527 included_file = line.split('"')[1]
5528 if _IsCPlusPlusFile(input_api, included_file):
5529 # The most common naming for external files with C++ code,
5530 # apart from standard headers, is to call them foo.inc, but
5531 # Chromium sometimes uses foo-inc.cc so allow that as well.
5532 if not included_file.endswith(('.h', '-inc.cc')):
5533 results.append(
5534 output_api.PresubmitError(
5535 'Only header files or .inc files should be included in other\n'
5536 'C++ files. Compiling the contents of a cc file more than once\n'
5537 'will cause duplicate information in the build which may later\n'
5538 'result in strange link_errors.\n' +
5539 f.LocalPath() + ':\n ' + line))
Daniel Bratell65b033262019-04-23 08:17:065540
Sam Maiera6e76d72022-02-11 21:43:505541 return results
Daniel Bratell65b033262019-04-23 08:17:065542
5543
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205544def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
Sam Maiera6e76d72022-02-11 21:43:505545 if not isinstance(key, ast.Str):
5546 return 'Key at line %d must be a string literal' % key.lineno
5547 if not isinstance(value, ast.Dict):
5548 return 'Value at line %d must be a dict' % value.lineno
5549 if len(value.keys) != 1:
5550 return 'Dict at line %d must have single entry' % value.lineno
5551 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
5552 return (
5553 'Entry at line %d must have a string literal \'filepath\' as key' %
5554 value.lineno)
5555 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:135556
Takeshi Yoshinoe387aa32017-08-02 13:16:135557
Sergey Ulanov4af16052018-11-08 02:41:465558def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Sam Maiera6e76d72022-02-11 21:43:505559 if not isinstance(key, ast.Str):
5560 return 'Key at line %d must be a string literal' % key.lineno
5561 if not isinstance(value, ast.List):
5562 return 'Value at line %d must be a list' % value.lineno
5563 for element in value.elts:
5564 if not isinstance(element, ast.Str):
5565 return 'Watchlist elements on line %d is not a string' % key.lineno
5566 if not email_regex.match(element.s):
5567 return ('Watchlist element on line %d doesn\'t look like a valid '
5568 + 'email: %s') % (key.lineno, element.s)
5569 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:135570
Takeshi Yoshinoe387aa32017-08-02 13:16:135571
Sergey Ulanov4af16052018-11-08 02:41:465572def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Sam Maiera6e76d72022-02-11 21:43:505573 mismatch_template = (
5574 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
5575 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:135576
Sam Maiera6e76d72022-02-11 21:43:505577 email_regex = input_api.re.compile(
5578 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
Sergey Ulanov4af16052018-11-08 02:41:465579
Sam Maiera6e76d72022-02-11 21:43:505580 ast = input_api.ast
5581 i = 0
5582 last_key = ''
5583 while True:
5584 if i >= len(wd_dict.keys):
5585 if i >= len(w_dict.keys):
5586 return None
5587 return mismatch_template % ('missing',
5588 'line %d' % w_dict.keys[i].lineno)
5589 elif i >= len(w_dict.keys):
5590 return (mismatch_template %
5591 ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:135592
Sam Maiera6e76d72022-02-11 21:43:505593 wd_key = wd_dict.keys[i]
5594 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:135595
Sam Maiera6e76d72022-02-11 21:43:505596 result = _CheckWatchlistDefinitionsEntrySyntax(wd_key,
5597 wd_dict.values[i], ast)
5598 if result is not None:
5599 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:135600
Sam Maiera6e76d72022-02-11 21:43:505601 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast,
5602 email_regex)
5603 if result is not None:
5604 return 'Bad entry in WATCHLISTS dict: %s' % result
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205605
Sam Maiera6e76d72022-02-11 21:43:505606 if wd_key.s != w_key.s:
5607 return mismatch_template % ('%s at line %d' %
5608 (wd_key.s, wd_key.lineno),
5609 '%s at line %d' %
5610 (w_key.s, w_key.lineno))
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205611
Sam Maiera6e76d72022-02-11 21:43:505612 if wd_key.s < last_key:
5613 return (
5614 'WATCHLISTS dict is not sorted lexicographically at line %d and %d'
5615 % (wd_key.lineno, w_key.lineno))
5616 last_key = wd_key.s
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205617
Sam Maiera6e76d72022-02-11 21:43:505618 i = i + 1
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205619
5620
Sergey Ulanov4af16052018-11-08 02:41:465621def _CheckWATCHLISTSSyntax(expression, input_api):
Sam Maiera6e76d72022-02-11 21:43:505622 ast = input_api.ast
5623 if not isinstance(expression, ast.Expression):
5624 return 'WATCHLISTS file must contain a valid expression'
5625 dictionary = expression.body
5626 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
5627 return 'WATCHLISTS file must have single dict with exactly two entries'
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205628
Sam Maiera6e76d72022-02-11 21:43:505629 first_key = dictionary.keys[0]
5630 first_value = dictionary.values[0]
5631 second_key = dictionary.keys[1]
5632 second_value = dictionary.values[1]
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205633
Sam Maiera6e76d72022-02-11 21:43:505634 if (not isinstance(first_key, ast.Str)
5635 or first_key.s != 'WATCHLIST_DEFINITIONS'
5636 or not isinstance(first_value, ast.Dict)):
5637 return ('The first entry of the dict in WATCHLISTS file must be '
5638 'WATCHLIST_DEFINITIONS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205639
Sam Maiera6e76d72022-02-11 21:43:505640 if (not isinstance(second_key, ast.Str) or second_key.s != 'WATCHLISTS'
5641 or not isinstance(second_value, ast.Dict)):
5642 return ('The second entry of the dict in WATCHLISTS file must be '
5643 'WATCHLISTS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205644
Sam Maiera6e76d72022-02-11 21:43:505645 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:135646
5647
Saagar Sanghavifceeaae2020-08-12 16:40:365648def CheckWATCHLISTS(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505649 for f in input_api.AffectedFiles(include_deletes=False):
5650 if f.LocalPath() == 'WATCHLISTS':
5651 contents = input_api.ReadFile(f, 'r')
Takeshi Yoshinoe387aa32017-08-02 13:16:135652
Sam Maiera6e76d72022-02-11 21:43:505653 try:
5654 # First, make sure that it can be evaluated.
5655 input_api.ast.literal_eval(contents)
5656 # Get an AST tree for it and scan the tree for detailed style checking.
5657 expression = input_api.ast.parse(contents,
5658 filename='WATCHLISTS',
5659 mode='eval')
5660 except ValueError as e:
5661 return [
5662 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5663 long_text=repr(e))
5664 ]
5665 except SyntaxError as e:
5666 return [
5667 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5668 long_text=repr(e))
5669 ]
5670 except TypeError as e:
5671 return [
5672 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5673 long_text=repr(e))
5674 ]
Takeshi Yoshinoe387aa32017-08-02 13:16:135675
Sam Maiera6e76d72022-02-11 21:43:505676 result = _CheckWATCHLISTSSyntax(expression, input_api)
5677 if result is not None:
5678 return [output_api.PresubmitError(result)]
5679 break
Takeshi Yoshinoe387aa32017-08-02 13:16:135680
Sam Maiera6e76d72022-02-11 21:43:505681 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:135682
Sean Kaucb7c9b32022-10-25 21:25:525683def CheckGnRebasePath(input_api, output_api):
Terrence Reilly313f44ff2025-01-22 15:10:145684 """Checks that target_gen_dir is not used with "//" in rebase_path().
Sean Kaucb7c9b32022-10-25 21:25:525685
5686 Developers should use root_build_dir instead of "//" when using target_gen_dir because
5687 Chromium is sometimes built outside of the source tree.
5688 """
5689
5690 def gn_files(f):
5691 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
5692
5693 rebase_path_regex = input_api.re.compile(r'rebase_path\(("\$target_gen_dir"|target_gen_dir), ("/"|"//")\)')
5694 problems = []
5695 for f in input_api.AffectedSourceFiles(gn_files):
5696 for line_num, line in f.ChangedContents():
5697 if rebase_path_regex.search(line):
5698 problems.append(
5699 'Absolute path in rebase_path() in %s:%d' %
5700 (f.LocalPath(), line_num))
5701
5702 if problems:
5703 return [
5704 output_api.PresubmitPromptWarning(
5705 'Using an absolute path in rebase_path()',
5706 items=sorted(problems),
5707 long_text=(
5708 'rebase_path() should use root_build_dir instead of "/" ',
5709 'since builds can be initiated from outside of the source ',
5710 'root.'))
5711 ]
5712 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:135713
Andrew Grieve1b290e4a22020-11-24 20:07:015714def CheckGnGlobForward(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505715 """Checks that forward_variables_from(invoker, "*") follows best practices.
Andrew Grieve1b290e4a22020-11-24 20:07:015716
Sam Maiera6e76d72022-02-11 21:43:505717 As documented at //build/docs/writing_gn_templates.md
5718 """
Andrew Grieve1b290e4a22020-11-24 20:07:015719
Sam Maiera6e76d72022-02-11 21:43:505720 def gn_files(f):
5721 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
Andrew Grieve1b290e4a22020-11-24 20:07:015722
Sam Maiera6e76d72022-02-11 21:43:505723 problems = []
5724 for f in input_api.AffectedSourceFiles(gn_files):
5725 for line_num, line in f.ChangedContents():
5726 if 'forward_variables_from(invoker, "*")' in line:
5727 problems.append(
5728 'Bare forward_variables_from(invoker, "*") in %s:%d' %
5729 (f.LocalPath(), line_num))
5730
5731 if problems:
5732 return [
5733 output_api.PresubmitPromptWarning(
5734 'forward_variables_from("*") without exclusions',
5735 items=sorted(problems),
5736 long_text=(
Gao Shenga79ebd42022-08-08 17:25:595737 'The variables "visibility" and "test_only" should be '
Sam Maiera6e76d72022-02-11 21:43:505738 'explicitly listed in forward_variables_from(). For more '
5739 'details, see:\n'
5740 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
5741 'build/docs/writing_gn_templates.md'
5742 '#Using-forward_variables_from'))
5743 ]
5744 return []
Andrew Grieve1b290e4a22020-11-24 20:07:015745
Saagar Sanghavifceeaae2020-08-12 16:40:365746def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505747 """Checks that newly added header files have corresponding GN changes.
5748 Note that this is only a heuristic. To be precise, run script:
5749 build/check_gn_headers.py.
5750 """
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195751
Sam Maiera6e76d72022-02-11 21:43:505752 def headers(f):
5753 return input_api.FilterSourceFile(
5754 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195755
Sam Maiera6e76d72022-02-11 21:43:505756 new_headers = []
5757 for f in input_api.AffectedSourceFiles(headers):
5758 if f.Action() != 'A':
5759 continue
5760 new_headers.append(f.LocalPath())
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195761
Sam Maiera6e76d72022-02-11 21:43:505762 def gn_files(f):
5763 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195764
Sam Maiera6e76d72022-02-11 21:43:505765 all_gn_changed_contents = ''
5766 for f in input_api.AffectedSourceFiles(gn_files):
5767 for _, line in f.ChangedContents():
5768 all_gn_changed_contents += line
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195769
Sam Maiera6e76d72022-02-11 21:43:505770 problems = []
5771 for header in new_headers:
5772 basename = input_api.os_path.basename(header)
5773 if basename not in all_gn_changed_contents:
5774 problems.append(header)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195775
Sam Maiera6e76d72022-02-11 21:43:505776 if problems:
5777 return [
5778 output_api.PresubmitPromptWarning(
5779 'Missing GN changes for new header files',
5780 items=sorted(problems),
5781 long_text=
5782 'Please double check whether newly added header files need '
5783 'corresponding changes in gn or gni files.\nThis checking is only a '
5784 'heuristic. Run build/check_gn_headers.py to be precise.\n'
5785 'Read https://crbug.com/661774 for more info.')
5786 ]
5787 return []
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195788
5789
Saagar Sanghavifceeaae2020-08-12 16:40:365790def CheckCorrectProductNameInMessages(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505791 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
Michael Giuffridad3bc8672018-10-25 22:48:025792
Sam Maiera6e76d72022-02-11 21:43:505793 This assumes we won't intentionally reference one product from the other
5794 product.
5795 """
5796 all_problems = []
5797 test_cases = [{
5798 "filename_postfix": "google_chrome_strings.grd",
5799 "correct_name": "Chrome",
5800 "incorrect_name": "Chromium",
5801 }, {
Thiago Perrotta099034f2023-06-05 18:10:205802 "filename_postfix": "google_chrome_strings.grd",
5803 "correct_name": "Chrome",
5804 "incorrect_name": "Chrome for Testing",
5805 }, {
Sam Maiera6e76d72022-02-11 21:43:505806 "filename_postfix": "chromium_strings.grd",
5807 "correct_name": "Chromium",
5808 "incorrect_name": "Chrome",
5809 }]
Michael Giuffridad3bc8672018-10-25 22:48:025810
Sam Maiera6e76d72022-02-11 21:43:505811 for test_case in test_cases:
5812 problems = []
5813 filename_filter = lambda x: x.LocalPath().endswith(test_case[
5814 "filename_postfix"])
Michael Giuffridad3bc8672018-10-25 22:48:025815
Sam Maiera6e76d72022-02-11 21:43:505816 # Check each new line. Can yield false positives in multiline comments, but
5817 # easier than trying to parse the XML because messages can have nested
5818 # children, and associating message elements with affected lines is hard.
5819 for f in input_api.AffectedSourceFiles(filename_filter):
5820 for line_num, line in f.ChangedContents():
5821 if "<message" in line or "<!--" in line or "-->" in line:
5822 continue
5823 if test_case["incorrect_name"] in line:
Thiago Perrotta099034f2023-06-05 18:10:205824 # Chrome for Testing is a special edge case: https://goo.gle/chrome-for-testing#bookmark=id.n1rat320av91
5825 if (test_case["correct_name"] == "Chromium" and line.count("Chrome") == line.count("Chrome for Testing")):
5826 continue
Sam Maiera6e76d72022-02-11 21:43:505827 problems.append("Incorrect product name in %s:%d" %
5828 (f.LocalPath(), line_num))
Michael Giuffridad3bc8672018-10-25 22:48:025829
Sam Maiera6e76d72022-02-11 21:43:505830 if problems:
5831 message = (
5832 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
5833 % (test_case["correct_name"], test_case["correct_name"],
5834 test_case["incorrect_name"]))
5835 all_problems.append(
5836 output_api.PresubmitPromptWarning(message, items=problems))
Michael Giuffridad3bc8672018-10-25 22:48:025837
Sam Maiera6e76d72022-02-11 21:43:505838 return all_problems
Michael Giuffridad3bc8672018-10-25 22:48:025839
5840
Saagar Sanghavifceeaae2020-08-12 16:40:365841def CheckForTooLargeFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505842 """Avoid large files, especially binary files, in the repository since
5843 git doesn't scale well for those. They will be in everyone's repo
5844 clones forever, forever making Chromium slower to clone and work
5845 with."""
Daniel Bratell93eb6c62019-04-29 20:13:365846
Sam Maiera6e76d72022-02-11 21:43:505847 # Uploading files to cloud storage is not trivial so we don't want
5848 # to set the limit too low, but the upper limit for "normal" large
5849 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
5850 # anything over 20 MB is exceptional.
Bruce Dawsonbb414db2022-12-27 20:21:255851 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024
Daniel Bratell93eb6c62019-04-29 20:13:365852
Sam Maiera6e76d72022-02-11 21:43:505853 too_large_files = []
5854 for f in input_api.AffectedFiles():
5855 # Check both added and modified files (but not deleted files).
5856 if f.Action() in ('A', 'M'):
5857 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Joe DeBlasio10a832f2023-04-21 20:20:185858 if size > TOO_LARGE_FILE_SIZE_LIMIT:
Sam Maiera6e76d72022-02-11 21:43:505859 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
Daniel Bratell93eb6c62019-04-29 20:13:365860
Sam Maiera6e76d72022-02-11 21:43:505861 if too_large_files:
5862 message = (
5863 'Do not commit large files to git since git scales badly for those.\n'
5864 +
5865 'Instead put the large files in cloud storage and use DEPS to\n' +
5866 'fetch them.\n' + '\n'.join(too_large_files))
5867 return [
5868 output_api.PresubmitError('Too large files found in commit',
5869 long_text=message + '\n')
5870 ]
5871 else:
5872 return []
Daniel Bratell93eb6c62019-04-29 20:13:365873
Max Morozb47503b2019-08-08 21:03:275874
Saagar Sanghavifceeaae2020-08-12 16:40:365875def CheckFuzzTargetsOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505876 """Checks specific for fuzz target sources."""
5877 EXPORTED_SYMBOLS = [
5878 'LLVMFuzzerInitialize',
5879 'LLVMFuzzerCustomMutator',
5880 'LLVMFuzzerCustomCrossOver',
5881 'LLVMFuzzerMutate',
5882 ]
Max Morozb47503b2019-08-08 21:03:275883
Sam Maiera6e76d72022-02-11 21:43:505884 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
Max Morozb47503b2019-08-08 21:03:275885
Sam Maiera6e76d72022-02-11 21:43:505886 def FilterFile(affected_file):
5887 """Ignore libFuzzer source code."""
5888 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
Bruce Dawson40fece62022-09-16 19:58:315889 files_to_skip = r"^third_party/libFuzzer"
Max Morozb47503b2019-08-08 21:03:275890
Sam Maiera6e76d72022-02-11 21:43:505891 return input_api.FilterSourceFile(affected_file,
5892 files_to_check=[files_to_check],
5893 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:275894
Sam Maiera6e76d72022-02-11 21:43:505895 files_with_missing_header = []
5896 for f in input_api.AffectedSourceFiles(FilterFile):
5897 contents = input_api.ReadFile(f, 'r')
5898 if REQUIRED_HEADER in contents:
5899 continue
Max Morozb47503b2019-08-08 21:03:275900
Sam Maiera6e76d72022-02-11 21:43:505901 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
5902 files_with_missing_header.append(f.LocalPath())
Max Morozb47503b2019-08-08 21:03:275903
Sam Maiera6e76d72022-02-11 21:43:505904 if not files_with_missing_header:
5905 return []
Max Morozb47503b2019-08-08 21:03:275906
Sam Maiera6e76d72022-02-11 21:43:505907 long_text = (
5908 'If you define any of the libFuzzer optional functions (%s), it is '
5909 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
5910 'work incorrectly on Mac (crbug.com/687076).\nNote that '
5911 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
5912 'to access command line arguments passed to the fuzzer. Instead, prefer '
5913 'static initialization and shared resources as documented in '
5914 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
5915 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n'
5916 % (', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER))
Max Morozb47503b2019-08-08 21:03:275917
Sam Maiera6e76d72022-02-11 21:43:505918 return [
5919 output_api.PresubmitPromptWarning(message="Missing '%s' in:" %
5920 REQUIRED_HEADER,
5921 items=files_with_missing_header,
5922 long_text=long_text)
5923 ]
Max Morozb47503b2019-08-08 21:03:275924
5925
Mohamed Heikald048240a2019-11-12 16:57:375926def _CheckNewImagesWarning(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505927 """
5928 Warns authors who add images into the repo to make sure their images are
5929 optimized before committing.
5930 """
5931 images_added = False
5932 image_paths = []
5933 errors = []
5934 filter_lambda = lambda x: input_api.FilterSourceFile(
5935 x,
5936 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
5937 DEFAULT_FILES_TO_SKIP),
5938 files_to_check=[r'.*\/(drawable|mipmap)'])
5939 for f in input_api.AffectedFiles(include_deletes=False,
5940 file_filter=filter_lambda):
5941 local_path = f.LocalPath().lower()
5942 if any(
5943 local_path.endswith(extension)
5944 for extension in _IMAGE_EXTENSIONS):
5945 images_added = True
5946 image_paths.append(f)
5947 if images_added:
5948 errors.append(
5949 output_api.PresubmitPromptWarning(
5950 'It looks like you are trying to commit some images. If these are '
5951 'non-test-only images, please make sure to read and apply the tips in '
5952 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
5953 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
5954 'FYI only and will not block your CL on the CQ.', image_paths))
5955 return errors
Mohamed Heikald048240a2019-11-12 16:57:375956
5957
Saagar Sanghavifceeaae2020-08-12 16:40:365958def ChecksAndroidSpecificOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505959 """Groups upload checks that target android code."""
5960 results = []
5961 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
5962 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
5963 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
5964 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505965 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
5966 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
5967 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
5968 results.extend(_CheckNewImagesWarning(input_api, output_api))
5969 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
5970 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
Henrique Nakashima224ee2482025-03-21 18:35:025971 results.extend(_CheckAndroidNullAwayAnnotatedClasses(input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505972 return results
5973
Becky Zhou7c69b50992018-12-10 19:37:575974
Saagar Sanghavifceeaae2020-08-12 16:40:365975def ChecksAndroidSpecificOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505976 """Groups commit checks that target android code."""
5977 results = []
5978 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
5979 return results
dgnaa68d5e2015-06-10 10:08:225980
Chris Hall59f8d0c72020-05-01 07:31:195981# TODO(chrishall): could we additionally match on any path owned by
5982# ui/accessibility/OWNERS ?
5983_ACCESSIBILITY_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:315984 r"^chrome/browser.*/accessibility/",
5985 r"^chrome/browser/extensions/api/automation.*/",
5986 r"^chrome/renderer/extensions/accessibility_.*",
5987 r"^chrome/tests/data/accessibility/",
5988 r"^content/browser/accessibility/",
5989 r"^content/renderer/accessibility/",
5990 r"^content/tests/data/accessibility/",
5991 r"^extensions/renderer/api/automation/",
Katie Dektar58ef07b2022-09-27 13:19:175992 r"^services/accessibility/",
Abigail Klein7a63c572024-02-28 20:45:095993 r"^services/screen_ai/",
Bruce Dawson40fece62022-09-16 19:58:315994 r"^ui/accessibility/",
5995 r"^ui/views/accessibility/",
Chris Hall59f8d0c72020-05-01 07:31:195996)
5997
Saagar Sanghavifceeaae2020-08-12 16:40:365998def CheckAccessibilityRelnotesField(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505999 """Checks that commits to accessibility code contain an AX-Relnotes field in
6000 their commit message."""
Chris Hall59f8d0c72020-05-01 07:31:196001
Sam Maiera6e76d72022-02-11 21:43:506002 def FileFilter(affected_file):
6003 paths = _ACCESSIBILITY_PATHS
6004 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:196005
Sam Maiera6e76d72022-02-11 21:43:506006 # Only consider changes affecting accessibility paths.
6007 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
6008 return []
Akihiro Ota08108e542020-05-20 15:30:536009
Sam Maiera6e76d72022-02-11 21:43:506010 # AX-Relnotes can appear in either the description or the footer.
6011 # When searching the description, require 'AX-Relnotes:' to appear at the
6012 # beginning of a line.
6013 ax_regex = input_api.re.compile('ax-relnotes[:=]')
6014 description_has_relnotes = any(
6015 ax_regex.match(line)
6016 for line in input_api.change.DescriptionText().lower().splitlines())
Chris Hall59f8d0c72020-05-01 07:31:196017
Sam Maiera6e76d72022-02-11 21:43:506018 footer_relnotes = input_api.change.GitFootersFromDescription().get(
6019 'AX-Relnotes', [])
6020 if description_has_relnotes or footer_relnotes:
6021 return []
Chris Hall59f8d0c72020-05-01 07:31:196022
Sam Maiera6e76d72022-02-11 21:43:506023 # TODO(chrishall): link to Relnotes documentation in message.
6024 message = (
6025 "Missing 'AX-Relnotes:' field required for accessibility changes"
6026 "\n please add 'AX-Relnotes: [release notes].' to describe any "
6027 "user-facing changes"
6028 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
6029 "user-facing effects"
6030 "\n if this is confusing or annoying then please contact members "
6031 "of ui/accessibility/OWNERS.")
6032
6033 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:226034
Mark Schillaci44c90b42024-11-22 20:44:386035
6036_ACCESSIBILITY_ARIA_METHOD_CANDIDATES_PATTERNS = r'(\-\>|\.)(get|has|FastGet|FastHas)Attribute\('
6037
6038_ACCESSIBILITY_ARIA_BAD_PARAMS_PATTERNS = (
6039 r"\(html_names::kAria(.*)Attr\)",
6040 r"\(html_names::kRoleAttr\)"
6041)
6042
6043_ACCESSIBILITY_ARIA_FILE_CANDIDATES_PATTERNS = (
6044 r".*/accessibility/.*.(cc|h)",
6045 r".*/ax_.*.(cc|h)"
6046)
6047
6048def CheckAccessibilityAriaElementAttributeGetters(input_api, output_api):
6049 """Checks that the blink accessibility code follows the defined patterns
6050 for checking aria attributes, so that ElementInternals is not bypassed."""
6051
6052 # Limit to accessibility-related files.
6053 def FileFilter(affected_file):
6054 paths = _ACCESSIBILITY_ARIA_FILE_CANDIDATES_PATTERNS
6055 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
6056
6057 aria_method_regex = input_api.re.compile(_ACCESSIBILITY_ARIA_METHOD_CANDIDATES_PATTERNS)
6058 aria_bad_params_regex = input_api.re.compile(
6059 "|".join(_ACCESSIBILITY_ARIA_BAD_PARAMS_PATTERNS)
6060 )
6061 problems = []
6062
6063 for f in input_api.AffectedSourceFiles(FileFilter):
6064 for line_num, line in f.ChangedContents():
6065 if aria_method_regex.search(line) and aria_bad_params_regex.search(line):
6066 problems.append(f"{f.LocalPath()}:{line_num}\n {line.strip()}")
6067
6068 if problems:
6069 return [
6070 output_api.PresubmitPromptWarning(
6071 "Accessibility code should not use element methods to get or check"
6072 "\nthe presence of aria attributes"
6073 "\nPlease use ARIA-specific attribute access, e.g. HasAriaAttribute(),"
6074 "\nAriaTokenAttribute(), AriaBoolAttribute(), AriaBooleanAttribute(),"
6075 "\nAriaFloatAttribute().",
6076 problems,
6077 )
6078 ]
6079 return []
6080
seanmccullough4a9356252021-04-08 19:54:096081# string pattern, sequence of strings to show when pattern matches,
6082# error flag. True if match is a presubmit error, otherwise it's a warning.
6083_NON_INCLUSIVE_TERMS = (
6084 (
6085 # Note that \b pattern in python re is pretty particular. In this
6086 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
6087 # ...' will not. This may require some tweaking to catch these cases
6088 # without triggering a lot of false positives. Leaving it naive and
6089 # less matchy for now.
Josip Sokcevic9d2806a02023-12-13 03:04:026090 r'/(?i)\b((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:096091 (
6092 'Please don\'t use blacklist, whitelist, ' # nocheck
6093 'or slave in your', # nocheck
6094 'code and make every effort to use other terms. Using "// nocheck"',
6095 '"# nocheck" or "<!-- nocheck -->"',
6096 'at the end of the offending line will bypass this PRESUBMIT error',
6097 'but avoid using this whenever possible. Reach out to',
6098 '[email protected] if you have questions'),
6099 True),)
6100
Saagar Sanghavifceeaae2020-08-12 16:40:366101def ChecksCommon(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506102 """Checks common to both upload and commit."""
6103 results = []
Eric Boren6fd2b932018-01-25 15:05:086104 results.extend(
Sam Maiera6e76d72022-02-11 21:43:506105 input_api.canned_checks.PanProjectChecks(
6106 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:086107
Sam Maiera6e76d72022-02-11 21:43:506108 author = input_api.change.author_email
6109 if author and author not in _KNOWN_ROBOTS:
6110 results.extend(
6111 input_api.canned_checks.CheckAuthorizedAuthor(
6112 input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:246113
Sam Maiera6e76d72022-02-11 21:43:506114 results.extend(
6115 input_api.canned_checks.CheckChangeHasNoTabs(
6116 input_api,
6117 output_api,
6118 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
6119 results.extend(
6120 input_api.RunTests(
6121 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Edward Lesmesce51df52020-08-04 22:10:176122
Bruce Dawsonc8054482022-03-28 15:33:376123 dirmd = 'dirmd.bat' if input_api.is_windows else 'dirmd'
Sam Maiera6e76d72022-02-11 21:43:506124 dirmd_bin = input_api.os_path.join(input_api.PresubmitLocalPath(),
Bruce Dawsonc8054482022-03-28 15:33:376125 'third_party', 'depot_tools', dirmd)
Sam Maiera6e76d72022-02-11 21:43:506126 results.extend(
6127 input_api.RunTests(
6128 input_api.canned_checks.CheckDirMetadataFormat(
6129 input_api, output_api, dirmd_bin)))
6130 results.extend(
6131 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
6132 input_api, output_api))
6133 results.extend(
6134 input_api.canned_checks.CheckNoNewMetadataInOwners(
6135 input_api, output_api))
6136 results.extend(
6137 input_api.canned_checks.CheckInclusiveLanguage(
6138 input_api,
6139 output_api,
6140 excluded_directories_relative_path=[
6141 'infra', 'inclusive_language_presubmit_exempt_dirs.txt'
6142 ],
6143 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Yiwei Zhang5341bf02025-03-20 16:34:136144 results.extend(
6145 input_api.canned_checks.CheckNewDEPSHooksHasRequiredReviewers(
6146 input_api, output_api))
Dirk Prankee3c9c62d2021-05-18 18:35:596147
Aleksey Khoroshilov2978c942022-06-13 16:14:126148 presubmit_py_filter = lambda f: input_api.FilterSourceFile(
Daniel Cheng6f3d1ae12025-04-07 17:11:276149 f, files_to_check=[r'.*PRESUBMIT(?:_test)?\.py$'])
6150 potential_paths = set(
6151 map(
6152 lambda f: input_api.os_path.dirname(f.AbsoluteLocalPath()),
6153 input_api.AffectedFiles(include_deletes=False,
6154 file_filter=presubmit_py_filter)))
6155 for full_path in potential_paths:
Aleksey Khoroshilov2978c942022-06-13 16:14:126156 test_file = input_api.os_path.join(full_path, 'PRESUBMIT_test.py')
6157 # The PRESUBMIT.py file (and the directory containing it) might have
6158 # been affected by being moved or removed, so only try to run the tests
6159 # if they still exist.
6160 if not input_api.os_path.exists(test_file):
6161 continue
Sam Maiera6e76d72022-02-11 21:43:506162
Aleksey Khoroshilov2978c942022-06-13 16:14:126163 results.extend(
6164 input_api.canned_checks.RunUnitTestsInDirectory(
6165 input_api,
6166 output_api,
6167 full_path,
Takuto Ikuta40def482023-06-02 02:23:496168 files_to_check=[r'^PRESUBMIT_test\.py$']))
Sam Maiera6e76d72022-02-11 21:43:506169 return results
[email protected]1f7b4172010-01-28 01:17:346170
[email protected]b337cb5b2011-01-23 21:24:056171
Saagar Sanghavifceeaae2020-08-12 16:40:366172def CheckPatchFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506173 problems = [
6174 f.LocalPath() for f in input_api.AffectedFiles()
6175 if f.LocalPath().endswith(('.orig', '.rej'))
6176 ]
6177 # Cargo.toml.orig files are part of third-party crates downloaded from
6178 # crates.io and should be included.
6179 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
6180 if problems:
6181 return [
6182 output_api.PresubmitError("Don't commit .rej and .orig files.",
6183 problems)
6184 ]
6185 else:
6186 return []
[email protected]b8079ae4a2012-12-05 19:56:496187
6188
Saagar Sanghavifceeaae2020-08-12 16:40:366189def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506190 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
6191 macro_re = input_api.re.compile(
6192 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
6193 include_re = input_api.re.compile(r'^#include\s+"build/build_config.h"',
6194 input_api.re.MULTILINE)
6195 extension_re = input_api.re.compile(r'\.[a-z]+$')
6196 errors = []
Bruce Dawsonf7679202022-08-09 20:24:006197 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:506198 for f in input_api.AffectedFiles(include_deletes=False):
Bruce Dawsonf7679202022-08-09 20:24:006199 # The build-config macros are allowed to be used in build_config.h
6200 # without including itself.
6201 if f.LocalPath() == config_h_file:
6202 continue
Sam Maiera6e76d72022-02-11 21:43:506203 if not f.LocalPath().endswith(
6204 ('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
6205 continue
Arthur Sonzognia3dec412024-04-29 12:05:376206
Sam Maiera6e76d72022-02-11 21:43:506207 found_line_number = None
6208 found_macro = None
6209 all_lines = input_api.ReadFile(f, 'r').splitlines()
6210 for line_num, line in enumerate(all_lines):
6211 match = macro_re.search(line)
6212 if match:
6213 found_line_number = line_num
6214 found_macro = match.group(2)
6215 break
6216 if not found_line_number:
6217 continue
Kent Tamura5a8755d2017-06-29 23:37:076218
Sam Maiera6e76d72022-02-11 21:43:506219 found_include_line = -1
6220 for line_num, line in enumerate(all_lines):
6221 if include_re.search(line):
6222 found_include_line = line_num
6223 break
6224 if found_include_line >= 0 and found_include_line < found_line_number:
6225 continue
Kent Tamura5a8755d2017-06-29 23:37:076226
Sam Maiera6e76d72022-02-11 21:43:506227 if not f.LocalPath().endswith('.h'):
6228 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
6229 try:
6230 content = input_api.ReadFile(primary_header_path, 'r')
6231 if include_re.search(content):
6232 continue
6233 except IOError:
6234 pass
6235 errors.append('%s:%d %s macro is used without first including build/'
6236 'build_config.h.' %
6237 (f.LocalPath(), found_line_number, found_macro))
6238 if errors:
6239 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
6240 return []
Kent Tamura5a8755d2017-06-29 23:37:076241
6242
Lei Zhang1c12a22f2021-05-12 11:28:456243def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506244 stl_include_re = input_api.re.compile(r'^#include\s+<('
6245 r'algorithm|'
6246 r'array|'
6247 r'limits|'
6248 r'list|'
6249 r'map|'
6250 r'memory|'
6251 r'queue|'
6252 r'set|'
6253 r'string|'
6254 r'unordered_map|'
6255 r'unordered_set|'
6256 r'utility|'
6257 r'vector)>')
6258 std_namespace_re = input_api.re.compile(r'std::')
6259 errors = []
6260 for f in input_api.AffectedFiles():
6261 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
6262 continue
Lei Zhang1c12a22f2021-05-12 11:28:456263
Sam Maiera6e76d72022-02-11 21:43:506264 uses_std_namespace = False
6265 has_stl_include = False
6266 for line in f.NewContents():
6267 if has_stl_include and uses_std_namespace:
6268 break
Lei Zhang1c12a22f2021-05-12 11:28:456269
Sam Maiera6e76d72022-02-11 21:43:506270 if not has_stl_include and stl_include_re.search(line):
6271 has_stl_include = True
6272 continue
Lei Zhang1c12a22f2021-05-12 11:28:456273
Bruce Dawson4a5579a2022-04-08 17:11:366274 if not uses_std_namespace and (std_namespace_re.search(line)
6275 or 'no-std-usage-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:506276 uses_std_namespace = True
6277 continue
Lei Zhang1c12a22f2021-05-12 11:28:456278
Sam Maiera6e76d72022-02-11 21:43:506279 if has_stl_include and not uses_std_namespace:
6280 errors.append(
6281 '%s: Includes STL header(s) but does not reference std::' %
6282 f.LocalPath())
6283 if errors:
6284 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
6285 return []
Lei Zhang1c12a22f2021-05-12 11:28:456286
6287
Xiaohan Wang42d96c22022-01-20 17:23:116288def _CheckForDeprecatedOSMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:506289 """Check for sensible looking, totally invalid OS macros."""
6290 preprocessor_statement = input_api.re.compile(r'^\s*#')
6291 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
6292 results = []
6293 for lnum, line in f.ChangedContents():
6294 if preprocessor_statement.search(line):
6295 for match in os_macro.finditer(line):
6296 results.append(
6297 ' %s:%d: %s' %
6298 (f.LocalPath(), lnum, 'defined(OS_' + match.group(1) +
6299 ') -> BUILDFLAG(IS_' + match.group(1) + ')'))
6300 return results
[email protected]b00342e7f2013-03-26 16:21:546301
6302
Xiaohan Wang42d96c22022-01-20 17:23:116303def CheckForDeprecatedOSMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506304 """Check all affected files for invalid OS macros."""
6305 bad_macros = []
Bruce Dawsonf7679202022-08-09 20:24:006306 # The OS_ macros are allowed to be used in build/build_config.h.
6307 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:506308 for f in input_api.AffectedSourceFiles(None):
Bruce Dawsonf7679202022-08-09 20:24:006309 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')) \
6310 and f.LocalPath() != config_h_file:
Sam Maiera6e76d72022-02-11 21:43:506311 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
[email protected]b00342e7f2013-03-26 16:21:546312
Sam Maiera6e76d72022-02-11 21:43:506313 if not bad_macros:
6314 return []
[email protected]b00342e7f2013-03-26 16:21:546315
Sam Maiera6e76d72022-02-11 21:43:506316 return [
6317 output_api.PresubmitError(
6318 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
6319 'defined in build_config.h):', bad_macros)
6320 ]
[email protected]b00342e7f2013-03-26 16:21:546321
lliabraa35bab3932014-10-01 12:16:446322
6323def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:506324 """Check all affected files for invalid "if defined" macros."""
6325 ALWAYS_DEFINED_MACROS = (
6326 "TARGET_CPU_PPC",
6327 "TARGET_CPU_PPC64",
6328 "TARGET_CPU_68K",
6329 "TARGET_CPU_X86",
6330 "TARGET_CPU_ARM",
6331 "TARGET_CPU_MIPS",
6332 "TARGET_CPU_SPARC",
6333 "TARGET_CPU_ALPHA",
6334 "TARGET_IPHONE_SIMULATOR",
6335 "TARGET_OS_EMBEDDED",
6336 "TARGET_OS_IPHONE",
6337 "TARGET_OS_MAC",
6338 "TARGET_OS_UNIX",
6339 "TARGET_OS_WIN32",
6340 )
6341 ifdef_macro = input_api.re.compile(
6342 r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
6343 results = []
6344 for lnum, line in f.ChangedContents():
6345 for match in ifdef_macro.finditer(line):
6346 if match.group(1) in ALWAYS_DEFINED_MACROS:
6347 always_defined = ' %s is always defined. ' % match.group(1)
6348 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
6349 results.append(
6350 ' %s:%d %s\n\t%s' %
6351 (f.LocalPath(), lnum, always_defined, did_you_mean))
6352 return results
lliabraa35bab3932014-10-01 12:16:446353
6354
Saagar Sanghavifceeaae2020-08-12 16:40:366355def CheckForInvalidIfDefinedMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506356 """Check all affected files for invalid "if defined" macros."""
Arthur Sonzogni4fd14fd2024-06-02 18:42:526357 SKIPPED_PATHS = [
6358 'base/allocator/partition_allocator/src/partition_alloc/build_config.h',
6359 'build/build_config.h',
6360 'third_party/abseil-cpp/',
6361 'third_party/sqlite/',
6362 ]
6363 def affected_files_filter(f):
6364 # Normalize the local path to Linux-style path separators so that the
6365 # path comparisons work on Windows as well.
Anton Bershanskyi4253349482025-02-11 21:01:276366 path = f.UnixLocalPath()
Arthur Sonzogni4fd14fd2024-06-02 18:42:526367
6368 for skipped_path in SKIPPED_PATHS:
6369 if path.startswith(skipped_path):
6370 return False
6371
6372 return path.endswith(('.h', '.c', '.cc', '.m', '.mm'))
6373
Sam Maiera6e76d72022-02-11 21:43:506374 bad_macros = []
Arthur Sonzogni4fd14fd2024-06-02 18:42:526375 for f in input_api.AffectedSourceFiles(affected_files_filter):
6376 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
lliabraa35bab3932014-10-01 12:16:446377
Sam Maiera6e76d72022-02-11 21:43:506378 if not bad_macros:
6379 return []
lliabraa35bab3932014-10-01 12:16:446380
Sam Maiera6e76d72022-02-11 21:43:506381 return [
6382 output_api.PresubmitError(
6383 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
6384 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
6385 bad_macros)
6386 ]
lliabraa35bab3932014-10-01 12:16:446387
Saagar Sanghavifceeaae2020-08-12 16:40:366388def CheckForIPCRules(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506389 """Check for same IPC rules described in
6390 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
6391 """
6392 base_pattern = r'IPC_ENUM_TRAITS\('
6393 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
6394 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
mlamouria82272622014-09-16 18:45:046395
Sam Maiera6e76d72022-02-11 21:43:506396 problems = []
6397 for f in input_api.AffectedSourceFiles(None):
6398 local_path = f.LocalPath()
6399 if not local_path.endswith('.h'):
6400 continue
6401 for line_number, line in f.ChangedContents():
6402 if inclusion_pattern.search(
6403 line) and not comment_pattern.search(line):
6404 problems.append('%s:%d\n %s' %
6405 (local_path, line_number, line.strip()))
mlamouria82272622014-09-16 18:45:046406
Sam Maiera6e76d72022-02-11 21:43:506407 if problems:
6408 return [
6409 output_api.PresubmitPromptWarning(_IPC_ENUM_TRAITS_DEPRECATED,
6410 problems)
6411 ]
6412 else:
6413 return []
mlamouria82272622014-09-16 18:45:046414
[email protected]b00342e7f2013-03-26 16:21:546415
Saagar Sanghavifceeaae2020-08-12 16:40:366416def CheckForLongPathnames(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506417 """Check to make sure no files being submitted have long paths.
6418 This causes issues on Windows.
6419 """
6420 problems = []
6421 for f in input_api.AffectedTestableFiles():
6422 local_path = f.LocalPath()
6423 # Windows has a path limit of 260 characters. Limit path length to 200 so
6424 # that we have some extra for the prefix on dev machines and the bots.
Weizhong Xia8b461f12024-06-21 21:46:336425 if (local_path.startswith('third_party/blink/web_tests/platform/') and
6426 not local_path.startswith('third_party/blink/web_tests/platform/win')):
6427 # Do not check length of the path for files not used by Windows
6428 continue
Sam Maiera6e76d72022-02-11 21:43:506429 if len(local_path) > 200:
6430 problems.append(local_path)
Stephen Martinis97a394142018-06-07 23:06:056431
Sam Maiera6e76d72022-02-11 21:43:506432 if problems:
6433 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
6434 else:
6435 return []
Stephen Martinis97a394142018-06-07 23:06:056436
6437
Saagar Sanghavifceeaae2020-08-12 16:40:366438def CheckForIncludeGuards(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506439 """Check that header files have proper guards against multiple inclusion.
6440 If a file should not have such guards (and it probably should) then it
Bruce Dawson4a5579a2022-04-08 17:11:366441 should include the string "no-include-guard-because-multiply-included" or
6442 "no-include-guard-because-pch-file".
Sam Maiera6e76d72022-02-11 21:43:506443 """
Daniel Bratell8ba52722018-03-02 16:06:146444
Sam Maiera6e76d72022-02-11 21:43:506445 def is_chromium_header_file(f):
6446 # We only check header files under the control of the Chromium
mikt84d6c712024-03-27 13:29:036447 # project. This excludes:
6448 # - third_party/*, except blink.
6449 # - base/allocator/partition_allocator/: PartitionAlloc is a standalone
6450 # library used outside of Chrome. Includes are referenced from its
6451 # own base directory. It has its own `CheckForIncludeGuards`
6452 # PRESUBMIT.py check.
6453 # - *_message_generator.h: They use include guards in a special,
6454 # non-typical way.
Sam Maiera6e76d72022-02-11 21:43:506455 file_with_path = input_api.os_path.normpath(f.LocalPath())
6456 return (file_with_path.endswith('.h')
6457 and not file_with_path.endswith('_message_generator.h')
Bruce Dawson4c4c2922022-05-02 18:07:336458 and not file_with_path.endswith('com_imported_mstscax.h')
Peter Kasting66c1f752024-12-02 15:28:376459 and not file_with_path.startswith(
6460 input_api.os_path.join('base', 'allocator',
6461 'partition_allocator'))
Sam Maiera6e76d72022-02-11 21:43:506462 and (not file_with_path.startswith('third_party')
6463 or file_with_path.startswith(
6464 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:146465
Sam Maiera6e76d72022-02-11 21:43:506466 def replace_special_with_underscore(string):
6467 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:146468
Sam Maiera6e76d72022-02-11 21:43:506469 errors = []
Daniel Bratell8ba52722018-03-02 16:06:146470
Sam Maiera6e76d72022-02-11 21:43:506471 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
6472 guard_name = None
6473 guard_line_number = None
6474 seen_guard_end = False
Lei Zhangd84f9512024-05-28 19:43:306475 bypass_checks_at_end_of_file = False
Daniel Bratell8ba52722018-03-02 16:06:146476
Sam Maiera6e76d72022-02-11 21:43:506477 file_with_path = input_api.os_path.normpath(f.LocalPath())
6478 base_file_name = input_api.os_path.splitext(
6479 input_api.os_path.basename(file_with_path))[0]
6480 upper_base_file_name = base_file_name.upper()
Daniel Bratell8ba52722018-03-02 16:06:146481
Sam Maiera6e76d72022-02-11 21:43:506482 expected_guard = replace_special_with_underscore(
6483 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:146484
Sam Maiera6e76d72022-02-11 21:43:506485 # For "path/elem/file_name.h" we should really only accept
6486 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
6487 # are too many (1000+) files with slight deviations from the
6488 # coding style. The most important part is that the include guard
6489 # is there, and that it's unique, not the name so this check is
6490 # forgiving for existing files.
6491 #
6492 # As code becomes more uniform, this could be made stricter.
Daniel Bratell8ba52722018-03-02 16:06:146493
Sam Maiera6e76d72022-02-11 21:43:506494 guard_name_pattern_list = [
6495 # Anything with the right suffix (maybe with an extra _).
6496 r'\w+_H__?',
Daniel Bratell8ba52722018-03-02 16:06:146497
Sam Maiera6e76d72022-02-11 21:43:506498 # To cover include guards with old Blink style.
6499 r'\w+_h',
Daniel Bratell8ba52722018-03-02 16:06:146500
Sam Maiera6e76d72022-02-11 21:43:506501 # Anything including the uppercase name of the file.
6502 r'\w*' + input_api.re.escape(
6503 replace_special_with_underscore(upper_base_file_name)) +
6504 r'\w*',
6505 ]
6506 guard_name_pattern = '|'.join(guard_name_pattern_list)
6507 guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
6508 guard_name_pattern + ')')
Daniel Bratell8ba52722018-03-02 16:06:146509
Sam Maiera6e76d72022-02-11 21:43:506510 for line_number, line in enumerate(f.NewContents()):
Bruce Dawson4a5579a2022-04-08 17:11:366511 if ('no-include-guard-because-multiply-included' in line
6512 or 'no-include-guard-because-pch-file' in line):
Lei Zhangd84f9512024-05-28 19:43:306513 bypass_checks_at_end_of_file = True
Sam Maiera6e76d72022-02-11 21:43:506514 break
Daniel Bratell8ba52722018-03-02 16:06:146515
Sam Maiera6e76d72022-02-11 21:43:506516 if guard_name is None:
6517 match = guard_pattern.match(line)
6518 if match:
6519 guard_name = match.group(1)
6520 guard_line_number = line_number
Daniel Bratell8ba52722018-03-02 16:06:146521
Sam Maiera6e76d72022-02-11 21:43:506522 # We allow existing files to use include guards whose names
6523 # don't match the chromium style guide, but new files should
6524 # get it right.
Bruce Dawson6cc154e2022-04-12 20:39:496525 if guard_name != expected_guard:
Bruce Dawson95eb7562022-09-14 15:27:166526 if f.Action() == 'A': # If file was just 'A'dded
Sam Maiera6e76d72022-02-11 21:43:506527 errors.append(
6528 output_api.PresubmitPromptWarning(
6529 'Header using the wrong include guard name %s'
6530 % guard_name, [
6531 '%s:%d' %
6532 (f.LocalPath(), line_number + 1)
6533 ], 'Expected: %r\nFound: %r' %
6534 (expected_guard, guard_name)))
6535 else:
6536 # The line after #ifndef should have a #define of the same name.
6537 if line_number == guard_line_number + 1:
6538 expected_line = '#define %s' % guard_name
6539 if line != expected_line:
6540 errors.append(
6541 output_api.PresubmitPromptWarning(
6542 'Missing "%s" for include guard' %
6543 expected_line,
6544 ['%s:%d' % (f.LocalPath(), line_number + 1)],
6545 'Expected: %r\nGot: %r' %
6546 (expected_line, line)))
Daniel Bratell8ba52722018-03-02 16:06:146547
Sam Maiera6e76d72022-02-11 21:43:506548 if not seen_guard_end and line == '#endif // %s' % guard_name:
6549 seen_guard_end = True
6550 elif seen_guard_end:
6551 if line.strip() != '':
6552 errors.append(
6553 output_api.PresubmitPromptWarning(
6554 'Include guard %s not covering the whole file'
6555 % (guard_name), [f.LocalPath()]))
6556 break # Nothing else to check and enough to warn once.
Daniel Bratell8ba52722018-03-02 16:06:146557
Lei Zhangd84f9512024-05-28 19:43:306558 if bypass_checks_at_end_of_file:
6559 continue
6560
Sam Maiera6e76d72022-02-11 21:43:506561 if guard_name is None:
6562 errors.append(
6563 output_api.PresubmitPromptWarning(
Bruce Dawson32114b62022-04-11 16:45:496564 'Missing include guard in %s\n'
Sam Maiera6e76d72022-02-11 21:43:506565 'Recommended name: %s\n'
6566 'This check can be disabled by having the string\n'
Bruce Dawson4a5579a2022-04-08 17:11:366567 '"no-include-guard-because-multiply-included" or\n'
6568 '"no-include-guard-because-pch-file" in the header.'
Sam Maiera6e76d72022-02-11 21:43:506569 % (f.LocalPath(), expected_guard)))
Lei Zhangd84f9512024-05-28 19:43:306570 elif not seen_guard_end:
6571 errors.append(
6572 output_api.PresubmitPromptWarning(
6573 'Incorrect or missing include guard #endif in %s\n'
6574 'Recommended #endif comment: // %s'
6575 % (f.LocalPath(), expected_guard)))
Sam Maiera6e76d72022-02-11 21:43:506576
6577 return errors
Daniel Bratell8ba52722018-03-02 16:06:146578
6579
Saagar Sanghavifceeaae2020-08-12 16:40:366580def CheckForWindowsLineEndings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506581 """Check source code and known ascii text files for Windows style line
6582 endings.
6583 """
Bruce Dawson5efbdc652022-04-11 19:29:516584 known_text_files = r'.*\.(txt|html|htm|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:236585
dpapadfd421fb2025-02-13 00:47:326586 _WEBUI_FILES_EXTENSIONS = r'\.(css|html|js|ts|svg)$'
6587
Sam Maiera6e76d72022-02-11 21:43:506588 file_inclusion_pattern = (known_text_files,
6589 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
dpapadfd421fb2025-02-13 00:47:326590 r'.+%s' % _HEADER_EXTENSIONS,
6591 r'.+%s' % _WEBUI_FILES_EXTENSIONS)
6592
6593 # Exclude folder that contains .ts files that are actually binary video
6594 # format and not TypeScript.
6595 file_exclusion_pattern = (r'media/test/data/')
mostynbb639aca52015-01-07 20:31:236596
Sam Maiera6e76d72022-02-11 21:43:506597 problems = []
6598 source_file_filter = lambda f: input_api.FilterSourceFile(
dpapadfd421fb2025-02-13 00:47:326599 f, files_to_check=file_inclusion_pattern,
6600 files_to_skip=file_exclusion_pattern)
Sam Maiera6e76d72022-02-11 21:43:506601 for f in input_api.AffectedSourceFiles(source_file_filter):
Bruce Dawson5efbdc652022-04-11 19:29:516602 # Ignore test files that contain crlf intentionally.
6603 if f.LocalPath().endswith('crlf.txt'):
Daniel Chenga37c03db2022-05-12 17:20:346604 continue
Sam Maiera6e76d72022-02-11 21:43:506605 include_file = False
6606 for line in input_api.ReadFile(f, 'r').splitlines(True):
6607 if line.endswith('\r\n'):
6608 include_file = True
6609 if include_file:
6610 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:236611
Sam Maiera6e76d72022-02-11 21:43:506612 if problems:
6613 return [
6614 output_api.PresubmitPromptWarning(
6615 'Are you sure that you want '
6616 'these files to contain Windows style line endings?\n' +
6617 '\n'.join(problems))
6618 ]
mostynbb639aca52015-01-07 20:31:236619
Sam Maiera6e76d72022-02-11 21:43:506620 return []
6621
mostynbb639aca52015-01-07 20:31:236622
Evan Stade6cfc964c12021-05-18 20:21:166623def CheckIconFilesForLicenseHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506624 """Check that .icon files (which are fragments of C++) have license headers.
6625 """
Evan Stade6cfc964c12021-05-18 20:21:166626
Sam Maiera6e76d72022-02-11 21:43:506627 icon_files = (r'.*\.icon$', )
Evan Stade6cfc964c12021-05-18 20:21:166628
Sam Maiera6e76d72022-02-11 21:43:506629 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
6630 return input_api.canned_checks.CheckLicense(input_api,
6631 output_api,
6632 source_file_filter=icons)
6633
Evan Stade6cfc964c12021-05-18 20:21:166634
Jose Magana2b456f22021-03-09 23:26:406635def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506636 """Check source code for use of Chrome App technologies being
6637 deprecated.
6638 """
Jose Magana2b456f22021-03-09 23:26:406639
Sam Maiera6e76d72022-02-11 21:43:506640 def _CheckForDeprecatedTech(input_api,
6641 output_api,
6642 detection_list,
6643 files_to_check=None,
6644 files_to_skip=None):
Jose Magana2b456f22021-03-09 23:26:406645
Sam Maiera6e76d72022-02-11 21:43:506646 if (files_to_check or files_to_skip):
6647 source_file_filter = lambda f: input_api.FilterSourceFile(
6648 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
6649 else:
6650 source_file_filter = None
6651
6652 problems = []
6653
6654 for f in input_api.AffectedSourceFiles(source_file_filter):
6655 if f.Action() == 'D':
6656 continue
6657 for _, line in f.ChangedContents():
6658 if any(detect in line for detect in detection_list):
6659 problems.append(f.LocalPath())
6660
6661 return problems
6662
6663 # to avoid this presubmit script triggering warnings
6664 files_to_skip = ['PRESUBMIT.py', 'PRESUBMIT_test.py']
Jose Magana2b456f22021-03-09 23:26:406665
6666 problems = []
6667
Sam Maiera6e76d72022-02-11 21:43:506668 # NMF: any files with extensions .nmf or NMF
6669 _NMF_FILES = r'\.(nmf|NMF)$'
6670 problems += _CheckForDeprecatedTech(
6671 input_api,
6672 output_api,
6673 detection_list=[''], # any change to the file will trigger warning
6674 files_to_check=[r'.+%s' % _NMF_FILES])
Jose Magana2b456f22021-03-09 23:26:406675
Sam Maiera6e76d72022-02-11 21:43:506676 # MANIFEST: any manifest.json that in its diff includes "app":
6677 _MANIFEST_FILES = r'(manifest\.json)$'
6678 problems += _CheckForDeprecatedTech(
6679 input_api,
6680 output_api,
6681 detection_list=['"app":'],
6682 files_to_check=[r'.*%s' % _MANIFEST_FILES])
Jose Magana2b456f22021-03-09 23:26:406683
Sam Maiera6e76d72022-02-11 21:43:506684 # NaCl / PNaCl: any file that in its diff contains the strings in the list
6685 problems += _CheckForDeprecatedTech(
6686 input_api,
6687 output_api,
6688 detection_list=['config=nacl', 'enable-nacl', 'cpu=pnacl', 'nacl_io'],
Bruce Dawson40fece62022-09-16 19:58:316689 files_to_skip=files_to_skip + [r"^native_client_sdk/"])
Jose Magana2b456f22021-03-09 23:26:406690
Gao Shenga79ebd42022-08-08 17:25:596691 # PPAPI: any C/C++ file that in its diff includes a ppapi library
Sam Maiera6e76d72022-02-11 21:43:506692 problems += _CheckForDeprecatedTech(
6693 input_api,
6694 output_api,
6695 detection_list=['#include "ppapi', '#include <ppapi'],
6696 files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,
6697 r'.+%s' % _IMPLEMENTATION_EXTENSIONS),
Bruce Dawson40fece62022-09-16 19:58:316698 files_to_skip=[r"^ppapi/"])
Jose Magana2b456f22021-03-09 23:26:406699
Sam Maiera6e76d72022-02-11 21:43:506700 if problems:
6701 return [
6702 output_api.PresubmitPromptWarning(
6703 'You are adding/modifying code'
6704 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
6705 ' PNaCl, PPAPI). See this blog post for more details:\n'
6706 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
6707 'and this documentation for options to replace these technologies:\n'
6708 'https://developer.chrome.com/docs/apps/migration/\n' +
6709 '\n'.join(problems))
6710 ]
Jose Magana2b456f22021-03-09 23:26:406711
Sam Maiera6e76d72022-02-11 21:43:506712 return []
Jose Magana2b456f22021-03-09 23:26:406713
mostynbb639aca52015-01-07 20:31:236714
Saagar Sanghavifceeaae2020-08-12 16:40:366715def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
Sam Maiera6e76d72022-02-11 21:43:506716 """Checks that all source files use SYSLOG properly."""
6717 syslog_files = []
6718 for f in input_api.AffectedSourceFiles(src_file_filter):
6719 for line_number, line in f.ChangedContents():
6720 if 'SYSLOG' in line:
6721 syslog_files.append(f.LocalPath() + ':' + str(line_number))
pastarmovj032ba5bc2017-01-12 10:41:566722
Sam Maiera6e76d72022-02-11 21:43:506723 if syslog_files:
6724 return [
6725 output_api.PresubmitPromptWarning(
6726 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
6727 ' calls.\nFiles to check:\n',
6728 items=syslog_files)
6729 ]
6730 return []
pastarmovj89f7ee12016-09-20 14:58:136731
6732
[email protected]1f7b4172010-01-28 01:17:346733def CheckChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506734 if input_api.version < [2, 0, 0]:
6735 return [
6736 output_api.PresubmitError(
6737 "Your depot_tools is out of date. "
6738 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
6739 "but your version is %d.%d.%d" % tuple(input_api.version))
6740 ]
6741 results = []
6742 results.extend(
6743 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
6744 return results
[email protected]ca8d1982009-02-19 16:33:126745
6746
6747def CheckChangeOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506748 if input_api.version < [2, 0, 0]:
6749 return [
6750 output_api.PresubmitError(
6751 "Your depot_tools is out of date. "
6752 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
6753 "but your version is %d.%d.%d" % tuple(input_api.version))
6754 ]
Saagar Sanghavifceeaae2020-08-12 16:40:366755
Sam Maiera6e76d72022-02-11 21:43:506756 results = []
6757 # Make sure the tree is 'open'.
6758 results.extend(
6759 input_api.canned_checks.CheckTreeIsOpen(
6760 input_api,
6761 output_api,
6762 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:276763
Sam Maiera6e76d72022-02-11 21:43:506764 results.extend(
6765 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
6766 results.extend(
6767 input_api.canned_checks.CheckChangeHasBugField(input_api, output_api))
6768 results.extend(
6769 input_api.canned_checks.CheckChangeHasNoUnwantedTags(
6770 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:506771 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146772
6773
Saagar Sanghavifceeaae2020-08-12 16:40:366774def CheckStrings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506775 """Check string ICU syntax validity and if translation screenshots exist."""
6776 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
6777 # footer is set to true.
6778 git_footers = input_api.change.GitFootersFromDescription()
6779 skip_screenshot_check_footer = [
6780 footer.lower() for footer in git_footers.get(
6781 u'Skip-Translation-Screenshots-Check', [])
6782 ]
6783 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:026784
Sam Maiera6e76d72022-02-11 21:43:506785 import os
6786 import re
6787 import sys
6788 from io import StringIO
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146789
Sam Maiera6e76d72022-02-11 21:43:506790 new_or_added_paths = set(f.LocalPath() for f in input_api.AffectedFiles()
6791 if (f.Action() == 'A' or f.Action() == 'M'))
6792 removed_paths = set(f.LocalPath()
6793 for f in input_api.AffectedFiles(include_deletes=True)
6794 if f.Action() == 'D')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146795
Sam Maiera6e76d72022-02-11 21:43:506796 affected_grds = [
6797 f for f in input_api.AffectedFiles()
6798 if f.LocalPath().endswith(('.grd', '.grdp'))
6799 ]
6800 affected_grds = [
6801 f for f in affected_grds if not 'testdata' in f.LocalPath()
6802 ]
6803 if not affected_grds:
6804 return []
meacer8c0d3832019-12-26 21:46:166805
Sam Maiera6e76d72022-02-11 21:43:506806 affected_png_paths = [
Andrew Grieve713b89b2024-10-15 20:20:086807 f.LocalPath() for f in input_api.AffectedFiles()
6808 if f.LocalPath().endswith('.png')
Sam Maiera6e76d72022-02-11 21:43:506809 ]
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146810
Sam Maiera6e76d72022-02-11 21:43:506811 # Check for screenshots. Developers can upload screenshots using
6812 # tools/translation/upload_screenshots.py which finds and uploads
6813 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
6814 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
6815 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
6816 #
6817 # The logic here is as follows:
6818 #
6819 # - If the CL has a .png file under the screenshots directory for a grd
6820 # file, warn the developer. Actual images should never be checked into the
6821 # Chrome repo.
6822 #
6823 # - If the CL contains modified or new messages in grd files and doesn't
6824 # contain the corresponding .sha1 files, warn the developer to add images
6825 # and upload them via tools/translation/upload_screenshots.py.
6826 #
6827 # - If the CL contains modified or new messages in grd files and the
6828 # corresponding .sha1 files, everything looks good.
6829 #
6830 # - If the CL contains removed messages in grd files but the corresponding
6831 # .sha1 files aren't removed, warn the developer to remove them.
6832 unnecessary_screenshots = []
Jens Mueller054652c2023-05-10 15:12:306833 invalid_sha1 = []
Sam Maiera6e76d72022-02-11 21:43:506834 missing_sha1 = []
Bruce Dawson55776c42022-12-09 17:23:476835 missing_sha1_modified = []
Sam Maiera6e76d72022-02-11 21:43:506836 unnecessary_sha1_files = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146837
Sam Maiera6e76d72022-02-11 21:43:506838 # This checks verifies that the ICU syntax of messages this CL touched is
6839 # valid, and reports any found syntax errors.
6840 # Without this presubmit check, ICU syntax errors in Chromium strings can land
6841 # without developers being aware of them. Later on, such ICU syntax errors
6842 # break message extraction for translation, hence would block Chromium
6843 # translations until they are fixed.
6844 icu_syntax_errors = []
Jens Mueller054652c2023-05-10 15:12:306845 sha1_pattern = input_api.re.compile(r'^[a-fA-F0-9]{40}$',
6846 input_api.re.MULTILINE)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146847
Sam Maiera6e76d72022-02-11 21:43:506848 def _CheckScreenshotAdded(screenshots_dir, message_id):
6849 sha1_path = input_api.os_path.join(screenshots_dir,
6850 message_id + '.png.sha1')
6851 if sha1_path not in new_or_added_paths:
6852 missing_sha1.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306853 elif not _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256854 invalid_sha1.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146855
Bruce Dawson55776c42022-12-09 17:23:476856 def _CheckScreenshotModified(screenshots_dir, message_id):
6857 sha1_path = input_api.os_path.join(screenshots_dir,
6858 message_id + '.png.sha1')
6859 if sha1_path not in new_or_added_paths:
6860 missing_sha1_modified.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306861 elif not _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256862 invalid_sha1.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306863
6864 def _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256865 return sha1_pattern.search(
6866 next("\n".join(f.NewContents()) for f in input_api.AffectedFiles()
6867 if f.LocalPath() == sha1_path))
Bruce Dawson55776c42022-12-09 17:23:476868
Sam Maiera6e76d72022-02-11 21:43:506869 def _CheckScreenshotRemoved(screenshots_dir, message_id):
6870 sha1_path = input_api.os_path.join(screenshots_dir,
6871 message_id + '.png.sha1')
6872 if input_api.os_path.exists(
6873 sha1_path) and sha1_path not in removed_paths:
6874 unnecessary_sha1_files.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146875
Sam Maiera6e76d72022-02-11 21:43:506876 def _ValidateIcuSyntax(text, level, signatures):
6877 """Validates ICU syntax of a text string.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146878
Sam Maiera6e76d72022-02-11 21:43:506879 Check if text looks similar to ICU and checks for ICU syntax correctness
6880 in this case. Reports various issues with ICU syntax and values of
6881 variants. Supports checking of nested messages. Accumulate information of
6882 each ICU messages found in the text for further checking.
Rainhard Findlingfc31844c52020-05-15 09:58:266883
Sam Maiera6e76d72022-02-11 21:43:506884 Args:
6885 text: a string to check.
6886 level: a number of current nesting level.
6887 signatures: an accumulator, a list of tuple of (level, variable,
6888 kind, variants).
Rainhard Findlingfc31844c52020-05-15 09:58:266889
Sam Maiera6e76d72022-02-11 21:43:506890 Returns:
6891 None if a string is not ICU or no issue detected.
6892 A tuple of (message, start index, end index) if an issue detected.
6893 """
6894 valid_types = {
6895 'plural': (frozenset(
Rainhard Findling3cde3ef02024-02-05 18:40:326896 ['=0', '=1', '=2', '=3', 'zero', 'one', 'two', 'few', 'many',
Sam Maiera6e76d72022-02-11 21:43:506897 'other']), frozenset(['=1', 'other'])),
6898 'selectordinal': (frozenset(
Rainhard Findling3cde3ef02024-02-05 18:40:326899 ['=0', '=1', '=2', '=3', 'zero', 'one', 'two', 'few', 'many',
Sam Maiera6e76d72022-02-11 21:43:506900 'other']), frozenset(['one', 'other'])),
6901 'select': (frozenset(), frozenset(['other'])),
6902 }
Rainhard Findlingfc31844c52020-05-15 09:58:266903
Sam Maiera6e76d72022-02-11 21:43:506904 # Check if the message looks like an attempt to use ICU
6905 # plural. If yes - check if its syntax strictly matches ICU format.
6906 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b',
6907 text)
6908 if not like:
6909 signatures.append((level, None, None, None))
6910 return
Rainhard Findlingfc31844c52020-05-15 09:58:266911
Sam Maiera6e76d72022-02-11 21:43:506912 # Check for valid prefix and suffix
6913 m = re.match(
6914 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
6915 r'(plural|selectordinal|select),\s*'
6916 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
6917 if not m:
6918 return (('This message looks like an ICU plural, '
6919 'but does not follow ICU syntax.'), like.start(),
6920 like.end())
6921 starting, variable, kind, variant_pairs = m.groups()
6922 variants, depth, last_pos = _ParseIcuVariants(variant_pairs,
6923 m.start(4))
6924 if depth:
6925 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
6926 len(text))
6927 first = text[0]
6928 ending = text[last_pos:]
6929 if not starting:
6930 return ('Invalid ICU format. No initial opening bracket',
6931 last_pos - 1, last_pos)
6932 if not ending or '}' not in ending:
6933 return ('Invalid ICU format. No final closing bracket',
6934 last_pos - 1, last_pos)
6935 elif first != '{':
6936 return ((
6937 'Invalid ICU format. Extra characters at the start of a complex '
6938 'message (go/icu-message-migration): "%s"') % starting, 0,
6939 len(starting))
6940 elif ending != '}':
6941 return ((
6942 'Invalid ICU format. Extra characters at the end of a complex '
6943 'message (go/icu-message-migration): "%s"') % ending,
6944 last_pos - 1, len(text) - 1)
6945 if kind not in valid_types:
6946 return (('Unknown ICU message type %s. '
6947 'Valid types are: plural, select, selectordinal') % kind,
6948 0, 0)
6949 known, required = valid_types[kind]
6950 defined_variants = set()
6951 for variant, variant_range, value, value_range in variants:
6952 start, end = variant_range
6953 if variant in defined_variants:
6954 return ('Variant "%s" is defined more than once' % variant,
6955 start, end)
6956 elif known and variant not in known:
6957 return ('Variant "%s" is not valid for %s message' %
6958 (variant, kind), start, end)
6959 defined_variants.add(variant)
6960 # Check for nested structure
6961 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
6962 if res:
6963 return (res[0], res[1] + value_range[0] + 1,
6964 res[2] + value_range[0] + 1)
6965 missing = required - defined_variants
6966 if missing:
6967 return ('Required variants missing: %s' % ', '.join(missing), 0,
6968 len(text))
6969 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:266970
Sam Maiera6e76d72022-02-11 21:43:506971 def _ParseIcuVariants(text, offset=0):
6972 """Parse variants part of ICU complex message.
Rainhard Findlingfc31844c52020-05-15 09:58:266973
Sam Maiera6e76d72022-02-11 21:43:506974 Builds a tuple of variant names and values, as well as
6975 their offsets in the input string.
Rainhard Findlingfc31844c52020-05-15 09:58:266976
Sam Maiera6e76d72022-02-11 21:43:506977 Args:
6978 text: a string to parse
6979 offset: additional offset to add to positions in the text to get correct
6980 position in the complete ICU string.
Rainhard Findlingfc31844c52020-05-15 09:58:266981
Sam Maiera6e76d72022-02-11 21:43:506982 Returns:
6983 List of tuples, each tuple consist of four fields: variant name,
6984 variant name span (tuple of two integers), variant value, value
6985 span (tuple of two integers).
6986 """
6987 depth, start, end = 0, -1, -1
6988 variants = []
6989 key = None
6990 for idx, char in enumerate(text):
6991 if char == '{':
6992 if not depth:
6993 start = idx
6994 chunk = text[end + 1:start]
6995 key = chunk.strip()
6996 pos = offset + end + 1 + chunk.find(key)
6997 span = (pos, pos + len(key))
6998 depth += 1
6999 elif char == '}':
7000 if not depth:
7001 return variants, depth, offset + idx
7002 depth -= 1
7003 if not depth:
7004 end = idx
7005 variants.append((key, span, text[start:end + 1],
7006 (offset + start, offset + end + 1)))
7007 return variants, depth, offset + end + 1
Rainhard Findlingfc31844c52020-05-15 09:58:267008
Terrence Reilly313f44ff2025-01-22 15:10:147009 old_sys_path = sys.path
Sam Maiera6e76d72022-02-11 21:43:507010 try:
Sam Maiera6e76d72022-02-11 21:43:507011 sys.path = sys.path + [
7012 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
7013 'translation')
7014 ]
7015 from helper import grd_helper
7016 finally:
7017 sys.path = old_sys_path
Rainhard Findlingfc31844c52020-05-15 09:58:267018
Sam Maiera6e76d72022-02-11 21:43:507019 for f in affected_grds:
7020 file_path = f.LocalPath()
7021 old_id_to_msg_map = {}
7022 new_id_to_msg_map = {}
7023 # Note that this code doesn't check if the file has been deleted. This is
7024 # OK because it only uses the old and new file contents and doesn't load
7025 # the file via its path.
7026 # It's also possible that a file's content refers to a renamed or deleted
7027 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
7028 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
7029 # .grdp files.
7030 if file_path.endswith('.grdp'):
7031 if f.OldContents():
7032 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
7033 '\n'.join(f.OldContents()))
7034 if f.NewContents():
7035 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
7036 '\n'.join(f.NewContents()))
7037 else:
7038 file_dir = input_api.os_path.dirname(file_path) or '.'
7039 if f.OldContents():
7040 old_id_to_msg_map = grd_helper.GetGrdMessages(
7041 StringIO('\n'.join(f.OldContents())), file_dir)
7042 if f.NewContents():
7043 new_id_to_msg_map = grd_helper.GetGrdMessages(
7044 StringIO('\n'.join(f.NewContents())), file_dir)
Rainhard Findlingfc31844c52020-05-15 09:58:267045
Sam Maiera6e76d72022-02-11 21:43:507046 grd_name, ext = input_api.os_path.splitext(
7047 input_api.os_path.basename(file_path))
7048 screenshots_dir = input_api.os_path.join(
7049 input_api.os_path.dirname(file_path),
7050 grd_name + ext.replace('.', '_'))
Rainhard Findlingfc31844c52020-05-15 09:58:267051
Sam Maiera6e76d72022-02-11 21:43:507052 # Compute added, removed and modified message IDs.
7053 old_ids = set(old_id_to_msg_map)
7054 new_ids = set(new_id_to_msg_map)
7055 added_ids = new_ids - old_ids
7056 removed_ids = old_ids - new_ids
7057 modified_ids = set([])
7058 for key in old_ids.intersection(new_ids):
7059 if (old_id_to_msg_map[key].ContentsAsXml('', True) !=
7060 new_id_to_msg_map[key].ContentsAsXml('', True)):
7061 # The message content itself changed. Require an updated screenshot.
7062 modified_ids.add(key)
7063 elif old_id_to_msg_map[key].attrs['meaning'] != \
7064 new_id_to_msg_map[key].attrs['meaning']:
Jens Mueller054652c2023-05-10 15:12:307065 # The message meaning changed. We later check for a screenshot.
7066 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147067
Sam Maiera6e76d72022-02-11 21:43:507068 if run_screenshot_check:
7069 # Check the screenshot directory for .png files. Warn if there is any.
7070 for png_path in affected_png_paths:
7071 if png_path.startswith(screenshots_dir):
7072 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147073
Sam Maiera6e76d72022-02-11 21:43:507074 for added_id in added_ids:
7075 _CheckScreenshotAdded(screenshots_dir, added_id)
Rainhard Findlingd8d04372020-08-13 13:30:097076
Sam Maiera6e76d72022-02-11 21:43:507077 for modified_id in modified_ids:
Bruce Dawson55776c42022-12-09 17:23:477078 _CheckScreenshotModified(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147079
Sam Maiera6e76d72022-02-11 21:43:507080 for removed_id in removed_ids:
7081 _CheckScreenshotRemoved(screenshots_dir, removed_id)
7082
7083 # Check new and changed strings for ICU syntax errors.
7084 for key in added_ids.union(modified_ids):
7085 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
7086 err = _ValidateIcuSyntax(msg, 0, [])
7087 if err is not None:
7088 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
7089
7090 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:267091 if run_screenshot_check:
Sam Maiera6e76d72022-02-11 21:43:507092 if unnecessary_screenshots:
7093 results.append(
7094 output_api.PresubmitError(
7095 'Do not include actual screenshots in the changelist. Run '
7096 'tools/translate/upload_screenshots.py to upload them instead:',
7097 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147098
Sam Maiera6e76d72022-02-11 21:43:507099 if missing_sha1:
7100 results.append(
7101 output_api.PresubmitError(
Bruce Dawson55776c42022-12-09 17:23:477102 'You are adding UI strings.\n'
Sam Maiera6e76d72022-02-11 21:43:507103 'To ensure the best translations, take screenshots of the relevant UI '
7104 '(https://g.co/chrome/translation) and add these files to your '
7105 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147106
Jens Mueller054652c2023-05-10 15:12:307107 if invalid_sha1:
7108 results.append(
7109 output_api.PresubmitError(
7110 'The following files do not seem to contain valid sha1 hashes. '
7111 'Make sure they contain hashes created by '
7112 'tools/translate/upload_screenshots.py:', sorted(invalid_sha1)))
7113
Bruce Dawson55776c42022-12-09 17:23:477114 if missing_sha1_modified:
7115 results.append(
7116 output_api.PresubmitError(
7117 'You are modifying UI strings or their meanings.\n'
7118 'To ensure the best translations, take screenshots of the relevant UI '
7119 '(https://g.co/chrome/translation) and add these files to your '
7120 'changelist:', sorted(missing_sha1_modified)))
7121
Sam Maiera6e76d72022-02-11 21:43:507122 if unnecessary_sha1_files:
7123 results.append(
7124 output_api.PresubmitError(
7125 'You removed strings associated with these files. Remove:',
7126 sorted(unnecessary_sha1_files)))
7127 else:
7128 results.append(
7129 output_api.PresubmitPromptOrNotify('Skipping translation '
7130 'screenshots check.'))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147131
Sam Maiera6e76d72022-02-11 21:43:507132 if icu_syntax_errors:
7133 results.append(
7134 output_api.PresubmitPromptWarning(
7135 'ICU syntax errors were found in the following strings (problems or '
7136 'feedback? Contact [email protected]):',
7137 items=icu_syntax_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:267138
Sam Maiera6e76d72022-02-11 21:43:507139 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:127140
7141
Saagar Sanghavifceeaae2020-08-12 16:40:367142def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:127143 repo_root=None,
7144 translation_expectations_path=None,
7145 grd_files=None):
Sam Maiera6e76d72022-02-11 21:43:507146 import sys
7147 affected_grds = [
7148 f for f in input_api.AffectedFiles()
7149 if (f.LocalPath().endswith('.grd') or f.LocalPath().endswith('.grdp'))
7150 ]
7151 if not affected_grds:
7152 return []
7153
Terrence Reilly313f44ff2025-01-22 15:10:147154 old_sys_path = sys.path
Sam Maiera6e76d72022-02-11 21:43:507155 try:
Sam Maiera6e76d72022-02-11 21:43:507156 sys.path = sys.path + [
7157 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
7158 'translation')
7159 ]
Terrence Reilly313f44ff2025-01-22 15:10:147160 sys.path = sys.path + [
7161 input_api.os_path.join(input_api.PresubmitLocalPath(),
7162 'third_party', 'depot_tools')
7163 ]
Sam Maiera6e76d72022-02-11 21:43:507164 from helper import git_helper
7165 from helper import translation_helper
Terrence Reilly313f44ff2025-01-22 15:10:147166 import gclient_utils
Sam Maiera6e76d72022-02-11 21:43:507167 finally:
7168 sys.path = old_sys_path
7169
7170 # Check that translation expectations can be parsed and we can get a list of
7171 # translatable grd files. |repo_root| and |translation_expectations_path| are
7172 # only passed by tests.
7173 if not repo_root:
7174 repo_root = input_api.PresubmitLocalPath()
7175 if not translation_expectations_path:
7176 translation_expectations_path = input_api.os_path.join(
7177 repo_root, 'tools', 'gritsettings', 'translation_expectations.pyl')
Terrence Reilly313f44ff2025-01-22 15:10:147178 is_cog = gclient_utils.IsEnvCog()
7179 # Git is not available in cog workspaces.
7180 if not grd_files and not is_cog:
Sam Maiera6e76d72022-02-11 21:43:507181 grd_files = git_helper.list_grds_in_repository(repo_root)
Terrence Reilly313f44ff2025-01-22 15:10:147182 if not grd_files:
7183 grd_files = []
Sam Maiera6e76d72022-02-11 21:43:507184
7185 # Ignore bogus grd files used only for testing
Gao Shenga79ebd42022-08-08 17:25:597186 # ui/webui/resources/tools/generate_grd.py.
Sam Maiera6e76d72022-02-11 21:43:507187 ignore_path = input_api.os_path.join('ui', 'webui', 'resources', 'tools',
7188 'tests')
7189 grd_files = [p for p in grd_files if ignore_path not in p]
7190
Ben Mason5d4c3242025-04-15 20:28:377191 # Ensure no duplicate basenames.
7192 basename_to_src_paths = {}
7193 for grd_path in grd_files:
7194 basename = input_api.os_path.basename(grd_path)
7195 basename_to_src_paths.setdefault(basename, [])
7196 basename_to_src_paths[basename].append(grd_path)
7197 for src_paths in basename_to_src_paths.values():
7198 if len(src_paths) > 1:
7199 return [
7200 output_api.PresubmitNotifyResult(
7201 'Multiple string files have the same basename. This will result in '
7202 'missing translations. Files: %s'
7203 % ', '.join(src_paths))
7204 ]
7205
Sam Maiera6e76d72022-02-11 21:43:507206 try:
7207 translation_helper.get_translatable_grds(
Terrence Reilly313f44ff2025-01-22 15:10:147208 repo_root, grd_files, translation_expectations_path, is_cog)
Sam Maiera6e76d72022-02-11 21:43:507209 except Exception as e:
7210 return [
7211 output_api.PresubmitNotifyResult(
7212 'Failed to get a list of translatable grd files. This happens when:\n'
7213 ' - One of the modified grd or grdp files cannot be parsed or\n'
7214 ' - %s is not updated.\n'
7215 'Stack:\n%s' % (translation_expectations_path, str(e)))
7216 ]
Mustafa Emre Acer51f2f742020-03-09 19:41:127217 return []
7218
Ken Rockotc31f4832020-05-29 18:58:517219
Saagar Sanghavifceeaae2020-08-12 16:40:367220def CheckStableMojomChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507221 """Changes to [Stable] mojom types must preserve backward-compatibility."""
7222 changed_mojoms = input_api.AffectedFiles(
7223 include_deletes=True,
7224 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:527225
Bruce Dawson344ab262022-06-04 11:35:107226 if not changed_mojoms or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:507227 return []
7228
7229 delta = []
7230 for mojom in changed_mojoms:
Sam Maiera6e76d72022-02-11 21:43:507231 delta.append({
7232 'filename': mojom.LocalPath(),
7233 'old': '\n'.join(mojom.OldContents()) or None,
7234 'new': '\n'.join(mojom.NewContents()) or None,
7235 })
7236
7237 process = input_api.subprocess.Popen([
Takuto Ikutadca10222022-04-13 02:51:217238 input_api.python3_executable,
Sam Maiera6e76d72022-02-11 21:43:507239 input_api.os_path.join(
7240 input_api.PresubmitLocalPath(), 'mojo', 'public', 'tools', 'mojom',
7241 'check_stable_mojom_compatibility.py'), '--src-root',
7242 input_api.PresubmitLocalPath()
7243 ],
7244 stdin=input_api.subprocess.PIPE,
7245 stdout=input_api.subprocess.PIPE,
7246 stderr=input_api.subprocess.PIPE,
7247 universal_newlines=True)
7248 (x, error) = process.communicate(input=input_api.json.dumps(delta))
7249 if process.returncode:
7250 return [
7251 output_api.PresubmitError(
7252 'One or more [Stable] mojom definitions appears to have been changed '
Alex Goughc99921652024-02-15 22:59:127253 'in a way that is not backward-compatible. See '
7254 'https://chromium.googlesource.com/chromium/src/+/HEAD/mojo/public/tools/bindings/README.md#versioning'
7255 ' for details.',
Sam Maiera6e76d72022-02-11 21:43:507256 long_text=error)
7257 ]
Erik Staabc734cd7a2021-11-23 03:11:527258 return []
7259
Dominic Battre645d42342020-12-04 16:14:107260def CheckDeprecationOfPreferences(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507261 """Removing a preference should come with a deprecation."""
Dominic Battre645d42342020-12-04 16:14:107262
Sam Maiera6e76d72022-02-11 21:43:507263 def FilterFile(affected_file):
7264 """Accept only .cc files and the like."""
7265 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
7266 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
7267 input_api.DEFAULT_FILES_TO_SKIP)
7268 return input_api.FilterSourceFile(
7269 affected_file,
7270 files_to_check=file_inclusion_pattern,
7271 files_to_skip=files_to_skip)
Dominic Battre645d42342020-12-04 16:14:107272
Sam Maiera6e76d72022-02-11 21:43:507273 def ModifiedLines(affected_file):
7274 """Returns a list of tuples (line number, line text) of added and removed
7275 lines.
Dominic Battre645d42342020-12-04 16:14:107276
Sam Maiera6e76d72022-02-11 21:43:507277 Deleted lines share the same line number as the previous line.
Dominic Battre645d42342020-12-04 16:14:107278
Sam Maiera6e76d72022-02-11 21:43:507279 This relies on the scm diff output describing each changed code section
7280 with a line of the form
Dominic Battre645d42342020-12-04 16:14:107281
Sam Maiera6e76d72022-02-11 21:43:507282 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
7283 """
7284 line_num = 0
7285 modified_lines = []
7286 for line in affected_file.GenerateScmDiff().splitlines():
7287 # Extract <new line num> of the patch fragment (see format above).
7288 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@',
7289 line)
7290 if m:
7291 line_num = int(m.groups(1)[0])
7292 continue
7293 if ((line.startswith('+') and not line.startswith('++'))
7294 or (line.startswith('-') and not line.startswith('--'))):
7295 modified_lines.append((line_num, line))
Dominic Battre645d42342020-12-04 16:14:107296
Sam Maiera6e76d72022-02-11 21:43:507297 if not line.startswith('-'):
7298 line_num += 1
7299 return modified_lines
Dominic Battre645d42342020-12-04 16:14:107300
Sam Maiera6e76d72022-02-11 21:43:507301 def FindLineWith(lines, needle):
7302 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
Dominic Battre645d42342020-12-04 16:14:107303
Sam Maiera6e76d72022-02-11 21:43:507304 If 0 or >1 lines contain `needle`, -1 is returned.
7305 """
7306 matching_line_numbers = [
7307 # + 1 for 1-based counting of line numbers.
7308 i + 1 for i, line in enumerate(lines) if needle in line
7309 ]
7310 return matching_line_numbers[0] if len(
7311 matching_line_numbers) == 1 else -1
Dominic Battre645d42342020-12-04 16:14:107312
Sam Maiera6e76d72022-02-11 21:43:507313 def ModifiedPrefMigration(affected_file):
7314 """Returns whether the MigrateObsolete.*Pref functions were modified."""
7315 # Determine first and last lines of MigrateObsolete.*Pref functions.
7316 new_contents = affected_file.NewContents()
7317 range_1 = (FindLineWith(new_contents,
7318 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
7319 FindLineWith(new_contents,
7320 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
7321 range_2 = (FindLineWith(new_contents,
7322 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
7323 FindLineWith(new_contents,
7324 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
7325 if (-1 in range_1 + range_2):
7326 raise Exception(
7327 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.'
7328 )
Dominic Battre645d42342020-12-04 16:14:107329
Sam Maiera6e76d72022-02-11 21:43:507330 # Check whether any of the modified lines are part of the
7331 # MigrateObsolete.*Pref functions.
7332 for line_nr, line in ModifiedLines(affected_file):
7333 if (range_1[0] <= line_nr <= range_1[1]
7334 or range_2[0] <= line_nr <= range_2[1]):
7335 return True
7336 return False
Dominic Battre645d42342020-12-04 16:14:107337
Sam Maiera6e76d72022-02-11 21:43:507338 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
7339 browser_prefs_file_pattern = input_api.re.compile(
7340 r'chrome/browser/prefs/browser_prefs.cc')
Dominic Battre645d42342020-12-04 16:14:107341
Sam Maiera6e76d72022-02-11 21:43:507342 changes = input_api.AffectedFiles(include_deletes=True,
7343 file_filter=FilterFile)
7344 potential_problems = []
7345 for f in changes:
7346 for line in f.GenerateScmDiff().splitlines():
7347 # Check deleted lines for pref registrations.
7348 if (line.startswith('-') and not line.startswith('--')
7349 and register_pref_pattern.search(line)):
7350 potential_problems.append('%s: %s' % (f.LocalPath(), line))
Dominic Battre645d42342020-12-04 16:14:107351
Sam Maiera6e76d72022-02-11 21:43:507352 if browser_prefs_file_pattern.search(f.LocalPath()):
7353 # If the developer modified the MigrateObsolete.*Prefs() functions, we
7354 # assume that they knew that they have to deprecate preferences and don't
7355 # warn.
7356 try:
7357 if ModifiedPrefMigration(f):
7358 return []
7359 except Exception as e:
7360 return [output_api.PresubmitError(str(e))]
Dominic Battre645d42342020-12-04 16:14:107361
Sam Maiera6e76d72022-02-11 21:43:507362 if potential_problems:
7363 return [
7364 output_api.PresubmitPromptWarning(
7365 'Discovered possible removal of preference registrations.\n\n'
7366 'Please make sure to properly deprecate preferences by clearing their\n'
7367 'value for a couple of milestones before finally removing the code.\n'
7368 'Otherwise data may stay in the preferences files forever. See\n'
7369 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
7370 'chrome/browser/prefs/README.md for examples.\n'
7371 'This may be a false positive warning (e.g. if you move preference\n'
7372 'registrations to a different place).\n', potential_problems)
7373 ]
7374 return []
7375
Matt Stark6ef08872021-07-29 01:21:467376
7377def CheckConsistentGrdChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507378 """Changes to GRD files must be consistent for tools to read them."""
7379 changed_grds = input_api.AffectedFiles(
7380 include_deletes=False,
7381 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
7382 errors = []
7383 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
7384 for matcher, msg in _INVALID_GRD_FILE_LINE]
7385 for grd in changed_grds:
7386 for i, line in enumerate(grd.NewContents()):
7387 for matcher, msg in invalid_file_regexes:
7388 if matcher.search(line):
7389 errors.append(
7390 output_api.PresubmitError(
7391 'Problem on {grd}:{i} - {msg}'.format(
7392 grd=grd.LocalPath(), i=i + 1, msg=msg)))
7393 return errors
7394
Kevin McNee967dd2d22021-11-15 16:09:297395
Henrique Ferreiro2a4b55942021-11-29 23:45:367396def CheckAssertAshOnlyCode(input_api, output_api):
7397 """Errors if a BUILD.gn file in an ash/ directory doesn't include
Georg Neis94f87f02024-10-22 08:20:137398 assert(is_chromeos).
7399 For a transition period, assert(is_chromeos_ash) is also accepted.
Henrique Ferreiro2a4b55942021-11-29 23:45:367400 """
7401
7402 def FileFilter(affected_file):
7403 """Includes directories known to be Ash only."""
7404 return input_api.FilterSourceFile(
7405 affected_file,
7406 files_to_check=(
7407 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
7408 r'.*/ash/.*BUILD\.gn'), # Any path component.
7409 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
7410
7411 errors = []
Georg Neis94f87f02024-10-22 08:20:137412 pattern = input_api.re.compile(r'assert\(is_chromeos(_ash)?\b')
Jameson Thies0ce669f2021-12-09 15:56:567413 for f in input_api.AffectedFiles(include_deletes=False,
7414 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:367415 if (not pattern.search(input_api.ReadFile(f))):
7416 errors.append(
7417 output_api.PresubmitError(
Georg Neis94f87f02024-10-22 08:20:137418 'Please add assert(is_chromeos) to %s. If that\'s not '
7419 'possible, please create an issue and add a comment such '
Alison Galed6b25fe2024-04-17 13:59:047420 'as:\n # TODO(crbug.com/XXX): add '
Georg Neis94f87f02024-10-22 08:20:137421 'assert(is_chromeos) when ...' % f.LocalPath()))
Henrique Ferreiro2a4b55942021-11-29 23:45:367422 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:277423
7424
Kalvin Lee84ad17a2023-09-25 11:14:417425def _IsMiraclePtrDisallowed(input_api, affected_file):
Anton Bershanskyi4253349482025-02-11 21:01:277426 path = affected_file.UnixLocalPath()
Sam Maiera6e76d72022-02-11 21:43:507427 if not _IsCPlusPlusFile(input_api, path):
7428 return False
7429
Bartek Nowierski49b1a452024-06-08 00:24:357430 # Renderer-only code is generally allowed to use MiraclePtr. These
7431 # directories, however, are specifically disallowed, for perf reasons.
Kalvin Lee84ad17a2023-09-25 11:14:417432 if ("third_party/blink/renderer/core/" in path
7433 or "third_party/blink/renderer/platform/heap/" in path
Bartek Nowierski49b1a452024-06-08 00:24:357434 or "third_party/blink/renderer/platform/wtf/" in path
7435 or "third_party/blink/renderer/platform/fonts/" in path):
7436 return True
7437
7438 # The below paths are an explicitly listed subset of Renderer-only code,
7439 # because the plan is to Oilpanize it.
7440 # TODO(crbug.com/330759291): Remove once Oilpanization is completed or
7441 # abandoned.
7442 if ("third_party/blink/renderer/core/paint/" in path
7443 or "third_party/blink/renderer/platform/graphics/compositing/" in path
7444 or "third_party/blink/renderer/platform/graphics/paint/" in path):
Sam Maiera6e76d72022-02-11 21:43:507445 return True
7446
Sam Maiera6e76d72022-02-11 21:43:507447 # We assume that everything else may be used outside of Renderer processes.
Lukasz Anforowicz7016d05e2021-11-30 03:56:277448 return False
7449
Alison Galed6b25fe2024-04-17 13:59:047450# TODO(crbug.com/40206238): Remove these checks, once they are replaced
Lukasz Anforowicz7016d05e2021-11-30 03:56:277451# by the Chromium Clang Plugin (which will be preferable because it will
7452# 1) report errors earlier - at compile-time and 2) cover more rules).
7453def CheckRawPtrUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507454 """Rough checks that raw_ptr<T> usage guidelines are followed."""
7455 errors = []
7456 # The regex below matches "raw_ptr<" following a word boundary, but not in a
7457 # C++ comment.
7458 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
Kalvin Lee84ad17a2023-09-25 11:14:417459 file_filter = lambda f: _IsMiraclePtrDisallowed(input_api, f)
Sam Maiera6e76d72022-02-11 21:43:507460 for f, line_num, line in input_api.RightHandSideLines(file_filter):
7461 if raw_ptr_matcher.search(line):
7462 errors.append(
7463 output_api.PresubmitError(
7464 'Problem on {path}:{line} - '\
Kalvin Lee84ad17a2023-09-25 11:14:417465 'raw_ptr<T> should not be used in this renderer code '\
Sam Maiera6e76d72022-02-11 21:43:507466 '(as documented in the "Pointers to unprotected memory" '\
7467 'section in //base/memory/raw_ptr.md)'.format(
7468 path=f.LocalPath(), line=line_num)))
7469 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:567470
mikt9337567c2023-09-08 18:38:177471def CheckAdvancedMemorySafetyChecksUsage(input_api, output_api):
7472 """Checks that ADVANCED_MEMORY_SAFETY_CHECKS() macro is neither added nor
7473 removed as it is managed by the memory safety team internally.
7474 Do not add / remove it manually."""
7475 paths = set([])
7476 # The regex below matches "ADVANCED_MEMORY_SAFETY_CHECKS(" following a word
7477 # boundary, but not in a C++ comment.
7478 macro_matcher = input_api.re.compile(
7479 r'^((?!//).)*\bADVANCED_MEMORY_SAFETY_CHECKS\(', input_api.re.MULTILINE)
7480 for f in input_api.AffectedFiles():
7481 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
7482 continue
7483 if macro_matcher.search(f.GenerateScmDiff()):
7484 paths.add(f.LocalPath())
7485 if not paths:
7486 return []
7487 return [output_api.PresubmitPromptWarning(
7488 'ADVANCED_MEMORY_SAFETY_CHECKS() macro is managed by ' \
7489 'the memory safety team (chrome-memory-safety@). ' \
7490 'Please contact us to add/delete the uses of the macro.',
7491 paths)]
Henrique Ferreirof9819f2e32021-11-30 13:31:567492
7493def CheckPythonShebang(input_api, output_api):
7494 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
7495 system-wide python.
7496 """
7497 errors = []
7498 sources = lambda affected_file: input_api.FilterSourceFile(
7499 affected_file,
7500 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
7501 r'third_party/blink/web_tests/external/') + input_api.
7502 DEFAULT_FILES_TO_SKIP),
7503 files_to_check=[r'.*\.py$'])
7504 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:277505 for line_num, line in f.ChangedContents():
7506 if line_num == 1 and line.startswith('#!/usr/bin/python'):
7507 errors.append(f.LocalPath())
7508 break
Henrique Ferreirof9819f2e32021-11-30 13:31:567509
7510 result = []
7511 for file in errors:
7512 result.append(
7513 output_api.PresubmitError(
7514 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
7515 file))
7516 return result
James Shen81cc0e22022-06-15 21:10:457517
7518
Andrew Grieve5a66ae72024-12-13 15:21:537519def CheckAndroidTestAnnotations(input_api, output_api):
James Shen81cc0e22022-06-15 21:10:457520 """Checks that tests have either @Batch or @DoNotBatch annotation. If this
7521 is not an instrumentation test, disregard."""
7522
7523 batch_annotation = input_api.re.compile(r'^\s*@Batch')
7524 do_not_batch_annotation = input_api.re.compile(r'^\s*@DoNotBatch')
Andrew Grieve5a66ae72024-12-13 15:21:537525 robolectric_test = input_api.re.compile(r'@RunWith\((.*?)RobolectricTestRunner')
James Shen81cc0e22022-06-15 21:10:457526 test_class_declaration = input_api.re.compile(r'^\s*public\sclass.*Test')
7527 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
Mark Schillaci8ef0d872023-07-18 22:07:597528 test_annotation_declaration = input_api.re.compile(r'^\s*public\s@interface\s.*{')
James Shen81cc0e22022-06-15 21:10:457529
ckitagawae8fd23b2022-06-17 15:29:387530 missing_annotation_errors = []
7531 extra_annotation_errors = []
Andrew Grieve5a66ae72024-12-13 15:21:537532 wrong_robolectric_test_runner_errors = []
James Shen81cc0e22022-06-15 21:10:457533
7534 def _FilterFile(affected_file):
7535 return input_api.FilterSourceFile(
7536 affected_file,
7537 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
7538 files_to_check=[r'.*Test\.java$'])
7539
7540 for f in input_api.AffectedSourceFiles(_FilterFile):
7541 batch_matched = None
7542 do_not_batch_matched = None
7543 is_instrumentation_test = True
Mark Schillaci8ef0d872023-07-18 22:07:597544 test_annotation_declaration_matched = None
Andrew Grieve5a66ae72024-12-13 15:21:537545 has_base_robolectric_rule = False
James Shen81cc0e22022-06-15 21:10:457546 for line in f.NewContents():
Andrew Grieve5a66ae72024-12-13 15:21:537547 if 'BaseRobolectricTestRule' in line:
7548 has_base_robolectric_rule = True
7549 continue
7550 if m := robolectric_test.search(line):
7551 is_instrumentation_test = False
7552 if m.group(1) == '' and not has_base_robolectric_rule:
Yiwei Zhang5341bf02025-03-20 16:34:137553 path = str(f.LocalPath())
7554 # These two spots cannot use it.
7555 if 'webapk' not in path and 'build' not in path:
7556 wrong_robolectric_test_runner_errors.append(path)
Andrew Grieve5a66ae72024-12-13 15:21:537557 break
7558 if uiautomator_test.search(line):
James Shen81cc0e22022-06-15 21:10:457559 is_instrumentation_test = False
7560 break
7561 if not batch_matched:
7562 batch_matched = batch_annotation.search(line)
7563 if not do_not_batch_matched:
7564 do_not_batch_matched = do_not_batch_annotation.search(line)
7565 test_class_declaration_matched = test_class_declaration.search(
7566 line)
Mark Schillaci8ef0d872023-07-18 22:07:597567 test_annotation_declaration_matched = test_annotation_declaration.search(line)
7568 if test_class_declaration_matched or test_annotation_declaration_matched:
James Shen81cc0e22022-06-15 21:10:457569 break
Mark Schillaci8ef0d872023-07-18 22:07:597570 if test_annotation_declaration_matched:
7571 continue
James Shen81cc0e22022-06-15 21:10:457572 if (is_instrumentation_test and
7573 not batch_matched and
7574 not do_not_batch_matched):
Sam Maier4cef9242022-10-03 14:21:247575 missing_annotation_errors.append(str(f.LocalPath()))
ckitagawae8fd23b2022-06-17 15:29:387576 if (not is_instrumentation_test and
7577 (batch_matched or
7578 do_not_batch_matched)):
Sam Maier4cef9242022-10-03 14:21:247579 extra_annotation_errors.append(str(f.LocalPath()))
James Shen81cc0e22022-06-15 21:10:457580
7581 results = []
7582
ckitagawae8fd23b2022-06-17 15:29:387583 if missing_annotation_errors:
James Shen81cc0e22022-06-15 21:10:457584 results.append(
7585 output_api.PresubmitPromptWarning(
7586 """
Andrew Grieve43a5cf82023-09-08 15:09:467587A change was made to an on-device test that has neither been annotated with
7588@Batch nor @DoNotBatch. If this is a new test, please add the annotation. If
7589this is an existing test, please consider adding it if you are sufficiently
7590familiar with the test (but do so as a separate change).
7591
Jens Mueller2085ff82023-02-27 11:54:497592See https://source.chromium.org/chromium/chromium/src/+/main:docs/testing/batching_instrumentation_tests.md
ckitagawae8fd23b2022-06-17 15:29:387593""", missing_annotation_errors))
7594 if extra_annotation_errors:
7595 results.append(
7596 output_api.PresubmitPromptWarning(
7597 """
7598Robolectric tests do not need a @Batch or @DoNotBatch annotations.
7599""", extra_annotation_errors))
Andrew Grieve5a66ae72024-12-13 15:21:537600 if wrong_robolectric_test_runner_errors:
7601 results.append(
7602 output_api.PresubmitPromptWarning(
7603 """
Wenyu Fu0005ab82025-01-03 18:13:267604Robolectric tests should use either @RunWith(BaseRobolectricTestRunner.class) (or
Andrew Grieve5a66ae72024-12-13 15:21:537605a subclass of it), or use "@Rule BaseRobolectricTestRule".
7606""", wrong_robolectric_test_runner_errors))
James Shen81cc0e22022-06-15 21:10:457607
7608 return results
Sam Maier4cef9242022-10-03 14:21:247609
7610
Henrique Nakashima224ee2482025-03-21 18:35:027611def _CheckAndroidNullAwayAnnotatedClasses(input_api, output_api):
7612 """Checks that Java classes/interfaces/annotations are null-annotated."""
7613
Henrique Nakashima2bdd8ad2025-04-08 18:24:577614 # Temporary, crbug.com/389129271
7615 if input_api.change.RepositoryRoot().endswith('clank'):
7616 return []
7617
Henrique Nakashima224ee2482025-03-21 18:35:027618 nullmarked_annotation = input_api.re.compile(r'^\s*@(NullMarked|NullUnmarked)')
7619
7620 missing_annotation_errors = []
7621
7622 def _FilterFile(affected_file):
7623 return input_api.FilterSourceFile(
7624 affected_file,
7625 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
7626 DEFAULT_FILES_TO_SKIP + (
7627 r'.*Test.*\.java',
7628 r'^android_webview/.*', # Temporary, crbug.com/389129271
7629 r'^build/.*',
Henrique Nakashimaf0a604802025-04-17 14:10:347630 r'^chrome/android/.*', # Temporary, crbug.com/389129271
Henrique Nakashima224ee2482025-03-21 18:35:027631 r'^chromecast/.*',
7632 r'^components/cronet/.*',
7633 r'^tools/.*',
7634 )),
7635 files_to_check=[r'.*\.java$'])
7636
7637 for f in input_api.AffectedSourceFiles(_FilterFile):
7638 for line in f.NewContents():
7639 if nullmarked_annotation.search(line):
7640 break
7641 else:
7642 missing_annotation_errors.append(str(f.LocalPath()))
7643
7644 results = []
7645
7646 if missing_annotation_errors:
7647 results.append(
Henrique Nakashima8bafbc52025-04-22 19:38:427648 output_api.PresubmitError(
Henrique Nakashima224ee2482025-03-21 18:35:027649 """
7650Please add @NullMarked and fix the NullAway warnings in the following files
7651(see https://chromium.googlesource.com/chromium/src/+/main/styleguide/java/nullaway.md):
7652""", missing_annotation_errors))
7653
7654 return results
7655
7656
Mike Dougherty1b8be712022-10-20 00:15:137657def CheckNoJsInIos(input_api, output_api):
7658 """Checks to make sure that JavaScript files are not used on iOS."""
7659
7660 def _FilterFile(affected_file):
7661 return input_api.FilterSourceFile(
7662 affected_file,
7663 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP +
Daniel White44b8bd02023-08-22 16:20:367664 (r'^ios/third_party/*', r'^ios/tools/*', r'^third_party/*',
7665 r'^components/autofill/ios/form_util/resources/*'),
Mike Dougherty1b8be712022-10-20 00:15:137666 files_to_check=[r'^ios/.*\.js$', r'.*/ios/.*\.js$'])
7667
Mike Dougherty4d1050b2023-03-14 15:59:537668 deleted_files = []
7669
7670 # Collect filenames of all removed JS files.
Arthur Sonzognic66e9c82024-04-23 07:53:047671 for f in input_api.AffectedFiles(file_filter=_FilterFile):
Mike Dougherty4d1050b2023-03-14 15:59:537672 local_path = f.LocalPath()
7673
7674 if input_api.os_path.splitext(local_path)[1] == '.js' and f.Action() == 'D':
7675 deleted_files.append(input_api.os_path.basename(local_path))
7676
Mike Dougherty1b8be712022-10-20 00:15:137677 error_paths = []
Mike Dougherty4d1050b2023-03-14 15:59:537678 moved_paths = []
Mike Dougherty1b8be712022-10-20 00:15:137679 warning_paths = []
7680
7681 for f in input_api.AffectedSourceFiles(_FilterFile):
7682 local_path = f.LocalPath()
7683
7684 if input_api.os_path.splitext(local_path)[1] == '.js':
7685 if f.Action() == 'A':
Mike Dougherty4d1050b2023-03-14 15:59:537686 if input_api.os_path.basename(local_path) in deleted_files:
7687 # This script was probably moved rather than newly created.
7688 # Present a warning instead of an error for these cases.
7689 moved_paths.append(local_path)
7690 else:
7691 error_paths.append(local_path)
Mike Dougherty1b8be712022-10-20 00:15:137692 elif f.Action() != 'D':
7693 warning_paths.append(local_path)
7694
7695 results = []
7696
7697 if warning_paths:
7698 results.append(output_api.PresubmitPromptWarning(
7699 'TypeScript is now fully supported for iOS feature scripts. '
7700 'Consider converting JavaScript files to TypeScript. See '
7701 '//ios/web/public/js_messaging/README.md for more details.',
7702 warning_paths))
7703
Mike Dougherty4d1050b2023-03-14 15:59:537704 if moved_paths:
7705 results.append(output_api.PresubmitPromptWarning(
7706 'Do not use JavaScript on iOS for new files as TypeScript is '
7707 'fully supported. (If this is a moved file, you may leave the '
7708 'script unconverted.) See //ios/web/public/js_messaging/README.md '
7709 'for help using scripts on iOS.', moved_paths))
7710
Mike Dougherty1b8be712022-10-20 00:15:137711 if error_paths:
7712 results.append(output_api.PresubmitError(
7713 'Do not use JavaScript on iOS as TypeScript is fully supported. '
7714 'See //ios/web/public/js_messaging/README.md for help using '
7715 'scripts on iOS.', error_paths))
7716
7717 return results
Hans Wennborg23a81d52023-03-24 16:38:137718
7719def CheckLibcxxRevisionsMatch(input_api, output_api):
7720 """Check to make sure the libc++ version matches across deps files."""
Andrew Grieve21bb6792023-03-27 19:06:487721 # Disable check for changes to sub-repositories.
7722 if input_api.PresubmitLocalPath() != input_api.change.RepositoryRoot():
Sam Maierb926c58c2023-08-08 19:58:257723 return []
Hans Wennborg23a81d52023-03-24 16:38:137724
7725 DEPS_FILES = [ 'DEPS', 'buildtools/deps_revisions.gni' ]
7726
Anton Bershanskyi4253349482025-02-11 21:01:277727 file_filter = lambda f: f.UnixLocalPath() in DEPS_FILES
Hans Wennborg23a81d52023-03-24 16:38:137728 changed_deps_files = input_api.AffectedFiles(file_filter=file_filter)
7729 if not changed_deps_files:
7730 return []
7731
7732 def LibcxxRevision(file):
7733 file = input_api.os_path.join(input_api.PresubmitLocalPath(),
7734 *file.split('/'))
7735 return input_api.re.search(
7736 r'libcxx_revision.*[:=].*[\'"](\w+)[\'"]',
7737 input_api.ReadFile(file)).group(1)
7738
7739 if len(set([LibcxxRevision(f) for f in DEPS_FILES])) == 1:
7740 return []
7741
7742 return [output_api.PresubmitError(
7743 'libcxx_revision not equal across %s' % ', '.join(DEPS_FILES),
7744 changed_deps_files)]
Arthur Sonzogni7109bd32023-10-03 10:34:427745
7746
7747def CheckDanglingUntriaged(input_api, output_api):
7748 """Warn developers adding DanglingUntriaged raw_ptr."""
7749
7750 # Ignore during git presubmit --all.
7751 #
7752 # This would be too costly, because this would check every lines of every
7753 # C++ files. Check from _BANNED_CPP_FUNCTIONS are also reading the whole
7754 # source code, but only once to apply every checks. It seems the bots like
7755 # `win-presubmit` are particularly sensitive to reading the files. Adding
7756 # this check caused the bot to run 2x longer. See https://crbug.com/1486612.
7757 if input_api.no_diffs:
Arthur Sonzogni9eafd222023-11-10 08:50:397758 return []
Arthur Sonzogni7109bd32023-10-03 10:34:427759
7760 def FilterFile(file):
7761 return input_api.FilterSourceFile(
7762 file,
7763 files_to_check=[r".*\.(h|cc|cpp|cxx|m|mm)$"],
7764 files_to_skip=[r"^base/allocator.*"],
7765 )
7766
7767 count = 0
Arthur Sonzognic66e9c82024-04-23 07:53:047768 for f in input_api.AffectedFiles(file_filter=FilterFile):
Arthur Sonzogni9eafd222023-11-10 08:50:397769 count -= sum([l.count("DanglingUntriaged") for l in f.OldContents()])
7770 count += sum([l.count("DanglingUntriaged") for l in f.NewContents()])
Arthur Sonzogni7109bd32023-10-03 10:34:427771
7772 # Most likely, nothing changed:
7773 if count == 0:
7774 return []
7775
7776 # Congrats developers for improving it:
7777 if count < 0:
Arthur Sonzogni9eafd222023-11-10 08:50:397778 message = f"DanglingUntriaged pointers removed: {-count}\nThank you!"
Arthur Sonzogni7109bd32023-10-03 10:34:427779 return [output_api.PresubmitNotifyResult(message)]
7780
7781 # Check for 'DanglingUntriaged-notes' in the description:
7782 notes_regex = input_api.re.compile("DanglingUntriaged-notes[:=]")
7783 if any(
7784 notes_regex.match(line)
7785 for line in input_api.change.DescriptionText().splitlines()):
7786 return []
7787
7788 # Check for DanglingUntriaged-notes in the git footer:
7789 if input_api.change.GitFootersFromDescription().get(
7790 "DanglingUntriaged-notes", []):
7791 return []
7792
7793 message = (
Arthur Sonzogni9eafd222023-11-10 08:50:397794 "Unexpected new occurrences of `DanglingUntriaged` detected. Please\n" +
7795 "avoid adding new ones\n" +
7796 "\n" +
7797 "See documentation:\n" +
7798 "https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr.md\n" +
7799 "\n" +
7800 "See also the guide to fix dangling pointers:\n" +
7801 "https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr_guide.md\n" +
7802 "\n" +
7803 "To disable this warning, please add in the commit description:\n" +
Alex Gough26dcd852023-12-22 16:47:197804 "DanglingUntriaged-notes: <rationale for new untriaged dangling " +
Arthur Sonzogni9eafd222023-11-10 08:50:397805 "pointers>"
Arthur Sonzogni7109bd32023-10-03 10:34:427806 )
7807 return [output_api.PresubmitPromptWarning(message)]
Jan Keitel77be7522023-10-12 20:40:497808
7809def CheckInlineConstexprDefinitionsInHeaders(input_api, output_api):
7810 """Checks that non-static constexpr definitions in headers are inline."""
7811 # In a properly formatted file, constexpr definitions inside classes or
7812 # structs will have additional whitespace at the beginning of the line.
7813 # The pattern looks for variables initialized as constexpr kVar = ...; or
7814 # constexpr kVar{...};
7815 # The pattern does not match expressions that have braces in kVar to avoid
7816 # matching constexpr functions.
7817 pattern = input_api.re.compile(r'^constexpr (?!inline )[^\(\)]*[={]')
7818 attribute_pattern = input_api.re.compile(r'(\[\[[a-zA-Z_:]+\]\]|[A-Z]+[A-Z_]+) ')
7819 problems = []
7820 for f in input_api.AffectedFiles():
7821 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
7822 continue
7823
7824 for line_number, line in f.ChangedContents():
7825 line = attribute_pattern.sub('', line)
7826 if pattern.search(line):
7827 problems.append(
7828 f"{f.LocalPath()}: {line_number}\n {line}")
7829
7830 if problems:
7831 return [
7832 output_api.PresubmitPromptWarning(
7833 'Consider inlining constexpr variable definitions in headers '
7834 'outside of classes to avoid unnecessary copies of the '
7835 'constant. See https://abseil.io/tips/168 for more details.',
7836 problems)
7837 ]
7838 else:
7839 return []
Alison Galed6b25fe2024-04-17 13:59:047840
7841def CheckTodoBugReferences(input_api, output_api):
7842 """Checks that bugs in TODOs use updated issue tracker IDs."""
7843
Manish Goregaokardc9e3512025-02-03 15:30:587844 files_to_skip = ['PRESUBMIT_test.py', r"^third_party/rust/chromium_crates_io/vendor/.*"]
Alison Galed6b25fe2024-04-17 13:59:047845
7846 def _FilterFile(affected_file):
7847 return input_api.FilterSourceFile(
7848 affected_file,
7849 files_to_skip=files_to_skip)
7850
7851 # Monorail bug IDs are all less than or equal to 1524553 so check that all
7852 # bugs in TODOs are greater than that value.
Tom Sepez8e628582025-02-14 02:18:557853 pattern = input_api.re.compile(r'.*\bTODO\([^\)0-9]*([0-9]+)\).*')
Alison Galed6b25fe2024-04-17 13:59:047854 problems = []
7855 for f in input_api.AffectedSourceFiles(_FilterFile):
7856 for line_number, line in f.ChangedContents():
7857 match = pattern.match(line)
7858 if match and int(match.group(1)) <= 1524553:
7859 problems.append(
7860 f"{f.LocalPath()}: {line_number}\n {line}")
7861
7862 if problems:
7863 return [
7864 output_api.PresubmitPromptWarning(
Alison Galecb598de52024-04-26 17:03:257865 'TODOs should use the new Chromium Issue Tracker IDs which can '
7866 'be found by navigating to the bug. See '
7867 'https://crbug.com/336778624 for more details.',
Alison Galed6b25fe2024-04-17 13:59:047868 problems)
7869 ]
7870 else:
7871 return []