blob: f3f93f222eff3da9bf2c94f41fe18b20c6d17007 [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 ),
Eric Stevensona9a980972017-09-23 00:04:41302)
303
Clement Yan9b330cb2022-11-17 05:25:29304_BANNED_JAVASCRIPT_FUNCTIONS : Sequence [BanRule] = (
305 BanRule(
306 r'/\bchrome\.send\b',
307 (
308 '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).',
309 'Please use mojo instead for new webuis. https://docs.google.com/document/d/1RF-GSUoveYa37eoyZ9EhwMtaIwoW7Z88pIgNZ9YzQi4/edit#heading=h.gkk22wgk6wff',
310 ),
311 True,
312 (
313 r'^(?!ash\/webui).+',
314 # TODO(crbug.com/1385601): pre-existing violations still need to be
315 # cleaned up.
Rebekah Potter57aa94df2022-12-13 20:30:58316 'ash/webui/common/resources/cr.m.js',
Clement Yan9b330cb2022-11-17 05:25:29317 'ash/webui/common/resources/multidevice_setup/multidevice_setup_browser_proxy.js',
Martin Bidlingmaiera921fee72023-06-03 07:52:22318 'ash/webui/common/resources/quick_unlock/lock_screen_constants.ts',
Clement Yan9b330cb2022-11-17 05:25:29319 'ash/webui/common/resources/smb_shares/smb_browser_proxy.js',
Chad Duffin06e47de2023-12-14 18:04:13320 'ash/webui/connectivity_diagnostics/resources/connectivity_diagnostics.ts',
Clement Yan9b330cb2022-11-17 05:25:29321 'ash/webui/diagnostics_ui/resources/diagnostics_browser_proxy.ts',
322 'ash/webui/multidevice_debug/resources/logs.js',
323 'ash/webui/multidevice_debug/resources/webui.js',
324 'ash/webui/projector_app/resources/annotator/trusted/annotator_browser_proxy.js',
325 'ash/webui/projector_app/resources/app/trusted/projector_browser_proxy.js',
Ashley Prasad71f9024e2023-09-25 22:33:55326 # TODO(b/301634378): Remove violation exception once Scanning App
327 # migrated off usage of `chrome.send`.
328 'ash/webui/scanning/resources/scanning_browser_proxy.ts',
Clement Yan9b330cb2022-11-17 05:25:29329 ),
330 ),
331)
332
Daniel Cheng917ce542022-03-15 20:46:57333_BANNED_OBJC_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15334 BanRule(
[email protected]127f18ec2012-06-16 05:05:59335 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20336 (
337 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59338 'prohibited. Please use CrTrackingArea instead.',
339 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
340 ),
341 False,
342 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15343 BanRule(
[email protected]eaae1972014-04-16 04:17:26344 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20345 (
346 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59347 'instead.',
348 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
349 ),
350 False,
351 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15352 BanRule(
[email protected]127f18ec2012-06-16 05:05:59353 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20354 (
355 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59356 'Please use |convertPoint:(point) fromView:nil| instead.',
357 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
358 ),
359 True,
360 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15361 BanRule(
[email protected]127f18ec2012-06-16 05:05:59362 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20363 (
364 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59365 'Please use |convertPoint:(point) toView:nil| instead.',
366 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
367 ),
368 True,
369 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15370 BanRule(
[email protected]127f18ec2012-06-16 05:05:59371 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20372 (
373 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59374 'Please use |convertRect:(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 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20381 (
382 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59383 'Please use |convertRect:(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 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20390 (
391 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59392 'Please use |convertSize:(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 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20399 (
400 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59401 'Please use |convertSize:(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(
jif65398702016-10-27 10:19:48407 r"/\s+UTF8String\s*]",
408 (
409 'The use of -[NSString UTF8String] is dangerous as it can return null',
410 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
411 'Please use |SysNSStringToUTF8| instead.',
412 ),
413 True,
Marijn Kruisselbrink1b7c48952023-08-31 16:58:34414 excluded_paths = (
415 '^third_party/ocmock/OCMock/',
416 ),
jif65398702016-10-27 10:19:48417 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15418 BanRule(
Sylvain Defresne4cf1d182017-09-18 14:16:34419 r'__unsafe_unretained',
420 (
421 'The use of __unsafe_unretained is almost certainly wrong, unless',
422 'when interacting with NSFastEnumeration or NSInvocation.',
423 'Please use __weak in files build with ARC, nothing otherwise.',
424 ),
425 False,
426 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15427 BanRule(
Avi Drissman7382afa02019-04-29 23:27:13428 'freeWhenDone:NO',
429 (
430 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
431 'Foundation types is prohibited.',
432 ),
433 True,
434 ),
Avi Drissman3d243a42023-08-01 16:53:59435 BanRule(
436 'This file requires ARC support.',
437 (
438 'ARC compilation is default in Chromium; do not add boilerplate to ',
439 'files that require ARC.',
440 ),
441 True,
442 ),
[email protected]127f18ec2012-06-16 05:05:59443)
444
Sylvain Defresnea8b73d252018-02-28 15:45:54445_BANNED_IOS_OBJC_FUNCTIONS = (
Daniel Chenga44a1bcd2022-03-15 20:00:15446 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54447 r'/\bTEST[(]',
448 (
449 'TEST() macro should not be used in Objective-C++ code as it does not ',
450 'drain the autorelease pool at the end of the test. Use TEST_F() ',
451 'macro instead with a fixture inheriting from PlatformTest (or a ',
452 'typedef).'
453 ),
454 True,
455 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15456 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54457 r'/\btesting::Test\b',
458 (
459 'testing::Test should not be used in Objective-C++ code as it does ',
460 'not drain the autorelease pool at the end of the test. Use ',
461 'PlatformTest instead.'
462 ),
463 True,
464 ),
Ewann2ecc8d72022-07-18 07:41:23465 BanRule(
466 ' systemImageNamed:',
467 (
468 '+[UIImage systemImageNamed:] should not be used to create symbols.',
469 'Instead use a wrapper defined in:',
Slobodan Pejic8ef56c702024-07-12 18:21:26470 'ios/chrome/browser/shared/ui/symbols/symbol_helpers.h'
Ewann2ecc8d72022-07-18 07:41:23471 ),
472 True,
Ewann450a2ef2022-07-19 14:38:23473 excluded_paths=(
Gauthier Ambard4d8756b2023-04-07 17:26:41474 'ios/chrome/browser/shared/ui/symbols/symbol_helpers.mm',
Slobodan Pejic8ef56c702024-07-12 18:21:26475 'ios/chrome/common',
Tommy Martino2a1182dc2024-11-20 19:34:42476 # App extensions have restricted dependencies and thus can't use the
477 # wrappers.
Riley Wong49be8a882025-02-27 00:38:23478 r'^ios/chrome/\w+_extension/',
Ewann450a2ef2022-07-19 14:38:23479 ),
Ewann2ecc8d72022-07-18 07:41:23480 ),
Sylvain Defresne781b9f92024-12-11 09:36:18481 BanRule(
482 r'public (RefCounted)?BrowserStateKeyedServiceFactory',
483 (
484 'KeyedService factories in //ios/chrome/browser should inherit from',
485 '(Refcounted)?ProfileKeyedServieFactoryIOS, not directory from',
486 '(Refcounted)?BrowserStateKeyedServiceFactory.'
487 ),
488 treat_as_error=True,
489 excluded_paths=(
490 'ios/components',
491 'ios/web_view',
492 ),
493 ),
Sylvain Defresnea8b73d252018-02-28 15:45:54494)
495
Daniel Cheng917ce542022-03-15 20:46:57496_BANNED_IOS_EGTEST_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15497 BanRule(
Peter K. Lee6c03ccff2019-07-15 14:40:05498 r'/\bEXPECT_OCMOCK_VERIFY\b',
499 (
500 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
501 'it is meant for GTests. Use [mock verify] instead.'
502 ),
503 True,
504 ),
505)
506
Daniel Cheng566634ff2024-06-29 14:56:53507_BANNED_CPP_FUNCTIONS: Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15508 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53509 '%#0',
510 (
511 'Zero-padded values that use "#" to add prefixes don\'t exhibit ',
512 'consistent behavior, since the prefix is not prepended for zero ',
513 'values. Use "0x%0..." instead.',
514 ),
515 False,
516 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting7c0d98a2023-10-06 15:42:39517 ),
518 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53519 r'/\busing namespace ',
520 (
521 'Using directives ("using namespace x") are banned by the Google Style',
522 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
523 'Explicitly qualify symbols or use using declarations ("using x::foo").',
524 ),
525 True,
526 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting94a56c42019-10-25 21:54:04527 ),
Antonio Gomes07300d02019-03-13 20:59:57528 # Make sure that gtest's FRIEND_TEST() macro is not used; the
529 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
530 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
Daniel Chenga44a1bcd2022-03-15 20:00:15531 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53532 'FRIEND_TEST(',
533 (
534 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
535 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
536 ),
537 False,
538 excluded_paths=(
539 "base/gtest_prod_util.h",
540 "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/gtest_prod_util.h",
541 ),
[email protected]23e6cbc2012-06-16 18:51:20542 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15543 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53544 'setMatrixClip',
545 (
546 'Overriding setMatrixClip() is prohibited; ',
547 'the base function is deprecated. ',
548 ),
549 True,
550 (),
tomhudsone2c14d552016-05-26 17:07:46551 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15552 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53553 'SkRefPtr',
554 ('The use of SkRefPtr is prohibited. ', 'Please use sk_sp<> instead.'),
555 True,
556 (),
[email protected]52657f62013-05-20 05:30:31557 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15558 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53559 'SkAutoRef',
560 ('The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
561 'Please use sk_sp<> instead.'),
562 True,
563 (),
[email protected]52657f62013-05-20 05:30:31564 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15565 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53566 'SkAutoTUnref',
567 ('The use of SkAutoTUnref is dangerous because it implicitly ',
568 'converts to a raw pointer. Please use sk_sp<> instead.'),
569 True,
570 (),
[email protected]52657f62013-05-20 05:30:31571 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15572 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53573 'SkAutoUnref',
574 ('The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
575 'because it implicitly converts to a raw pointer. ',
576 'Please use sk_sp<> instead.'),
577 True,
578 (),
[email protected]52657f62013-05-20 05:30:31579 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15580 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53581 r'/HANDLE_EINTR\(.*close',
582 ('HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
583 'descriptor will be closed, and it is incorrect to retry the close.',
584 'Either call close directly and ignore its return value, or wrap close',
585 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
586 ),
587 True,
588 (),
[email protected]d89eec82013-12-03 14:10:59589 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15590 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53591 r'/IGNORE_EINTR\((?!.*close)',
592 (
593 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
594 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
595 ),
596 True,
597 (
598 # Files that #define IGNORE_EINTR.
599 r'^base/posix/eintr_wrapper\.h$',
600 r'^ppapi/tests/test_broker\.cc$',
601 ),
[email protected]d89eec82013-12-03 14:10:59602 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15603 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53604 r'/v8::Extension\(',
605 (
606 'Do not introduce new v8::Extensions into the code base, use',
607 'gin::Wrappable instead. See http://crbug.com/334679',
608 ),
609 True,
610 (r'extensions/renderer/safe_builtins\.*', ),
[email protected]ec5b3f02014-04-04 18:43:43611 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15612 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53613 '#pragma comment(lib,',
614 ('Specify libraries to link with in build files and not in the source.',
615 ),
616 True,
617 (
618 r'^base/third_party/symbolize/.*',
619 r'^third_party/abseil-cpp/.*',
620 ),
jame2d1a952016-04-02 00:27:10621 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15622 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53623 r'/base::SequenceChecker\b',
624 ('Consider using SEQUENCE_CHECKER macros instead of the class directly.',
625 ),
626 False,
627 (),
gabd52c912a2017-05-11 04:15:59628 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15629 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53630 r'/base::ThreadChecker\b',
631 ('Consider using THREAD_CHECKER macros instead of the class directly.',
632 ),
633 False,
634 (),
gabd52c912a2017-05-11 04:15:59635 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15636 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53637 r'/\b(?!(Sequenced|SingleThread))\w*TaskRunner::(GetCurrentDefault|CurrentDefaultHandle)',
638 (
639 'It is not allowed to call these methods from the subclasses ',
640 'of Sequenced or SingleThread task runners.',
641 ),
642 True,
643 (),
Sean Maher03efef12022-09-23 22:43:13644 ),
645 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53646 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
647 (
648 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
649 'deprecated (http://crbug.com/634507). Please avoid converting away',
650 'from the Time types in Chromium code, especially if any math is',
651 'being done on time values. For interfacing with platform/library',
652 'APIs, use base::Time::(From,To)DeltaSinceWindowsEpoch() or',
653 'base::{TimeDelta::In}Microseconds(), or one of the other type',
654 'converter methods instead. For faking TimeXXX values (for unit',
655 'testing only), use TimeXXX() + Microseconds(N). For',
656 'other use cases, please contact base/time/OWNERS.',
657 ),
658 False,
659 excluded_paths=(
660 "base/time/time.h",
661 "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/time/time.h",
662 ),
Yuri Wiitala2f8de5c2017-07-21 00:11:06663 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15664 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53665 'CallJavascriptFunctionUnsafe',
666 (
667 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
668 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
669 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
670 ),
671 False,
672 (
673 r'^content/browser/webui/web_ui_impl\.(cc|h)$',
674 r'^content/public/browser/web_ui\.h$',
675 r'^content/public/test/test_web_ui\.(cc|h)$',
676 ),
dbeamb6f4fde2017-06-15 04:03:06677 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15678 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53679 'leveldb::DB::Open',
680 (
681 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
682 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
683 "Chrome's tracing, making their memory usage visible.",
684 ),
685 True,
686 (r'^third_party/leveldatabase/.*\.(cc|h)$', ),
Gabriel Charette0592c3a2017-07-26 12:02:04687 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15688 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53689 'leveldb::NewMemEnv',
690 (
691 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
692 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
693 "to Chrome's tracing, making their memory usage visible.",
694 ),
695 True,
696 (r'^third_party/leveldatabase/.*\.(cc|h)$', ),
Chris Mumfordc38afb62017-10-09 17:55:08697 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15698 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53699 'base::ScopedMockTimeMessageLoopTaskRunner',
700 (
701 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
702 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
703 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
704 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
705 'with gab@ first if you think you need it)',
706 ),
707 False,
708 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57709 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15710 BanRule(
Peter Kasting5fdcd782025-01-13 14:57:07711 '\bstd::aligned_(storage|union)\b',
712 (
713 'std::aligned_storage and std::aligned_union are deprecated in',
714 'C++23. Use an aligned char array instead.'
715 ),
716 True,
717 (),
718 ),
719 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53720 'std::regex',
721 (
722 'Using std::regex adds unnecessary binary size to Chrome. Please use',
723 're2::RE2 instead (crbug.com/755321)',
724 ),
725 True,
726 [
727 # Abseil's benchmarks never linked into chrome.
728 'third_party/abseil-cpp/.*_benchmark.cc',
729 ],
Francois Doray43670e32017-09-27 12:40:38730 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15731 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53732 r'/\bstd::sto(i|l|ul|ll|ull)\b',
733 (
734 'std::sto{i,l,ul,ll,ull}() use exceptions to communicate results. ',
735 'Use base::StringTo[U]Int[64]() instead.',
736 ),
737 True,
738 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting991618a62019-06-17 22:00:09739 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15740 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53741 r'/\bstd::sto(f|d|ld)\b',
742 (
743 'std::sto{f,d,ld}() use exceptions to communicate results. ',
744 'For locale-independent values, e.g. reading numbers from disk',
745 'profiles, use base::StringToDouble().',
746 'For user-visible values, parse using ICU.',
747 ),
748 True,
749 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting991618a62019-06-17 22:00:09750 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15751 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53752 r'/\bstd::to_string\b',
753 (
754 'std::to_string() is locale dependent and slower than alternatives.',
755 'For locale-independent strings, e.g. writing numbers to disk',
756 'profiles, use base::NumberToString().',
757 'For user-visible strings, use base::FormatNumber() and',
758 'the related functions in base/i18n/number_formatting.h.',
759 ),
760 True,
761 [
762 # TODO(crbug.com/335672557): Please do not add to this list. Existing
763 # uses should removed.
Daniel Cheng566634ff2024-06-29 14:56:53764 "third_party/blink/renderer/core/css/parser/css_proto_converter.cc",
765 "third_party/blink/renderer/core/editing/ime/edit_context.cc",
766 "third_party/blink/renderer/platform/graphics/bitmap_image_test.cc",
Daniel Cheng566634ff2024-06-29 14:56:53767 _THIRD_PARTY_EXCEPT_BLINK
768 ],
Daniel Bratell69334cc2019-03-26 11:07:45769 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15770 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53771 r'/#include <(cctype|ctype\.h|cwctype|wctype.h)>',
772 (
773 '<cctype>/<ctype.h>/<cwctype>/<wctype.h> are banned. Use',
774 '"third_party/abseil-cpp/absl/strings/ascii.h" instead.',
775 ),
776 True,
777 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting6f79b202023-08-09 21:25:41778 ),
779 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53780 r'/\bstd::shared_ptr\b',
781 ('std::shared_ptr is banned. Use scoped_refptr instead.', ),
782 True,
783 [
784 # Needed for interop with third-party library.
Dirk Prankee4df27972025-02-26 18:39:35785 r'^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
786 r'array_buffer_contents\.(cc|h)',
787 r'^third_party/blink/renderer/core/typed_arrays/dom_array_buffer\.cc',
Daniel Cheng566634ff2024-06-29 14:56:53788 '^third_party/blink/renderer/bindings/core/v8/' +
789 'v8_wasm_response_extensions.cc',
Dirk Prankee4df27972025-02-26 18:39:35790 r'^gin/array_buffer\.(cc|h)',
791 r'^gin/per_isolate_data\.(cc|h)',
Daniel Cheng566634ff2024-06-29 14:56:53792 '^chrome/services/sharing/nearby/',
793 # Needed for interop with third-party library libunwindstack.
Dirk Prankee4df27972025-02-26 18:39:35794 r'^base/profiler/libunwindstack_unwinder_android\.(cc|h)',
795 r'^base/profiler/native_unwinder_android_memory_regions_map_impl.(cc|h)',
Daniel Cheng566634ff2024-06-29 14:56:53796 # Needed for interop with third-party boringssl cert verifier
797 '^third_party/boringssl/',
798 '^net/cert/',
799 '^net/tools/cert_verify_tool/',
800 '^services/cert_verifier/',
801 '^components/certificate_transparency/',
802 '^components/media_router/common/providers/cast/certificate/',
803 # gRPC provides some C++ libraries that use std::shared_ptr<>.
804 '^chromeos/ash/services/libassistant/grpc/',
805 '^chromecast/cast_core/grpc',
806 '^chromecast/cast_core/runtime/browser',
Dirk Prankee4df27972025-02-26 18:39:35807 r'^ios/chrome/test/earl_grey/chrome_egtest_plugin_client\.(mm|h)',
Daniel Cheng566634ff2024-06-29 14:56:53808 # Fuchsia provides C++ libraries that use std::shared_ptr<>.
Dirk Prankee4df27972025-02-26 18:39:35809 r'^base/fuchsia/.*\.(cc|h)',
810 r'.*fuchsia.*test\.(cc|h)',
Daniel Cheng566634ff2024-06-29 14:56:53811 # Clang plugins have different build config.
812 '^tools/clang/plugins/',
813 _THIRD_PARTY_EXCEPT_BLINK
814 ], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21815 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15816 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53817 r'/\bstd::weak_ptr\b',
818 ('std::weak_ptr is banned. Use base::WeakPtr instead.', ),
819 True,
820 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting991618a62019-06-17 22:00:09821 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15822 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53823 r'/\blong long\b',
824 ('long long is banned. Use [u]int64_t instead.', ),
825 False, # Only a warning since it is already used.
826 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21827 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15828 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53829 r'/\b(absl|std)::any\b',
830 (
831 '{absl,std}::any are banned due to incompatibility with the component ',
832 'build.',
833 ),
834 True,
835 # Not an error in third party folders, though it probably should be :)
836 [_THIRD_PARTY_EXCEPT_BLINK],
Daniel Chengc05fcc62022-01-12 16:54:29837 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15838 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53839 r'/\bstd::bind\b',
840 (
841 'std::bind() is banned because of lifetime risks. Use ',
842 'base::Bind{Once,Repeating}() instead.',
843 ),
844 True,
845 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error 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'/\bstd::(?:'
849 r'linear_congruential_engine|mersenne_twister_engine|'
850 r'subtract_with_carry_engine|discard_block_engine|'
851 r'independent_bits_engine|shuffle_order_engine|'
852 r'minstd_rand0?|mt19937(_64)?|ranlux(24|48)(_base)?|knuth_b|'
853 r'default_random_engine|'
854 r'random_device|'
855 r'seed_seq'
856 r')\b'),
857 (
858 'STL random number engines and generators are banned. Use the ',
859 'helpers in base/rand_util.h instead, e.g. base::RandBytes() or ',
860 'base::RandomBitGenerator.'
861 '',
862 'Please reach out to [email protected] if the base APIs are ',
863 'insufficient for your needs.',
864 ),
865 True,
866 [
867 # Not an error in third_party folders.
868 _THIRD_PARTY_EXCEPT_BLINK,
869 # Various tools which build outside of Chrome.
870 r'testing/libfuzzer',
Steinar H. Gundersone5689e42024-08-07 18:17:19871 r'testing/perf/confidence',
Daniel Cheng566634ff2024-06-29 14:56:53872 r'tools/android/io_benchmark/',
873 # Fuzzers are allowed to use standard library random number generators
874 # since fuzzing speed + reproducibility is important.
875 r'tools/ipc_fuzzer/',
876 r'.+_fuzzer\.cc$',
877 r'.+_fuzzertest\.cc$',
878 # TODO(https://crbug.com/1380528): These are all unsanctioned uses of
879 # the standard library's random number generators, and should be
880 # migrated to the //base equivalent.
881 r'ash/ambient/model/ambient_topic_queue\.cc',
882 r'base/allocator/partition_allocator/src/partition_alloc/partition_alloc_unittest\.cc',
Daniel Cheng566634ff2024-06-29 14:56:53883 r'base/test/launcher/test_launcher\.cc',
884 r'cc/metrics/video_playback_roughness_reporter_unittest\.cc',
885 r'chrome/browser/apps/app_service/metrics/website_metrics\.cc',
886 r'chrome/browser/ash/power/auto_screen_brightness/monotone_cubic_spline_unittest\.cc',
887 r'chrome/browser/ash/printing/zeroconf_printer_detector_unittest\.cc',
888 r'chrome/browser/nearby_sharing/contacts/nearby_share_contact_manager_impl_unittest\.cc',
889 r'chrome/browser/nearby_sharing/contacts/nearby_share_contacts_sorter_unittest\.cc',
890 r'chrome/browser/privacy_budget/mesa_distribution_unittest\.cc',
891 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
892 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
893 r'chrome/browser/win/conflicts/module_blocklist_cache_util_unittest\.cc',
894 r'chromeos/ash/components/memory/userspace_swap/swap_storage_unittest\.cc',
895 r'chromeos/ash/components/memory/userspace_swap/userspace_swap\.cc',
896 r'components/metrics/metrics_state_manager\.cc',
897 r'components/omnibox/browser/history_quick_provider_performance_unittest\.cc',
898 r'components/zucchini/disassembler_elf_unittest\.cc',
899 r'content/browser/webid/federated_auth_request_impl\.cc',
900 r'content/browser/webid/federated_auth_request_impl\.cc',
901 r'media/cast/test/utility/udp_proxy\.h',
902 r'sql/recover_module/module_unittest\.cc',
903 r'components/search_engines/template_url_prepopulate_data.cc',
904 # Do not add new entries to this list. If you have a use case which is
905 # not satisfied by the current APIs (i.e. you need an explicitly-seeded
906 # sequence, or stability of some sort is required), please contact
907 # [email protected].
908 ],
Daniel Cheng192683f2022-11-01 20:52:44909 ),
910 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53911 r'/\b(absl,std)::bind_front\b',
912 ('{absl,std}::bind_front() are banned. Use base::Bind{Once,Repeating}() '
913 'instead.', ),
914 True,
915 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12916 ),
917 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53918 r'/\bABSL_FLAG\b',
919 ('ABSL_FLAG is banned. Use base::CommandLine instead.', ),
920 True,
921 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12922 ),
923 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53924 r'/\babsl::c_',
925 (
Peter Kasting3b811ffd2025-01-29 22:20:16926 'Abseil container utilities are banned. Use std::ranges:: instead.',
Daniel Cheng566634ff2024-06-29 14:56:53927 ),
928 True,
929 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12930 ),
931 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53932 r'/\babsl::FixedArray\b',
933 ('absl::FixedArray is banned. Use base::FixedArray instead.', ),
934 True,
935 [
936 # base::FixedArray provides canonical access.
937 r'^base/types/fixed_array.h',
938 # Not an error in third_party folders.
939 _THIRD_PARTY_EXCEPT_BLINK,
940 ],
Peter Kasting431239a2023-09-29 03:11:44941 ),
942 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53943 r'/\babsl::FunctionRef\b',
944 ('absl::FunctionRef is banned. Use base::FunctionRef instead.', ),
945 True,
946 [
947 # base::Bind{Once,Repeating} references absl::FunctionRef to disallow
948 # interoperability.
949 r'^base/functional/bind_internal\.h',
950 # base::FunctionRef is implemented on top of absl::FunctionRef.
951 r'^base/functional/function_ref.*\..+',
952 # Not an error in third_party folders.
953 _THIRD_PARTY_EXCEPT_BLINK,
954 ],
Peter Kasting4f35bfc2022-10-18 18:39:12955 ),
956 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53957 r'/\babsl::(Insecure)?BitGen\b',
958 ('absl random number generators are banned. Use the helpers in '
959 'base/rand_util.h instead, e.g. base::RandBytes() or ',
960 'base::RandomBitGenerator.'),
961 True,
962 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12963 ),
964 BanRule(
Peter Kasting3b77a0c2024-08-22 00:22:26965 pattern=
966 r'/\babsl::(optional|nullopt|make_optional)\b',
967 explanation=('absl::optional is banned. Use std::optional instead.', ),
968 treat_as_error=True,
969 excluded_paths=[
970 _THIRD_PARTY_EXCEPT_BLINK,
971 ]),
972 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53973 r'/(\babsl::Span\b|#include <span>|\bstd::span\b)',
974 (
Peter Kastinge73b89d2024-11-26 19:35:52975 'absl::Span and std::span are banned. Use base::span instead.',
Daniel Cheng566634ff2024-06-29 14:56:53976 ),
977 True,
978 [
979 # Included for conversions between base and std.
980 r'base/containers/span.h',
981 # Test base::span<> compatibility against std::span<>.
982 r'base/containers/span_unittest.cc',
983 # //base/numerics can't use base or absl. So it uses std.
984 r'base/numerics/.*'
Lei Zhang1f9d9ec42024-06-20 18:42:27985
Daniel Cheng566634ff2024-06-29 14:56:53986 # Needed to use QUICHE API.
Ciara McMullinc029c8e2024-08-21 14:22:32987 r'android_webview/browser/ip_protection/.*',
Daniel Cheng566634ff2024-06-29 14:56:53988 r'chrome/browser/ip_protection/.*',
989 r'components/ip_protection/.*',
990 r'net/third_party/quiche/overrides/quiche_platform_impl/quiche_stack_trace_impl\.*',
991 r'services/network/web_transport\.cc',
Lei Zhang1f9d9ec42024-06-20 18:42:27992
Daniel Cheng566634ff2024-06-29 14:56:53993 # Not an error in third_party folders.
994 _THIRD_PARTY_EXCEPT_BLINK,
995 ],
Peter Kasting4f35bfc2022-10-18 18:39:12996 ),
997 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53998 r'/\babsl::StatusOr\b',
999 ('absl::StatusOr is banned. Use base::expected instead.', ),
1000 True,
1001 [
1002 # Needed to use liburlpattern API.
1003 r'components/url_pattern/.*',
1004 r'services/network/shared_dictionary/simple_url_pattern_matcher\.cc',
1005 r'third_party/blink/renderer/core/url_pattern/.*',
1006 r'third_party/blink/renderer/modules/manifest/manifest_parser\.cc',
Lei Zhang1f9d9ec42024-06-20 18:42:271007
Daniel Cheng566634ff2024-06-29 14:56:531008 # Needed to use QUICHE API.
Ciara McMullinc029c8e2024-08-21 14:22:321009 r'android_webview/browser/ip_protection/.*',
Daniel Cheng566634ff2024-06-29 14:56:531010 r'chrome/browser/ip_protection/.*',
1011 r'components/ip_protection/.*',
Lei Zhang1f9d9ec42024-06-20 18:42:271012
Daniel Cheng566634ff2024-06-29 14:56:531013 # Needed to use MediaPipe API.
1014 r'components/media_effects/.*\.cc',
1015 # Not an error in third_party folders.
1016 _THIRD_PARTY_EXCEPT_BLINK
1017 ],
Peter Kasting4f35bfc2022-10-18 18:39:121018 ),
1019 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531020 r'/\babsl::(StrSplit|StrJoin|StrCat|StrAppend|Substitute|StrContains)\b',
1021 ('Abseil string utilities are banned. Use base/strings instead.', ),
1022 True,
1023 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:121024 ),
1025 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531026 r'/\babsl::(Mutex|CondVar|Notification|Barrier|BlockingCounter)\b',
1027 (
1028 'Abseil synchronization primitives are banned. Use',
1029 'base/synchronization instead.',
1030 ),
1031 True,
1032 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:121033 ),
1034 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531035 r'/\babsl::(Duration|Time|TimeZone|CivilDay)\b',
1036 ('Abseil\'s time library is banned. Use base/time instead.', ),
1037 True,
1038 [
1039 # Needed to use QUICHE API.
Ciara McMullinc029c8e2024-08-21 14:22:321040 r'android_webview/browser/ip_protection/.*',
Daniel Cheng566634ff2024-06-29 14:56:531041 r'chrome/browser/ip_protection/.*',
1042 r'components/ip_protection/.*',
Lei Zhang1f9d9ec42024-06-20 18:42:271043
Daniel Cheng566634ff2024-06-29 14:56:531044 # Needed to integrate with //third_party/nearby
1045 r'components/cross_device/nearby/system_clock.cc',
1046 _THIRD_PARTY_EXCEPT_BLINK # Not an error in third_party folders.
1047 ],
1048 ),
1049 BanRule(
1050 r'/#include <chrono>',
1051 ('<chrono> is banned. Use base/time instead.', ),
1052 True,
1053 [
1054 # Not an error in third_party folders:
1055 _THIRD_PARTY_EXCEPT_BLINK,
Daniel Cheng566634ff2024-06-29 14:56:531056 # This uses openscreen API depending on std::chrono.
1057 "components/openscreen_platform/task_runner.cc",
1058 ]),
1059 BanRule(
1060 r'/#include <exception>',
1061 ('Exceptions are banned and disabled in Chromium.', ),
1062 True,
1063 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1064 ),
1065 BanRule(
1066 r'/\bstd::function\b',
1067 ('std::function is banned. Use base::{Once,Repeating}Callback instead.',
1068 ),
1069 True,
1070 [
1071 # Has tests that template trait helpers don't unintentionally match
1072 # std::function.
1073 r'base/functional/callback_helpers_unittest\.cc',
1074 # Required to implement interfaces from the third-party perfetto
1075 # library.
1076 r'base/tracing/perfetto_task_runner\.cc',
1077 r'base/tracing/perfetto_task_runner\.h',
1078 # Needed for interop with the third-party nearby library type
1079 # location::nearby::connections::ResultCallback.
Dirk Prankee4df27972025-02-26 18:39:351080 r'chrome/services/sharing/nearby/nearby_connections_conversions\.cc'
Daniel Cheng566634ff2024-06-29 14:56:531081 # Needed for interop with the internal libassistant library.
Dirk Prankee4df27972025-02-26 18:39:351082 r'chromeos/ash/services/libassistant/callback_utils\.h',
Daniel Cheng566634ff2024-06-29 14:56:531083 # Needed for interop with Fuchsia fidl APIs.
Dirk Prankee4df27972025-02-26 18:39:351084 r'fuchsia_web/webengine/browser/context_impl_browsertest\.cc',
1085 r'fuchsia_web/webengine/browser/cookie_manager_impl_unittest\.cc',
1086 r'fuchsia_web/webengine/browser/media_player_impl_unittest\.cc',
Daniel Cheng566634ff2024-06-29 14:56:531087 # Required to interop with interfaces from the third-party ChromeML
1088 # library API.
Dirk Prankee4df27972025-02-26 18:39:351089 r'services/on_device_model/ml/chrome_ml_api\.h',
1090 r'services/on_device_model/ml/on_device_model_executor\.cc',
1091 r'services/on_device_model/ml/on_device_model_executor\.h',
Daniel Cheng566634ff2024-06-29 14:56:531092 # Required to interop with interfaces from the third-party perfetto
1093 # library.
Dirk Prankee4df27972025-02-26 18:39:351094 r'components/tracing/common/etw_consumer_win_unittest\.cc',
1095 r'services/tracing/public/cpp/perfetto/custom_event_recorder\.cc',
1096 r'services/tracing/public/cpp/perfetto/perfetto_traced_process\.cc',
1097 r'services/tracing/public/cpp/perfetto/perfetto_traced_process\.h',
1098 r'services/tracing/public/cpp/perfetto/perfetto_tracing_backend\.cc',
1099 r'services/tracing/public/cpp/perfetto/producer_client\.cc',
1100 r'services/tracing/public/cpp/perfetto/producer_client\.h',
1101 r'services/tracing/public/cpp/perfetto/producer_test_utils\.cc',
1102 r'services/tracing/public/cpp/perfetto/producer_test_utils\.h',
Daniel Cheng566634ff2024-06-29 14:56:531103 # Required for interop with the third-party webrtc library.
Dirk Prankee4df27972025-02-26 18:39:351104 r'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.cc',
1105 r'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.h',
Daniel Cheng566634ff2024-06-29 14:56:531106 # TODO(https://crbug.com/1364577): Various uses that should be
1107 # migrated to something else.
1108 # Should use base::OnceCallback or base::RepeatingCallback.
Dirk Prankee4df27972025-02-26 18:39:351109 r'base/allocator/dispatcher/initializer_unittest\.cc',
1110 r'chrome/browser/ash/accessibility/speech_monitor\.cc',
1111 r'chrome/browser/ash/accessibility/speech_monitor\.h',
1112 r'chrome/browser/ash/login/ash_hud_login_browsertest\.cc',
1113 r'chromecast/base/observer_unittest\.cc',
1114 r'chromecast/browser/cast_web_view\.h',
1115 r'chromecast/public/cast_media_shlib\.h',
1116 r'device/bluetooth/floss/exported_callback_manager\.h',
1117 r'device/bluetooth/floss/floss_dbus_client\.h',
1118 r'device/fido/cable/v2_handshake_unittest\.cc',
1119 r'device/fido/pin\.cc',
1120 r'services/tracing/perfetto/test_utils\.h',
Daniel Cheng566634ff2024-06-29 14:56:531121 # Should use base::FunctionRef.
Dirk Prankee4df27972025-02-26 18:39:351122 r'chrome/browser/media/webrtc/test_stats_dictionary\.cc',
1123 r'chrome/browser/media/webrtc/test_stats_dictionary\.h',
1124 r'chromeos/ash/services/libassistant/device_settings_controller\.cc',
1125 r'components/browser_ui/client_certificate/android/ssl_client_certificate_request\.cc',
1126 r'components/gwp_asan/client/sampling_malloc_shims_unittest\.cc',
1127 r'content/browser/font_unique_name_lookup/font_unique_name_lookup_unittest\.cc',
Daniel Cheng566634ff2024-06-29 14:56:531128 # Does not need std::function at all.
Dirk Prankee4df27972025-02-26 18:39:351129 r'components/omnibox/browser/autocomplete_result\.cc',
1130 r'device/fido/win/webauthn_api\.cc',
1131 r'media/audio/alsa/alsa_util\.cc',
1132 r'media/remoting/stream_provider\.h',
1133 r'sql/vfs_wrapper\.cc',
Daniel Cheng566634ff2024-06-29 14:56:531134 # TODO(https://crbug.com/1364585): Remove usage and exception list
1135 # entries.
Dirk Prankee4df27972025-02-26 18:39:351136 r'extensions/renderer/api/automation/automation_internal_custom_bindings\.cc',
1137 r'extensions/renderer/api/automation/automation_internal_custom_bindings\.h',
Daniel Cheng566634ff2024-06-29 14:56:531138 # TODO(https://crbug.com/1364579): Remove usage and exception list
1139 # entry.
Dirk Prankee4df27972025-02-26 18:39:351140 r'ui/views/controls/focus_ring\.h',
Lei Zhang1f9d9ec42024-06-20 18:42:271141
Daniel Cheng566634ff2024-06-29 14:56:531142 # Various pre-existing uses in //tools that is low-priority to fix.
Dirk Prankee4df27972025-02-26 18:39:351143 r'tools/binary_size/libsupersize/viewer/caspian/diff\.cc',
1144 r'tools/binary_size/libsupersize/viewer/caspian/model\.cc',
1145 r'tools/binary_size/libsupersize/viewer/caspian/model\.h',
1146 r'tools/binary_size/libsupersize/viewer/caspian/tree_builder\.h',
1147 r'tools/clang/base_bind_rewriters/BaseBindRewriters\.cpp',
Daniel Chenge5583e3c2022-09-22 00:19:411148
Daniel Cheng566634ff2024-06-29 14:56:531149 # Not an error in third_party folders.
1150 _THIRD_PARTY_EXCEPT_BLINK
1151 ],
Daniel Bratell609102be2019-03-27 20:53:211152 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151153 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531154 r'/#include <X11/',
1155 ('Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.', ),
1156 True,
1157 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Tom Andersona95e12042020-09-09 23:08:001158 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151159 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531160 r'/\bstd::ratio\b',
1161 ('std::ratio is banned by the Google Style Guide.', ),
1162 True,
1163 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:451164 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151165 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531166 r'/\bstd::aligned_alloc\b',
1167 (
1168 'std::aligned_alloc() is not yet allowed (crbug.com/1412818). Use ',
1169 'base::AlignedAlloc() instead.',
1170 ),
1171 True,
1172 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181173 ),
1174 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531175 r'/#include <(barrier|latch|semaphore|stop_token)>',
1176 ('The thread support library is banned. Use base/synchronization '
1177 'instead.', ),
1178 True,
1179 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181180 ),
1181 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531182 r'/\bstd::execution::(par|seq)\b',
1183 ('std::execution::(par|seq) is banned; they do not fit into '
1184 ' Chrome\'s threading model, and libc++ doesn\'t have full '
mikt19226ff22024-08-27 05:28:211185 'support.', ),
Daniel Cheng566634ff2024-06-29 14:56:531186 True,
1187 [_THIRD_PARTY_EXCEPT_BLINK],
Helmut Januschka7cc8a84f2024-02-07 22:50:411188 ),
1189 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531190 r'/\bstd::bit_cast\b',
1191 ('std::bit_cast is banned; use base::bit_cast instead for values and '
1192 'standard C++ casting when pointers are involved.', ),
1193 True,
1194 [
1195 # Don't warn in third_party folders.
1196 _THIRD_PARTY_EXCEPT_BLINK,
1197 # //base/numerics can't use base or absl.
1198 r'base/numerics/.*'
1199 ],
Avi Drissman70cb7f72023-12-12 17:44:371200 ),
1201 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531202 r'/\bstd::(c8rtomb|mbrtoc8)\b',
1203 ('std::c8rtomb() and std::mbrtoc8() are banned.', ),
1204 True,
1205 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181206 ),
1207 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531208 r'/\bchar8_t|std::u8string\b',
1209 (
1210 'char8_t and std::u8string are not yet allowed. Can you use [unsigned]',
1211 ' char and std::string instead?',
1212 ),
1213 True,
1214 [
1215 # The demangler does not use this type but needs to know about it.
Dirk Prankee4df27972025-02-26 18:39:351216 r'base/third_party/symbolize/demangle\.cc',
Daniel Cheng566634ff2024-06-29 14:56:531217 # Don't warn in third_party folders.
1218 _THIRD_PARTY_EXCEPT_BLINK
1219 ],
Peter Kastinge2c5ee82023-02-15 17:23:081220 ),
1221 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531222 r'/(\b(co_await|co_return|co_yield)\b|#include <coroutine>)',
1223 ('Coroutines are not yet allowed (https://crbug.com/1403840).', ),
1224 True,
1225 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081226 ),
1227 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531228 r'/^\s*(export\s|import\s+["<:\w]|module(;|\s+[:\w]))',
1229 ('Modules are disallowed for now due to lack of toolchain support.', ),
1230 True,
1231 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting69357dc2023-03-14 01:34:291232 ),
1233 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531234 r'/\[\[(\w*::)?no_unique_address\]\]',
1235 (
1236 '[[no_unique_address]] does not work as expected on Windows ',
1237 '(https://crbug.com/1414621). Use NO_UNIQUE_ADDRESS instead.',
1238 ),
1239 True,
1240 [
1241 # NO_UNIQUE_ADDRESS / PA_NO_UNIQUE_ADDRESS provide canonical access.
1242 r'^base/compiler_specific\.h',
1243 r'^base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/compiler_specific\.h',
1244 # Not an error in third_party folders.
1245 _THIRD_PARTY_EXCEPT_BLINK,
1246 ],
Peter Kasting8bc046d22023-11-14 00:38:031247 ),
1248 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531249 r'/#include <format>',
1250 ('<format> is not yet allowed. Use base::StringPrintf() instead.', ),
1251 True,
1252 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081253 ),
1254 BanRule(
Daniel Cheng89719222024-07-04 04:59:291255 pattern='std::views',
1256 explanation=(
1257 'Use of std::views is banned in Chrome. If you need this '
1258 'functionality, please contact [email protected].',
1259 ),
1260 treat_as_error=True,
1261 excluded_paths=[
1262 # Don't warn in third_party folders.
1263 _THIRD_PARTY_EXCEPT_BLINK
1264 ],
1265 ),
1266 BanRule(
1267 # Ban everything except specifically allowlisted constructs.
1268 pattern=r'/std::ranges::(?!' + '|'.join((
1269 # From https://en.cppreference.com/w/cpp/ranges:
1270 # Range access
1271 'begin',
1272 'end',
1273 'cbegin',
1274 'cend',
1275 'rbegin',
1276 'rend',
1277 'crbegin',
1278 'crend',
1279 'size',
1280 'ssize',
1281 'empty',
1282 'data',
1283 'cdata',
1284 # Range primitives
1285 'iterator_t',
1286 'const_iterator_t',
1287 'sentinel_t',
1288 'const_sentinel_t',
1289 'range_difference_t',
1290 'range_size_t',
1291 'range_value_t',
1292 'range_reference_t',
1293 'range_const_reference_t',
1294 'range_rvalue_reference_t',
1295 'range_common_reference_t',
1296 # Dangling iterator handling
1297 'dangling',
1298 'borrowed_iterator_t',
1299 # Banned: borrowed_subrange_t
1300 # Range concepts
1301 'range',
1302 'borrowed_range',
1303 'sized_range',
1304 'view',
1305 'input_range',
1306 'output_range',
1307 'forward_range',
1308 'bidirectional_range',
1309 'random_access_range',
1310 'contiguous_range',
1311 'common_range',
1312 'viewable_range',
1313 'constant_range',
1314 # Banned: Views
1315 # Banned: Range factories
1316 # Banned: Range adaptors
Peter Kastinga7f93752024-10-24 22:15:401317 # Incidentally listed on
1318 # https://en.cppreference.com/w/cpp/header/ranges:
1319 'enable_borrowed_range',
1320 'enable_view',
Daniel Cheng89719222024-07-04 04:59:291321 # From https://en.cppreference.com/w/cpp/algorithm/ranges:
1322 # Constrained algorithms: non-modifying sequence operations
1323 'all_of',
1324 'any_of',
1325 'none_of',
1326 'for_each',
1327 'for_each_n',
1328 'count',
1329 'count_if',
1330 'mismatch',
1331 'equal',
1332 'lexicographical_compare',
1333 'find',
1334 'find_if',
1335 'find_if_not',
1336 'find_end',
1337 'find_first_of',
1338 'adjacent_find',
1339 'search',
1340 'search_n',
1341 # Constrained algorithms: modifying sequence operations
1342 'copy',
1343 'copy_if',
1344 'copy_n',
1345 'copy_backward',
1346 'move',
1347 'move_backward',
1348 'fill',
1349 'fill_n',
1350 'transform',
1351 'generate',
1352 'generate_n',
1353 'remove',
1354 'remove_if',
1355 'remove_copy',
1356 'remove_copy_if',
1357 'replace',
1358 'replace_if',
1359 'replace_copy',
1360 'replace_copy_if',
1361 'swap_ranges',
1362 'reverse',
1363 'reverse_copy',
1364 'rotate',
1365 'rotate_copy',
1366 'shuffle',
1367 'sample',
1368 'unique',
1369 'unique_copy',
1370 # Constrained algorithms: partitioning operations
1371 'is_partitioned',
1372 'partition',
1373 'partition_copy',
1374 'stable_partition',
1375 'partition_point',
1376 # Constrained algorithms: sorting operations
1377 'is_sorted',
1378 'is_sorted_until',
1379 'sort',
1380 'partial_sort',
1381 'partial_sort_copy',
1382 'stable_sort',
1383 'nth_element',
1384 # Constrained algorithms: binary search operations (on sorted ranges)
1385 'lower_bound',
1386 'upper_bound',
1387 'binary_search',
1388 'equal_range',
1389 # Constrained algorithms: set operations (on sorted ranges)
1390 'merge',
1391 'inplace_merge',
1392 'includes',
1393 'set_difference',
1394 'set_intersection',
1395 'set_symmetric_difference',
1396 'set_union',
1397 # Constrained algorithms: heap operations
1398 'is_heap',
1399 'is_heap_until',
1400 'make_heap',
1401 'push_heap',
1402 'pop_heap',
1403 'sort_heap',
1404 # Constrained algorithms: minimum/maximum operations
1405 'max',
1406 'max_element',
1407 'min',
1408 'min_element',
1409 'minmax',
1410 'minmax_element',
1411 'clamp',
1412 # Constrained algorithms: permutation operations
1413 'is_permutation',
1414 'next_permutation',
1415 'prev_premutation',
1416 # Constrained uninitialized memory algorithms
1417 'uninitialized_copy',
1418 'uninitialized_copy_n',
1419 'uninitialized_fill',
1420 'uninitialized_fill_n',
1421 'uninitialized_move',
1422 'uninitialized_move_n',
1423 'uninitialized_default_construct',
1424 'uninitialized_default_construct_n',
1425 'uninitialized_value_construct',
1426 'uninitialized_value_construct_n',
1427 'destroy',
1428 'destroy_n',
1429 'destroy_at',
1430 'construct_at',
1431 # Return types
1432 'in_fun_result',
1433 'in_in_result',
1434 'in_out_result',
1435 'in_in_out_result',
1436 'in_out_out_result',
1437 'min_max_result',
1438 'in_found_result',
Peter Kastingf379c022025-01-13 14:01:001439 # From https://en.cppreference.com/w/cpp/header/functional
1440 'equal_to',
1441 'not_equal_to',
1442 'greater',
1443 'less',
1444 'greater_equal',
1445 'less_equal',
danakj91c715b2024-07-10 13:24:261446 # From https://en.cppreference.com/w/cpp/iterator
1447 'advance',
1448 'distance',
1449 'next',
1450 'prev',
Daniel Cheng89719222024-07-04 04:59:291451 )) + r')\w+',
1452 explanation=(
1453 'Use of range views and associated helpers is banned in Chrome. '
1454 'If you need this functionality, please contact [email protected].',
1455 ),
1456 treat_as_error=True,
1457 excluded_paths=[
1458 # Don't warn in third_party folders.
1459 _THIRD_PARTY_EXCEPT_BLINK
1460 ],
Peter Kastinge2c5ee82023-02-15 17:23:081461 ),
1462 BanRule(
Peter Kasting31879d82024-10-07 20:18:391463 r'/#include <regex>',
1464 ('<regex> is not allowed. Use third_party/re2 instead.',
1465 ),
1466 True,
1467 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1468 ),
1469 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531470 r'/#include <source_location>',
1471 ('<source_location> is not yet allowed. Use base/location.h instead.',
1472 ),
1473 True,
1474 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081475 ),
1476 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531477 r'/\bstd::to_address\b',
1478 (
1479 'std::to_address is banned because it is not guaranteed to be',
1480 'SFINAE-compatible. Use base::to_address from base/types/to_address.h',
1481 'instead.',
1482 ),
1483 True,
1484 [
1485 # Needed in base::to_address implementation.
1486 r'base/types/to_address.h',
1487 _THIRD_PARTY_EXCEPT_BLINK
1488 ], # Not an error in third_party folders.
Nick Diego Yamanee522ae82024-02-27 04:23:221489 ),
1490 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531491 r'/#include <syncstream>',
1492 ('<syncstream> is banned.', ),
1493 True,
1494 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181495 ),
1496 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531497 r'/\bRunMessageLoop\b',
1498 ('RunMessageLoop is deprecated, use RunLoop instead.', ),
1499 False,
1500 (),
Gabriel Charette147335ea2018-03-22 15:59:191501 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151502 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531503 'RunAllPendingInMessageLoop()',
1504 (
1505 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
1506 "if you're convinced you need this.",
1507 ),
1508 False,
1509 (),
Gabriel Charette147335ea2018-03-22 15:59:191510 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151511 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531512 'RunAllPendingInMessageLoop(BrowserThread',
1513 (
1514 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
1515 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
1516 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
1517 'async events instead of flushing threads.',
1518 ),
1519 False,
1520 (),
Gabriel Charette147335ea2018-03-22 15:59:191521 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151522 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531523 r'MessageLoopRunner',
1524 ('MessageLoopRunner is deprecated, use RunLoop instead.', ),
1525 False,
1526 (),
Gabriel Charette147335ea2018-03-22 15:59:191527 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151528 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531529 'GetDeferredQuitTaskForRunLoop',
1530 (
1531 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
1532 "gab@ if you found a use case where this is the only solution.",
1533 ),
1534 False,
1535 (),
Gabriel Charette147335ea2018-03-22 15:59:191536 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151537 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531538 'sqlite3_initialize(',
1539 (
1540 'Instead of calling sqlite3_initialize(), depend on //sql, ',
1541 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
1542 ),
1543 True,
1544 (
1545 r'^sql/initialization\.(cc|h)$',
1546 r'^third_party/sqlite/.*\.(c|cc|h)$',
1547 ),
Victor Costan3653df62018-02-08 21:38:161548 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151549 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531550 'CREATE VIEW',
1551 (
1552 'SQL views are disabled in Chromium feature code',
1553 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-views',
1554 ),
1555 True,
1556 (
1557 _THIRD_PARTY_EXCEPT_BLINK,
1558 # sql/ itself uses views when using memory-mapped IO.
1559 r'^sql/.*',
1560 # Various performance tools that do not build as part of Chrome.
1561 r'^infra/.*',
1562 r'^tools/perf.*',
1563 r'.*perfetto.*',
1564 ),
Austin Sullivand661ab52022-11-16 08:55:151565 ),
1566 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531567 'CREATE VIRTUAL TABLE',
1568 (
1569 'SQL virtual tables are disabled in Chromium feature code',
1570 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-virtual-tables',
1571 ),
1572 True,
1573 (
1574 _THIRD_PARTY_EXCEPT_BLINK,
1575 # sql/ itself uses virtual tables in the recovery module and tests.
1576 r'^sql/.*',
1577 # TODO(https://crbug.com/695592): Remove once WebSQL is deprecated.
1578 r'third_party/blink/web_tests/storage/websql/.*'
1579 # Various performance tools that do not build as part of Chrome.
1580 r'^tools/perf.*',
1581 r'.*perfetto.*',
1582 ),
Austin Sullivand661ab52022-11-16 08:55:151583 ),
1584 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531585 'std::random_shuffle',
1586 ('std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
1587 'base::RandomShuffle instead.'),
1588 True,
1589 (),
tzik5de2157f2018-05-08 03:42:471590 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151591 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531592 'ios/web/public/test/http_server',
1593 ('web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
1594 ),
1595 False,
1596 (),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:241597 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151598 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531599 'GetAddressOf',
1600 ('Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
1601 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
1602 'operator& is generally recommended. So always use operator& instead. ',
1603 'See http://crbug.com/914910 for more conversion guidance.'),
1604 True,
1605 (),
Robert Liao764c9492019-01-24 18:46:281606 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151607 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531608 'SHFileOperation',
1609 ('SHFileOperation was deprecated in Windows Vista, and there are less ',
1610 'complex functions to achieve the same goals. Use IFileOperation for ',
1611 'any esoteric actions instead.'),
1612 True,
1613 (),
Ben Lewisa9514602019-04-29 17:53:051614 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151615 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531616 'StringFromGUID2',
1617 ('StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
1618 'Use base::win::WStringFromGUID instead.'),
1619 True,
1620 (r'/base/win/win_util_unittest.cc', ),
Cliff Smolinsky81951642019-04-30 21:39:511621 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151622 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531623 'StringFromCLSID',
1624 ('StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
1625 'Use base::win::WStringFromGUID instead.'),
1626 True,
1627 (r'/base/win/win_util_unittest.cc', ),
Cliff Smolinsky81951642019-04-30 21:39:511628 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151629 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531630 'kCFAllocatorNull',
1631 (
1632 'The use of kCFAllocatorNull with the NoCopy creation of ',
1633 'CoreFoundation types is prohibited.',
1634 ),
1635 True,
1636 (),
Avi Drissman7382afa02019-04-29 23:27:131637 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151638 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531639 'mojo::ConvertTo',
1640 ('mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1641 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1642 'StringTraits if you would like to convert between custom types and',
1643 'the wire format of mojom types.'),
1644 False,
1645 (
1646 r'^fuchsia_web/webengine/browser/url_request_rewrite_rules_manager\.cc$',
1647 r'^fuchsia_web/webengine/url_request_rewrite_type_converters\.cc$',
1648 r'^third_party/blink/.*\.(cc|h)$',
1649 r'^content/renderer/.*\.(cc|h)$',
1650 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291651 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151652 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531653 'GetInterfaceProvider',
1654 ('InterfaceProvider is deprecated.',
1655 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1656 'or Platform::GetBrowserInterfaceBroker.'),
1657 False,
1658 (),
Oksana Zhuravlovac8222d22019-12-19 19:21:161659 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151660 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531661 'CComPtr',
1662 ('New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1663 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1664 'details.'),
1665 False,
1666 (),
Robert Liao1d78df52019-11-11 20:02:011667 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151668 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531669 r'/\b(IFACE|STD)METHOD_?\(',
1670 ('IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1671 'Instead, always use IFACEMETHODIMP in the declaration.'),
1672 False,
1673 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Xiaohan Wang72bd2ba2020-02-18 21:38:201674 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151675 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531676 'set_owned_by_client',
1677 ('set_owned_by_client is deprecated.',
1678 'views::View already owns the child views by default. This introduces ',
1679 'a competing ownership model which makes the code difficult to reason ',
1680 'about. See http://crbug.com/1044687 for more details.'),
1681 False,
1682 (),
Allen Bauer53b43fb12020-03-12 17:21:471683 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151684 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531685 'RemoveAllChildViewsWithoutDeleting',
1686 ('RemoveAllChildViewsWithoutDeleting is deprecated.',
1687 'This method is deemed dangerous as, unless raw pointers are re-added,',
1688 'calls to this method introduce memory leaks.'),
1689 False,
1690 (),
Peter Boström7ff41522021-07-29 03:43:271691 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151692 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531693 r'/\bTRACE_EVENT_ASYNC_',
1694 (
1695 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1696 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1697 ),
1698 False,
1699 (
1700 r'^base/trace_event/.*',
1701 r'^base/tracing/.*',
1702 ),
Eric Secklerbe6f48d2020-05-06 18:09:121703 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151704 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531705 'RoInitialize',
1706 ('Improper use of [base::win]::RoInitialize() has been implicated in a ',
1707 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
1708 'instead. See http://crbug.com/1197722 for more information.'),
1709 True,
1710 (
1711 r'^base/win/scoped_winrt_initializer\.cc$',
1712 r'^third_party/abseil-cpp/absl/.*',
1713 ),
Robert Liao22f66a52021-04-10 00:57:521714 ),
Patrick Monettec343bb982022-06-01 17:18:451715 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531716 r'base::Watchdog',
1717 (
1718 'base::Watchdog is deprecated because it creates its own thread.',
1719 'Instead, manually start a timer on a SequencedTaskRunner.',
1720 ),
1721 False,
1722 (),
Patrick Monettec343bb982022-06-01 17:18:451723 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091724 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531725 'base::Passed',
1726 ('Do not use base::Passed. It is a legacy helper for capturing ',
1727 'move-only types with base::BindRepeating, but invoking the ',
1728 'resulting RepeatingCallback moves the captured value out of ',
1729 'the callback storage, and subsequent invocations may pass the ',
1730 'value in a valid but undefined state. Prefer base::BindOnce().',
1731 'See http://crbug.com/1326449 for context.'),
1732 False,
1733 (
1734 # False positive, but it is also fine to let bind internals reference
1735 # base::Passed.
1736 r'^base[\\/]functional[\\/]bind\.h',
1737 r'^base[\\/]functional[\\/]bind_internal\.h',
1738 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091739 ),
Daniel Cheng2248b332022-07-27 06:16:591740 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531741 r'base::Feature k',
1742 ('Please use BASE_DECLARE_FEATURE() or BASE_FEATURE() instead of ',
1743 'directly declaring/defining features.'),
1744 True,
1745 [
1746 # Implements BASE_DECLARE_FEATURE().
1747 r'^base/feature_list\.h',
1748 ],
Daniel Chengba3bc2e2022-10-03 02:45:431749 ),
Robert Ogden92101dcb2022-10-19 23:49:361750 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531751 r'/\bchartorune\b',
1752 ('chartorune is not memory-safe, unless you can guarantee the input ',
1753 'string is always null-terminated. Otherwise, please use charntorune ',
1754 'from libphonenumber instead.'),
1755 True,
1756 [
1757 _THIRD_PARTY_EXCEPT_BLINK,
1758 # Exceptions to this rule should have a fuzzer.
1759 ],
Robert Ogden92101dcb2022-10-19 23:49:361760 ),
Arthur Sonzogni1da65fa2023-03-27 16:01:521761 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531762 r'/\b#include "base/atomicops\.h"\b',
1763 ('Do not use base::subtle atomics, but std::atomic, which are simpler '
1764 'to use, have better understood, clearer and richer semantics, and are '
1765 'harder to mis-use. See details in base/atomicops.h.', ),
1766 False,
1767 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Benoit Lize79cf0592023-01-27 10:01:571768 ),
Daniel Cheng566634ff2024-06-29 14:56:531769 BanRule(r'CrossThreadPersistent<', (
Arthur Sonzogni60348572e2023-04-07 10:22:521770 'Do not use blink::CrossThreadPersistent, but '
Daniel Cheng566634ff2024-06-29 14:56:531771 'blink::CrossThreadHandle. It is harder to mis-use.', 'More info: '
Arthur Sonzogni60348572e2023-04-07 10:22:521772 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1773 'Please contact platform-architecture-dev@ before adding new instances.'
Daniel Cheng566634ff2024-06-29 14:56:531774 ), False, []),
1775 BanRule(r'CrossThreadWeakPersistent<', (
Arthur Sonzogni60348572e2023-04-07 10:22:521776 'Do not use blink::CrossThreadWeakPersistent, but '
Daniel Cheng566634ff2024-06-29 14:56:531777 'blink::CrossThreadWeakHandle. It is harder to mis-use.', 'More info: '
Arthur Sonzogni60348572e2023-04-07 10:22:521778 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1779 'Please contact platform-architecture-dev@ before adding new instances.'
Daniel Cheng566634ff2024-06-29 14:56:531780 ), False, []),
1781 BanRule(r'objc/objc.h', (
Avi Drissman491617c2023-04-13 17:33:151782 'Do not include <objc/objc.h>. It defines away ARC lifetime '
1783 'annotations, and is thus dangerous.',
1784 'Please use the pimpl pattern; search for `ObjCStorage` for examples.',
1785 'For further reading on how to safely mix C++ and Obj-C, see',
1786 'https://chromium.googlesource.com/chromium/src/+/main/docs/mac/mixing_cpp_and_objc.md'
Daniel Cheng566634ff2024-06-29 14:56:531787 ), True, []),
1788 BanRule(
1789 r'/#include <filesystem>',
1790 ('libc++ <filesystem> is banned per the Google C++ styleguide.', ),
1791 True,
1792 # This fuzzing framework is a standalone open source project and
1793 # cannot rely on Chromium base.
1794 (r'third_party/centipede'),
Avi Drissman491617c2023-04-13 17:33:151795 ),
Grace Park8d59b54b2023-04-26 17:53:351796 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531797 r'TopDocument()',
1798 ('TopDocument() does not work correctly with out-of-process iframes. '
1799 'Please do not introduce new uses.', ),
1800 True,
1801 (
1802 # TODO(crbug.com/617677): Remove all remaining uses.
1803 r'^third_party/blink/renderer/core/dom/document\.cc',
1804 r'^third_party/blink/renderer/core/dom/document\.h',
1805 r'^third_party/blink/renderer/core/dom/element\.cc',
1806 r'^third_party/blink/renderer/core/exported/web_disallow_transition_scope_test\.cc',
1807 r'^third_party/blink/renderer/core/exported/web_document_test\.cc',
1808 r'^third_party/blink/renderer/core/html/html_anchor_element\.cc',
1809 r'^third_party/blink/renderer/core/html/html_dialog_element\.cc',
1810 r'^third_party/blink/renderer/core/html/html_element\.cc',
1811 r'^third_party/blink/renderer/core/html/html_frame_owner_element\.cc',
1812 r'^third_party/blink/renderer/core/html/media/video_wake_lock\.cc',
1813 r'^third_party/blink/renderer/core/loader/anchor_element_interaction_tracker\.cc',
1814 r'^third_party/blink/renderer/core/page/scrolling/root_scroller_controller\.cc',
1815 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.cc',
1816 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.h',
1817 r'^third_party/blink/renderer/core/script/classic_pending_script\.cc',
1818 r'^third_party/blink/renderer/core/script/script_loader\.cc',
1819 ),
Grace Park8d59b54b2023-04-26 17:53:351820 ),
Daniel Cheng72153e02023-05-18 21:18:141821 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531822 pattern=r'base::raw_ptr<',
1823 explanation=('Do not use base::raw_ptr, use raw_ptr.', ),
1824 treat_as_error=True,
1825 excluded_paths=(
1826 '^base/',
1827 '^tools/',
1828 ),
Daniel Cheng72153e02023-05-18 21:18:141829 ),
Arthur Sonzognif0eea302023-08-18 19:20:311830 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531831 pattern=r'base:raw_ref<',
1832 explanation=('Do not use base::raw_ref, use raw_ref.', ),
1833 treat_as_error=True,
1834 excluded_paths=(
1835 '^base/',
1836 '^tools/',
1837 ),
Arthur Sonzognif0eea302023-08-18 19:20:311838 ),
1839 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531840 pattern=r'/raw_ptr<[^;}]*\w{};',
1841 explanation=(
1842 'Do not use {} for raw_ptr initialization, use = nullptr instead.',
1843 ),
1844 treat_as_error=True,
1845 excluded_paths=(
1846 '^base/',
1847 '^tools/',
1848 ),
Arthur Sonzognif0eea302023-08-18 19:20:311849 ),
Anton Maliev66751812023-08-24 16:28:131850 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531851 pattern=r'/#include "base/allocator/.*/raw_'
1852 r'(ptr|ptr_cast|ptr_exclusion|ref).h"',
1853 explanation=(
1854 'Please include the corresponding facade headers:',
1855 '- #include "base/memory/raw_ptr.h"',
1856 '- #include "base/memory/raw_ptr_cast.h"',
1857 '- #include "base/memory/raw_ptr_exclusion.h"',
1858 '- #include "base/memory/raw_ref.h"',
1859 ),
1860 treat_as_error=True,
1861 excluded_paths=(
1862 '^base/',
1863 '^tools/',
1864 ),
Tom Sepez41eb158d2023-09-12 16:16:221865 ),
1866 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531867 pattern=r'ContentSettingsType::COOKIES',
1868 explanation=
1869 ('Do not use ContentSettingsType::COOKIES to check whether cookies are '
1870 'supported in the provided context. Instead rely on the '
1871 'content_settings::CookieSettings API. If you are using '
1872 'ContentSettingsType::COOKIES to check the user preference setting '
1873 'specifically, disregard this warning.', ),
1874 treat_as_error=False,
1875 excluded_paths=(
1876 '^chrome/browser/ui/content_settings/',
1877 '^components/content_settings/',
1878 '^services/network/cookie_settings.cc',
1879 '.*test.cc',
1880 ),
Arthur Sonzogni48c6aea22023-09-04 22:25:201881 ),
1882 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531883 pattern=r'ContentSettingsType::TRACKING_PROTECTION',
1884 explanation=
1885 ('Do not directly use ContentSettingsType::TRACKING_PROTECTION to check '
1886 'for tracking protection exceptions. Instead rely on the '
1887 'privacy_sandbox::TrackingProtectionSettings API.', ),
1888 treat_as_error=False,
1889 excluded_paths=(
1890 '^chrome/browser/ui/content_settings/',
1891 '^components/content_settings/',
1892 '^components/privacy_sandbox/tracking_protection_settings.cc',
1893 '.*test.cc',
1894 ),
Anton Maliev66751812023-08-24 16:28:131895 ),
Tom Andersoncd522072023-10-03 00:52:351896 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531897 pattern=r'/\bg_signal_connect',
1898 explanation=('Use ScopedGSignal instead of g_signal_connect*()', ),
1899 treat_as_error=True,
1900 excluded_paths=('^ui/base/glib/scoped_gsignal.h', ),
Michelle Abreo6b7437822024-04-26 17:29:041901 ),
1902 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531903 pattern=r'features::kIsolatedWebApps',
1904 explanation=(
1905 'Do not use `features::kIsolatedWebApps` directly to guard Isolated ',
1906 'Web App code. ',
1907 'Use `content::IsolatedWebAppsPolicy::AreIsolatedWebAppsEnabled()` in ',
1908 'the browser process or check the `kEnableIsolatedWebAppsInRenderer` ',
1909 'command line flag in the renderer process.',
1910 ),
1911 treat_as_error=True,
1912 excluded_paths=_TEST_CODE_EXCLUDED_PATHS +
1913 ('^chrome/browser/about_flags.cc',
1914 '^chrome/browser/web_applications/isolated_web_apps/chrome_content_browser_client_isolated_web_apps_part.cc',
1915 '^chrome/browser/ui/startup/bad_flags_prompt.cc',
1916 '^content/shell/browser/shell_content_browser_client.cc')),
1917 BanRule(
1918 pattern=r'features::kIsolatedWebAppDevMode',
1919 explanation=(
1920 'Do not use `features::kIsolatedWebAppDevMode` directly to guard code ',
1921 'related to Isolated Web App Developer Mode. ',
1922 'Use `web_app::IsIwaDevModeEnabled()` instead.',
1923 ),
1924 treat_as_error=True,
1925 excluded_paths=_TEST_CODE_EXCLUDED_PATHS + (
1926 '^chrome/browser/about_flags.cc',
1927 '^chrome/browser/web_applications/isolated_web_apps/isolated_web_app_features.cc',
1928 '^chrome/browser/ui/startup/bad_flags_prompt.cc',
1929 )),
1930 BanRule(
1931 pattern=r'features::kIsolatedWebAppUnmanagedInstall',
1932 explanation=(
1933 'Do not use `features::kIsolatedWebAppUnmanagedInstall` directly to ',
1934 'guard code related to unmanaged install flow for Isolated Web Apps. ',
1935 'Use `web_app::IsIwaUnmanagedInstallEnabled()` instead.',
1936 ),
1937 treat_as_error=True,
1938 excluded_paths=_TEST_CODE_EXCLUDED_PATHS + (
1939 '^chrome/browser/about_flags.cc',
1940 '^chrome/browser/web_applications/isolated_web_apps/isolated_web_app_features.cc',
1941 )),
1942 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531943 pattern='/(CUIAutomation|AccessibleObjectFromWindow)',
1944 explanation=
1945 ('Direct usage of UIAutomation or IAccessible2 in client code is '
1946 'discouraged in Chromium, as it is not an assistive technology and '
1947 'should not rely on accessibility APIs directly. These APIs can '
1948 'introduce significant performance overhead. However, if you believe '
1949 'your use case warrants an exception, please discuss it with an '
1950 'accessibility owner before proceeding. For more information on the '
1951 'performance implications, see https://docs.google.com/document/d/1jN4itpCe_bDXF0BhFaYwv4xVLsCWkL9eULdzjmLzkuk/edit#heading=h.pwth3nbwdub0.',
1952 ),
1953 treat_as_error=False,
Andrew Rayskiycdd45e732024-03-20 14:32:391954 ),
1955 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531956 pattern=r'/WIDGET_OWNS_NATIVE_WIDGET|'
1957 r'NATIVE_WIDGET_OWNS_WIDGET',
1958 explanation=
1959 ('WIDGET_OWNS_NATIVE_WIDGET and NATIVE_WIDGET_OWNS_WIDGET are in the '
1960 'process of being deprecated. Consider using the new '
1961 'CLIENT_OWNS_WIDGET ownership model. Eventually, this will be the only '
1962 'available ownership model available and the associated enumeration'
1963 'will be removed.', ),
1964 treat_as_error=False,
Andrew Rayskiycdd45e732024-03-20 14:32:391965 ),
1966 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531967 pattern='ProfileManager::GetLastUsedProfile',
1968 explanation=
1969 ('Most code should already be scoped to a Profile. Pass in a Profile* '
1970 'or retreive from an existing entity with a reference to the Profile '
1971 '(e.g. WebContents).', ),
1972 treat_as_error=False,
Arthur Sonzogni5cbd3e32024-02-08 17:51:321973 ),
Helmut Januschkab3f71ab52024-03-12 02:48:051974 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531975 pattern=(r'/FindBrowserWithUiElementContext|'
1976 r'FindBrowserWithTab|'
1977 r'FindBrowserWithGroup|'
1978 r'FindTabbedBrowser|'
1979 r'FindAnyBrowser|'
1980 r'FindBrowserWithProfile|'
Erik Chen5f02eb4c2024-08-23 06:30:441981 r'FindLastActive|'
Daniel Cheng566634ff2024-06-29 14:56:531982 r'FindBrowserWithActiveWindow'),
1983 explanation=
1984 ('Most code should already be scoped to a Browser. Pass in a Browser* '
1985 'or retreive from an existing entity with a reference to the Browser.',
1986 ),
1987 treat_as_error=False,
Helmut Januschkab3f71ab52024-03-12 02:48:051988 ),
1989 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531990 pattern='BrowserUserData',
1991 explanation=
1992 ('Do not use BrowserUserData to store state on a Browser instance. '
1993 'Instead use BrowserWindowFeatures. BrowserWindowFeatures is '
1994 'functionally identical but has two benefits: it does not force a '
1995 'dependency onto class Browser, and lifetime semantics are explicit '
1996 'rather than implicit. See BrowserUserData header file for more '
1997 'details.', ),
1998 treat_as_error=False,
Mike Doughertyab1bdec2024-08-06 16:39:011999 excluded_paths=(
2000 # Exclude iOS as the iOS implementation of BrowserUserData is separate
2001 # and still in use.
2002 '^ios/',
2003 ),
Erik Chen87358e82024-06-04 02:13:122004 ),
Tom Sepezea67b6e2024-08-08 18:17:272005 BanRule(
Tom Sepezd3272cd2025-02-21 19:11:312006 pattern=r'subspan(0u,',
2007 explanation=
2008 ('Prefer first(n) over subspan(0u, n) as it is shorter, and the '
2009 'compiler may have to emit a branch for the n == dynamic_extent '
2010 'case of subspan().',
2011 ),
2012 treat_as_error=False,
2013 ),
2014 BanRule(
Tom Sepezea67b6e2024-08-08 18:17:272015 pattern=r'UNSAFE_TODO(',
2016 explanation=
2017 ('Do not use UNSAFE_TODO() to write new unsafe code. Use only when '
Tom Sepeza90f92b2024-08-15 16:01:352018 'removing a pre-existing file-wide allow_unsafe_buffers pragma, or '
2019 'when incrementally converting code off of unsafe interfaces',
Tom Sepezea67b6e2024-08-08 18:17:272020 ),
2021 treat_as_error=False,
2022 ),
2023 BanRule(
2024 pattern=r'UNSAFE_BUFFERS(',
2025 explanation=
Tom Sepeza90f92b2024-08-15 16:01:352026 ('Try to avoid using UNSAFE_BUFFERS() if at all possible. Otherwise, '
2027 'be sure to justify in a // SAFETY comment why other options are not '
2028 'available, and why the code is safe.',
Tom Sepezea67b6e2024-08-08 18:17:272029 ),
2030 treat_as_error=False,
2031 ),
Erik Chend086ae02024-08-20 22:53:332032 BanRule(
2033 pattern='BrowserWithTestWindowTest',
2034 explanation=
2035 ('Do not use BrowserWithTestWindowTest. By instantiating an instance '
2036 'of class Browser, the test is no longer a unit test but is instead a '
2037 'browser test. The class BrowserWithTestWindowTest forces production '
2038 'logic to take on test-only conditionals, which is an anti-pattern. '
2039 'Features should be performing dependency injection rather than '
2040 'directly using class Browser. See '
mikt19226ff22024-08-27 05:28:212041 'docs/chrome_browser_design_principles.md for more details.',
Erik Chend086ae02024-08-20 22:53:332042 ),
2043 treat_as_error=False,
2044 ),
Erik Chen8cf3a652024-08-23 17:13:302045 BanRule(
Erik Chen959cdd72024-08-29 02:11:212046 pattern='TestWithBrowserView',
2047 explanation=
2048 ('Do not use TestWithBrowserView. See '
2049 'docs/chrome_browser_design_principles.md for details. If you want '
2050 'to write a test that has both a Browser and a BrowserView, create '
2051 'a browser_test. If you want to write a unit_test, your code must '
Erik Chendba23692024-09-26 06:43:362052 'not reference Browser*.',
Erik Chen959cdd72024-08-29 02:11:212053 ),
2054 treat_as_error=False,
2055 ),
2056 BanRule(
Erik Chene89ebe32025-02-22 02:46:492057 pattern='CreateBrowserWithTestWindow',
2058 explanation=
2059 ('Do not use CreateBrowserWithTestWindow. See '
2060 'docs/chrome_browser_design_principles.md for details. If you want '
2061 'to write a test that has a Browser, create a browser_test. If you '
2062 'want to write a unit_test, your code must not reference Browser*.',
2063 ),
2064 treat_as_error=False,
2065 ),
2066 BanRule(
Erik Chen8cf3a652024-08-23 17:13:302067 pattern='RunUntilIdle',
2068 explanation=
2069 ('Do not RunUntilIdle. If possible, explicitly quit the run loop using '
2070 'run_loop.Quit() or run_loop.QuitClosure() if completion can be '
2071 'observed using a lambda or callback. Otherwise, wait for the '
mikt19226ff22024-08-27 05:28:212072 'condition to be true via base::test::RunUntil().',
Erik Chen8cf3a652024-08-23 17:13:302073 ),
2074 treat_as_error=False,
2075 ),
Daniel Chengddde13a2024-09-05 21:39:282076 BanRule(
2077 pattern=r'/\bstd::(literals|string_literals|string_view_literals)\b',
2078 explanation = (
2079 'User-defined literals are banned by the Google C++ style guide. '
2080 'Exceptions are provided in Chrome for string and string_view '
2081 'literals that embed \\0.',
2082 ),
2083 treat_as_error=True,
2084 excluded_paths=(
2085 # Various tests or test helpers that embed NUL in strings or
2086 # string_views.
Daniel Chengddde13a2024-09-05 21:39:282087 r'^base/strings/string_util_unittest\.cc',
2088 r'^base/strings/utf_string_conversions_unittest\.cc',
2089 r'^chrome/browser/ash/crosapi/browser_data_back_migrator_unittest\.cc',
2090 r'^chrome/browser/ash/crosapi/browser_data_migrator_util_unittest\.cc',
2091 r'^chrome/browser/ash/crosapi/move_migrator_unittest\.cc',
Hidehiko Abe51601812025-01-12 16:17:352092 r'^chromeos/ash/experiences/arc/session/serial_number_util_unittest\.cc',
Daniel Chengddde13a2024-09-05 21:39:282093 r'^components/history/core/browser/visit_annotations_database\.cc',
2094 r'^components/history/core/browser/visit_annotations_database_unittest\.cc',
2095 r'^components/os_crypt/sync/os_crypt_unittest\.cc',
2096 r'^components/password_manager/core/browser/credentials_cleaner_unittest\.cc',
2097 r'^content/browser/file_system_access/file_system_access_file_writer_impl_unittest\.cc',
2098 r'^net/cookies/parsed_cookie_unittest\.cc',
2099 r'^third_party/blink/renderer/modules/webcodecs/test_helpers\.cc',
2100 r'^third_party/blink/renderer/modules/websockets/websocket_channel_impl_test\.cc',
2101 ),
Erik Chenba8b0cd32024-10-01 08:36:362102 ),
2103 BanRule(
2104 pattern='BUILDFLAG(GOOGLE_CHROME_BRANDING)',
2105 explanation=
2106 ('Code gated by GOOGLE_CHROME_BRANDING is effectively untested. This '
2107 'is typically wrong. Valid use cases are glue for private modules '
2108 'shipped alongside Chrome, and installation-related logic.',
2109 ),
2110 treat_as_error=False,
2111 ),
2112 BanRule(
2113 pattern='defined(OFFICIAL_BUILD)',
2114 explanation=
2115 ('Code gated by OFFICIAL_BUILD is effectively untested. This '
2116 'is typically wrong. One valid use case is low-level code that '
2117 'handles subtleties related to high-levels of optimizations that come '
2118 'with OFFICIAL_BUILD.',
2119 ),
2120 treat_as_error=False,
2121 ),
Erik Chen95b9c782024-11-08 03:26:272122 BanRule(
2123 pattern='WebContentsDestroyed',
2124 explanation=
2125 ('Do not use this method. It is invoked half-way through the '
2126 'destructor of WebContentsImpl and using it often results in crashes '
2127 'or surprising behavior. Conceptually, this is only necessary by '
2128 'objects that depend on, but outlive the WebContents. These objects '
2129 'should instead coordinate with the owner of the WebContents which is '
2130 'responsible for destroying the WebContents.',
2131 ),
2132 treat_as_error=False,
2133 ),
Maksim Sisovc98fdfa2024-11-16 20:12:272134 BanRule(
Georg Neisa7f94e62025-02-28 07:01:482135 pattern='IS_CHROMEOS_ASH',
Maksim Sisovc98fdfa2024-11-16 20:12:272136 explanation=
Georg Neisa7f94e62025-02-28 07:01:482137 ('IS_CHROMEOS_ASH is deprecated. Please use the equivalent IS_CHROMEOS '
2138 'instead (Lacros is gone).',
Maksim Sisovc98fdfa2024-11-16 20:12:272139 ),
2140 treat_as_error=False,
2141 ),
Erik Chen1396bbe2025-01-27 23:39:362142 BanRule(
2143 pattern=(r'namespace {'),
2144 explanation=
2145 ('Anonymous namespaces are disallowed in C++ header files. See '
2146 'https://google.github.io/styleguide/cppguide.html#Internal_Linkage '
2147 ' for details.',
2148 ),
2149 treat_as_error=False,
2150 excluded_paths=[
2151 _THIRD_PARTY_EXCEPT_BLINK, # Don't warn in third_party folders.
2152 r'^(?!.*\.h$).*$', # Exclude all files except those that end in .h
2153 ],
2154 ),
[email protected]127f18ec2012-06-16 05:05:592155)
2156
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152157_DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING = (
2158 'Used a predicate related to signin::ConsentLevel::kSync which will always '
2159 'return false in the future (crbug.com/40066949). Prefer using a predicate '
2160 'that also supports signin::ConsentLevel::kSignin when appropriate. It is '
2161 'safe to ignore this warning if you are just moving an existing call, or if '
2162 'you want special handling for users in the legacy state. In doubt, reach '
Victor Hugo Vianna Silvae2292972024-06-04 17:11:552163 'out to //components/sync/OWNERS.',
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152164)
2165
2166# C++ functions related to signin::ConsentLevel::kSync which are deprecated.
2167_DEPRECATED_SYNC_CONSENT_CPP_FUNCTIONS : Sequence[BanRule] = (
2168 BanRule(
2169 'HasSyncConsent',
2170 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2171 False,
2172 ),
2173 BanRule(
2174 'CanSyncFeatureStart',
2175 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2176 False,
2177 ),
2178 BanRule(
2179 'IsSyncFeatureEnabled',
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152180 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152181 False,
2182 ),
2183 BanRule(
2184 'IsSyncFeatureActive',
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152185 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152186 False,
2187 ),
2188)
2189
2190# Java functions related to signin::ConsentLevel::kSync which are deprecated.
2191_DEPRECATED_SYNC_CONSENT_JAVA_FUNCTIONS : Sequence[BanRule] = (
2192 BanRule(
2193 'hasSyncConsent',
2194 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2195 False,
2196 ),
2197 BanRule(
2198 'canSyncFeatureStart',
2199 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2200 False,
2201 ),
2202 BanRule(
2203 'isSyncFeatureEnabled',
2204 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2205 False,
2206 ),
2207 BanRule(
2208 'isSyncFeatureActive',
2209 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2210 False,
2211 ),
2212)
2213
Daniel Cheng92c15e32022-03-16 17:48:222214_BANNED_MOJOM_PATTERNS : Sequence[BanRule] = (
2215 BanRule(
2216 'handle<shared_buffer>',
2217 (
2218 'Please use one of the more specific shared memory types instead:',
2219 ' mojo_base.mojom.ReadOnlySharedMemoryRegion',
2220 ' mojo_base.mojom.WritableSharedMemoryRegion',
2221 ' mojo_base.mojom.UnsafeSharedMemoryRegion',
2222 ),
2223 True,
2224 ),
2225)
2226
mlamouria82272622014-09-16 18:45:042227_IPC_ENUM_TRAITS_DEPRECATED = (
2228 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:502229 'See http://www.chromium.org/Home/chromium-security/education/'
2230 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:042231
Stephen Martinis97a394142018-06-07 23:06:052232_LONG_PATH_ERROR = (
2233 'Some files included in this CL have file names that are too long (> 200'
2234 ' characters). If committed, these files will cause issues on Windows. See'
2235 ' https://crbug.com/612667 for more details.'
2236)
2237
Shenghua Zhangbfaa38b82017-11-16 21:58:022238_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Bruce Dawson40fece62022-09-16 19:58:312239 r".*/BuildHooksAndroidImpl\.java",
2240 r".*/LicenseContentProvider\.java",
2241 r".*/PlatformServiceBridgeImpl.java",
2242 r".*chrome/android/feed/dummy/.*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:022243]
[email protected]127f18ec2012-06-16 05:05:592244
Mohamed Heikald048240a2019-11-12 16:57:372245# List of image extensions that are used as resources in chromium.
2246_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
2247
Sean Kau46e29bc2017-08-28 16:31:162248# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:402249_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Bruce Dawson40fece62022-09-16 19:58:312250 r'test/data/',
2251 r'testing/buildbot/',
2252 r'^components/policy/resources/policy_templates\.json$',
2253 r'^third_party/protobuf/',
Camillo Bruni1411a352023-05-24 12:39:032254 r'^third_party/blink/perf_tests/speedometer.*/resources/todomvc/learn\.json',
Bruce Dawson40fece62022-09-16 19:58:312255 r'^third_party/blink/renderer/devtools/protocol\.json$',
2256 r'^third_party/blink/web_tests/external/wpt/',
2257 r'^tools/perf/',
2258 r'^tools/traceline/svgui/startup-release.json',
Daniel Cheng2d4c2d192022-07-01 01:38:312259 # vscode configuration files allow comments
Bruce Dawson40fece62022-09-16 19:58:312260 r'^tools/vscode/',
Sean Kau46e29bc2017-08-28 16:31:162261]
2262
Andrew Grieveb773bad2020-06-05 18:00:382263# These are not checked on the public chromium-presubmit trybot.
2264# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:042265# checkouts.
agrievef32bcc72016-04-04 14:57:402266_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:382267 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382268]
2269
2270
2271_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:042272 'android_webview/tools/run_cts.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:362273 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042274 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362275 'build/android/gyp/aar.pydeps',
2276 'build/android/gyp/aidl.pydeps',
2277 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:382278 'build/android/gyp/assert_static_initializers.pydeps',
Mohamed Heikal133e1f22023-04-18 20:04:372279 'build/android/gyp/binary_baseline_profile.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:022280 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:222281 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieveacac4242024-12-20 19:39:422282 'build/android/gyp/check_for_missing_direct_deps.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:112283 'build/android/gyp/compile_java.pydeps',
Peter Weneaa963f2023-01-20 19:40:302284 'build/android/gyp/compile_kt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362285 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362286 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362287 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:112288 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042289 'build/android/gyp/create_app_bundle_apks.pydeps',
2290 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362291 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:122292 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:092293 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:222294 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve2d972e5f2025-01-28 18:28:142295 'build/android/gyp/create_stub_manifest.pydeps',
Peter Wene6e017e2022-07-27 21:40:402296 'build/android/gyp/create_test_apk_wrapper_script.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002297 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362298 'build/android/gyp/dex.pydeps',
2299 'build/android/gyp/dist_aar.pydeps',
Andrew Grieve651ddb32025-01-23 03:27:342300 'build/android/gyp/errorprone.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362301 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:212302 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362303 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:362304 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362305 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:582306 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362307 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:142308 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:262309 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:472310 'build/android/gyp/java_google_api_keys.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042311 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362312 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362313 'build/android/gyp/merge_manifest.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:102314 'build/android/gyp/optimize_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362315 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:222316 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362317 'build/android/gyp/proguard.pydeps',
Mohamed Heikaldd52b452024-09-10 17:10:502318 'build/android/gyp/rename_java_classes.pydeps',
Andrew Grievee3a775ab2022-05-16 15:59:222319 'build/android/gyp/system_image_apks.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:102320 'build/android/gyp/trace_event_bytecode_rewriter.pydeps',
Andrew Grieve170b9782025-02-03 15:54:532321 'build/android/gyp/tracereferences.pydeps',
Peter Wen578730b2020-03-19 19:55:462322 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:302323 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:242324 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362325 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:462326 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:562327 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362328 'build/android/incremental_install/generate_android_manifest.pydeps',
2329 'build/android/incremental_install/write_installer_json.pydeps',
Stephanie Kim392913b452022-06-15 17:25:322330 'build/android/pylib/results/presentation/test_results_presentation.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042331 'build/android/resource_sizes.pydeps',
2332 'build/android/test_runner.pydeps',
2333 'build/android/test_wrapper/logdog_wrapper.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362334 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:322335 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:272336 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
2337 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:042338 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Mohannad Farrag19102742023-12-01 01:16:302339 'components/cronet/tools/check_combined_proguard_file.pydeps',
2340 'components/cronet/tools/generate_proguard_file.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002341 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382342 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002343 'content/public/android/generate_child_service.pydeps',
Hzj_jie77bdb802024-07-22 18:14:512344 'fuchsia_web/av_testing/av_sync_tests.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382345 'net/tools/testserver/testserver.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:182346 'testing/scripts/run_isolated_script_test.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:412347 'testing/merge_scripts/standard_isolated_script_merge.pydeps',
2348 'testing/merge_scripts/standard_gtest_merge.pydeps',
2349 'testing/merge_scripts/code_coverage/merge_results.pydeps',
2350 'testing/merge_scripts/code_coverage/merge_steps.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042351 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:422352 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
Yuki Shiino38eeaad12022-08-11 06:40:252353 'third_party/blink/renderer/bindings/scripts/check_generated_file_list.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:422354 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:132355 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Yuki Shiinoea477d32023-08-21 06:24:342356 'third_party/blink/renderer/bindings/scripts/generate_event_interface_names.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:502357 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:412358 'third_party/blink/tools/blinkpy/web_tests/merge_results.pydeps',
2359 'third_party/blink/tools/merge_web_test_results.pydeps',
John Budorickbc3571aa2019-04-25 02:20:062360 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:222361 'tools/binary_size/supersize.pydeps',
Ben Pastene028104a2022-08-10 19:17:452362 'tools/perf/process_perf_results.pydeps',
Peter Wence103e12024-10-09 19:23:512363 'tools/pgo/generate_profile.pydeps',
agrievef32bcc72016-04-04 14:57:402364]
2365
wnwenbdc444e2016-05-25 13:44:152366
agrievef32bcc72016-04-04 14:57:402367_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
2368
2369
Eric Boren6fd2b932018-01-25 15:05:082370# Bypass the AUTHORS check for these accounts.
2371_KNOWN_ROBOTS = set(
Shuai Xia0d99ebf2025-02-11 23:47:592372 ) | set('%[email protected]' % s for s in ('findit-for-me',
2373 'luci-bisection',
2374 'predator-for-me-staging',
2375 'predator-for-me')
Achuith Bhandarkar35905562018-07-25 19:28:452376 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:592377 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:522378 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:232379 'wpt-autoroller', 'chrome-weblayer-builder',
Georg Neise5817eb2025-02-06 03:47:312380 'skylab-test-cros-roller', 'infra-try-recipes-tester',
2381 'chrome-automated-expectation',
Stephanie Kimb49bdd242023-04-28 16:46:042382 'chromium-automated-expectation', 'chrome-branch-day',
2383 'chromium-autosharder')
Eric Boren835d71f2018-09-07 21:09:042384 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:272385 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:042386 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:162387 for s in ('chromium-internal-autoroll',)
Kyungjun Lee3b7c9352024-04-02 23:59:142388 ) | set('%[email protected]' % s
2389 for s in ('chrome-screen-ai-releaser',)
Yulan Lineb0cfba2021-04-09 18:43:162390 ) | set('%[email protected]' % s
Chong Gub277e342022-10-15 03:30:552391 for s in ('swarming-tasks',)
2392 ) | set('%[email protected]' % s
2393 for s in ('global-integration-try-builder',
Joey Scarr1103c5d2023-09-14 01:17:552394 'global-integration-ci-builder')
Suma Kasa3b9cf7a2023-09-21 22:05:542395 ) | set('%[email protected]' % s
2396 for s in ('chops-security-borg',
2397 'chops-security-cronjobs-cpesuggest'))
Eric Boren6fd2b932018-01-25 15:05:082398
Matt Stark6ef08872021-07-29 01:21:462399_INVALID_GRD_FILE_LINE = [
2400 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
2401]
Eric Boren6fd2b932018-01-25 15:05:082402
Daniel Bratell65b033262019-04-23 08:17:062403def _IsCPlusPlusFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502404 """Returns True if this file contains C++-like code (and not Python,
2405 Go, Java, MarkDown, ...)"""
Daniel Bratell65b033262019-04-23 08:17:062406
Sam Maiera6e76d72022-02-11 21:43:502407 ext = input_api.os_path.splitext(file_path)[1]
2408 # This list is compatible with CppChecker.IsCppFile but we should
2409 # consider adding ".c" to it. If we do that we can use this function
2410 # at more places in the code.
2411 return ext in (
2412 '.h',
2413 '.cc',
2414 '.cpp',
2415 '.m',
2416 '.mm',
2417 )
2418
Daniel Bratell65b033262019-04-23 08:17:062419
2420def _IsCPlusPlusHeaderFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502421 return input_api.os_path.splitext(file_path)[1] == ".h"
Daniel Bratell65b033262019-04-23 08:17:062422
2423
2424def _IsJavaFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502425 return input_api.os_path.splitext(file_path)[1] == ".java"
Daniel Bratell65b033262019-04-23 08:17:062426
2427
2428def _IsProtoFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502429 return input_api.os_path.splitext(file_path)[1] == ".proto"
Daniel Bratell65b033262019-04-23 08:17:062430
Mohamed Heikal5e5b7922020-10-29 18:57:592431
Erik Staabc734cd7a2021-11-23 03:11:522432def _IsXmlOrGrdFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502433 ext = input_api.os_path.splitext(file_path)[1]
2434 return ext in ('.grd', '.xml')
Erik Staabc734cd7a2021-11-23 03:11:522435
2436
Sven Zheng76a79ea2022-12-21 21:25:242437def _IsMojomFile(input_api, file_path):
2438 return input_api.os_path.splitext(file_path)[1] == ".mojom"
2439
2440
Mohamed Heikal5e5b7922020-10-29 18:57:592441def CheckNoUpstreamDepsOnClank(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502442 """Prevent additions of dependencies from the upstream repo on //clank."""
2443 # clank can depend on clank
2444 if input_api.change.RepositoryRoot().endswith('clank'):
2445 return []
2446 build_file_patterns = [
2447 r'(.+/)?BUILD\.gn',
2448 r'.+\.gni',
2449 ]
2450 excluded_files = [r'build[/\\]config[/\\]android[/\\]config\.gni']
2451 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
Mohamed Heikal5e5b7922020-10-29 18:57:592452
Sam Maiera6e76d72022-02-11 21:43:502453 error_message = 'Disallowed import on //clank in an upstream build file:'
Mohamed Heikal5e5b7922020-10-29 18:57:592454
Sam Maiera6e76d72022-02-11 21:43:502455 def FilterFile(affected_file):
2456 return input_api.FilterSourceFile(affected_file,
2457 files_to_check=build_file_patterns,
2458 files_to_skip=excluded_files)
Mohamed Heikal5e5b7922020-10-29 18:57:592459
Sam Maiera6e76d72022-02-11 21:43:502460 problems = []
2461 for f in input_api.AffectedSourceFiles(FilterFile):
2462 local_path = f.LocalPath()
2463 for line_number, line in f.ChangedContents():
2464 if (bad_pattern.search(line)):
2465 problems.append('%s:%d\n %s' %
2466 (local_path, line_number, line.strip()))
2467 if problems:
2468 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
2469 else:
2470 return []
Mohamed Heikal5e5b7922020-10-29 18:57:592471
2472
Saagar Sanghavifceeaae2020-08-12 16:40:362473def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502474 """Attempts to prevent use of functions intended only for testing in
2475 non-testing code. For now this is just a best-effort implementation
2476 that ignores header files and may have some false positives. A
2477 better implementation would probably need a proper C++ parser.
2478 """
2479 # We only scan .cc files and the like, as the declaration of
2480 # for-testing functions in header files are hard to distinguish from
2481 # calls to such functions without a proper C++ parser.
2482 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:192483
Sam Maiera6e76d72022-02-11 21:43:502484 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
2485 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' %
2486 base_function_pattern)
2487 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
2488 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
2489 exclusion_pattern = input_api.re.compile(
2490 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' %
2491 (base_function_pattern, base_function_pattern))
2492 # Avoid a false positive in this case, where the method name, the ::, and
2493 # the closing { are all on different lines due to line wrapping.
2494 # HelperClassForTesting::
2495 # HelperClassForTesting(
2496 # args)
2497 # : member(0) {}
2498 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:192499
Sam Maiera6e76d72022-02-11 21:43:502500 def FilterFile(affected_file):
2501 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2502 input_api.DEFAULT_FILES_TO_SKIP)
2503 return input_api.FilterSourceFile(
2504 affected_file,
2505 files_to_check=file_inclusion_pattern,
2506 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:192507
Sam Maiera6e76d72022-02-11 21:43:502508 problems = []
2509 for f in input_api.AffectedSourceFiles(FilterFile):
2510 local_path = f.LocalPath()
2511 in_method_defn = False
2512 for line_number, line in f.ChangedContents():
2513 if (inclusion_pattern.search(line)
2514 and not comment_pattern.search(line)
2515 and not exclusion_pattern.search(line)
2516 and not allowlist_pattern.search(line)
2517 and not in_method_defn):
2518 problems.append('%s:%d\n %s' %
2519 (local_path, line_number, line.strip()))
2520 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:192521
Sam Maiera6e76d72022-02-11 21:43:502522 if problems:
2523 return [
2524 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
2525 ]
2526 else:
2527 return []
[email protected]55459852011-08-10 15:17:192528
2529
Saagar Sanghavifceeaae2020-08-12 16:40:362530def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502531 """This is a simplified version of
2532 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
2533 """
2534 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
2535 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
2536 name_pattern = r'ForTest(s|ing)?'
2537 # Describes an occurrence of "ForTest*" inside a // comment.
2538 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
2539 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
2540 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
2541 # Catch calls.
2542 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
2543 # Ignore definitions. (Comments are ignored separately.)
2544 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
Andrew Grieve40f451d2023-07-06 19:46:512545 allowlist_re = input_api.re.compile(r'// IN-TEST$')
Vaclav Brozek7dbc28c2018-03-27 08:35:232546
Sam Maiera6e76d72022-02-11 21:43:502547 problems = []
2548 sources = lambda x: input_api.FilterSourceFile(
2549 x,
2550 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
2551 DEFAULT_FILES_TO_SKIP),
2552 files_to_check=[r'.*\.java$'])
2553 for f in input_api.AffectedFiles(include_deletes=False,
2554 file_filter=sources):
2555 local_path = f.LocalPath()
Vaclav Brozek7dbc28c2018-03-27 08:35:232556 is_inside_javadoc = False
Sam Maiera6e76d72022-02-11 21:43:502557 for line_number, line in f.ChangedContents():
2558 if is_inside_javadoc and javadoc_end_re.search(line):
2559 is_inside_javadoc = False
2560 if not is_inside_javadoc and javadoc_start_re.search(line):
2561 is_inside_javadoc = True
2562 if is_inside_javadoc:
2563 continue
2564 if (inclusion_re.search(line) and not comment_re.search(line)
2565 and not annotation_re.search(line)
Andrew Grieve40f451d2023-07-06 19:46:512566 and not allowlist_re.search(line)
Sam Maiera6e76d72022-02-11 21:43:502567 and not exclusion_re.search(line)):
2568 problems.append('%s:%d\n %s' %
2569 (local_path, line_number, line.strip()))
Vaclav Brozek7dbc28c2018-03-27 08:35:232570
Sam Maiera6e76d72022-02-11 21:43:502571 if problems:
2572 return [
2573 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
2574 ]
2575 else:
2576 return []
Vaclav Brozek7dbc28c2018-03-27 08:35:232577
2578
Saagar Sanghavifceeaae2020-08-12 16:40:362579def CheckNoIOStreamInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502580 """Checks to make sure no .h files include <iostream>."""
2581 files = []
2582 pattern = input_api.re.compile(r'^#include\s*<iostream>',
2583 input_api.re.MULTILINE)
2584 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2585 if not f.LocalPath().endswith('.h'):
2586 continue
2587 contents = input_api.ReadFile(f)
2588 if pattern.search(contents):
2589 files.append(f)
[email protected]10689ca2011-09-02 02:31:542590
Sam Maiera6e76d72022-02-11 21:43:502591 if len(files):
2592 return [
2593 output_api.PresubmitError(
2594 'Do not #include <iostream> in header files, since it inserts static '
2595 'initialization into every file including the header. Instead, '
2596 '#include <ostream>. See http://crbug.com/94794', files)
2597 ]
2598 return []
2599
[email protected]10689ca2011-09-02 02:31:542600
Aleksey Khoroshilov9b28c032022-06-03 16:35:322601def CheckNoStrCatRedefines(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502602 """Checks no windows headers with StrCat redefined are included directly."""
2603 files = []
Aleksey Khoroshilov9b28c032022-06-03 16:35:322604 files_to_check = (r'.+%s' % _HEADER_EXTENSIONS,
2605 r'.+%s' % _IMPLEMENTATION_EXTENSIONS)
2606 files_to_skip = (input_api.DEFAULT_FILES_TO_SKIP +
2607 _NON_BASE_DEPENDENT_PATHS)
2608 sources_filter = lambda f: input_api.FilterSourceFile(
2609 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
2610
Sam Maiera6e76d72022-02-11 21:43:502611 pattern_deny = input_api.re.compile(
2612 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
2613 input_api.re.MULTILINE)
2614 pattern_allow = input_api.re.compile(
2615 r'^#include\s"base/win/windows_defines.inc"', input_api.re.MULTILINE)
Aleksey Khoroshilov9b28c032022-06-03 16:35:322616 for f in input_api.AffectedSourceFiles(sources_filter):
Sam Maiera6e76d72022-02-11 21:43:502617 contents = input_api.ReadFile(f)
2618 if pattern_deny.search(
2619 contents) and not pattern_allow.search(contents):
2620 files.append(f.LocalPath())
Danil Chapovalov3518f362018-08-11 16:13:432621
Sam Maiera6e76d72022-02-11 21:43:502622 if len(files):
2623 return [
2624 output_api.PresubmitError(
2625 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
2626 'directly since they pollute code with StrCat macro. Instead, '
2627 'include matching header from base/win. See http://crbug.com/856536',
2628 files)
2629 ]
2630 return []
Danil Chapovalov3518f362018-08-11 16:13:432631
[email protected]10689ca2011-09-02 02:31:542632
Andrew Williamsc9f69b482023-07-10 16:07:362633def _CheckNoUNIT_TESTInSourceFiles(input_api, f):
2634 problems = []
2635
2636 unit_test_macro = input_api.re.compile(
Riley Wong49be8a882025-02-27 00:38:232637 r'^\s*#.*(?:ifn?def\s+UNIT_TEST|defined\s*\(?\s*UNIT_TEST\s*\)?)(?:$|\s+)')
Andrew Williamsc9f69b482023-07-10 16:07:362638 for line_num, line in f.ChangedContents():
2639 if unit_test_macro.match(line):
2640 problems.append(' %s:%d' % (f.LocalPath(), line_num))
2641
2642 return problems
2643
2644
Saagar Sanghavifceeaae2020-08-12 16:40:362645def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502646 """Checks to make sure no source files use UNIT_TEST."""
2647 problems = []
2648 for f in input_api.AffectedFiles():
2649 if (not f.LocalPath().endswith(('.cc', '.mm'))):
2650 continue
Andrew Williamsc9f69b482023-07-10 16:07:362651 problems.extend(
2652 _CheckNoUNIT_TESTInSourceFiles(input_api, f))
[email protected]72df4e782012-06-21 16:28:182653
Sam Maiera6e76d72022-02-11 21:43:502654 if not problems:
2655 return []
2656 return [
2657 output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
2658 '\n'.join(problems))
2659 ]
2660
[email protected]72df4e782012-06-21 16:28:182661
Saagar Sanghavifceeaae2020-08-12 16:40:362662def CheckNoDISABLETypoInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502663 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
Dominic Battre033531052018-09-24 15:45:342664
Sam Maiera6e76d72022-02-11 21:43:502665 This test warns if somebody tries to disable a test with the DISABLE_ prefix
2666 instead of DISABLED_. To filter false positives, reports are only generated
2667 if a corresponding MAYBE_ line exists.
2668 """
2669 problems = []
Dominic Battre033531052018-09-24 15:45:342670
Sam Maiera6e76d72022-02-11 21:43:502671 # The following two patterns are looked for in tandem - is a test labeled
2672 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
2673 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
2674 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
Dominic Battre033531052018-09-24 15:45:342675
Sam Maiera6e76d72022-02-11 21:43:502676 # This is for the case that a test is disabled on all platforms.
2677 full_disable_pattern = input_api.re.compile(
2678 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
2679 input_api.re.MULTILINE)
Dominic Battre033531052018-09-24 15:45:342680
Arthur Sonzognic66e9c82024-04-23 07:53:042681 for f in input_api.AffectedFiles(include_deletes=False):
Sam Maiera6e76d72022-02-11 21:43:502682 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2683 continue
Dominic Battre033531052018-09-24 15:45:342684
Arthur Sonzognic66e9c82024-04-23 07:53:042685 # Search for MAYBE_, DISABLE_ pairs.
Sam Maiera6e76d72022-02-11 21:43:502686 disable_lines = {} # Maps of test name to line number.
2687 maybe_lines = {}
2688 for line_num, line in f.ChangedContents():
2689 disable_match = disable_pattern.search(line)
2690 if disable_match:
2691 disable_lines[disable_match.group(1)] = line_num
2692 maybe_match = maybe_pattern.search(line)
2693 if maybe_match:
2694 maybe_lines[maybe_match.group(1)] = line_num
Dominic Battre033531052018-09-24 15:45:342695
Sam Maiera6e76d72022-02-11 21:43:502696 # Search for DISABLE_ occurrences within a TEST() macro.
2697 disable_tests = set(disable_lines.keys())
2698 maybe_tests = set(maybe_lines.keys())
2699 for test in disable_tests.intersection(maybe_tests):
2700 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
Dominic Battre033531052018-09-24 15:45:342701
Sam Maiera6e76d72022-02-11 21:43:502702 contents = input_api.ReadFile(f)
2703 full_disable_match = full_disable_pattern.search(contents)
2704 if full_disable_match:
2705 problems.append(' %s' % f.LocalPath())
Dominic Battre033531052018-09-24 15:45:342706
Sam Maiera6e76d72022-02-11 21:43:502707 if not problems:
2708 return []
2709 return [
2710 output_api.PresubmitPromptWarning(
2711 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
2712 '\n'.join(problems))
2713 ]
2714
Dominic Battre033531052018-09-24 15:45:342715
Nina Satragnof7660532021-09-20 18:03:352716def CheckForgettingMAYBEInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502717 """Checks to make sure tests disabled conditionally are not missing a
2718 corresponding MAYBE_ prefix.
2719 """
2720 # Expect at least a lowercase character in the test name. This helps rule out
2721 # false positives with macros wrapping the actual tests name.
2722 define_maybe_pattern = input_api.re.compile(
2723 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
Bruce Dawsonffc55292022-04-20 04:18:192724 # The test_maybe_pattern needs to handle all of these forms. The standard:
2725 # IN_PROC_TEST_F(SyncTest, MAYBE_Start) {
2726 # With a wrapper macro around the test name:
2727 # IN_PROC_TEST_F(SyncTest, E2E_ENABLED(MAYBE_Start)) {
2728 # And the odd-ball NACL_BROWSER_TEST_f format:
2729 # NACL_BROWSER_TEST_F(NaClBrowserTest, SimpleLoad, {
2730 # The optional E2E_ENABLED-style is handled with (\w*\()?
2731 # The NACL_BROWSER_TEST_F pattern is handled by allowing a trailing comma or
2732 # trailing ')'.
2733 test_maybe_pattern = (
2734 r'^\s*\w*TEST[^(]*\(\s*\w+,\s*(\w*\()?MAYBE_{test_name}[\),]')
Sam Maiera6e76d72022-02-11 21:43:502735 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
2736 warnings = []
Nina Satragnof7660532021-09-20 18:03:352737
Sam Maiera6e76d72022-02-11 21:43:502738 # Read the entire files. We can't just read the affected lines, forgetting to
2739 # add MAYBE_ on a change would not show up otherwise.
Arthur Sonzognic66e9c82024-04-23 07:53:042740 for f in input_api.AffectedFiles(include_deletes=False):
Sam Maiera6e76d72022-02-11 21:43:502741 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2742 continue
2743 contents = input_api.ReadFile(f)
2744 lines = contents.splitlines(True)
2745 current_position = 0
2746 warning_test_names = set()
2747 for line_num, line in enumerate(lines, start=1):
2748 current_position += len(line)
2749 maybe_match = define_maybe_pattern.search(line)
2750 if maybe_match:
2751 test_name = maybe_match.group('test_name')
2752 # Do not warn twice for the same test.
2753 if (test_name in warning_test_names):
2754 continue
2755 warning_test_names.add(test_name)
Nina Satragnof7660532021-09-20 18:03:352756
Sam Maiera6e76d72022-02-11 21:43:502757 # Attempt to find the corresponding MAYBE_ test or suite, starting from
2758 # the current position.
2759 test_match = input_api.re.compile(
2760 test_maybe_pattern.format(test_name=test_name),
2761 input_api.re.MULTILINE).search(contents, current_position)
2762 suite_match = input_api.re.compile(
2763 suite_maybe_pattern.format(test_name=test_name),
2764 input_api.re.MULTILINE).search(contents, current_position)
2765 if not test_match and not suite_match:
2766 warnings.append(
2767 output_api.PresubmitPromptWarning(
2768 '%s:%d found MAYBE_ defined without corresponding test %s'
2769 % (f.LocalPath(), line_num, test_name)))
2770 return warnings
2771
[email protected]72df4e782012-06-21 16:28:182772
Saagar Sanghavifceeaae2020-08-12 16:40:362773def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502774 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
2775 errors = []
Kalvin Lee4a3b79de2022-05-26 16:00:162776 pattern = input_api.re.compile(r'\bDCHECK_IS_ON\b(?!\(\))',
Sam Maiera6e76d72022-02-11 21:43:502777 input_api.re.MULTILINE)
2778 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2779 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
2780 continue
2781 for lnum, line in f.ChangedContents():
2782 if input_api.re.search(pattern, line):
2783 errors.append(
2784 output_api.PresubmitError((
2785 '%s:%d: Use of DCHECK_IS_ON() must be written as "#if '
2786 + 'DCHECK_IS_ON()", not forgetting the parentheses.') %
2787 (f.LocalPath(), lnum)))
2788 return errors
danakj61c1aa22015-10-26 19:55:522789
2790
Weilun Shia487fad2020-10-28 00:10:342791# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
2792# more reliable way. See
2793# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:192794
wnwenbdc444e2016-05-25 13:44:152795
Saagar Sanghavifceeaae2020-08-12 16:40:362796def CheckFlakyTestUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502797 """Check that FlakyTest annotation is our own instead of the android one"""
2798 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
2799 files = []
2800 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2801 if f.LocalPath().endswith('Test.java'):
2802 if pattern.search(input_api.ReadFile(f)):
2803 files.append(f)
2804 if len(files):
2805 return [
2806 output_api.PresubmitError(
2807 'Use org.chromium.base.test.util.FlakyTest instead of '
2808 'android.test.FlakyTest', files)
2809 ]
2810 return []
mcasasb7440c282015-02-04 14:52:192811
wnwenbdc444e2016-05-25 13:44:152812
Saagar Sanghavifceeaae2020-08-12 16:40:362813def CheckNoDEPSGIT(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502814 """Make sure .DEPS.git is never modified manually."""
2815 if any(f.LocalPath().endswith('.DEPS.git')
2816 for f in input_api.AffectedFiles()):
2817 return [
2818 output_api.PresubmitError(
2819 'Never commit changes to .DEPS.git. This file is maintained by an\n'
2820 'automated system based on what\'s in DEPS and your changes will be\n'
2821 'overwritten.\n'
2822 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
2823 'get-the-code#Rolling_DEPS\n'
2824 'for more information')
2825 ]
2826 return []
[email protected]2a8ac9c2011-10-19 17:20:442827
2828
Sven Zheng76a79ea2022-12-21 21:25:242829def CheckCrosApiNeedBrowserTest(input_api, output_api):
2830 """Check new crosapi should add browser test."""
2831 has_new_crosapi = False
2832 has_browser_test = False
2833 for f in input_api.AffectedFiles():
Anton Bershanskyi4253349482025-02-11 21:01:272834 path = f.UnixLocalPath()
Sven Zheng76a79ea2022-12-21 21:25:242835 if (path.startswith('chromeos/crosapi/mojom') and
2836 _IsMojomFile(input_api, path) and f.Action() == 'A'):
2837 has_new_crosapi = True
2838 if path.endswith('browsertest.cc') or path.endswith('browser_test.cc'):
2839 has_browser_test = True
2840 if has_new_crosapi and not has_browser_test:
2841 return [
2842 output_api.PresubmitPromptWarning(
2843 'You are adding a new crosapi, but there is no file ends with '
2844 'browsertest.cc file being added or modified. It is important '
2845 'to add crosapi browser test coverage to avoid version '
2846 ' skew issues.\n'
2847 'Check //docs/lacros/test_instructions.md for more information.'
2848 )
2849 ]
2850 return []
2851
2852
Saagar Sanghavifceeaae2020-08-12 16:40:362853def CheckValidHostsInDEPSOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502854 """Checks that DEPS file deps are from allowed_hosts."""
2855 # Run only if DEPS file has been modified to annoy fewer bystanders.
2856 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
2857 return []
2858 # Outsource work to gclient verify
2859 try:
2860 gclient_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
2861 'third_party', 'depot_tools',
2862 'gclient.py')
2863 input_api.subprocess.check_output(
Bruce Dawson8a43cf72022-05-13 17:10:322864 [input_api.python3_executable, gclient_path, 'verify'],
Sam Maiera6e76d72022-02-11 21:43:502865 stderr=input_api.subprocess.STDOUT)
2866 return []
2867 except input_api.subprocess.CalledProcessError as error:
2868 return [
2869 output_api.PresubmitError(
2870 'DEPS file must have only git dependencies.',
2871 long_text=error.output)
2872 ]
tandriief664692014-09-23 14:51:472873
2874
Mario Sanchez Prada2472cab2019-09-18 10:58:312875def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152876 ban_rule):
Allen Bauer84778682022-09-22 16:28:562877 """Helper method for checking for banned constructs.
Mario Sanchez Prada2472cab2019-09-18 10:58:312878
Sam Maiera6e76d72022-02-11 21:43:502879 Returns an string composed of the name of the file, the line number where the
2880 match has been found and the additional text passed as |message| in case the
2881 target type name matches the text inside the line passed as parameter.
2882 """
2883 result = []
Peng Huang9c5949a02020-06-11 19:20:542884
Daniel Chenga44a1bcd2022-03-15 20:00:152885 # Ignore comments about banned types.
2886 if input_api.re.search(r"^ *//", line):
Sam Maiera6e76d72022-02-11 21:43:502887 return result
Daniel Chenga44a1bcd2022-03-15 20:00:152888 # A // nocheck comment will bypass this error.
2889 if line.endswith(" nocheck"):
Sam Maiera6e76d72022-02-11 21:43:502890 return result
2891
2892 matched = False
Daniel Chenga44a1bcd2022-03-15 20:00:152893 if ban_rule.pattern[0:1] == '/':
2894 regex = ban_rule.pattern[1:]
Sam Maiera6e76d72022-02-11 21:43:502895 if input_api.re.search(regex, line):
2896 matched = True
Daniel Chenga44a1bcd2022-03-15 20:00:152897 elif ban_rule.pattern in line:
Sam Maiera6e76d72022-02-11 21:43:502898 matched = True
2899
2900 if matched:
2901 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
Daniel Chenga44a1bcd2022-03-15 20:00:152902 for line in ban_rule.explanation:
2903 result.append(' %s' % line)
Sam Maiera6e76d72022-02-11 21:43:502904
danakjd18e8892020-12-17 17:42:012905 return result
Mario Sanchez Prada2472cab2019-09-18 10:58:312906
2907
Saagar Sanghavifceeaae2020-08-12 16:40:362908def CheckNoBannedFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502909 """Make sure that banned functions are not used."""
2910 warnings = []
2911 errors = []
[email protected]127f18ec2012-06-16 05:05:592912
Sam Maiera6e76d72022-02-11 21:43:502913 def IsExcludedFile(affected_file, excluded_paths):
Daniel Chenga44a1bcd2022-03-15 20:00:152914 if not excluded_paths:
2915 return False
2916
Anton Bershanskyi4253349482025-02-11 21:01:272917 local_path = affected_file.UnixLocalPath()
Sam Maiera6e76d72022-02-11 21:43:502918 for item in excluded_paths:
2919 if input_api.re.match(item, local_path):
2920 return True
2921 return False
wnwenbdc444e2016-05-25 13:44:152922
Sam Maiera6e76d72022-02-11 21:43:502923 def IsIosObjcFile(affected_file):
2924 local_path = affected_file.LocalPath()
2925 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m',
2926 '.h'):
2927 return False
2928 basename = input_api.os_path.basename(local_path)
2929 if 'ios' in basename.split('_'):
2930 return True
2931 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
2932 if sep and 'ios' in local_path.split(sep):
2933 return True
2934 return False
Sylvain Defresnea8b73d252018-02-28 15:45:542935
Daniel Chenga44a1bcd2022-03-15 20:00:152936 def CheckForMatch(affected_file, line_num: int, line: str,
2937 ban_rule: BanRule):
2938 if IsExcludedFile(affected_file, ban_rule.excluded_paths):
2939 return
2940
Sam Maiera6e76d72022-02-11 21:43:502941 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152942 ban_rule)
Sam Maiera6e76d72022-02-11 21:43:502943 if problems:
Daniel Chenga44a1bcd2022-03-15 20:00:152944 if ban_rule.treat_as_error is not None and ban_rule.treat_as_error:
Sam Maiera6e76d72022-02-11 21:43:502945 errors.extend(problems)
2946 else:
2947 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:152948
Sam Maiera6e76d72022-02-11 21:43:502949 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2950 for f in input_api.AffectedFiles(file_filter=file_filter):
2951 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152952 for ban_rule in _BANNED_JAVA_FUNCTIONS:
2953 CheckForMatch(f, line_num, line, ban_rule)
Eric Stevensona9a980972017-09-23 00:04:412954
Clement Yan9b330cb2022-11-17 05:25:292955 file_filter = lambda f: f.LocalPath().endswith(('.js', '.ts'))
2956 for f in input_api.AffectedFiles(file_filter=file_filter):
2957 for line_num, line in f.ChangedContents():
2958 for ban_rule in _BANNED_JAVASCRIPT_FUNCTIONS:
2959 CheckForMatch(f, line_num, line, ban_rule)
2960
Sam Maiera6e76d72022-02-11 21:43:502961 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
2962 for f in input_api.AffectedFiles(file_filter=file_filter):
2963 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152964 for ban_rule in _BANNED_OBJC_FUNCTIONS:
2965 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:592966
Sam Maiera6e76d72022-02-11 21:43:502967 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
2968 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152969 for ban_rule in _BANNED_IOS_OBJC_FUNCTIONS:
2970 CheckForMatch(f, line_num, line, ban_rule)
Sylvain Defresnea8b73d252018-02-28 15:45:542971
Sam Maiera6e76d72022-02-11 21:43:502972 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
2973 for f in input_api.AffectedFiles(file_filter=egtest_filter):
2974 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152975 for ban_rule in _BANNED_IOS_EGTEST_FUNCTIONS:
2976 CheckForMatch(f, line_num, line, ban_rule)
Peter K. Lee6c03ccff2019-07-15 14:40:052977
Sam Maiera6e76d72022-02-11 21:43:502978 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
2979 for f in input_api.AffectedFiles(file_filter=file_filter):
2980 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152981 for ban_rule in _BANNED_CPP_FUNCTIONS:
2982 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:592983
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152984 # As of 05/2024, iOS fully migrated ConsentLevel::kSync to kSignin, and
2985 # Android is in the process of preventing new users from entering kSync.
2986 # So the warning is restricted to those platforms.
Riley Wong49be8a882025-02-27 00:38:232987 ios_pattern = input_api.re.compile(r'(^|[\W_])ios[\W_]')
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152988 file_filter = lambda f: (f.LocalPath().endswith(('.cc', '.mm', '.h')) and
2989 ('android' in f.LocalPath() or
2990 # Simply checking for an 'ios' substring would
2991 # catch unrelated cases, use a regex.
2992 ios_pattern.search(f.LocalPath())))
2993 for f in input_api.AffectedFiles(file_filter=file_filter):
2994 for line_num, line in f.ChangedContents():
2995 for ban_rule in _DEPRECATED_SYNC_CONSENT_CPP_FUNCTIONS:
2996 CheckForMatch(f, line_num, line, ban_rule)
2997
2998 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2999 for f in input_api.AffectedFiles(file_filter=file_filter):
3000 for line_num, line in f.ChangedContents():
3001 for ban_rule in _DEPRECATED_SYNC_CONSENT_JAVA_FUNCTIONS:
3002 CheckForMatch(f, line_num, line, ban_rule)
3003
Daniel Cheng92c15e32022-03-16 17:48:223004 file_filter = lambda f: f.LocalPath().endswith(('.mojom'))
3005 for f in input_api.AffectedFiles(file_filter=file_filter):
3006 for line_num, line in f.ChangedContents():
3007 for ban_rule in _BANNED_MOJOM_PATTERNS:
3008 CheckForMatch(f, line_num, line, ban_rule)
3009
3010
Sam Maiera6e76d72022-02-11 21:43:503011 result = []
3012 if (warnings):
3013 result.append(
3014 output_api.PresubmitPromptWarning('Banned functions were used.\n' +
3015 '\n'.join(warnings)))
3016 if (errors):
3017 result.append(
3018 output_api.PresubmitError('Banned functions were used.\n' +
3019 '\n'.join(errors)))
3020 return result
[email protected]127f18ec2012-06-16 05:05:593021
Michael Thiessen44457642020-02-06 00:24:153022def _CheckAndroidNoBannedImports(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503023 """Make sure that banned java imports are not used."""
3024 errors = []
Michael Thiessen44457642020-02-06 00:24:153025
Sam Maiera6e76d72022-02-11 21:43:503026 file_filter = lambda f: f.LocalPath().endswith(('.java'))
3027 for f in input_api.AffectedFiles(file_filter=file_filter):
3028 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:153029 for ban_rule in _BANNED_JAVA_IMPORTS:
3030 # Consider merging this into the above function. There is no
3031 # real difference anymore other than helping with a little
3032 # bit of boilerplate text. Doing so means things like
3033 # `treat_as_error` will also be uniformly handled.
Sam Maiera6e76d72022-02-11 21:43:503034 problems = _GetMessageForMatchingType(input_api, f, line_num,
Daniel Chenga44a1bcd2022-03-15 20:00:153035 line, ban_rule)
Sam Maiera6e76d72022-02-11 21:43:503036 if problems:
3037 errors.extend(problems)
3038 result = []
3039 if (errors):
3040 result.append(
3041 output_api.PresubmitError('Banned imports were used.\n' +
3042 '\n'.join(errors)))
3043 return result
Michael Thiessen44457642020-02-06 00:24:153044
3045
Saagar Sanghavifceeaae2020-08-12 16:40:363046def CheckNoPragmaOnce(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503047 """Make sure that banned functions are not used."""
3048 files = []
3049 pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
3050 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
3051 if not f.LocalPath().endswith('.h'):
3052 continue
Bruce Dawson4c4c2922022-05-02 18:07:333053 if f.LocalPath().endswith('com_imported_mstscax.h'):
3054 continue
Sam Maiera6e76d72022-02-11 21:43:503055 contents = input_api.ReadFile(f)
3056 if pattern.search(contents):
3057 files.append(f)
[email protected]6c063c62012-07-11 19:11:063058
Sam Maiera6e76d72022-02-11 21:43:503059 if files:
3060 return [
3061 output_api.PresubmitError(
3062 'Do not use #pragma once in header files.\n'
3063 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
3064 files)
3065 ]
3066 return []
[email protected]6c063c62012-07-11 19:11:063067
[email protected]127f18ec2012-06-16 05:05:593068
Saagar Sanghavifceeaae2020-08-12 16:40:363069def CheckNoTrinaryTrueFalse(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503070 """Checks to make sure we don't introduce use of foo ? true : false."""
3071 problems = []
3072 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
3073 for f in input_api.AffectedFiles():
3074 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
3075 continue
[email protected]e7479052012-09-19 00:26:123076
Sam Maiera6e76d72022-02-11 21:43:503077 for line_num, line in f.ChangedContents():
3078 if pattern.match(line):
3079 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]e7479052012-09-19 00:26:123080
Sam Maiera6e76d72022-02-11 21:43:503081 if not problems:
3082 return []
3083 return [
3084 output_api.PresubmitPromptWarning(
3085 'Please consider avoiding the "? true : false" pattern if possible.\n'
3086 + '\n'.join(problems))
3087 ]
[email protected]e7479052012-09-19 00:26:123088
3089
Saagar Sanghavifceeaae2020-08-12 16:40:363090def CheckUnwantedDependencies(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503091 """Runs checkdeps on #include and import statements added in this
3092 change. Breaking - rules is an error, breaking ! rules is a
3093 warning.
3094 """
3095 # Return early if no relevant file types were modified.
3096 for f in input_api.AffectedFiles():
3097 path = f.LocalPath()
3098 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path)
3099 or _IsJavaFile(input_api, path)):
3100 break
[email protected]55f9f382012-07-31 11:02:183101 else:
Sam Maiera6e76d72022-02-11 21:43:503102 return []
rhalavati08acd232017-04-03 07:23:283103
Sam Maiera6e76d72022-02-11 21:43:503104 import sys
3105 # We need to wait until we have an input_api object and use this
3106 # roundabout construct to import checkdeps because this file is
3107 # eval-ed and thus doesn't have __file__.
3108 original_sys_path = sys.path
3109 try:
3110 sys.path = sys.path + [
3111 input_api.os_path.join(input_api.PresubmitLocalPath(),
3112 'buildtools', 'checkdeps')
3113 ]
3114 import checkdeps
3115 from rules import Rule
3116 finally:
3117 # Restore sys.path to what it was before.
3118 sys.path = original_sys_path
[email protected]55f9f382012-07-31 11:02:183119
Sam Maiera6e76d72022-02-11 21:43:503120 added_includes = []
3121 added_imports = []
3122 added_java_imports = []
3123 for f in input_api.AffectedFiles():
3124 if _IsCPlusPlusFile(input_api, f.LocalPath()):
3125 changed_lines = [line for _, line in f.ChangedContents()]
3126 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
3127 elif _IsProtoFile(input_api, f.LocalPath()):
3128 changed_lines = [line for _, line in f.ChangedContents()]
3129 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
3130 elif _IsJavaFile(input_api, f.LocalPath()):
3131 changed_lines = [line for _, line in f.ChangedContents()]
3132 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:243133
Sam Maiera6e76d72022-02-11 21:43:503134 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
3135
3136 error_descriptions = []
3137 warning_descriptions = []
3138 error_subjects = set()
3139 warning_subjects = set()
3140
3141 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
3142 added_includes):
3143 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3144 description_with_path = '%s\n %s' % (path, rule_description)
3145 if rule_type == Rule.DISALLOW:
3146 error_descriptions.append(description_with_path)
3147 error_subjects.add("#includes")
3148 else:
3149 warning_descriptions.append(description_with_path)
3150 warning_subjects.add("#includes")
3151
3152 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
3153 added_imports):
3154 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3155 description_with_path = '%s\n %s' % (path, rule_description)
3156 if rule_type == Rule.DISALLOW:
3157 error_descriptions.append(description_with_path)
3158 error_subjects.add("imports")
3159 else:
3160 warning_descriptions.append(description_with_path)
3161 warning_subjects.add("imports")
3162
3163 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
3164 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
3165 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3166 description_with_path = '%s\n %s' % (path, rule_description)
3167 if rule_type == Rule.DISALLOW:
3168 error_descriptions.append(description_with_path)
3169 error_subjects.add("imports")
3170 else:
3171 warning_descriptions.append(description_with_path)
3172 warning_subjects.add("imports")
3173
3174 results = []
3175 if error_descriptions:
3176 results.append(
3177 output_api.PresubmitError(
3178 'You added one or more %s that violate checkdeps rules.' %
3179 " and ".join(error_subjects), error_descriptions))
3180 if warning_descriptions:
3181 results.append(
3182 output_api.PresubmitPromptOrNotify(
3183 'You added one or more %s of files that are temporarily\n'
3184 'allowed but being removed. Can you avoid introducing the\n'
3185 '%s? See relevant DEPS file(s) for details and contacts.' %
3186 (" and ".join(warning_subjects), "/".join(warning_subjects)),
3187 warning_descriptions))
3188 return results
[email protected]55f9f382012-07-31 11:02:183189
3190
Saagar Sanghavifceeaae2020-08-12 16:40:363191def CheckFilePermissions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503192 """Check that all files have their permissions properly set."""
3193 if input_api.platform == 'win32':
3194 return []
3195 checkperms_tool = input_api.os_path.join(input_api.PresubmitLocalPath(),
3196 'tools', 'checkperms',
3197 'checkperms.py')
3198 args = [
Bruce Dawson8a43cf72022-05-13 17:10:323199 input_api.python3_executable, checkperms_tool, '--root',
Sam Maiera6e76d72022-02-11 21:43:503200 input_api.change.RepositoryRoot()
3201 ]
3202 with input_api.CreateTemporaryFile() as file_list:
3203 for f in input_api.AffectedFiles():
3204 # checkperms.py file/directory arguments must be relative to the
3205 # repository.
3206 file_list.write((f.LocalPath() + '\n').encode('utf8'))
3207 file_list.close()
3208 args += ['--file-list', file_list.name]
3209 try:
3210 input_api.subprocess.check_output(args)
3211 return []
3212 except input_api.subprocess.CalledProcessError as error:
3213 return [
3214 output_api.PresubmitError('checkperms.py failed:',
3215 long_text=error.output.decode(
3216 'utf-8', 'ignore'))
3217 ]
[email protected]fbcafe5a2012-08-08 15:31:223218
3219
Saagar Sanghavifceeaae2020-08-12 16:40:363220def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503221 """Makes sure we don't include ui/aura/window_property.h
3222 in header files.
3223 """
3224 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
3225 errors = []
3226 for f in input_api.AffectedFiles():
3227 if not f.LocalPath().endswith('.h'):
3228 continue
3229 for line_num, line in f.ChangedContents():
3230 if pattern.match(line):
3231 errors.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]c8278b32012-10-30 20:35:493232
Sam Maiera6e76d72022-02-11 21:43:503233 results = []
3234 if errors:
3235 results.append(
3236 output_api.PresubmitError(
3237 'Header files should not include ui/aura/window_property.h',
3238 errors))
3239 return results
[email protected]c8278b32012-10-30 20:35:493240
3241
Omer Katzcc77ea92021-04-26 10:23:283242def CheckNoInternalHeapIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503243 """Makes sure we don't include any headers from
3244 third_party/blink/renderer/platform/heap/impl or
3245 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
3246 third_party/blink/renderer/platform/heap
3247 """
3248 impl_pattern = input_api.re.compile(
3249 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
3250 v8_wrapper_pattern = input_api.re.compile(
3251 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"'
3252 )
3253 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:313254 r"^third_party/blink/renderer/platform/heap/.*",
Anton Bershanskyi4253349482025-02-11 21:01:273255 f.UnixLocalPath())
Sam Maiera6e76d72022-02-11 21:43:503256 errors = []
Omer Katzcc77ea92021-04-26 10:23:283257
Sam Maiera6e76d72022-02-11 21:43:503258 for f in input_api.AffectedFiles(file_filter=file_filter):
3259 for line_num, line in f.ChangedContents():
3260 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
3261 errors.append(' %s:%d' % (f.LocalPath(), line_num))
Omer Katzcc77ea92021-04-26 10:23:283262
Sam Maiera6e76d72022-02-11 21:43:503263 results = []
3264 if errors:
3265 results.append(
3266 output_api.PresubmitError(
3267 'Do not include files from third_party/blink/renderer/platform/heap/impl'
3268 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
3269 'relevant counterparts from third_party/blink/renderer/platform/heap',
3270 errors))
3271 return results
Omer Katzcc77ea92021-04-26 10:23:283272
3273
[email protected]70ca77752012-11-20 03:45:033274def _CheckForVersionControlConflictsInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:503275 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
3276 errors = []
3277 for line_num, line in f.ChangedContents():
3278 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
3279 # First-level headers in markdown look a lot like version control
3280 # conflict markers. http://daringfireball.net/projects/markdown/basics
3281 continue
3282 if pattern.match(line):
3283 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
3284 return errors
[email protected]70ca77752012-11-20 03:45:033285
3286
Saagar Sanghavifceeaae2020-08-12 16:40:363287def CheckForVersionControlConflicts(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503288 """Usually this is not intentional and will cause a compile failure."""
3289 errors = []
3290 for f in input_api.AffectedFiles():
3291 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
[email protected]70ca77752012-11-20 03:45:033292
Sam Maiera6e76d72022-02-11 21:43:503293 results = []
3294 if errors:
3295 results.append(
3296 output_api.PresubmitError(
3297 'Version control conflict markers found, please resolve.',
3298 errors))
3299 return results
[email protected]70ca77752012-11-20 03:45:033300
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203301
Saagar Sanghavifceeaae2020-08-12 16:40:363302def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
Dirk Prankee4df27972025-02-26 18:39:353303 pattern = input_api.re.compile(r'support\.google\.com\/chrome.*/answer')
Sam Maiera6e76d72022-02-11 21:43:503304 errors = []
3305 for f in input_api.AffectedFiles():
3306 for line_num, line in f.ChangedContents():
3307 if pattern.search(line):
3308 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
estadee17314a02017-01-12 16:22:163309
Sam Maiera6e76d72022-02-11 21:43:503310 results = []
3311 if errors:
3312 results.append(
3313 output_api.PresubmitPromptWarning(
3314 'Found Google support URL addressed by answer number. Please replace '
3315 'with a p= identifier instead. See crbug.com/679462\n',
3316 errors))
3317 return results
estadee17314a02017-01-12 16:22:163318
[email protected]70ca77752012-11-20 03:45:033319
Saagar Sanghavifceeaae2020-08-12 16:40:363320def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503321 def FilterFile(affected_file):
3322 """Filter function for use with input_api.AffectedSourceFiles,
3323 below. This filters out everything except non-test files from
3324 top-level directories that generally speaking should not hard-code
3325 service URLs (e.g. src/android_webview/, src/content/ and others).
3326 """
3327 return input_api.FilterSourceFile(
3328 affected_file,
Bruce Dawson40fece62022-09-16 19:58:313329 files_to_check=[r'^(android_webview|base|content|net)/.*'],
Sam Maiera6e76d72022-02-11 21:43:503330 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3331 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:443332
Dirk Prankee4df27972025-02-26 18:39:353333 base_pattern = (r'"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
3334 r'\.(com|net)[^"]*"')
Sam Maiera6e76d72022-02-11 21:43:503335 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
3336 pattern = input_api.re.compile(base_pattern)
3337 problems = [] # items are (filename, line_number, line)
3338 for f in input_api.AffectedSourceFiles(FilterFile):
3339 for line_num, line in f.ChangedContents():
3340 if not comment_pattern.search(line) and pattern.search(line):
3341 problems.append((f.LocalPath(), line_num, line))
[email protected]06e6d0ff2012-12-11 01:36:443342
Sam Maiera6e76d72022-02-11 21:43:503343 if problems:
3344 return [
3345 output_api.PresubmitPromptOrNotify(
3346 'Most layers below src/chrome/ should not hardcode service URLs.\n'
3347 'Are you sure this is correct?', [
3348 ' %s:%d: %s' % (problem[0], problem[1], problem[2])
3349 for problem in problems
3350 ])
3351 ]
3352 else:
3353 return []
[email protected]06e6d0ff2012-12-11 01:36:443354
3355
Saagar Sanghavifceeaae2020-08-12 16:40:363356def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503357 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
James Cook6b6597c2019-11-06 22:05:293358
Sam Maiera6e76d72022-02-11 21:43:503359 def FileFilter(affected_file):
3360 """Includes directories known to be Chrome OS only."""
3361 return input_api.FilterSourceFile(
3362 affected_file,
3363 files_to_check=(
3364 '^ash/',
3365 '^chromeos/', # Top-level src/chromeos.
3366 '.*/chromeos/', # Any path component.
3367 '^components/arc',
3368 '^components/exo'),
3369 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:293370
Sam Maiera6e76d72022-02-11 21:43:503371 prefs = []
3372 priority_prefs = []
3373 for f in input_api.AffectedFiles(file_filter=FileFilter):
3374 for line_num, line in f.ChangedContents():
3375 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF',
3376 line):
3377 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
3378 prefs.append(' %s' % line)
3379 if input_api.re.search(
3380 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
3381 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
3382 priority_prefs.append(' %s' % line)
3383
3384 results = []
3385 if (prefs):
3386 results.append(
3387 output_api.PresubmitPromptWarning(
3388 'Preferences were registered as SYNCABLE_PREF and will be controlled '
3389 'by browser sync settings. If these prefs should be controlled by OS '
3390 'sync settings use SYNCABLE_OS_PREF instead.\n' +
3391 '\n'.join(prefs)))
3392 if (priority_prefs):
3393 results.append(
3394 output_api.PresubmitPromptWarning(
3395 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
3396 'controlled by browser sync settings. If these prefs should be '
3397 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
3398 'instead.\n' + '\n'.join(prefs)))
3399 return results
James Cook6b6597c2019-11-06 22:05:293400
3401
Saagar Sanghavifceeaae2020-08-12 16:40:363402def CheckNoAbbreviationInPngFileName(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503403 """Makes sure there are no abbreviations in the name of PNG files.
3404 The native_client_sdk directory is excluded because it has auto-generated PNG
3405 files for documentation.
3406 """
3407 errors = []
Yuanqing Zhu9eef02832022-12-04 14:42:173408 files_to_check = [r'.*\.png$']
Bruce Dawson40fece62022-09-16 19:58:313409 files_to_skip = [r'^native_client_sdk/',
3410 r'^services/test/',
3411 r'^third_party/blink/web_tests/',
Bruce Dawson3db456212022-05-02 05:34:183412 ]
Sam Maiera6e76d72022-02-11 21:43:503413 file_filter = lambda f: input_api.FilterSourceFile(
3414 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Dirk Prankee4df27972025-02-26 18:39:353415 abbreviation = input_api.re.compile(r'.+_[a-z]\.png|.+_[a-z]_.*\.png')
Sam Maiera6e76d72022-02-11 21:43:503416 for f in input_api.AffectedFiles(include_deletes=False,
3417 file_filter=file_filter):
Yuanqing Zhu9eef02832022-12-04 14:42:173418 file_name = input_api.os_path.split(f.LocalPath())[1]
3419 if abbreviation.search(file_name):
3420 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:273421
Sam Maiera6e76d72022-02-11 21:43:503422 results = []
3423 if errors:
3424 results.append(
3425 output_api.PresubmitError(
3426 'The name of PNG files should not have abbreviations. \n'
3427 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
3428 'Contact [email protected] if you have questions.', errors))
3429 return results
[email protected]d2530012013-01-25 16:39:273430
Evan Stade7cd4a2c2022-08-04 23:37:253431def CheckNoProductIconsAddedToPublicRepo(input_api, output_api):
3432 """Heuristically identifies product icons based on their file name and reminds
3433 contributors not to add them to the Chromium repository.
3434 """
3435 errors = []
3436 files_to_check = [r'.*google.*\.png$|.*google.*\.svg$|.*google.*\.icon$']
3437 file_filter = lambda f: input_api.FilterSourceFile(
3438 f, files_to_check=files_to_check)
3439 for f in input_api.AffectedFiles(include_deletes=False,
3440 file_filter=file_filter):
3441 errors.append(' %s' % f.LocalPath())
3442
3443 results = []
3444 if errors:
Bruce Dawson3bcf0c92022-08-12 00:03:083445 # Give warnings instead of errors on presubmit --all and presubmit
3446 # --files.
3447 message_type = (output_api.PresubmitNotifyResult if input_api.no_diffs
3448 else output_api.PresubmitError)
Evan Stade7cd4a2c2022-08-04 23:37:253449 results.append(
Bruce Dawson3bcf0c92022-08-12 00:03:083450 message_type(
Evan Stade7cd4a2c2022-08-04 23:37:253451 'Trademarked images should not be added to the public repo. '
3452 'See crbug.com/944754', errors))
3453 return results
3454
[email protected]d2530012013-01-25 16:39:273455
Daniel Cheng4dcdb6b2017-04-13 08:30:173456def _ExtractAddRulesFromParsedDeps(parsed_deps):
Sam Maiera6e76d72022-02-11 21:43:503457 """Extract the rules that add dependencies from a parsed DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:173458
Sam Maiera6e76d72022-02-11 21:43:503459 Args:
3460 parsed_deps: the locals dictionary from evaluating the DEPS file."""
3461 add_rules = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:173462 add_rules.update([
Sam Maiera6e76d72022-02-11 21:43:503463 rule[1:] for rule in parsed_deps.get('include_rules', [])
Daniel Cheng4dcdb6b2017-04-13 08:30:173464 if rule.startswith('+') or rule.startswith('!')
3465 ])
Sam Maiera6e76d72022-02-11 21:43:503466 for _, rules in parsed_deps.get('specific_include_rules', {}).items():
3467 add_rules.update([
3468 rule[1:] for rule in rules
3469 if rule.startswith('+') or rule.startswith('!')
3470 ])
3471 return add_rules
Daniel Cheng4dcdb6b2017-04-13 08:30:173472
3473
3474def _ParseDeps(contents):
Sam Maiera6e76d72022-02-11 21:43:503475 """Simple helper for parsing DEPS files."""
Daniel Cheng4dcdb6b2017-04-13 08:30:173476
Sam Maiera6e76d72022-02-11 21:43:503477 # Stubs for handling special syntax in the root DEPS file.
3478 class _VarImpl:
3479 def __init__(self, local_scope):
3480 self._local_scope = local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:173481
Sam Maiera6e76d72022-02-11 21:43:503482 def Lookup(self, var_name):
3483 """Implements the Var syntax."""
3484 try:
3485 return self._local_scope['vars'][var_name]
3486 except KeyError:
3487 raise Exception('Var is not defined: %s' % var_name)
Daniel Cheng4dcdb6b2017-04-13 08:30:173488
Sam Maiera6e76d72022-02-11 21:43:503489 local_scope = {}
3490 global_scope = {
3491 'Var': _VarImpl(local_scope).Lookup,
3492 'Str': str,
3493 }
Dirk Pranke1b9e06382021-05-14 01:16:223494
Sam Maiera6e76d72022-02-11 21:43:503495 exec(contents, global_scope, local_scope)
3496 return local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:173497
3498
Andrew Grieveb77ac762024-11-29 15:01:483499def _FindAllDepsFilesForSubpath(input_api, subpath):
3500 ret = []
3501 while subpath:
3502 cur = input_api.os_path.join(input_api.change.RepositoryRoot(), subpath, 'DEPS')
Joanna Wang130e7bdd2024-12-10 17:39:033503 if input_api.os_path.isfile(cur):
Andrew Grieveb77ac762024-11-29 15:01:483504 ret.append(cur)
3505 subpath = input_api.os_path.dirname(subpath)
3506 return ret
3507
3508
3509def _FindAddedDepsThatRequireReview(input_api, depended_on_paths):
3510 """Filters to those whose DEPS set new_usages_require_review=True"""
3511 ret = set()
3512 cache = {}
3513 for target_path in depended_on_paths:
3514 for subpath in _FindAllDepsFilesForSubpath(input_api, target_path):
3515 config = cache.get(subpath)
3516 if config is None:
3517 config = _ParseDeps(input_api.ReadFile(subpath))
3518 cache[subpath] = config
3519 if config.get('new_usages_require_review'):
3520 ret.add(target_path)
3521 break
3522 return ret
3523
3524
Daniel Cheng4dcdb6b2017-04-13 08:30:173525def _CalculateAddedDeps(os_path, old_contents, new_contents):
Sam Maiera6e76d72022-02-11 21:43:503526 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
3527 a set of DEPS entries that we should look up.
[email protected]14a6131c2014-01-08 01:15:413528
Sam Maiera6e76d72022-02-11 21:43:503529 For a directory (rather than a specific filename) we fake a path to
3530 a specific filename by adding /DEPS. This is chosen as a file that
3531 will seldom or never be subject to per-file include_rules.
3532 """
3533 # We ignore deps entries on auto-generated directories.
3534 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:083535
Sam Maiera6e76d72022-02-11 21:43:503536 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
3537 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
Daniel Cheng4dcdb6b2017-04-13 08:30:173538
Sam Maiera6e76d72022-02-11 21:43:503539 added_deps = new_deps.difference(old_deps)
Daniel Cheng4dcdb6b2017-04-13 08:30:173540
Sam Maiera6e76d72022-02-11 21:43:503541 results = set()
3542 for added_dep in added_deps:
3543 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
3544 continue
3545 # Assume that a rule that ends in .h is a rule for a specific file.
3546 if added_dep.endswith('.h'):
3547 results.add(added_dep)
3548 else:
3549 results.add(os_path.join(added_dep, 'DEPS'))
3550 return results
[email protected]f32e2d1e2013-07-26 21:39:083551
Stephanie Kimec4f55a2024-04-24 16:54:023552def CheckForNewDEPSDownloadFromGoogleStorageHooks(input_api, output_api):
3553 """Checks that there are no new download_from_google_storage hooks"""
3554 for f in input_api.AffectedFiles(include_deletes=False):
3555 if f.LocalPath() == 'DEPS':
3556 old_hooks = _ParseDeps('\n'.join(f.OldContents()))['hooks']
3557 new_hooks = _ParseDeps('\n'.join(f.NewContents()))['hooks']
3558 old_name_to_hook = {hook['name']: hook for hook in old_hooks}
3559 new_name_to_hook = {hook['name']: hook for hook in new_hooks}
3560 added_hook_names = set(new_name_to_hook.keys()) - set(
3561 old_name_to_hook.keys())
3562 if not added_hook_names:
3563 return []
3564 new_download_from_google_storage_hooks = []
3565 for new_hook in added_hook_names:
3566 hook = new_name_to_hook[new_hook]
3567 action_cmd = hook['action']
3568 if any('download_from_google_storage' in arg
3569 for arg in action_cmd):
3570 new_download_from_google_storage_hooks.append(new_hook)
3571 if new_download_from_google_storage_hooks:
3572 return [
3573 output_api.PresubmitError(
3574 'Please do not add new download_from_google_storage '
3575 'hooks. Instead, add a `gcs` dep_type entry to `deps`. '
3576 'See https://chromium.googlesource.com/chromium/src.git'
3577 '/+/refs/heads/main/docs/gcs_dependencies.md for more '
3578 'info. Added hooks:',
3579 items=new_download_from_google_storage_hooks)
3580 ]
3581 return []
3582
[email protected]f32e2d1e2013-07-26 21:39:083583
Rasika Navarangec2d33d22024-05-23 15:19:023584def CheckEachPerfettoTestDataFileHasDepsEntry(input_api, output_api):
3585 test_data_filter = lambda f: input_api.FilterSourceFile(
Rasika Navarange08e542162024-05-31 13:31:263586 f, files_to_check=[r'^base/tracing/test/data_sha256/.*\.sha256'])
Rasika Navarangec2d33d22024-05-23 15:19:023587 if not any(input_api.AffectedFiles(file_filter=test_data_filter)):
3588 return []
3589
3590 # Find DEPS entry
3591 deps_entry = []
Rasika Navarange277cd662024-06-04 10:14:593592 old_deps_entry = []
Rasika Navarangec2d33d22024-05-23 15:19:023593 for f in input_api.AffectedFiles(include_deletes=False):
3594 if f.LocalPath() == 'DEPS':
3595 new_deps = _ParseDeps('\n'.join(f.NewContents()))['deps']
3596 deps_entry = new_deps['src/base/tracing/test/data']
Rasika Navarange277cd662024-06-04 10:14:593597 old_deps = _ParseDeps('\n'.join(f.OldContents()))['deps']
3598 old_deps_entry = old_deps['src/base/tracing/test/data']
Rasika Navarangec2d33d22024-05-23 15:19:023599 if not deps_entry:
Rasika Navarange08e542162024-05-31 13:31:263600 # TODO(312895063):Add back error when .sha256 files have been moved.
Rasika Navaranged977df342024-06-05 10:01:273601 return [output_api.PresubmitError(
Rasika Navarangec2d33d22024-05-23 15:19:023602 'You must update the DEPS file when you update a '
Rasika Navarange08e542162024-05-31 13:31:263603 '.sha256 file in base/tracing/test/data_sha256'
Rasika Navarangec2d33d22024-05-23 15:19:023604 )]
3605
3606 output = []
3607 for f in input_api.AffectedFiles(file_filter=test_data_filter):
3608 objects = deps_entry['objects']
3609 if not f.NewContents():
3610 # Deleted file so check that DEPS entry removed
3611 sha256_from_file = f.OldContents()[0]
3612 object_entry = next(
3613 (item for item in objects if item["sha256sum"] == sha256_from_file),
3614 None)
Rasika Navarange277cd662024-06-04 10:14:593615 old_entry = next(
3616 (item for item in old_deps_entry['objects'] if item["sha256sum"] == sha256_from_file),
3617 None)
Rasika Navarangec2d33d22024-05-23 15:19:023618 if object_entry:
Rasika Navarange277cd662024-06-04 10:14:593619 # Allow renaming of objects with the same hash
3620 if object_entry['object_name'] != old_entry['object_name']:
3621 continue
Rasika Navarangec2d33d22024-05-23 15:19:023622 output.append(output_api.PresubmitError(
3623 'You deleted %s so you must also remove the corresponding DEPS entry.'
3624 % f.LocalPath()
3625 ))
3626 continue
3627
3628 sha256_from_file = f.NewContents()[0]
3629 object_entry = next(
3630 (item for item in objects if item["sha256sum"] == sha256_from_file),
3631 None)
3632 if not object_entry:
3633 output.append(output_api.PresubmitError(
3634 'No corresponding DEPS entry found for %s. '
3635 'Run `base/tracing/test/test_data.py get_deps --filepath %s` '
3636 'to generate the DEPS entry.'
3637 % (f.LocalPath(), f.LocalPath())
3638 ))
3639
3640 if output:
3641 output.append(output_api.PresubmitError(
3642 'The DEPS entry for `src/base/tracing/test/data` in the DEPS file has not been '
3643 'updated properly. Run `base/tracing/test/test_data.py get_all_deps` to see what '
3644 'the DEPS entry should look like.'
3645 ))
3646 return output
3647
3648
Saagar Sanghavifceeaae2020-08-12 16:40:363649def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503650 """When a dependency prefixed with + is added to a DEPS file, we
3651 want to make sure that the change is reviewed by an OWNER of the
3652 target file or directory, to avoid layering violations from being
3653 introduced. This check verifies that this happens.
3654 """
3655 # We rely on Gerrit's code-owners to check approvals.
3656 # input_api.gerrit is always set for Chromium, but other projects
3657 # might not use Gerrit.
Bruce Dawson344ab262022-06-04 11:35:103658 if not input_api.gerrit or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:503659 return []
Bruce Dawsonb357aeb2022-08-09 15:38:303660 if 'PRESUBMIT_SKIP_NETWORK' in input_api.environ:
Sam Maiera6e76d72022-02-11 21:43:503661 return []
Bruce Dawsonb357aeb2022-08-09 15:38:303662 try:
3663 if (input_api.change.issue and
3664 input_api.gerrit.IsOwnersOverrideApproved(
3665 input_api.change.issue)):
3666 # Skip OWNERS check when Owners-Override label is approved. This is
3667 # intended for global owners, trusted bots, and on-call sheriffs.
3668 # Review is still required for these changes.
3669 return []
3670 except Exception as e:
Sam Maier4cef9242022-10-03 14:21:243671 return [output_api.PresubmitPromptWarning(
3672 'Failed to retrieve owner override status - %s' % str(e))]
Edward Lesmes6fba51082021-01-20 04:20:233673
Andrew Grieveb77ac762024-11-29 15:01:483674 # A set of paths (that might not exist) that are being added as DEPS
3675 # (via lines like "+foo/bar/baz").
3676 depended_on_paths = set()
jochen53efcdd2016-01-29 05:09:243677
Sam Maiera6e76d72022-02-11 21:43:503678 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:313679 r"^third_party/blink/.*",
Anton Bershanskyi4253349482025-02-11 21:01:273680 f.UnixLocalPath())
Sam Maiera6e76d72022-02-11 21:43:503681 for f in input_api.AffectedFiles(include_deletes=False,
3682 file_filter=file_filter):
3683 filename = input_api.os_path.basename(f.LocalPath())
3684 if filename == 'DEPS':
Andrew Grieveb77ac762024-11-29 15:01:483685 depended_on_paths.update(
Sam Maiera6e76d72022-02-11 21:43:503686 _CalculateAddedDeps(input_api.os_path,
3687 '\n'.join(f.OldContents()),
3688 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:553689
Andrew Grieveb77ac762024-11-29 15:01:483690 # Requiring reviews is opt-in as of https://crbug.com/365797506
3691 depended_on_paths = _FindAddedDepsThatRequireReview(input_api, depended_on_paths)
3692 if not depended_on_paths:
Sam Maiera6e76d72022-02-11 21:43:503693 return []
[email protected]e871964c2013-05-13 14:14:553694
Sam Maiera6e76d72022-02-11 21:43:503695 if input_api.is_committing:
3696 if input_api.tbr:
3697 return [
3698 output_api.PresubmitNotifyResult(
3699 '--tbr was specified, skipping OWNERS check for DEPS additions'
3700 )
3701 ]
Daniel Cheng3008dc12022-05-13 04:02:113702 # TODO(dcheng): Make this generate an error on dry runs if the reviewer
3703 # is not added, to prevent review serialization.
Sam Maiera6e76d72022-02-11 21:43:503704 if input_api.dry_run:
3705 return [
3706 output_api.PresubmitNotifyResult(
3707 'This is a dry run, skipping OWNERS check for DEPS additions'
3708 )
3709 ]
3710 if not input_api.change.issue:
3711 return [
3712 output_api.PresubmitError(
3713 "DEPS approval by OWNERS check failed: this change has "
3714 "no change number, so we can't check it for approvals.")
3715 ]
3716 output = output_api.PresubmitError
[email protected]14a6131c2014-01-08 01:15:413717 else:
Sam Maiera6e76d72022-02-11 21:43:503718 output = output_api.PresubmitNotifyResult
[email protected]e871964c2013-05-13 14:14:553719
Sam Maiera6e76d72022-02-11 21:43:503720 owner_email, reviewers = (
3721 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3722 input_api, None, approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:553723
Sam Maiera6e76d72022-02-11 21:43:503724 owner_email = owner_email or input_api.change.author_email
3725
3726 approval_status = input_api.owners_client.GetFilesApprovalStatus(
Andrew Grieveb77ac762024-11-29 15:01:483727 depended_on_paths, reviewers.union([owner_email]), [])
Sam Maiera6e76d72022-02-11 21:43:503728 missing_files = [
Andrew Grieveb77ac762024-11-29 15:01:483729 p for p in depended_on_paths
3730 if approval_status[p] != input_api.owners_client.APPROVED
Sam Maiera6e76d72022-02-11 21:43:503731 ]
3732
3733 # We strip the /DEPS part that was added by
3734 # _FilesToCheckForIncomingDeps to fake a path to a file in a
3735 # directory.
3736 def StripDeps(path):
3737 start_deps = path.rfind('/DEPS')
3738 if start_deps != -1:
3739 return path[:start_deps]
3740 else:
3741 return path
3742
Scott Leebf6a0942024-06-26 22:59:393743 submodule_paths = set(input_api.ListSubmodules())
3744 def is_from_submodules(path, submodule_paths):
3745 path = input_api.os_path.normpath(path)
3746 while path:
3747 if path in submodule_paths:
3748 return True
3749
3750 # All deps should be a relative path from the checkout.
3751 # i.e., shouldn't start with "/" or "c:\", for example.
3752 #
3753 # That said, this is to prevent an infinite loop, just in case
3754 # an input dep path starts with "/", because
3755 # os.path.dirname("/") => "/"
3756 parent = input_api.os_path.dirname(path)
3757 if parent == path:
3758 break
3759 path = parent
3760
3761 return False
3762
Sam Maiera6e76d72022-02-11 21:43:503763 unapproved_dependencies = [
3764 "'+%s'," % StripDeps(path) for path in missing_files
Scott Leebf6a0942024-06-26 22:59:393765 # if a newly added dep is from a submodule, it becomes trickier
3766 # to get suggested owners, especially it is from a different host.
3767 #
3768 # skip the review enforcement for cross-repo deps.
3769 if not is_from_submodules(path, submodule_paths)
Sam Maiera6e76d72022-02-11 21:43:503770 ]
3771
3772 if unapproved_dependencies:
3773 output_list = [
3774 output(
3775 'You need LGTM from owners of depends-on paths in DEPS that were '
3776 'modified in this CL:\n %s' %
3777 '\n '.join(sorted(unapproved_dependencies)))
3778 ]
3779 suggested_owners = input_api.owners_client.SuggestOwners(
3780 missing_files, exclude=[owner_email])
3781 output_list.append(
3782 output('Suggested missing target path OWNERS:\n %s' %
3783 '\n '.join(suggested_owners or [])))
3784 return output_list
3785
3786 return []
[email protected]e871964c2013-05-13 14:14:553787
3788
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493789# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:363790def CheckSpamLogging(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503791 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3792 files_to_skip = (
3793 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3794 input_api.DEFAULT_FILES_TO_SKIP + (
Jaewon Jung2f323bb2022-12-07 23:55:013795 r"^base/fuchsia/scoped_fx_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313796 r"^base/logging\.h$",
3797 r"^base/logging\.cc$",
3798 r"^base/task/thread_pool/task_tracker\.cc$",
3799 r"^chrome/app/chrome_main_delegate\.cc$",
Yao Li359937b2023-02-15 23:43:033800 r"^chrome/browser/ash/arc/enterprise/cert_store/arc_cert_installer\.cc$",
3801 r"^chrome/browser/ash/policy/remote_commands/user_command_arc_job\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313802 r"^chrome/browser/chrome_browser_main\.cc$",
3803 r"^chrome/browser/ui/startup/startup_browser_creator\.cc$",
3804 r"^chrome/browser/browser_switcher/bho/.*",
3805 r"^chrome/browser/diagnostics/diagnostics_writer\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313806 r"^chrome/chrome_elf/dll_hash/dll_hash_main\.cc$",
3807 r"^chrome/installer/setup/.*",
Daniel Ruberyad36eea2024-08-01 01:38:323808 # crdmg runs as a separate binary which intentionally does
3809 # not depend on base logging.
3810 r"^chrome/utility/safe_browsing/mac/crdmg\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313811 r"^chromecast/",
Vigen Issahhanjane2d93822023-06-30 15:57:203812 r"^components/cast",
Bruce Dawson40fece62022-09-16 19:58:313813 r"^components/media_control/renderer/media_playback_options\.cc$",
Salma Elmahallawy52976452023-01-27 17:04:493814 r"^components/policy/core/common/policy_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313815 r"^components/viz/service/display/"
Sam Maiera6e76d72022-02-11 21:43:503816 r"overlay_strategy_underlay_cast\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313817 r"^components/zucchini/.*",
Sam Maiera6e76d72022-02-11 21:43:503818 # TODO(peter): Remove exception. https://crbug.com/534537
Bruce Dawson40fece62022-09-16 19:58:313819 r"^content/browser/notifications/"
Sam Maiera6e76d72022-02-11 21:43:503820 r"notification_event_dispatcher_impl\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313821 r"^content/common/gpu/client/gl_helper_benchmark\.cc$",
3822 r"^courgette/courgette_minimal_tool\.cc$",
3823 r"^courgette/courgette_tool\.cc$",
3824 r"^extensions/renderer/logging_native_handler\.cc$",
3825 r"^fuchsia_web/common/init_logging\.cc$",
3826 r"^fuchsia_web/runners/common/web_component\.cc$",
Caroline Liua7050132023-02-13 22:23:153827 r"^fuchsia_web/shell/.*\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313828 r"^headless/app/headless_shell\.cc$",
3829 r"^ipc/ipc_logging\.cc$",
3830 r"^native_client_sdk/",
3831 r"^remoting/base/logging\.h$",
3832 r"^remoting/host/.*",
3833 r"^sandbox/linux/.*",
Austin Sullivana6054e02024-05-20 16:31:293834 r"^services/webnn/tflite/graph_impl_tflite\.cc$",
3835 r"^services/webnn/coreml/graph_impl_coreml\.mm$",
Bruce Dawson40fece62022-09-16 19:58:313836 r"^storage/browser/file_system/dump_file_system\.cc$",
Steinar H. Gundersone5689e42024-08-07 18:17:193837 r"^testing/perf/",
Bruce Dawson40fece62022-09-16 19:58:313838 r"^tools/",
3839 r"^ui/base/resource/data_pack\.cc$",
3840 r"^ui/aura/bench/bench_main\.cc$",
3841 r"^ui/ozone/platform/cast/",
3842 r"^ui/base/x/xwmstartupcheck/"
Sam Maiera6e76d72022-02-11 21:43:503843 r"xwmstartupcheck\.cc$"))
3844 source_file_filter = lambda x: input_api.FilterSourceFile(
3845 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:403846
Sam Maiera6e76d72022-02-11 21:43:503847 log_info = set([])
3848 printf = set([])
[email protected]85218562013-11-22 07:41:403849
Sam Maiera6e76d72022-02-11 21:43:503850 for f in input_api.AffectedSourceFiles(source_file_filter):
3851 for _, line in f.ChangedContents():
3852 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
3853 log_info.add(f.LocalPath())
3854 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
3855 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:373856
Sam Maiera6e76d72022-02-11 21:43:503857 if input_api.re.search(r"\bprintf\(", line):
3858 printf.add(f.LocalPath())
3859 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
3860 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:403861
Sam Maiera6e76d72022-02-11 21:43:503862 if log_info:
3863 return [
3864 output_api.PresubmitError(
3865 'These files spam the console log with LOG(INFO):',
3866 items=log_info)
3867 ]
3868 if printf:
3869 return [
3870 output_api.PresubmitError(
3871 'These files spam the console log with printf/fprintf:',
3872 items=printf)
3873 ]
3874 return []
[email protected]85218562013-11-22 07:41:403875
3876
Saagar Sanghavifceeaae2020-08-12 16:40:363877def CheckForAnonymousVariables(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503878 """These types are all expected to hold locks while in scope and
3879 so should never be anonymous (which causes them to be immediately
3880 destroyed)."""
3881 they_who_must_be_named = [
3882 'base::AutoLock',
3883 'base::AutoReset',
3884 'base::AutoUnlock',
3885 'SkAutoAlphaRestore',
3886 'SkAutoBitmapShaderInstall',
3887 'SkAutoBlitterChoose',
3888 'SkAutoBounderCommit',
3889 'SkAutoCallProc',
3890 'SkAutoCanvasRestore',
3891 'SkAutoCommentBlock',
3892 'SkAutoDescriptor',
3893 'SkAutoDisableDirectionCheck',
3894 'SkAutoDisableOvalCheck',
3895 'SkAutoFree',
3896 'SkAutoGlyphCache',
3897 'SkAutoHDC',
3898 'SkAutoLockColors',
3899 'SkAutoLockPixels',
3900 'SkAutoMalloc',
3901 'SkAutoMaskFreeImage',
3902 'SkAutoMutexAcquire',
3903 'SkAutoPathBoundsUpdate',
3904 'SkAutoPDFRelease',
3905 'SkAutoRasterClipValidate',
3906 'SkAutoRef',
3907 'SkAutoTime',
3908 'SkAutoTrace',
3909 'SkAutoUnref',
3910 ]
3911 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
3912 # bad: base::AutoLock(lock.get());
3913 # not bad: base::AutoLock lock(lock.get());
3914 bad_pattern = input_api.re.compile(anonymous)
3915 # good: new base::AutoLock(lock.get())
3916 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
3917 errors = []
[email protected]49aa76a2013-12-04 06:59:163918
Sam Maiera6e76d72022-02-11 21:43:503919 for f in input_api.AffectedFiles():
3920 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
3921 continue
3922 for linenum, line in f.ChangedContents():
3923 if bad_pattern.search(line) and not good_pattern.search(line):
3924 errors.append('%s:%d' % (f.LocalPath(), linenum))
[email protected]49aa76a2013-12-04 06:59:163925
Sam Maiera6e76d72022-02-11 21:43:503926 if errors:
3927 return [
3928 output_api.PresubmitError(
3929 'These lines create anonymous variables that need to be named:',
3930 items=errors)
3931 ]
3932 return []
[email protected]49aa76a2013-12-04 06:59:163933
3934
Saagar Sanghavifceeaae2020-08-12 16:40:363935def CheckUniquePtrOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503936 # Returns whether |template_str| is of the form <T, U...> for some types T
Glen Robertson9142ffd72024-05-16 01:37:473937 # and U, or is invalid due to mismatched angle bracket pairs. Assumes that
3938 # |template_str| is already in the form <...>.
3939 def HasMoreThanOneArgOrInvalid(template_str):
Sam Maiera6e76d72022-02-11 21:43:503940 # Level of <...> nesting.
3941 nesting = 0
3942 for c in template_str:
3943 if c == '<':
3944 nesting += 1
3945 elif c == '>':
3946 nesting -= 1
3947 elif c == ',' and nesting == 1:
3948 return True
Glen Robertson9142ffd72024-05-16 01:37:473949 if nesting != 0:
Daniel Cheng566634ff2024-06-29 14:56:533950 # Invalid.
3951 return True
Sam Maiera6e76d72022-02-11 21:43:503952 return False
Vaclav Brozekb7fadb692018-08-30 06:39:533953
Sam Maiera6e76d72022-02-11 21:43:503954 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3955 sources = lambda affected_file: input_api.FilterSourceFile(
3956 affected_file,
3957 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3958 DEFAULT_FILES_TO_SKIP),
3959 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:553960
Sam Maiera6e76d72022-02-11 21:43:503961 # Pattern to capture a single "<...>" block of template arguments. It can
3962 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
3963 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
3964 # latter would likely require counting that < and > match, which is not
3965 # expressible in regular languages. Should the need arise, one can introduce
3966 # limited counting (matching up to a total number of nesting depth), which
3967 # should cover all practical cases for already a low nesting limit.
3968 template_arg_pattern = (
3969 r'<[^>]*' # Opening block of <.
3970 r'>([^<]*>)?') # Closing block of >.
3971 # Prefix expressing that whatever follows is not already inside a <...>
3972 # block.
3973 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
3974 null_construct_pattern = input_api.re.compile(
3975 not_inside_template_arg_pattern + r'\bstd::unique_ptr' +
3976 template_arg_pattern + r'\(\)')
Vaclav Brozeka54c528b2018-04-06 19:23:553977
Sam Maiera6e76d72022-02-11 21:43:503978 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
3979 template_arg_no_array_pattern = (
3980 r'<[^>]*[^]]' # Opening block of <.
3981 r'>([^(<]*[^]]>)?') # Closing block of >.
3982 # Prefix saying that what follows is the start of an expression.
3983 start_of_expr_pattern = r'(=|\breturn|^)\s*'
3984 # Suffix saying that what follows are call parentheses with a non-empty list
3985 # of arguments.
3986 nonempty_arg_list_pattern = r'\(([^)]|$)'
3987 # Put the template argument into a capture group for deeper examination later.
3988 return_construct_pattern = input_api.re.compile(
3989 start_of_expr_pattern + r'std::unique_ptr' + '(?P<template_arg>' +
3990 template_arg_no_array_pattern + ')' + nonempty_arg_list_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:553991
Sam Maiera6e76d72022-02-11 21:43:503992 problems_constructor = []
3993 problems_nullptr = []
3994 for f in input_api.AffectedSourceFiles(sources):
3995 for line_number, line in f.ChangedContents():
3996 # Disallow:
3997 # return std::unique_ptr<T>(foo);
3998 # bar = std::unique_ptr<T>(foo);
3999 # But allow:
4000 # return std::unique_ptr<T[]>(foo);
4001 # bar = std::unique_ptr<T[]>(foo);
4002 # And also allow cases when the second template argument is present. Those
4003 # cases cannot be handled by std::make_unique:
4004 # return std::unique_ptr<T, U>(foo);
4005 # bar = std::unique_ptr<T, U>(foo);
4006 local_path = f.LocalPath()
4007 return_construct_result = return_construct_pattern.search(line)
Glen Robertson9142ffd72024-05-16 01:37:474008 if return_construct_result and not HasMoreThanOneArgOrInvalid(
Sam Maiera6e76d72022-02-11 21:43:504009 return_construct_result.group('template_arg')):
4010 problems_constructor.append(
4011 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4012 # Disallow:
4013 # std::unique_ptr<T>()
4014 if null_construct_pattern.search(line):
4015 problems_nullptr.append(
4016 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Vaclav Brozek851d9602018-04-04 16:13:054017
Sam Maiera6e76d72022-02-11 21:43:504018 errors = []
4019 if problems_nullptr:
4020 errors.append(
4021 output_api.PresubmitPromptWarning(
4022 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
4023 problems_nullptr))
4024 if problems_constructor:
4025 errors.append(
4026 output_api.PresubmitError(
4027 'The following files use explicit std::unique_ptr constructor. '
4028 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
4029 'std::make_unique is not an option.', problems_constructor))
4030 return errors
Peter Kasting4844e46e2018-02-23 07:27:104031
4032
Saagar Sanghavifceeaae2020-08-12 16:40:364033def CheckUserActionUpdate(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504034 """Checks if any new user action has been added."""
4035 if any('actions.xml' == input_api.os_path.basename(f)
4036 for f in input_api.LocalPaths()):
4037 # If actions.xml is already included in the changelist, the PRESUBMIT
4038 # for actions.xml will do a more complete presubmit check.
4039 return []
4040
4041 file_inclusion_pattern = [r'.*\.(cc|mm)$']
4042 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
4043 input_api.DEFAULT_FILES_TO_SKIP)
4044 file_filter = lambda f: input_api.FilterSourceFile(
4045 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
4046
4047 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
4048 current_actions = None
4049 for f in input_api.AffectedFiles(file_filter=file_filter):
4050 for line_num, line in f.ChangedContents():
4051 match = input_api.re.search(action_re, line)
4052 if match:
4053 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
4054 # loaded only once.
4055 if not current_actions:
Bruce Dawson6cb2d4d2023-03-01 21:35:094056 with open('tools/metrics/actions/actions.xml',
4057 encoding='utf-8') as actions_f:
Sam Maiera6e76d72022-02-11 21:43:504058 current_actions = actions_f.read()
4059 # Search for the matched user action name in |current_actions|.
4060 for action_name in match.groups():
4061 action = 'name="{0}"'.format(action_name)
4062 if action not in current_actions:
4063 return [
4064 output_api.PresubmitPromptWarning(
4065 'File %s line %d: %s is missing in '
4066 'tools/metrics/actions/actions.xml. Please run '
4067 'tools/metrics/actions/extract_actions.py to update.'
4068 % (f.LocalPath(), line_num, action_name))
4069 ]
[email protected]999261d2014-03-03 20:08:084070 return []
4071
[email protected]999261d2014-03-03 20:08:084072
Daniel Cheng13ca61a882017-08-25 15:11:254073def _ImportJSONCommentEater(input_api):
Sam Maiera6e76d72022-02-11 21:43:504074 import sys
4075 sys.path = sys.path + [
4076 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4077 'json_comment_eater')
4078 ]
4079 import json_comment_eater
4080 return json_comment_eater
Daniel Cheng13ca61a882017-08-25 15:11:254081
4082
[email protected]99171a92014-06-03 08:44:474083def _GetJSONParseError(input_api, filename, eat_comments=True):
dchenge07de812016-06-20 19:27:174084 try:
Sam Maiera6e76d72022-02-11 21:43:504085 contents = input_api.ReadFile(filename)
4086 if eat_comments:
4087 json_comment_eater = _ImportJSONCommentEater(input_api)
4088 contents = json_comment_eater.Nom(contents)
dchenge07de812016-06-20 19:27:174089
Sam Maiera6e76d72022-02-11 21:43:504090 input_api.json.loads(contents)
4091 except ValueError as e:
4092 return e
Andrew Grieve4deedb12022-02-03 21:34:504093 return None
4094
4095
Sam Maiera6e76d72022-02-11 21:43:504096def _GetIDLParseError(input_api, filename):
4097 try:
4098 contents = input_api.ReadFile(filename)
Devlin Croninf7582a12022-04-21 21:14:284099 for i, char in enumerate(contents):
Daniel Chenga37c03db2022-05-12 17:20:344100 if not char.isascii():
4101 return (
4102 'Non-ascii character "%s" (ord %d) found at offset %d.' %
4103 (char, ord(char), i))
Sam Maiera6e76d72022-02-11 21:43:504104 idl_schema = input_api.os_path.join(input_api.PresubmitLocalPath(),
4105 'tools', 'json_schema_compiler',
4106 'idl_schema.py')
4107 process = input_api.subprocess.Popen(
Bruce Dawson679fb082022-04-14 00:47:284108 [input_api.python3_executable, idl_schema],
Sam Maiera6e76d72022-02-11 21:43:504109 stdin=input_api.subprocess.PIPE,
4110 stdout=input_api.subprocess.PIPE,
4111 stderr=input_api.subprocess.PIPE,
4112 universal_newlines=True)
4113 (_, error) = process.communicate(input=contents)
4114 return error or None
4115 except ValueError as e:
4116 return e
agrievef32bcc72016-04-04 14:57:404117
agrievef32bcc72016-04-04 14:57:404118
Sam Maiera6e76d72022-02-11 21:43:504119def CheckParseErrors(input_api, output_api):
4120 """Check that IDL and JSON files do not contain syntax errors."""
4121 actions = {
4122 '.idl': _GetIDLParseError,
4123 '.json': _GetJSONParseError,
4124 }
4125 # Most JSON files are preprocessed and support comments, but these do not.
4126 json_no_comments_patterns = [
Bruce Dawson40fece62022-09-16 19:58:314127 r'^testing/',
Sam Maiera6e76d72022-02-11 21:43:504128 ]
4129 # Only run IDL checker on files in these directories.
4130 idl_included_patterns = [
Bruce Dawson40fece62022-09-16 19:58:314131 r'^chrome/common/extensions/api/',
4132 r'^extensions/common/api/',
Sam Maiera6e76d72022-02-11 21:43:504133 ]
agrievef32bcc72016-04-04 14:57:404134
Sam Maiera6e76d72022-02-11 21:43:504135 def get_action(affected_file):
4136 filename = affected_file.LocalPath()
4137 return actions.get(input_api.os_path.splitext(filename)[1])
agrievef32bcc72016-04-04 14:57:404138
Sam Maiera6e76d72022-02-11 21:43:504139 def FilterFile(affected_file):
4140 action = get_action(affected_file)
4141 if not action:
4142 return False
Anton Bershanskyi4253349482025-02-11 21:01:274143 path = affected_file.UnixLocalPath()
agrievef32bcc72016-04-04 14:57:404144
Sam Maiera6e76d72022-02-11 21:43:504145 if _MatchesFile(input_api,
4146 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS, path):
4147 return False
4148
4149 if (action == _GetIDLParseError
4150 and not _MatchesFile(input_api, idl_included_patterns, path)):
4151 return False
4152 return True
4153
4154 results = []
4155 for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
4156 include_deletes=False):
4157 action = get_action(affected_file)
4158 kwargs = {}
4159 if (action == _GetJSONParseError
4160 and _MatchesFile(input_api, json_no_comments_patterns,
Anton Bershanskyi4253349482025-02-11 21:01:274161 affected_file.UnixLocalPath())):
Sam Maiera6e76d72022-02-11 21:43:504162 kwargs['eat_comments'] = False
4163 parse_error = action(input_api, affected_file.AbsoluteLocalPath(),
4164 **kwargs)
4165 if parse_error:
4166 results.append(
4167 output_api.PresubmitError(
4168 '%s could not be parsed: %s' %
4169 (affected_file.LocalPath(), parse_error)))
4170 return results
4171
4172
4173def CheckJavaStyle(input_api, output_api):
4174 """Runs checkstyle on changed java files and returns errors if any exist."""
4175
4176 # Return early if no java files were modified.
4177 if not any(
4178 _IsJavaFile(input_api, f.LocalPath())
4179 for f in input_api.AffectedFiles()):
4180 return []
4181
4182 import sys
4183 original_sys_path = sys.path
4184 try:
4185 sys.path = sys.path + [
4186 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4187 'android', 'checkstyle')
4188 ]
4189 import checkstyle
4190 finally:
4191 # Restore sys.path to what it was before.
4192 sys.path = original_sys_path
4193
Andrew Grieve4f88e3ca2022-11-22 19:09:204194 return checkstyle.run_presubmit(
Sam Maiera6e76d72022-02-11 21:43:504195 input_api,
4196 output_api,
Sam Maiera6e76d72022-02-11 21:43:504197 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
4198
4199
4200def CheckPythonDevilInit(input_api, output_api):
4201 """Checks to make sure devil is initialized correctly in python scripts."""
4202 script_common_initialize_pattern = input_api.re.compile(
4203 r'script_common\.InitializeEnvironment\(')
4204 devil_env_config_initialize = input_api.re.compile(
4205 r'devil_env\.config\.Initialize\(')
4206
4207 errors = []
4208
4209 sources = lambda affected_file: input_api.FilterSourceFile(
4210 affected_file,
4211 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314212 r'^build/android/devil_chromium\.py',
Sven Zheng8e079562024-05-10 20:11:064213 r'^tools/bisect-builds\.py',
Bruce Dawson40fece62022-09-16 19:58:314214 r'^third_party/.*',
Sam Maiera6e76d72022-02-11 21:43:504215 )),
4216 files_to_check=[r'.*\.py$'])
4217
4218 for f in input_api.AffectedSourceFiles(sources):
4219 for line_num, line in f.ChangedContents():
4220 if (script_common_initialize_pattern.search(line)
4221 or devil_env_config_initialize.search(line)):
4222 errors.append("%s:%d" % (f.LocalPath(), line_num))
4223
4224 results = []
4225
4226 if errors:
4227 results.append(
4228 output_api.PresubmitError(
4229 'Devil initialization should always be done using '
4230 'devil_chromium.Initialize() in the chromium project, to use better '
4231 'defaults for dependencies (ex. up-to-date version of adb).',
4232 errors))
4233
4234 return results
4235
4236
4237def _MatchesFile(input_api, patterns, path):
4238 for pattern in patterns:
4239 if input_api.re.search(pattern, path):
4240 return True
4241 return False
4242
4243
Daniel Chenga37c03db2022-05-12 17:20:344244def _ChangeHasSecurityReviewer(input_api, owners_file):
4245 """Returns True iff the CL has a reviewer from SECURITY_OWNERS.
Sam Maiera6e76d72022-02-11 21:43:504246
Daniel Chenga37c03db2022-05-12 17:20:344247 Args:
4248 input_api: The presubmit input API.
4249 owners_file: OWNERS file with required reviewers. Typically, this is
4250 something like ipc/SECURITY_OWNERS.
4251
4252 Note: if the presubmit is running for commit rather than for upload, this
4253 only returns True if a security reviewer has also approved the CL.
Sam Maiera6e76d72022-02-11 21:43:504254 """
Daniel Chengd88244472022-05-16 09:08:474255 # Owners-Override should bypass all additional OWNERS enforcement checks.
4256 # A CR+1 vote will still be required to land this change.
4257 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
4258 input_api.change.issue)):
4259 return True
4260
Daniel Chenga37c03db2022-05-12 17:20:344261 owner_email, reviewers = (
4262 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
Daniel Cheng3008dc12022-05-13 04:02:114263 input_api,
4264 None,
4265 approval_needed=input_api.is_committing and not input_api.dry_run))
Sam Maiera6e76d72022-02-11 21:43:504266
Daniel Chenga37c03db2022-05-12 17:20:344267 security_owners = input_api.owners_client.ListOwners(owners_file)
4268 return any(owner in reviewers for owner in security_owners)
Sam Maiera6e76d72022-02-11 21:43:504269
Daniel Chenga37c03db2022-05-12 17:20:344270
4271@dataclass
Daniel Cheng171dad8d2022-05-21 00:40:254272class _SecurityProblemWithItems:
4273 problem: str
4274 items: Sequence[str]
4275
4276
4277@dataclass
Daniel Chenga37c03db2022-05-12 17:20:344278class _MissingSecurityOwnersResult:
Daniel Cheng171dad8d2022-05-21 00:40:254279 owners_file_problems: Sequence[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:344280 has_security_sensitive_files: bool
Daniel Cheng171dad8d2022-05-21 00:40:254281 missing_reviewer_problem: Optional[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:344282
4283
4284def _FindMissingSecurityOwners(input_api,
4285 output_api,
4286 file_patterns: Sequence[str],
4287 excluded_patterns: Sequence[str],
4288 required_owners_file: str,
4289 custom_rule_function: Optional[Callable] = None
4290 ) -> _MissingSecurityOwnersResult:
4291 """Find OWNERS files missing per-file rules for security-sensitive files.
4292
4293 Args:
4294 input_api: the PRESUBMIT input API object.
4295 output_api: the PRESUBMIT output API object.
4296 file_patterns: basename patterns that require a corresponding per-file
4297 security restriction.
4298 excluded_patterns: path patterns that should be exempted from
4299 requiring a security restriction.
4300 required_owners_file: path to the required OWNERS file, e.g.
4301 ipc/SECURITY_OWNERS
4302 cc_alias: If not None, email that will be CCed automatically if the
4303 change contains security-sensitive files, as determined by
4304 `file_patterns` and `excluded_patterns`.
4305 custom_rule_function: If not None, will be called with `input_api` and
4306 the current file under consideration. Returning True will add an
4307 exact match per-file rule check for the current file.
4308 """
4309
4310 # `to_check` is a mapping of an OWNERS file path to Patterns.
4311 #
4312 # Patterns is a dictionary mapping glob patterns (suitable for use in
4313 # per-file rules) to a PatternEntry.
4314 #
Sam Maiera6e76d72022-02-11 21:43:504315 # PatternEntry is a dictionary with two keys:
4316 # - 'files': the files that are matched by this pattern
4317 # - 'rules': the per-file rules needed for this pattern
Daniel Chenga37c03db2022-05-12 17:20:344318 #
Sam Maiera6e76d72022-02-11 21:43:504319 # For example, if we expect OWNERS file to contain rules for *.mojom and
4320 # *_struct_traits*.*, Patterns might look like this:
4321 # {
4322 # '*.mojom': {
4323 # 'files': ...,
4324 # 'rules': [
4325 # 'per-file *.mojom=set noparent',
4326 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
4327 # ],
4328 # },
4329 # '*_struct_traits*.*': {
4330 # 'files': ...,
4331 # 'rules': [
4332 # 'per-file *_struct_traits*.*=set noparent',
4333 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
4334 # ],
4335 # },
4336 # }
4337 to_check = {}
Daniel Chenga37c03db2022-05-12 17:20:344338 files_to_review = []
Sam Maiera6e76d72022-02-11 21:43:504339
Daniel Chenga37c03db2022-05-12 17:20:344340 def AddPatternToCheck(file, pattern):
Sam Maiera6e76d72022-02-11 21:43:504341 owners_file = input_api.os_path.join(
Daniel Chengd88244472022-05-16 09:08:474342 input_api.os_path.dirname(file.LocalPath()), 'OWNERS')
Sam Maiera6e76d72022-02-11 21:43:504343 if owners_file not in to_check:
4344 to_check[owners_file] = {}
4345 if pattern not in to_check[owners_file]:
4346 to_check[owners_file][pattern] = {
4347 'files': [],
4348 'rules': [
Daniel Chenga37c03db2022-05-12 17:20:344349 f'per-file {pattern}=set noparent',
4350 f'per-file {pattern}=file://{required_owners_file}',
Sam Maiera6e76d72022-02-11 21:43:504351 ]
4352 }
Daniel Chenged57a162022-05-25 02:56:344353 to_check[owners_file][pattern]['files'].append(file.LocalPath())
Daniel Chenga37c03db2022-05-12 17:20:344354 files_to_review.append(file.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:504355
Daniel Chenga37c03db2022-05-12 17:20:344356 # Only enforce security OWNERS rules for a directory if that directory has a
4357 # file that matches `file_patterns`. For example, if a directory only
4358 # contains *.mojom files and no *_messages*.h files, the check should only
4359 # ensure that rules for *.mojom files are present.
4360 for file in input_api.AffectedFiles(include_deletes=False):
4361 file_basename = input_api.os_path.basename(file.LocalPath())
4362 if custom_rule_function is not None and custom_rule_function(
4363 input_api, file):
4364 AddPatternToCheck(file, file_basename)
4365 continue
Sam Maiera6e76d72022-02-11 21:43:504366
Daniel Chenga37c03db2022-05-12 17:20:344367 if any(
4368 input_api.fnmatch.fnmatch(file.LocalPath(), pattern)
4369 for pattern in excluded_patterns):
Sam Maiera6e76d72022-02-11 21:43:504370 continue
4371
4372 for pattern in file_patterns:
Daniel Chenga37c03db2022-05-12 17:20:344373 # Unlike `excluded_patterns`, `file_patterns` is checked only against the
4374 # file's basename.
4375 if input_api.fnmatch.fnmatch(file_basename, pattern):
4376 AddPatternToCheck(file, pattern)
Sam Maiera6e76d72022-02-11 21:43:504377 break
4378
Daniel Chenga37c03db2022-05-12 17:20:344379 has_security_sensitive_files = bool(to_check)
Daniel Cheng171dad8d2022-05-21 00:40:254380
4381 # Check if any newly added lines in OWNERS files intersect with required
4382 # per-file OWNERS lines. If so, ensure that a security reviewer is included.
4383 # This is a hack, but is needed because the OWNERS check (by design) ignores
4384 # new OWNERS entries; otherwise, a non-owner could add someone as a new
4385 # OWNER and have that newly-added OWNER self-approve their own addition.
4386 newly_covered_files = []
4387 for file in input_api.AffectedFiles(include_deletes=False):
4388 if not file.LocalPath() in to_check:
4389 continue
4390 for _, line in file.ChangedContents():
4391 for _, entry in to_check[file.LocalPath()].items():
4392 if line in entry['rules']:
4393 newly_covered_files.extend(entry['files'])
4394
4395 missing_reviewer_problems = None
4396 if newly_covered_files and not _ChangeHasSecurityReviewer(
Daniel Chenga37c03db2022-05-12 17:20:344397 input_api, required_owners_file):
Daniel Cheng171dad8d2022-05-21 00:40:254398 missing_reviewer_problems = _SecurityProblemWithItems(
4399 f'Review from an owner in {required_owners_file} is required for '
4400 'the following newly-added files:',
4401 [f'{file}' for file in sorted(set(newly_covered_files))])
Sam Maiera6e76d72022-02-11 21:43:504402
4403 # Go through the OWNERS files to check, filtering out rules that are already
4404 # present in that OWNERS file.
4405 for owners_file, patterns in to_check.items():
4406 try:
Daniel Cheng171dad8d2022-05-21 00:40:254407 lines = set(
4408 input_api.ReadFile(
4409 input_api.os_path.join(input_api.change.RepositoryRoot(),
4410 owners_file)).splitlines())
4411 for entry in patterns.values():
4412 entry['rules'] = [
4413 rule for rule in entry['rules'] if rule not in lines
4414 ]
Sam Maiera6e76d72022-02-11 21:43:504415 except IOError:
4416 # No OWNERS file, so all the rules are definitely missing.
4417 continue
4418
4419 # All the remaining lines weren't found in OWNERS files, so emit an error.
Daniel Cheng171dad8d2022-05-21 00:40:254420 owners_file_problems = []
Daniel Chenga37c03db2022-05-12 17:20:344421
Sam Maiera6e76d72022-02-11 21:43:504422 for owners_file, patterns in to_check.items():
4423 missing_lines = []
4424 files = []
4425 for _, entry in patterns.items():
Daniel Chenged57a162022-05-25 02:56:344426 files.extend(entry['files'])
Sam Maiera6e76d72022-02-11 21:43:504427 missing_lines.extend(entry['rules'])
Sam Maiera6e76d72022-02-11 21:43:504428 if missing_lines:
Daniel Cheng171dad8d2022-05-21 00:40:254429 joined_missing_lines = '\n'.join(line for line in missing_lines)
4430 owners_file_problems.append(
4431 _SecurityProblemWithItems(
4432 'Found missing OWNERS lines for security-sensitive files. '
4433 f'Please add the following lines to {owners_file}:\n'
4434 f'{joined_missing_lines}\n\nTo ensure security review for:',
4435 files))
Daniel Chenga37c03db2022-05-12 17:20:344436
Daniel Cheng171dad8d2022-05-21 00:40:254437 return _MissingSecurityOwnersResult(owners_file_problems,
Daniel Chenga37c03db2022-05-12 17:20:344438 has_security_sensitive_files,
Daniel Cheng171dad8d2022-05-21 00:40:254439 missing_reviewer_problems)
Daniel Chenga37c03db2022-05-12 17:20:344440
4441
4442def _CheckChangeForIpcSecurityOwners(input_api, output_api):
4443 # Whether or not a file affects IPC is (mostly) determined by a simple list
4444 # of filename patterns.
4445 file_patterns = [
4446 # Legacy IPC:
4447 '*_messages.cc',
4448 '*_messages*.h',
4449 '*_param_traits*.*',
4450 # Mojo IPC:
4451 '*.mojom',
4452 '*_mojom_traits*.*',
4453 '*_type_converter*.*',
4454 # Android native IPC:
4455 '*.aidl',
4456 ]
4457
Daniel Chenga37c03db2022-05-12 17:20:344458 excluded_patterns = [
Daniel Cheng518943f2022-05-12 22:15:464459 # These third_party directories do not contain IPCs, but contain files
4460 # matching the above patterns, which trigger false positives.
Daniel Chenga37c03db2022-05-12 17:20:344461 'third_party/crashpad/*',
4462 'third_party/blink/renderer/platform/bindings/*',
Evan Stade23a77da2025-02-06 21:15:314463 'third_party/protobuf/*',
Daniel Chenga37c03db2022-05-12 17:20:344464 'third_party/win_build_output/*',
Daniel Chengd88244472022-05-16 09:08:474465 # Enum-only mojoms used for web metrics, so no security review needed.
4466 'third_party/blink/public/mojom/use_counter/metrics/*',
Daniel Chenga37c03db2022-05-12 17:20:344467 # These files are just used to communicate between class loaders running
4468 # in the same process.
4469 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
4470 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
4471 ]
4472
4473 def IsMojoServiceManifestFile(input_api, file):
Dirk Prankee4df27972025-02-26 18:39:354474 manifest_pattern = input_api.re.compile(r'manifests?\.(cc|h)$')
4475 test_manifest_pattern = input_api.re.compile(r'test_manifests?\.(cc|h)')
Daniel Chenga37c03db2022-05-12 17:20:344476 if not manifest_pattern.search(file.LocalPath()):
4477 return False
4478
4479 if test_manifest_pattern.search(file.LocalPath()):
4480 return False
4481
4482 # All actual service manifest files should contain at least one
4483 # qualified reference to service_manager::Manifest.
4484 return any('service_manager::Manifest' in line
4485 for line in file.NewContents())
4486
4487 return _FindMissingSecurityOwners(
4488 input_api,
4489 output_api,
4490 file_patterns,
4491 excluded_patterns,
4492 'ipc/SECURITY_OWNERS',
4493 custom_rule_function=IsMojoServiceManifestFile)
4494
4495
4496def _CheckChangeForFuchsiaSecurityOwners(input_api, output_api):
4497 file_patterns = [
4498 # Component specifications.
4499 '*.cml', # Component Framework v2.
4500 '*.cmx', # Component Framework v1.
4501
4502 # Fuchsia IDL protocol specifications.
4503 '*.fidl',
4504 ]
4505
4506 # Don't check for owners files for changes in these directories.
4507 excluded_patterns = [
4508 'third_party/crashpad/*',
4509 ]
4510
4511 return _FindMissingSecurityOwners(input_api, output_api, file_patterns,
4512 excluded_patterns,
4513 'build/fuchsia/SECURITY_OWNERS')
4514
4515
4516def CheckSecurityOwners(input_api, output_api):
4517 """Checks that various security-sensitive files have an IPC OWNERS rule."""
4518 ipc_results = _CheckChangeForIpcSecurityOwners(input_api, output_api)
4519 fuchsia_results = _CheckChangeForFuchsiaSecurityOwners(
4520 input_api, output_api)
4521
4522 if ipc_results.has_security_sensitive_files:
4523 output_api.AppendCC('[email protected]')
Sam Maiera6e76d72022-02-11 21:43:504524
4525 results = []
Daniel Chenga37c03db2022-05-12 17:20:344526
Daniel Cheng171dad8d2022-05-21 00:40:254527 missing_reviewer_problems = []
4528 if ipc_results.missing_reviewer_problem:
4529 missing_reviewer_problems.append(ipc_results.missing_reviewer_problem)
4530 if fuchsia_results.missing_reviewer_problem:
4531 missing_reviewer_problems.append(
4532 fuchsia_results.missing_reviewer_problem)
Daniel Chenga37c03db2022-05-12 17:20:344533
Daniel Cheng171dad8d2022-05-21 00:40:254534 # Missing reviewers are an error unless there's no issue number
4535 # associated with this branch; in that case, the presubmit is being run
4536 # with --all or --files.
4537 #
4538 # Note that upload should never be an error; otherwise, it would be
4539 # impossible to upload changes at all.
4540 if input_api.is_committing and input_api.change.issue:
4541 make_presubmit_message = output_api.PresubmitError
4542 else:
4543 make_presubmit_message = output_api.PresubmitNotifyResult
4544 for problem in missing_reviewer_problems:
Sam Maiera6e76d72022-02-11 21:43:504545 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:254546 make_presubmit_message(problem.problem, items=problem.items))
Daniel Chenga37c03db2022-05-12 17:20:344547
Daniel Cheng171dad8d2022-05-21 00:40:254548 owners_file_problems = []
4549 owners_file_problems.extend(ipc_results.owners_file_problems)
4550 owners_file_problems.extend(fuchsia_results.owners_file_problems)
Daniel Chenga37c03db2022-05-12 17:20:344551
Daniel Cheng171dad8d2022-05-21 00:40:254552 for problem in owners_file_problems:
Daniel Cheng3008dc12022-05-13 04:02:114553 # Missing per-file rules are always an error. While swarming and caching
4554 # means that uploading a patchset with updated OWNERS files and sending
4555 # it to the CQ again should not have a large incremental cost, it is
4556 # still frustrating to discover the error only after the change has
4557 # already been uploaded.
Daniel Chenga37c03db2022-05-12 17:20:344558 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:254559 output_api.PresubmitError(problem.problem, items=problem.items))
Sam Maiera6e76d72022-02-11 21:43:504560
4561 return results
4562
4563
4564def _GetFilesUsingSecurityCriticalFunctions(input_api):
4565 """Checks affected files for changes to security-critical calls. This
4566 function checks the full change diff, to catch both additions/changes
4567 and removals.
4568
4569 Returns a dict keyed by file name, and the value is a set of detected
4570 functions.
4571 """
4572 # Map of function pretty name (displayed in an error) to the pattern to
4573 # match it with.
4574 _PATTERNS_TO_CHECK = {
4575 'content::GetServiceSandboxType<>()': 'GetServiceSandboxType\\<'
4576 }
4577 _PATTERNS_TO_CHECK = {
4578 k: input_api.re.compile(v)
4579 for k, v in _PATTERNS_TO_CHECK.items()
4580 }
4581
Sam Maiera6e76d72022-02-11 21:43:504582 # We don't want to trigger on strings within this file.
4583 def presubmit_file_filter(f):
Daniel Chenga37c03db2022-05-12 17:20:344584 return 'PRESUBMIT.py' != input_api.os_path.split(f.LocalPath())[1]
Sam Maiera6e76d72022-02-11 21:43:504585
4586 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
4587 files_to_functions = {}
4588 for f in input_api.AffectedFiles(file_filter=presubmit_file_filter):
4589 diff = f.GenerateScmDiff()
4590 for line in diff.split('\n'):
4591 # Not using just RightHandSideLines() because removing a
4592 # call to a security-critical function can be just as important
4593 # as adding or changing the arguments.
4594 if line.startswith('-') or (line.startswith('+')
4595 and not line.startswith('++')):
4596 for name, pattern in _PATTERNS_TO_CHECK.items():
4597 if pattern.search(line):
4598 path = f.LocalPath()
4599 if not path in files_to_functions:
4600 files_to_functions[path] = set()
4601 files_to_functions[path].add(name)
4602 return files_to_functions
4603
4604
4605def CheckSecurityChanges(input_api, output_api):
4606 """Checks that changes involving security-critical functions are reviewed
4607 by the security team.
4608 """
4609 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
4610 if not len(files_to_functions):
4611 return []
4612
Sam Maiera6e76d72022-02-11 21:43:504613 owners_file = 'ipc/SECURITY_OWNERS'
Daniel Chenga37c03db2022-05-12 17:20:344614 if _ChangeHasSecurityReviewer(input_api, owners_file):
Sam Maiera6e76d72022-02-11 21:43:504615 return []
4616
Daniel Chenga37c03db2022-05-12 17:20:344617 msg = 'The following files change calls to security-sensitive functions\n' \
Sam Maiera6e76d72022-02-11 21:43:504618 'that need to be reviewed by {}.\n'.format(owners_file)
4619 for path, names in files_to_functions.items():
4620 msg += ' {}\n'.format(path)
4621 for name in names:
4622 msg += ' {}\n'.format(name)
4623 msg += '\n'
4624
4625 if input_api.is_committing:
4626 output = output_api.PresubmitError
Mohamed Heikale217fc852020-07-06 19:44:034627 else:
Sam Maiera6e76d72022-02-11 21:43:504628 output = output_api.PresubmitNotifyResult
4629 return [output(msg)]
4630
4631
4632def CheckSetNoParent(input_api, output_api):
4633 """Checks that set noparent is only used together with an OWNERS file in
4634 //build/OWNERS.setnoparent (see also
4635 //docs/code_reviews.md#owners-files-details)
4636 """
4637 # Return early if no OWNERS files were modified.
4638 if not any(f.LocalPath().endswith('OWNERS')
4639 for f in input_api.AffectedFiles(include_deletes=False)):
4640 return []
4641
4642 errors = []
4643
4644 allowed_owners_files_file = 'build/OWNERS.setnoparent'
4645 allowed_owners_files = set()
Bruce Dawson58a45d22023-02-27 11:24:164646 with open(allowed_owners_files_file, 'r', encoding='utf-8') as f:
Sam Maiera6e76d72022-02-11 21:43:504647 for line in f:
4648 line = line.strip()
4649 if not line or line.startswith('#'):
4650 continue
4651 allowed_owners_files.add(line)
4652
4653 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
4654
4655 for f in input_api.AffectedFiles(include_deletes=False):
4656 if not f.LocalPath().endswith('OWNERS'):
4657 continue
4658
4659 found_owners_files = set()
4660 found_set_noparent_lines = dict()
4661
4662 # Parse the OWNERS file.
4663 for lineno, line in enumerate(f.NewContents(), 1):
4664 line = line.strip()
4665 if line.startswith('set noparent'):
4666 found_set_noparent_lines[''] = lineno
4667 if line.startswith('file://'):
4668 if line in allowed_owners_files:
4669 found_owners_files.add('')
4670 if line.startswith('per-file'):
4671 match = per_file_pattern.match(line)
4672 if match:
4673 glob = match.group(1).strip()
4674 directive = match.group(2).strip()
4675 if directive == 'set noparent':
4676 found_set_noparent_lines[glob] = lineno
4677 if directive.startswith('file://'):
4678 if directive in allowed_owners_files:
4679 found_owners_files.add(glob)
4680
4681 # Check that every set noparent line has a corresponding file:// line
4682 # listed in build/OWNERS.setnoparent. An exception is made for top level
4683 # directories since src/OWNERS shouldn't review them.
Anton Bershanskyi4253349482025-02-11 21:01:274684 linux_path = f.UnixLocalPath()
Bruce Dawson6bb0d672022-04-06 15:13:494685 if (linux_path.count('/') != 1
4686 and (not linux_path in _EXCLUDED_SET_NO_PARENT_PATHS)):
Sam Maiera6e76d72022-02-11 21:43:504687 for set_noparent_line in found_set_noparent_lines:
4688 if set_noparent_line in found_owners_files:
4689 continue
4690 errors.append(' %s:%d' %
Bruce Dawson6bb0d672022-04-06 15:13:494691 (linux_path,
Sam Maiera6e76d72022-02-11 21:43:504692 found_set_noparent_lines[set_noparent_line]))
4693
4694 results = []
4695 if errors:
4696 if input_api.is_committing:
4697 output = output_api.PresubmitError
4698 else:
4699 output = output_api.PresubmitPromptWarning
4700 results.append(
4701 output(
4702 'Found the following "set noparent" restrictions in OWNERS files that '
4703 'do not include owners from build/OWNERS.setnoparent:',
4704 long_text='\n\n'.join(errors)))
4705 return results
4706
4707
4708def CheckUselessForwardDeclarations(input_api, output_api):
4709 """Checks that added or removed lines in non third party affected
4710 header files do not lead to new useless class or struct forward
4711 declaration.
4712 """
4713 results = []
4714 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
4715 input_api.re.MULTILINE)
4716 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
4717 input_api.re.MULTILINE)
4718 for f in input_api.AffectedFiles(include_deletes=False):
Anton Bershanskyi4253349482025-02-11 21:01:274719 local_path = f.UnixLocalPath()
4720 if (local_path.startswith('third_party')
4721 and not local_path.startswith('third_party/blink')):
Sam Maiera6e76d72022-02-11 21:43:504722 continue
4723
Anton Bershanskyi4253349482025-02-11 21:01:274724 if not local_path.endswith('.h'):
Sam Maiera6e76d72022-02-11 21:43:504725 continue
4726
4727 contents = input_api.ReadFile(f)
4728 fwd_decls = input_api.re.findall(class_pattern, contents)
4729 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
4730
4731 useless_fwd_decls = []
4732 for decl in fwd_decls:
4733 count = sum(1 for _ in input_api.re.finditer(
4734 r'\b%s\b' % input_api.re.escape(decl), contents))
4735 if count == 1:
4736 useless_fwd_decls.append(decl)
4737
4738 if not useless_fwd_decls:
4739 continue
4740
4741 for line in f.GenerateScmDiff().splitlines():
4742 if (line.startswith('-') and not line.startswith('--')
4743 or line.startswith('+') and not line.startswith('++')):
4744 for decl in useless_fwd_decls:
4745 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
4746 results.append(
4747 output_api.PresubmitPromptWarning(
4748 '%s: %s forward declaration is no longer needed'
4749 % (f.LocalPath(), decl)))
4750 useless_fwd_decls.remove(decl)
4751
4752 return results
4753
4754
4755def _CheckAndroidDebuggableBuild(input_api, output_api):
4756 """Checks that code uses BuildInfo.isDebugAndroid() instead of
4757 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
4758 this is a debuggable build of Android.
4759 """
4760 build_type_check_pattern = input_api.re.compile(
4761 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
4762
4763 errors = []
4764
4765 sources = lambda affected_file: input_api.FilterSourceFile(
4766 affected_file,
4767 files_to_skip=(
4768 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4769 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314770 r"^android_webview/support_library/boundary_interfaces/",
4771 r"^chrome/android/webapk/.*",
4772 r'^third_party/.*',
4773 r"tools/android/customtabs_benchmark/.*",
4774 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504775 )),
4776 files_to_check=[r'.*\.java$'])
4777
4778 for f in input_api.AffectedSourceFiles(sources):
4779 for line_num, line in f.ChangedContents():
4780 if build_type_check_pattern.search(line):
4781 errors.append("%s:%d" % (f.LocalPath(), line_num))
4782
4783 results = []
4784
4785 if errors:
4786 results.append(
4787 output_api.PresubmitPromptWarning(
4788 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
4789 ' Please use BuildInfo.isDebugAndroid() instead.', errors))
4790
4791 return results
4792
4793# TODO: add unit tests
4794def _CheckAndroidToastUsage(input_api, output_api):
4795 """Checks that code uses org.chromium.ui.widget.Toast instead of
4796 android.widget.Toast (Chromium Toast doesn't force hardware
4797 acceleration on low-end devices, saving memory).
4798 """
4799 toast_import_pattern = input_api.re.compile(
4800 r'^import android\.widget\.Toast;$')
4801
4802 errors = []
4803
4804 sources = lambda affected_file: input_api.FilterSourceFile(
4805 affected_file,
4806 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
Bruce Dawson40fece62022-09-16 19:58:314807 DEFAULT_FILES_TO_SKIP + (r'^chromecast/.*',
4808 r'^remoting/.*')),
Sam Maiera6e76d72022-02-11 21:43:504809 files_to_check=[r'.*\.java$'])
4810
4811 for f in input_api.AffectedSourceFiles(sources):
4812 for line_num, line in f.ChangedContents():
4813 if toast_import_pattern.search(line):
4814 errors.append("%s:%d" % (f.LocalPath(), line_num))
4815
4816 results = []
4817
4818 if errors:
4819 results.append(
4820 output_api.PresubmitError(
4821 'android.widget.Toast usage is detected. Android toasts use hardware'
4822 ' acceleration, and can be\ncostly on low-end devices. Please use'
4823 ' org.chromium.ui.widget.Toast instead.\n'
4824 'Contact [email protected] if you have any questions.',
4825 errors))
4826
4827 return results
4828
4829
4830def _CheckAndroidCrLogUsage(input_api, output_api):
4831 """Checks that new logs using org.chromium.base.Log:
4832 - Are using 'TAG' as variable name for the tags (warn)
4833 - Are using a tag that is shorter than 20 characters (error)
4834 """
4835
4836 # Do not check format of logs in the given files
4837 cr_log_check_excluded_paths = [
4838 # //chrome/android/webapk cannot depend on //base
Bruce Dawson40fece62022-09-16 19:58:314839 r"^chrome/android/webapk/.*",
Sam Maiera6e76d72022-02-11 21:43:504840 # WebView license viewer code cannot depend on //base; used in stub APK.
Bruce Dawson40fece62022-09-16 19:58:314841 r"^android_webview/glue/java/src/com/android/"
4842 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504843 # The customtabs_benchmark is a small app that does not depend on Chromium
4844 # java pieces.
Bruce Dawson40fece62022-09-16 19:58:314845 r"tools/android/customtabs_benchmark/.*",
Sam Maiera6e76d72022-02-11 21:43:504846 ]
4847
4848 cr_log_import_pattern = input_api.re.compile(
4849 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
4850 class_in_base_pattern = input_api.re.compile(
4851 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
4852 has_some_log_import_pattern = input_api.re.compile(r'^import .*\.Log;$',
4853 input_api.re.MULTILINE)
4854 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
4855 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
4856 log_decl_pattern = input_api.re.compile(
4857 r'static final String TAG = "(?P<name>(.*))"')
4858 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
4859
4860 REF_MSG = ('See docs/android_logging.md for more info.')
4861 sources = lambda x: input_api.FilterSourceFile(
4862 x,
4863 files_to_check=[r'.*\.java$'],
4864 files_to_skip=cr_log_check_excluded_paths)
4865
4866 tag_decl_errors = []
Andrew Grieved3a35d82024-01-02 21:24:384867 tag_length_errors = []
Sam Maiera6e76d72022-02-11 21:43:504868 tag_errors = []
4869 tag_with_dot_errors = []
4870 util_log_errors = []
4871
4872 for f in input_api.AffectedSourceFiles(sources):
4873 file_content = input_api.ReadFile(f)
4874 has_modified_logs = False
4875 # Per line checks
4876 if (cr_log_import_pattern.search(file_content)
4877 or (class_in_base_pattern.search(file_content)
4878 and not has_some_log_import_pattern.search(file_content))):
4879 # Checks to run for files using cr log
4880 for line_num, line in f.ChangedContents():
4881 if rough_log_decl_pattern.search(line):
4882 has_modified_logs = True
4883
4884 # Check if the new line is doing some logging
4885 match = log_call_pattern.search(line)
4886 if match:
4887 has_modified_logs = True
4888
4889 # Make sure it uses "TAG"
4890 if not match.group('tag') == 'TAG':
4891 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
4892 else:
4893 # Report non cr Log function calls in changed lines
4894 for line_num, line in f.ChangedContents():
4895 if log_call_pattern.search(line):
4896 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
4897
4898 # Per file checks
4899 if has_modified_logs:
4900 # Make sure the tag is using the "cr" prefix and is not too long
4901 match = log_decl_pattern.search(file_content)
4902 tag_name = match.group('name') if match else None
4903 if not tag_name:
4904 tag_decl_errors.append(f.LocalPath())
Andrew Grieved3a35d82024-01-02 21:24:384905 elif len(tag_name) > 20:
4906 tag_length_errors.append(f.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:504907 elif '.' in tag_name:
4908 tag_with_dot_errors.append(f.LocalPath())
4909
4910 results = []
4911 if tag_decl_errors:
4912 results.append(
4913 output_api.PresubmitPromptWarning(
4914 'Please define your tags using the suggested format: .\n'
4915 '"private static final String TAG = "<package tag>".\n'
4916 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
4917 tag_decl_errors))
4918
Andrew Grieved3a35d82024-01-02 21:24:384919 if tag_length_errors:
4920 results.append(
4921 output_api.PresubmitError(
4922 'The tag length is restricted by the system to be at most '
4923 '20 characters.\n' + REF_MSG, tag_length_errors))
4924
Sam Maiera6e76d72022-02-11 21:43:504925 if tag_errors:
4926 results.append(
4927 output_api.PresubmitPromptWarning(
4928 'Please use a variable named "TAG" for your log tags.\n' +
4929 REF_MSG, tag_errors))
4930
4931 if util_log_errors:
4932 results.append(
4933 output_api.PresubmitPromptWarning(
4934 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
4935 util_log_errors))
4936
4937 if tag_with_dot_errors:
4938 results.append(
4939 output_api.PresubmitPromptWarning(
4940 'Dot in log tags cause them to be elided in crash reports.\n' +
4941 REF_MSG, tag_with_dot_errors))
4942
4943 return results
4944
4945
Sam Maiera6e76d72022-02-11 21:43:504946def _CheckAndroidTestAnnotationUsage(input_api, output_api):
4947 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
4948 deprecated_annotation_import_pattern = input_api.re.compile(
4949 r'^import android\.test\.suitebuilder\.annotation\..*;',
4950 input_api.re.MULTILINE)
4951 sources = lambda x: input_api.FilterSourceFile(
4952 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
4953 errors = []
4954 for f in input_api.AffectedFiles(file_filter=sources):
4955 for line_num, line in f.ChangedContents():
4956 if deprecated_annotation_import_pattern.search(line):
4957 errors.append("%s:%d" % (f.LocalPath(), line_num))
4958
4959 results = []
4960 if errors:
4961 results.append(
4962 output_api.PresubmitError(
4963 'Annotations in android.test.suitebuilder.annotation have been'
Mohamed Heikal3d7a94c2023-03-28 16:55:244964 ' deprecated since API level 24. Please use androidx.test.filters'
4965 ' from //third_party/androidx:androidx_test_runner_java instead.'
Sam Maiera6e76d72022-02-11 21:43:504966 ' Contact [email protected] if you have any questions.',
4967 errors))
4968 return results
4969
4970
4971def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
4972 """Checks if MDPI assets are placed in a correct directory."""
Anton Bershanskyi4253349482025-02-11 21:01:274973 file_filter = lambda f: (f.UnixLocalPath().endswith(
4974 '.png') and ('/res/drawable/' in f.
4975 UnixLocalPath() or '/res/drawable-ldrtl/' in f.UnixLocalPath()))
Sam Maiera6e76d72022-02-11 21:43:504976 errors = []
4977 for f in input_api.AffectedFiles(include_deletes=False,
4978 file_filter=file_filter):
4979 errors.append(' %s' % f.LocalPath())
4980
4981 results = []
4982 if errors:
4983 results.append(
4984 output_api.PresubmitError(
4985 'MDPI assets should be placed in /res/drawable-mdpi/ or '
4986 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
4987 '/res/drawable-ldrtl/.\n'
4988 'Contact [email protected] if you have questions.', errors))
4989 return results
4990
4991
4992def _CheckAndroidWebkitImports(input_api, output_api):
4993 """Checks that code uses org.chromium.base.Callback instead of
4994 android.webview.ValueCallback except in the WebView glue layer
4995 and WebLayer.
4996 """
4997 valuecallback_import_pattern = input_api.re.compile(
4998 r'^import android\.webkit\.ValueCallback;$')
4999
5000 errors = []
5001
5002 sources = lambda affected_file: input_api.FilterSourceFile(
5003 affected_file,
5004 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
5005 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:315006 r'^android_webview/glue/.*',
elabadysayedcbbaea72024-08-01 16:10:425007 r'^android_webview/support_library/.*',
Bruce Dawson40fece62022-09-16 19:58:315008 r'^weblayer/.*',
Sam Maiera6e76d72022-02-11 21:43:505009 )),
5010 files_to_check=[r'.*\.java$'])
5011
5012 for f in input_api.AffectedSourceFiles(sources):
5013 for line_num, line in f.ChangedContents():
5014 if valuecallback_import_pattern.search(line):
5015 errors.append("%s:%d" % (f.LocalPath(), line_num))
5016
5017 results = []
5018
5019 if errors:
5020 results.append(
5021 output_api.PresubmitError(
5022 'android.webkit.ValueCallback usage is detected outside of the glue'
5023 ' layer. To stay compatible with the support library, android.webkit.*'
5024 ' classes should only be used inside the glue layer and'
5025 ' org.chromium.base.Callback should be used instead.', errors))
5026
5027 return results
5028
5029
5030def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
5031 """Checks Android XML styles """
5032
5033 # Return early if no relevant files were modified.
5034 if not any(
5035 _IsXmlOrGrdFile(input_api, f.LocalPath())
5036 for f in input_api.AffectedFiles(include_deletes=False)):
5037 return []
5038
5039 import sys
5040 original_sys_path = sys.path
5041 try:
5042 sys.path = sys.path + [
5043 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5044 'android', 'checkxmlstyle')
5045 ]
5046 import checkxmlstyle
5047 finally:
5048 # Restore sys.path to what it was before.
5049 sys.path = original_sys_path
5050
5051 if is_check_on_upload:
5052 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
5053 else:
5054 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
5055
5056
5057def _CheckAndroidInfoBarDeprecation(input_api, output_api):
5058 """Checks Android Infobar Deprecation """
5059
5060 import sys
5061 original_sys_path = sys.path
5062 try:
5063 sys.path = sys.path + [
5064 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5065 'android', 'infobar_deprecation')
5066 ]
5067 import infobar_deprecation
5068 finally:
5069 # Restore sys.path to what it was before.
5070 sys.path = original_sys_path
5071
5072 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
5073
5074
5075class _PydepsCheckerResult:
5076 def __init__(self, cmd, pydeps_path, process, old_contents):
5077 self._cmd = cmd
5078 self._pydeps_path = pydeps_path
5079 self._process = process
5080 self._old_contents = old_contents
5081
5082 def GetError(self):
5083 """Returns an error message, or None."""
5084 import difflib
Andrew Grieved27620b62023-07-13 16:35:075085 new_contents = self._process.stdout.read().splitlines()[2:]
Sam Maiera6e76d72022-02-11 21:43:505086 if self._process.wait() != 0:
5087 # STDERR should already be printed.
5088 return 'Command failed: ' + self._cmd
Sam Maiera6e76d72022-02-11 21:43:505089 if self._old_contents != new_contents:
5090 diff = '\n'.join(
5091 difflib.context_diff(self._old_contents, new_contents))
5092 return ('File is stale: {}\n'
5093 'Diff (apply to fix):\n'
5094 '{}\n'
5095 'To regenerate, run:\n\n'
5096 ' {}').format(self._pydeps_path, diff, self._cmd)
5097 return None
5098
5099
5100class PydepsChecker:
5101 def __init__(self, input_api, pydeps_files):
5102 self._file_cache = {}
5103 self._input_api = input_api
5104 self._pydeps_files = pydeps_files
5105
5106 def _LoadFile(self, path):
5107 """Returns the list of paths within a .pydeps file relative to //."""
5108 if path not in self._file_cache:
5109 with open(path, encoding='utf-8') as f:
5110 self._file_cache[path] = f.read()
5111 return self._file_cache[path]
5112
5113 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
Gao Shenga79ebd42022-08-08 17:25:595114 """Returns an iterable of paths within the .pydep, relativized to //."""
Sam Maiera6e76d72022-02-11 21:43:505115 pydeps_data = self._LoadFile(pydeps_path)
5116 uses_gn_paths = '--gn-paths' in pydeps_data
5117 entries = (l for l in pydeps_data.splitlines()
5118 if not l.startswith('#'))
5119 if uses_gn_paths:
5120 # Paths look like: //foo/bar/baz
5121 return (e[2:] for e in entries)
5122 else:
5123 # Paths look like: path/relative/to/file.pydeps
5124 os_path = self._input_api.os_path
5125 pydeps_dir = os_path.dirname(pydeps_path)
5126 return (os_path.normpath(os_path.join(pydeps_dir, e))
5127 for e in entries)
5128
5129 def _CreateFilesToPydepsMap(self):
5130 """Returns a map of local_path -> list_of_pydeps."""
5131 ret = {}
5132 for pydep_local_path in self._pydeps_files:
5133 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
5134 ret.setdefault(path, []).append(pydep_local_path)
5135 return ret
5136
5137 def ComputeAffectedPydeps(self):
5138 """Returns an iterable of .pydeps files that might need regenerating."""
5139 affected_pydeps = set()
5140 file_to_pydeps_map = None
5141 for f in self._input_api.AffectedFiles(include_deletes=True):
5142 local_path = f.LocalPath()
5143 # Changes to DEPS can lead to .pydeps changes if any .py files are in
5144 # subrepositories. We can't figure out which files change, so re-check
5145 # all files.
5146 # Changes to print_python_deps.py affect all .pydeps.
5147 if local_path in ('DEPS', 'PRESUBMIT.py'
5148 ) or local_path.endswith('print_python_deps.py'):
5149 return self._pydeps_files
5150 elif local_path.endswith('.pydeps'):
5151 if local_path in self._pydeps_files:
5152 affected_pydeps.add(local_path)
5153 elif local_path.endswith('.py'):
5154 if file_to_pydeps_map is None:
5155 file_to_pydeps_map = self._CreateFilesToPydepsMap()
5156 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
5157 return affected_pydeps
5158
5159 def DetermineIfStaleAsync(self, pydeps_path):
5160 """Runs print_python_deps.py to see if the files is stale."""
5161 import os
5162
5163 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
5164 if old_pydeps_data:
5165 cmd = old_pydeps_data[1][1:].strip()
5166 if '--output' not in cmd:
5167 cmd += ' --output ' + pydeps_path
5168 old_contents = old_pydeps_data[2:]
5169 else:
5170 # A default cmd that should work in most cases (as long as pydeps filename
5171 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
5172 # file is empty/new.
5173 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
5174 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
5175 old_contents = []
5176 env = dict(os.environ)
5177 env['PYTHONDONTWRITEBYTECODE'] = '1'
5178 process = self._input_api.subprocess.Popen(
5179 cmd + ' --output ""',
5180 shell=True,
5181 env=env,
5182 stdout=self._input_api.subprocess.PIPE,
5183 encoding='utf-8')
5184 return _PydepsCheckerResult(cmd, pydeps_path, process, old_contents)
agrievef32bcc72016-04-04 14:57:405185
5186
Tibor Goldschwendt360793f72019-06-25 18:23:495187def _ParseGclientArgs():
Sam Maiera6e76d72022-02-11 21:43:505188 args = {}
5189 with open('build/config/gclient_args.gni', 'r') as f:
5190 for line in f:
5191 line = line.strip()
5192 if not line or line.startswith('#'):
5193 continue
5194 attribute, value = line.split('=')
5195 args[attribute.strip()] = value.strip()
5196 return args
Tibor Goldschwendt360793f72019-06-25 18:23:495197
5198
Saagar Sanghavifceeaae2020-08-12 16:40:365199def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
Sam Maiera6e76d72022-02-11 21:43:505200 """Checks if a .pydeps file needs to be regenerated."""
5201 # This check is for Python dependency lists (.pydeps files), and involves
5202 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
5203 # doesn't work on Windows and Mac, so skip it on other platforms.
5204 if not input_api.platform.startswith('linux'):
5205 return []
Erik Staabc734cd7a2021-11-23 03:11:525206
Sam Maiera6e76d72022-02-11 21:43:505207 results = []
5208 # First, check for new / deleted .pydeps.
5209 for f in input_api.AffectedFiles(include_deletes=True):
5210 # Check whether we are running the presubmit check for a file in src.
Sam Maiera6e76d72022-02-11 21:43:505211 if f.LocalPath().endswith('.pydeps'):
Andrew Grieve713b89b2024-10-15 20:20:085212 # f.LocalPath is relative to repo (src, or internal repo).
5213 # os_path.exists is relative to src repo.
5214 # Therefore if os_path.exists is true, it means f.LocalPath is relative
5215 # to src and we can conclude that the pydeps is in src.
5216 exists = input_api.os_path.exists(f.LocalPath())
5217 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
5218 results.append(
5219 output_api.PresubmitError(
5220 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
5221 'remove %s' % f.LocalPath()))
5222 elif (f.Action() != 'D' and exists
5223 and f.LocalPath() not in _ALL_PYDEPS_FILES):
5224 results.append(
5225 output_api.PresubmitError(
5226 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
5227 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:405228
Sam Maiera6e76d72022-02-11 21:43:505229 if results:
5230 return results
5231
Gavin Mak23884402024-07-25 20:39:265232 try:
5233 parsed_args = _ParseGclientArgs()
5234 except FileNotFoundError:
5235 message = (
5236 'build/config/gclient_args.gni not found. Please make sure your '
5237 'workspace has been initialized with gclient sync.'
5238 )
5239 import sys
5240 original_sys_path = sys.path
5241 try:
5242 sys.path = sys.path + [
5243 input_api.os_path.join(input_api.PresubmitLocalPath(),
5244 'third_party', 'depot_tools')
5245 ]
5246 import gclient_utils
5247 if gclient_utils.IsEnvCog():
5248 # Users will always hit this when they run presubmits before cog
5249 # workspace initialization finishes. The check shouldn't fail in
5250 # this case. This is an unavoidable workaround that's needed for
5251 # good presubmit UX for cog.
5252 results.append(output_api.PresubmitPromptWarning(message))
5253 else:
5254 results.append(output_api.PresubmitError(message))
5255 return results
5256 finally:
5257 # Restore sys.path to what it was before.
5258 sys.path = original_sys_path
5259
5260 is_android = parsed_args.get('checkout_android', 'false') == 'true'
Sam Maiera6e76d72022-02-11 21:43:505261 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
5262 affected_pydeps = set(checker.ComputeAffectedPydeps())
5263 affected_android_pydeps = affected_pydeps.intersection(
5264 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
5265 if affected_android_pydeps and not is_android:
5266 results.append(
5267 output_api.PresubmitPromptOrNotify(
5268 'You have changed python files that may affect pydeps for android\n'
Gao Shenga79ebd42022-08-08 17:25:595269 'specific scripts. However, the relevant presubmit check cannot be\n'
Sam Maiera6e76d72022-02-11 21:43:505270 'run because you are not using an Android checkout. To validate that\n'
5271 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
5272 'use the android-internal-presubmit optional trybot.\n'
5273 'Possibly stale pydeps files:\n{}'.format(
5274 '\n'.join(affected_android_pydeps))))
5275
5276 all_pydeps = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
5277 pydeps_to_check = affected_pydeps.intersection(all_pydeps)
5278 # Process these concurrently, as each one takes 1-2 seconds.
5279 pydep_results = [checker.DetermineIfStaleAsync(p) for p in pydeps_to_check]
5280 for result in pydep_results:
5281 error_msg = result.GetError()
5282 if error_msg:
5283 results.append(output_api.PresubmitError(error_msg))
5284
agrievef32bcc72016-04-04 14:57:405285 return results
5286
agrievef32bcc72016-04-04 14:57:405287
Saagar Sanghavifceeaae2020-08-12 16:40:365288def CheckSingletonInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505289 """Checks to make sure no header files have |Singleton<|."""
5290
5291 def FileFilter(affected_file):
5292 # It's ok for base/memory/singleton.h to have |Singleton<|.
5293 files_to_skip = (_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
Bruce Dawson40fece62022-09-16 19:58:315294 (r"^base/memory/singleton\.h$",
5295 r"^net/quic/platform/impl/quic_singleton_impl\.h$"))
Sam Maiera6e76d72022-02-11 21:43:505296 return input_api.FilterSourceFile(affected_file,
5297 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:435298
Sam Maiera6e76d72022-02-11 21:43:505299 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
5300 files = []
5301 for f in input_api.AffectedSourceFiles(FileFilter):
5302 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx')
5303 or f.LocalPath().endswith('.hpp')
5304 or f.LocalPath().endswith('.inl')):
5305 contents = input_api.ReadFile(f)
5306 for line in contents.splitlines(False):
5307 if (not line.lstrip().startswith('//')
5308 and # Strip C++ comment.
5309 pattern.search(line)):
5310 files.append(f)
5311 break
glidere61efad2015-02-18 17:39:435312
Sam Maiera6e76d72022-02-11 21:43:505313 if files:
5314 return [
5315 output_api.PresubmitError(
5316 'Found base::Singleton<T> in the following header files.\n' +
5317 'Please move them to an appropriate source file so that the ' +
5318 'template gets instantiated in a single compilation unit.',
5319 files)
5320 ]
5321 return []
glidere61efad2015-02-18 17:39:435322
5323
[email protected]fd20b902014-05-09 02:14:535324_DEPRECATED_CSS = [
5325 # Values
5326 ( "-webkit-box", "flex" ),
5327 ( "-webkit-inline-box", "inline-flex" ),
5328 ( "-webkit-flex", "flex" ),
5329 ( "-webkit-inline-flex", "inline-flex" ),
5330 ( "-webkit-min-content", "min-content" ),
5331 ( "-webkit-max-content", "max-content" ),
5332
5333 # Properties
5334 ( "-webkit-background-clip", "background-clip" ),
5335 ( "-webkit-background-origin", "background-origin" ),
5336 ( "-webkit-background-size", "background-size" ),
5337 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:445338 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:535339
5340 # Functions
5341 ( "-webkit-gradient", "gradient" ),
5342 ( "-webkit-repeating-gradient", "repeating-gradient" ),
5343 ( "-webkit-linear-gradient", "linear-gradient" ),
5344 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
5345 ( "-webkit-radial-gradient", "radial-gradient" ),
5346 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
5347]
5348
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:205349
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:495350# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:365351def CheckNoDeprecatedCss(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505352 """ Make sure that we don't use deprecated CSS
5353 properties, functions or values. Our external
5354 documentation and iOS CSS for dom distiller
5355 (reader mode) are ignored by the hooks as it
5356 needs to be consumed by WebKit. """
5357 results = []
5358 file_inclusion_pattern = [r".+\.css$"]
5359 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
5360 input_api.DEFAULT_FILES_TO_SKIP +
dpapad7fcdfc42024-12-06 01:21:385361 (# Legacy CSS file using deprecated CSS.
5362 r"^chrome/browser/resources/chromeos/arc_support/cr_overlay.css$",
5363 r"^chrome/common/extensions/docs", r"^chrome/docs",
Teresa Mao1d910882024-04-26 21:06:255364 r"^native_client_sdk",
5365 # The NTP team prefers reserving -webkit-line-clamp for
5366 # ellipsis effect which can only be used with -webkit-box.
5367 r"ui/webui/resources/cr_components/most_visited/.*\.css$"))
Sam Maiera6e76d72022-02-11 21:43:505368 file_filter = lambda f: input_api.FilterSourceFile(
5369 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
5370 for fpath in input_api.AffectedFiles(file_filter=file_filter):
5371 for line_num, line in fpath.ChangedContents():
5372 for (deprecated_value, value) in _DEPRECATED_CSS:
5373 if deprecated_value in line:
5374 results.append(
5375 output_api.PresubmitError(
5376 "%s:%d: Use of deprecated CSS %s, use %s instead" %
5377 (fpath.LocalPath(), line_num, deprecated_value,
5378 value)))
5379 return results
[email protected]fd20b902014-05-09 02:14:535380
mohan.reddyf21db962014-10-16 12:26:475381
Saagar Sanghavifceeaae2020-08-12 16:40:365382def CheckForRelativeIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505383 bad_files = {}
5384 for f in input_api.AffectedFiles(include_deletes=False):
Anton Bershanskyi4253349482025-02-11 21:01:275385 if (f.UnixLocalPath().startswith('third_party')
5386 and not f.LocalPath().startswith('third_party/blink')):
Sam Maiera6e76d72022-02-11 21:43:505387 continue
rlanday6802cf632017-05-30 17:48:365388
Sam Maiera6e76d72022-02-11 21:43:505389 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
5390 continue
rlanday6802cf632017-05-30 17:48:365391
Sam Maiera6e76d72022-02-11 21:43:505392 relative_includes = [
5393 line for _, line in f.ChangedContents()
5394 if "#include" in line and "../" in line
5395 ]
5396 if not relative_includes:
5397 continue
5398 bad_files[f.LocalPath()] = relative_includes
rlanday6802cf632017-05-30 17:48:365399
Sam Maiera6e76d72022-02-11 21:43:505400 if not bad_files:
5401 return []
rlanday6802cf632017-05-30 17:48:365402
Sam Maiera6e76d72022-02-11 21:43:505403 error_descriptions = []
5404 for file_path, bad_lines in bad_files.items():
5405 error_description = file_path
5406 for line in bad_lines:
5407 error_description += '\n ' + line
5408 error_descriptions.append(error_description)
rlanday6802cf632017-05-30 17:48:365409
Sam Maiera6e76d72022-02-11 21:43:505410 results = []
5411 results.append(
5412 output_api.PresubmitError(
5413 'You added one or more relative #include paths (including "../").\n'
5414 'These shouldn\'t be used because they can be used to include headers\n'
5415 'from code that\'s not correctly specified as a dependency in the\n'
5416 'relevant BUILD.gn file(s).', error_descriptions))
rlanday6802cf632017-05-30 17:48:365417
Sam Maiera6e76d72022-02-11 21:43:505418 return results
rlanday6802cf632017-05-30 17:48:365419
Takeshi Yoshinoe387aa32017-08-02 13:16:135420
Saagar Sanghavifceeaae2020-08-12 16:40:365421def CheckForCcIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505422 """Check that nobody tries to include a cc file. It's a relatively
5423 common error which results in duplicate symbols in object
5424 files. This may not always break the build until someone later gets
5425 very confusing linking errors."""
5426 results = []
5427 for f in input_api.AffectedFiles(include_deletes=False):
5428 # We let third_party code do whatever it wants
Anton Bershanskyi4253349482025-02-11 21:01:275429 if (f.UnixLocalPath().startswith('third_party')
5430 and not f.LocalPath().startswith('third_party/blink')):
Sam Maiera6e76d72022-02-11 21:43:505431 continue
Daniel Bratell65b033262019-04-23 08:17:065432
Sam Maiera6e76d72022-02-11 21:43:505433 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
5434 continue
Daniel Bratell65b033262019-04-23 08:17:065435
Sam Maiera6e76d72022-02-11 21:43:505436 for _, line in f.ChangedContents():
5437 if line.startswith('#include "'):
5438 included_file = line.split('"')[1]
5439 if _IsCPlusPlusFile(input_api, included_file):
5440 # The most common naming for external files with C++ code,
5441 # apart from standard headers, is to call them foo.inc, but
5442 # Chromium sometimes uses foo-inc.cc so allow that as well.
5443 if not included_file.endswith(('.h', '-inc.cc')):
5444 results.append(
5445 output_api.PresubmitError(
5446 'Only header files or .inc files should be included in other\n'
5447 'C++ files. Compiling the contents of a cc file more than once\n'
5448 'will cause duplicate information in the build which may later\n'
5449 'result in strange link_errors.\n' +
5450 f.LocalPath() + ':\n ' + line))
Daniel Bratell65b033262019-04-23 08:17:065451
Sam Maiera6e76d72022-02-11 21:43:505452 return results
Daniel Bratell65b033262019-04-23 08:17:065453
5454
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205455def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
Sam Maiera6e76d72022-02-11 21:43:505456 if not isinstance(key, ast.Str):
5457 return 'Key at line %d must be a string literal' % key.lineno
5458 if not isinstance(value, ast.Dict):
5459 return 'Value at line %d must be a dict' % value.lineno
5460 if len(value.keys) != 1:
5461 return 'Dict at line %d must have single entry' % value.lineno
5462 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
5463 return (
5464 'Entry at line %d must have a string literal \'filepath\' as key' %
5465 value.lineno)
5466 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:135467
Takeshi Yoshinoe387aa32017-08-02 13:16:135468
Sergey Ulanov4af16052018-11-08 02:41:465469def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Sam Maiera6e76d72022-02-11 21:43:505470 if not isinstance(key, ast.Str):
5471 return 'Key at line %d must be a string literal' % key.lineno
5472 if not isinstance(value, ast.List):
5473 return 'Value at line %d must be a list' % value.lineno
5474 for element in value.elts:
5475 if not isinstance(element, ast.Str):
5476 return 'Watchlist elements on line %d is not a string' % key.lineno
5477 if not email_regex.match(element.s):
5478 return ('Watchlist element on line %d doesn\'t look like a valid '
5479 + 'email: %s') % (key.lineno, element.s)
5480 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:135481
Takeshi Yoshinoe387aa32017-08-02 13:16:135482
Sergey Ulanov4af16052018-11-08 02:41:465483def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Sam Maiera6e76d72022-02-11 21:43:505484 mismatch_template = (
5485 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
5486 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:135487
Sam Maiera6e76d72022-02-11 21:43:505488 email_regex = input_api.re.compile(
5489 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
Sergey Ulanov4af16052018-11-08 02:41:465490
Sam Maiera6e76d72022-02-11 21:43:505491 ast = input_api.ast
5492 i = 0
5493 last_key = ''
5494 while True:
5495 if i >= len(wd_dict.keys):
5496 if i >= len(w_dict.keys):
5497 return None
5498 return mismatch_template % ('missing',
5499 'line %d' % w_dict.keys[i].lineno)
5500 elif i >= len(w_dict.keys):
5501 return (mismatch_template %
5502 ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:135503
Sam Maiera6e76d72022-02-11 21:43:505504 wd_key = wd_dict.keys[i]
5505 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:135506
Sam Maiera6e76d72022-02-11 21:43:505507 result = _CheckWatchlistDefinitionsEntrySyntax(wd_key,
5508 wd_dict.values[i], ast)
5509 if result is not None:
5510 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:135511
Sam Maiera6e76d72022-02-11 21:43:505512 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast,
5513 email_regex)
5514 if result is not None:
5515 return 'Bad entry in WATCHLISTS dict: %s' % result
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205516
Sam Maiera6e76d72022-02-11 21:43:505517 if wd_key.s != w_key.s:
5518 return mismatch_template % ('%s at line %d' %
5519 (wd_key.s, wd_key.lineno),
5520 '%s at line %d' %
5521 (w_key.s, w_key.lineno))
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205522
Sam Maiera6e76d72022-02-11 21:43:505523 if wd_key.s < last_key:
5524 return (
5525 'WATCHLISTS dict is not sorted lexicographically at line %d and %d'
5526 % (wd_key.lineno, w_key.lineno))
5527 last_key = wd_key.s
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205528
Sam Maiera6e76d72022-02-11 21:43:505529 i = i + 1
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205530
5531
Sergey Ulanov4af16052018-11-08 02:41:465532def _CheckWATCHLISTSSyntax(expression, input_api):
Sam Maiera6e76d72022-02-11 21:43:505533 ast = input_api.ast
5534 if not isinstance(expression, ast.Expression):
5535 return 'WATCHLISTS file must contain a valid expression'
5536 dictionary = expression.body
5537 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
5538 return 'WATCHLISTS file must have single dict with exactly two entries'
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205539
Sam Maiera6e76d72022-02-11 21:43:505540 first_key = dictionary.keys[0]
5541 first_value = dictionary.values[0]
5542 second_key = dictionary.keys[1]
5543 second_value = dictionary.values[1]
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205544
Sam Maiera6e76d72022-02-11 21:43:505545 if (not isinstance(first_key, ast.Str)
5546 or first_key.s != 'WATCHLIST_DEFINITIONS'
5547 or not isinstance(first_value, ast.Dict)):
5548 return ('The first entry of the dict in WATCHLISTS file must be '
5549 'WATCHLIST_DEFINITIONS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205550
Sam Maiera6e76d72022-02-11 21:43:505551 if (not isinstance(second_key, ast.Str) or second_key.s != 'WATCHLISTS'
5552 or not isinstance(second_value, ast.Dict)):
5553 return ('The second entry of the dict in WATCHLISTS file must be '
5554 'WATCHLISTS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205555
Sam Maiera6e76d72022-02-11 21:43:505556 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:135557
5558
Saagar Sanghavifceeaae2020-08-12 16:40:365559def CheckWATCHLISTS(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505560 for f in input_api.AffectedFiles(include_deletes=False):
5561 if f.LocalPath() == 'WATCHLISTS':
5562 contents = input_api.ReadFile(f, 'r')
Takeshi Yoshinoe387aa32017-08-02 13:16:135563
Sam Maiera6e76d72022-02-11 21:43:505564 try:
5565 # First, make sure that it can be evaluated.
5566 input_api.ast.literal_eval(contents)
5567 # Get an AST tree for it and scan the tree for detailed style checking.
5568 expression = input_api.ast.parse(contents,
5569 filename='WATCHLISTS',
5570 mode='eval')
5571 except ValueError as e:
5572 return [
5573 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5574 long_text=repr(e))
5575 ]
5576 except SyntaxError as e:
5577 return [
5578 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5579 long_text=repr(e))
5580 ]
5581 except TypeError as e:
5582 return [
5583 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5584 long_text=repr(e))
5585 ]
Takeshi Yoshinoe387aa32017-08-02 13:16:135586
Sam Maiera6e76d72022-02-11 21:43:505587 result = _CheckWATCHLISTSSyntax(expression, input_api)
5588 if result is not None:
5589 return [output_api.PresubmitError(result)]
5590 break
Takeshi Yoshinoe387aa32017-08-02 13:16:135591
Sam Maiera6e76d72022-02-11 21:43:505592 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:135593
Sean Kaucb7c9b32022-10-25 21:25:525594def CheckGnRebasePath(input_api, output_api):
Terrence Reilly313f44ff2025-01-22 15:10:145595 """Checks that target_gen_dir is not used with "//" in rebase_path().
Sean Kaucb7c9b32022-10-25 21:25:525596
5597 Developers should use root_build_dir instead of "//" when using target_gen_dir because
5598 Chromium is sometimes built outside of the source tree.
5599 """
5600
5601 def gn_files(f):
5602 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
5603
5604 rebase_path_regex = input_api.re.compile(r'rebase_path\(("\$target_gen_dir"|target_gen_dir), ("/"|"//")\)')
5605 problems = []
5606 for f in input_api.AffectedSourceFiles(gn_files):
5607 for line_num, line in f.ChangedContents():
5608 if rebase_path_regex.search(line):
5609 problems.append(
5610 'Absolute path in rebase_path() in %s:%d' %
5611 (f.LocalPath(), line_num))
5612
5613 if problems:
5614 return [
5615 output_api.PresubmitPromptWarning(
5616 'Using an absolute path in rebase_path()',
5617 items=sorted(problems),
5618 long_text=(
5619 'rebase_path() should use root_build_dir instead of "/" ',
5620 'since builds can be initiated from outside of the source ',
5621 'root.'))
5622 ]
5623 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:135624
Andrew Grieve1b290e4a22020-11-24 20:07:015625def CheckGnGlobForward(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505626 """Checks that forward_variables_from(invoker, "*") follows best practices.
Andrew Grieve1b290e4a22020-11-24 20:07:015627
Sam Maiera6e76d72022-02-11 21:43:505628 As documented at //build/docs/writing_gn_templates.md
5629 """
Andrew Grieve1b290e4a22020-11-24 20:07:015630
Sam Maiera6e76d72022-02-11 21:43:505631 def gn_files(f):
5632 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
Andrew Grieve1b290e4a22020-11-24 20:07:015633
Sam Maiera6e76d72022-02-11 21:43:505634 problems = []
5635 for f in input_api.AffectedSourceFiles(gn_files):
5636 for line_num, line in f.ChangedContents():
5637 if 'forward_variables_from(invoker, "*")' in line:
5638 problems.append(
5639 'Bare forward_variables_from(invoker, "*") in %s:%d' %
5640 (f.LocalPath(), line_num))
5641
5642 if problems:
5643 return [
5644 output_api.PresubmitPromptWarning(
5645 'forward_variables_from("*") without exclusions',
5646 items=sorted(problems),
5647 long_text=(
Gao Shenga79ebd42022-08-08 17:25:595648 'The variables "visibility" and "test_only" should be '
Sam Maiera6e76d72022-02-11 21:43:505649 'explicitly listed in forward_variables_from(). For more '
5650 'details, see:\n'
5651 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
5652 'build/docs/writing_gn_templates.md'
5653 '#Using-forward_variables_from'))
5654 ]
5655 return []
Andrew Grieve1b290e4a22020-11-24 20:07:015656
Saagar Sanghavifceeaae2020-08-12 16:40:365657def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505658 """Checks that newly added header files have corresponding GN changes.
5659 Note that this is only a heuristic. To be precise, run script:
5660 build/check_gn_headers.py.
5661 """
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195662
Sam Maiera6e76d72022-02-11 21:43:505663 def headers(f):
5664 return input_api.FilterSourceFile(
5665 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195666
Sam Maiera6e76d72022-02-11 21:43:505667 new_headers = []
5668 for f in input_api.AffectedSourceFiles(headers):
5669 if f.Action() != 'A':
5670 continue
5671 new_headers.append(f.LocalPath())
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195672
Sam Maiera6e76d72022-02-11 21:43:505673 def gn_files(f):
5674 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195675
Sam Maiera6e76d72022-02-11 21:43:505676 all_gn_changed_contents = ''
5677 for f in input_api.AffectedSourceFiles(gn_files):
5678 for _, line in f.ChangedContents():
5679 all_gn_changed_contents += line
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195680
Sam Maiera6e76d72022-02-11 21:43:505681 problems = []
5682 for header in new_headers:
5683 basename = input_api.os_path.basename(header)
5684 if basename not in all_gn_changed_contents:
5685 problems.append(header)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195686
Sam Maiera6e76d72022-02-11 21:43:505687 if problems:
5688 return [
5689 output_api.PresubmitPromptWarning(
5690 'Missing GN changes for new header files',
5691 items=sorted(problems),
5692 long_text=
5693 'Please double check whether newly added header files need '
5694 'corresponding changes in gn or gni files.\nThis checking is only a '
5695 'heuristic. Run build/check_gn_headers.py to be precise.\n'
5696 'Read https://crbug.com/661774 for more info.')
5697 ]
5698 return []
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195699
5700
Saagar Sanghavifceeaae2020-08-12 16:40:365701def CheckCorrectProductNameInMessages(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505702 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
Michael Giuffridad3bc8672018-10-25 22:48:025703
Sam Maiera6e76d72022-02-11 21:43:505704 This assumes we won't intentionally reference one product from the other
5705 product.
5706 """
5707 all_problems = []
5708 test_cases = [{
5709 "filename_postfix": "google_chrome_strings.grd",
5710 "correct_name": "Chrome",
5711 "incorrect_name": "Chromium",
5712 }, {
Thiago Perrotta099034f2023-06-05 18:10:205713 "filename_postfix": "google_chrome_strings.grd",
5714 "correct_name": "Chrome",
5715 "incorrect_name": "Chrome for Testing",
5716 }, {
Sam Maiera6e76d72022-02-11 21:43:505717 "filename_postfix": "chromium_strings.grd",
5718 "correct_name": "Chromium",
5719 "incorrect_name": "Chrome",
5720 }]
Michael Giuffridad3bc8672018-10-25 22:48:025721
Sam Maiera6e76d72022-02-11 21:43:505722 for test_case in test_cases:
5723 problems = []
5724 filename_filter = lambda x: x.LocalPath().endswith(test_case[
5725 "filename_postfix"])
Michael Giuffridad3bc8672018-10-25 22:48:025726
Sam Maiera6e76d72022-02-11 21:43:505727 # Check each new line. Can yield false positives in multiline comments, but
5728 # easier than trying to parse the XML because messages can have nested
5729 # children, and associating message elements with affected lines is hard.
5730 for f in input_api.AffectedSourceFiles(filename_filter):
5731 for line_num, line in f.ChangedContents():
5732 if "<message" in line or "<!--" in line or "-->" in line:
5733 continue
5734 if test_case["incorrect_name"] in line:
Thiago Perrotta099034f2023-06-05 18:10:205735 # Chrome for Testing is a special edge case: https://goo.gle/chrome-for-testing#bookmark=id.n1rat320av91
5736 if (test_case["correct_name"] == "Chromium" and line.count("Chrome") == line.count("Chrome for Testing")):
5737 continue
Sam Maiera6e76d72022-02-11 21:43:505738 problems.append("Incorrect product name in %s:%d" %
5739 (f.LocalPath(), line_num))
Michael Giuffridad3bc8672018-10-25 22:48:025740
Sam Maiera6e76d72022-02-11 21:43:505741 if problems:
5742 message = (
5743 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
5744 % (test_case["correct_name"], test_case["correct_name"],
5745 test_case["incorrect_name"]))
5746 all_problems.append(
5747 output_api.PresubmitPromptWarning(message, items=problems))
Michael Giuffridad3bc8672018-10-25 22:48:025748
Sam Maiera6e76d72022-02-11 21:43:505749 return all_problems
Michael Giuffridad3bc8672018-10-25 22:48:025750
5751
Saagar Sanghavifceeaae2020-08-12 16:40:365752def CheckForTooLargeFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505753 """Avoid large files, especially binary files, in the repository since
5754 git doesn't scale well for those. They will be in everyone's repo
5755 clones forever, forever making Chromium slower to clone and work
5756 with."""
Daniel Bratell93eb6c62019-04-29 20:13:365757
Sam Maiera6e76d72022-02-11 21:43:505758 # Uploading files to cloud storage is not trivial so we don't want
5759 # to set the limit too low, but the upper limit for "normal" large
5760 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
5761 # anything over 20 MB is exceptional.
Bruce Dawsonbb414db2022-12-27 20:21:255762 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024
Daniel Bratell93eb6c62019-04-29 20:13:365763
Sam Maiera6e76d72022-02-11 21:43:505764 too_large_files = []
5765 for f in input_api.AffectedFiles():
5766 # Check both added and modified files (but not deleted files).
5767 if f.Action() in ('A', 'M'):
5768 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Joe DeBlasio10a832f2023-04-21 20:20:185769 if size > TOO_LARGE_FILE_SIZE_LIMIT:
Sam Maiera6e76d72022-02-11 21:43:505770 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
Daniel Bratell93eb6c62019-04-29 20:13:365771
Sam Maiera6e76d72022-02-11 21:43:505772 if too_large_files:
5773 message = (
5774 'Do not commit large files to git since git scales badly for those.\n'
5775 +
5776 'Instead put the large files in cloud storage and use DEPS to\n' +
5777 'fetch them.\n' + '\n'.join(too_large_files))
5778 return [
5779 output_api.PresubmitError('Too large files found in commit',
5780 long_text=message + '\n')
5781 ]
5782 else:
5783 return []
Daniel Bratell93eb6c62019-04-29 20:13:365784
Max Morozb47503b2019-08-08 21:03:275785
Saagar Sanghavifceeaae2020-08-12 16:40:365786def CheckFuzzTargetsOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505787 """Checks specific for fuzz target sources."""
5788 EXPORTED_SYMBOLS = [
5789 'LLVMFuzzerInitialize',
5790 'LLVMFuzzerCustomMutator',
5791 'LLVMFuzzerCustomCrossOver',
5792 'LLVMFuzzerMutate',
5793 ]
Max Morozb47503b2019-08-08 21:03:275794
Sam Maiera6e76d72022-02-11 21:43:505795 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
Max Morozb47503b2019-08-08 21:03:275796
Sam Maiera6e76d72022-02-11 21:43:505797 def FilterFile(affected_file):
5798 """Ignore libFuzzer source code."""
5799 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
Bruce Dawson40fece62022-09-16 19:58:315800 files_to_skip = r"^third_party/libFuzzer"
Max Morozb47503b2019-08-08 21:03:275801
Sam Maiera6e76d72022-02-11 21:43:505802 return input_api.FilterSourceFile(affected_file,
5803 files_to_check=[files_to_check],
5804 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:275805
Sam Maiera6e76d72022-02-11 21:43:505806 files_with_missing_header = []
5807 for f in input_api.AffectedSourceFiles(FilterFile):
5808 contents = input_api.ReadFile(f, 'r')
5809 if REQUIRED_HEADER in contents:
5810 continue
Max Morozb47503b2019-08-08 21:03:275811
Sam Maiera6e76d72022-02-11 21:43:505812 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
5813 files_with_missing_header.append(f.LocalPath())
Max Morozb47503b2019-08-08 21:03:275814
Sam Maiera6e76d72022-02-11 21:43:505815 if not files_with_missing_header:
5816 return []
Max Morozb47503b2019-08-08 21:03:275817
Sam Maiera6e76d72022-02-11 21:43:505818 long_text = (
5819 'If you define any of the libFuzzer optional functions (%s), it is '
5820 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
5821 'work incorrectly on Mac (crbug.com/687076).\nNote that '
5822 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
5823 'to access command line arguments passed to the fuzzer. Instead, prefer '
5824 'static initialization and shared resources as documented in '
5825 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
5826 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n'
5827 % (', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER))
Max Morozb47503b2019-08-08 21:03:275828
Sam Maiera6e76d72022-02-11 21:43:505829 return [
5830 output_api.PresubmitPromptWarning(message="Missing '%s' in:" %
5831 REQUIRED_HEADER,
5832 items=files_with_missing_header,
5833 long_text=long_text)
5834 ]
Max Morozb47503b2019-08-08 21:03:275835
5836
Mohamed Heikald048240a2019-11-12 16:57:375837def _CheckNewImagesWarning(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505838 """
5839 Warns authors who add images into the repo to make sure their images are
5840 optimized before committing.
5841 """
5842 images_added = False
5843 image_paths = []
5844 errors = []
5845 filter_lambda = lambda x: input_api.FilterSourceFile(
5846 x,
5847 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
5848 DEFAULT_FILES_TO_SKIP),
5849 files_to_check=[r'.*\/(drawable|mipmap)'])
5850 for f in input_api.AffectedFiles(include_deletes=False,
5851 file_filter=filter_lambda):
5852 local_path = f.LocalPath().lower()
5853 if any(
5854 local_path.endswith(extension)
5855 for extension in _IMAGE_EXTENSIONS):
5856 images_added = True
5857 image_paths.append(f)
5858 if images_added:
5859 errors.append(
5860 output_api.PresubmitPromptWarning(
5861 'It looks like you are trying to commit some images. If these are '
5862 'non-test-only images, please make sure to read and apply the tips in '
5863 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
5864 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
5865 'FYI only and will not block your CL on the CQ.', image_paths))
5866 return errors
Mohamed Heikald048240a2019-11-12 16:57:375867
5868
Saagar Sanghavifceeaae2020-08-12 16:40:365869def ChecksAndroidSpecificOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505870 """Groups upload checks that target android code."""
5871 results = []
5872 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
5873 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
5874 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
5875 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505876 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
5877 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
5878 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
5879 results.extend(_CheckNewImagesWarning(input_api, output_api))
5880 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
5881 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
5882 return results
5883
Becky Zhou7c69b50992018-12-10 19:37:575884
Saagar Sanghavifceeaae2020-08-12 16:40:365885def ChecksAndroidSpecificOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505886 """Groups commit checks that target android code."""
5887 results = []
5888 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
5889 return results
dgnaa68d5e2015-06-10 10:08:225890
Chris Hall59f8d0c72020-05-01 07:31:195891# TODO(chrishall): could we additionally match on any path owned by
5892# ui/accessibility/OWNERS ?
5893_ACCESSIBILITY_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:315894 r"^chrome/browser.*/accessibility/",
5895 r"^chrome/browser/extensions/api/automation.*/",
5896 r"^chrome/renderer/extensions/accessibility_.*",
5897 r"^chrome/tests/data/accessibility/",
5898 r"^content/browser/accessibility/",
5899 r"^content/renderer/accessibility/",
5900 r"^content/tests/data/accessibility/",
5901 r"^extensions/renderer/api/automation/",
Katie Dektar58ef07b2022-09-27 13:19:175902 r"^services/accessibility/",
Abigail Klein7a63c572024-02-28 20:45:095903 r"^services/screen_ai/",
Bruce Dawson40fece62022-09-16 19:58:315904 r"^ui/accessibility/",
5905 r"^ui/views/accessibility/",
Chris Hall59f8d0c72020-05-01 07:31:195906)
5907
Saagar Sanghavifceeaae2020-08-12 16:40:365908def CheckAccessibilityRelnotesField(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505909 """Checks that commits to accessibility code contain an AX-Relnotes field in
5910 their commit message."""
Chris Hall59f8d0c72020-05-01 07:31:195911
Sam Maiera6e76d72022-02-11 21:43:505912 def FileFilter(affected_file):
5913 paths = _ACCESSIBILITY_PATHS
5914 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:195915
Sam Maiera6e76d72022-02-11 21:43:505916 # Only consider changes affecting accessibility paths.
5917 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
5918 return []
Akihiro Ota08108e542020-05-20 15:30:535919
Sam Maiera6e76d72022-02-11 21:43:505920 # AX-Relnotes can appear in either the description or the footer.
5921 # When searching the description, require 'AX-Relnotes:' to appear at the
5922 # beginning of a line.
5923 ax_regex = input_api.re.compile('ax-relnotes[:=]')
5924 description_has_relnotes = any(
5925 ax_regex.match(line)
5926 for line in input_api.change.DescriptionText().lower().splitlines())
Chris Hall59f8d0c72020-05-01 07:31:195927
Sam Maiera6e76d72022-02-11 21:43:505928 footer_relnotes = input_api.change.GitFootersFromDescription().get(
5929 'AX-Relnotes', [])
5930 if description_has_relnotes or footer_relnotes:
5931 return []
Chris Hall59f8d0c72020-05-01 07:31:195932
Sam Maiera6e76d72022-02-11 21:43:505933 # TODO(chrishall): link to Relnotes documentation in message.
5934 message = (
5935 "Missing 'AX-Relnotes:' field required for accessibility changes"
5936 "\n please add 'AX-Relnotes: [release notes].' to describe any "
5937 "user-facing changes"
5938 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
5939 "user-facing effects"
5940 "\n if this is confusing or annoying then please contact members "
5941 "of ui/accessibility/OWNERS.")
5942
5943 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:225944
Mark Schillaci44c90b42024-11-22 20:44:385945
5946_ACCESSIBILITY_ARIA_METHOD_CANDIDATES_PATTERNS = r'(\-\>|\.)(get|has|FastGet|FastHas)Attribute\('
5947
5948_ACCESSIBILITY_ARIA_BAD_PARAMS_PATTERNS = (
5949 r"\(html_names::kAria(.*)Attr\)",
5950 r"\(html_names::kRoleAttr\)"
5951)
5952
5953_ACCESSIBILITY_ARIA_FILE_CANDIDATES_PATTERNS = (
5954 r".*/accessibility/.*.(cc|h)",
5955 r".*/ax_.*.(cc|h)"
5956)
5957
5958def CheckAccessibilityAriaElementAttributeGetters(input_api, output_api):
5959 """Checks that the blink accessibility code follows the defined patterns
5960 for checking aria attributes, so that ElementInternals is not bypassed."""
5961
5962 # Limit to accessibility-related files.
5963 def FileFilter(affected_file):
5964 paths = _ACCESSIBILITY_ARIA_FILE_CANDIDATES_PATTERNS
5965 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
5966
5967 aria_method_regex = input_api.re.compile(_ACCESSIBILITY_ARIA_METHOD_CANDIDATES_PATTERNS)
5968 aria_bad_params_regex = input_api.re.compile(
5969 "|".join(_ACCESSIBILITY_ARIA_BAD_PARAMS_PATTERNS)
5970 )
5971 problems = []
5972
5973 for f in input_api.AffectedSourceFiles(FileFilter):
5974 for line_num, line in f.ChangedContents():
5975 if aria_method_regex.search(line) and aria_bad_params_regex.search(line):
5976 problems.append(f"{f.LocalPath()}:{line_num}\n {line.strip()}")
5977
5978 if problems:
5979 return [
5980 output_api.PresubmitPromptWarning(
5981 "Accessibility code should not use element methods to get or check"
5982 "\nthe presence of aria attributes"
5983 "\nPlease use ARIA-specific attribute access, e.g. HasAriaAttribute(),"
5984 "\nAriaTokenAttribute(), AriaBoolAttribute(), AriaBooleanAttribute(),"
5985 "\nAriaFloatAttribute().",
5986 problems,
5987 )
5988 ]
5989 return []
5990
seanmccullough4a9356252021-04-08 19:54:095991# string pattern, sequence of strings to show when pattern matches,
5992# error flag. True if match is a presubmit error, otherwise it's a warning.
5993_NON_INCLUSIVE_TERMS = (
5994 (
5995 # Note that \b pattern in python re is pretty particular. In this
5996 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
5997 # ...' will not. This may require some tweaking to catch these cases
5998 # without triggering a lot of false positives. Leaving it naive and
5999 # less matchy for now.
Josip Sokcevic9d2806a02023-12-13 03:04:026000 r'/(?i)\b((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:096001 (
6002 'Please don\'t use blacklist, whitelist, ' # nocheck
6003 'or slave in your', # nocheck
6004 'code and make every effort to use other terms. Using "// nocheck"',
6005 '"# nocheck" or "<!-- nocheck -->"',
6006 'at the end of the offending line will bypass this PRESUBMIT error',
6007 'but avoid using this whenever possible. Reach out to',
6008 '[email protected] if you have questions'),
6009 True),)
6010
Saagar Sanghavifceeaae2020-08-12 16:40:366011def ChecksCommon(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506012 """Checks common to both upload and commit."""
6013 results = []
Eric Boren6fd2b932018-01-25 15:05:086014 results.extend(
Sam Maiera6e76d72022-02-11 21:43:506015 input_api.canned_checks.PanProjectChecks(
6016 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:086017
Sam Maiera6e76d72022-02-11 21:43:506018 author = input_api.change.author_email
6019 if author and author not in _KNOWN_ROBOTS:
6020 results.extend(
6021 input_api.canned_checks.CheckAuthorizedAuthor(
6022 input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:246023
Sam Maiera6e76d72022-02-11 21:43:506024 results.extend(
6025 input_api.canned_checks.CheckChangeHasNoTabs(
6026 input_api,
6027 output_api,
6028 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
6029 results.extend(
6030 input_api.RunTests(
6031 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Edward Lesmesce51df52020-08-04 22:10:176032
Bruce Dawsonc8054482022-03-28 15:33:376033 dirmd = 'dirmd.bat' if input_api.is_windows else 'dirmd'
Sam Maiera6e76d72022-02-11 21:43:506034 dirmd_bin = input_api.os_path.join(input_api.PresubmitLocalPath(),
Bruce Dawsonc8054482022-03-28 15:33:376035 'third_party', 'depot_tools', dirmd)
Sam Maiera6e76d72022-02-11 21:43:506036 results.extend(
6037 input_api.RunTests(
6038 input_api.canned_checks.CheckDirMetadataFormat(
6039 input_api, output_api, dirmd_bin)))
6040 results.extend(
6041 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
6042 input_api, output_api))
6043 results.extend(
6044 input_api.canned_checks.CheckNoNewMetadataInOwners(
6045 input_api, output_api))
6046 results.extend(
6047 input_api.canned_checks.CheckInclusiveLanguage(
6048 input_api,
6049 output_api,
6050 excluded_directories_relative_path=[
6051 'infra', 'inclusive_language_presubmit_exempt_dirs.txt'
6052 ],
6053 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Dirk Prankee3c9c62d2021-05-18 18:35:596054
Aleksey Khoroshilov2978c942022-06-13 16:14:126055 presubmit_py_filter = lambda f: input_api.FilterSourceFile(
Bruce Dawson696963f2022-09-13 01:15:476056 f, files_to_check=[r'.*PRESUBMIT\.py$'])
Aleksey Khoroshilov2978c942022-06-13 16:14:126057 for f in input_api.AffectedFiles(include_deletes=False,
6058 file_filter=presubmit_py_filter):
6059 full_path = input_api.os_path.dirname(f.AbsoluteLocalPath())
6060 test_file = input_api.os_path.join(full_path, 'PRESUBMIT_test.py')
6061 # The PRESUBMIT.py file (and the directory containing it) might have
6062 # been affected by being moved or removed, so only try to run the tests
6063 # if they still exist.
6064 if not input_api.os_path.exists(test_file):
6065 continue
Sam Maiera6e76d72022-02-11 21:43:506066
Aleksey Khoroshilov2978c942022-06-13 16:14:126067 results.extend(
6068 input_api.canned_checks.RunUnitTestsInDirectory(
6069 input_api,
6070 output_api,
6071 full_path,
Takuto Ikuta40def482023-06-02 02:23:496072 files_to_check=[r'^PRESUBMIT_test\.py$']))
Sam Maiera6e76d72022-02-11 21:43:506073 return results
[email protected]1f7b4172010-01-28 01:17:346074
[email protected]b337cb5b2011-01-23 21:24:056075
Saagar Sanghavifceeaae2020-08-12 16:40:366076def CheckPatchFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506077 problems = [
6078 f.LocalPath() for f in input_api.AffectedFiles()
6079 if f.LocalPath().endswith(('.orig', '.rej'))
6080 ]
6081 # Cargo.toml.orig files are part of third-party crates downloaded from
6082 # crates.io and should be included.
6083 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
6084 if problems:
6085 return [
6086 output_api.PresubmitError("Don't commit .rej and .orig files.",
6087 problems)
6088 ]
6089 else:
6090 return []
[email protected]b8079ae4a2012-12-05 19:56:496091
6092
Saagar Sanghavifceeaae2020-08-12 16:40:366093def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506094 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
6095 macro_re = input_api.re.compile(
6096 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
6097 include_re = input_api.re.compile(r'^#include\s+"build/build_config.h"',
6098 input_api.re.MULTILINE)
6099 extension_re = input_api.re.compile(r'\.[a-z]+$')
6100 errors = []
Bruce Dawsonf7679202022-08-09 20:24:006101 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:506102 for f in input_api.AffectedFiles(include_deletes=False):
Bruce Dawsonf7679202022-08-09 20:24:006103 # The build-config macros are allowed to be used in build_config.h
6104 # without including itself.
6105 if f.LocalPath() == config_h_file:
6106 continue
Sam Maiera6e76d72022-02-11 21:43:506107 if not f.LocalPath().endswith(
6108 ('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
6109 continue
Arthur Sonzognia3dec412024-04-29 12:05:376110
Sam Maiera6e76d72022-02-11 21:43:506111 found_line_number = None
6112 found_macro = None
6113 all_lines = input_api.ReadFile(f, 'r').splitlines()
6114 for line_num, line in enumerate(all_lines):
6115 match = macro_re.search(line)
6116 if match:
6117 found_line_number = line_num
6118 found_macro = match.group(2)
6119 break
6120 if not found_line_number:
6121 continue
Kent Tamura5a8755d2017-06-29 23:37:076122
Sam Maiera6e76d72022-02-11 21:43:506123 found_include_line = -1
6124 for line_num, line in enumerate(all_lines):
6125 if include_re.search(line):
6126 found_include_line = line_num
6127 break
6128 if found_include_line >= 0 and found_include_line < found_line_number:
6129 continue
Kent Tamura5a8755d2017-06-29 23:37:076130
Sam Maiera6e76d72022-02-11 21:43:506131 if not f.LocalPath().endswith('.h'):
6132 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
6133 try:
6134 content = input_api.ReadFile(primary_header_path, 'r')
6135 if include_re.search(content):
6136 continue
6137 except IOError:
6138 pass
6139 errors.append('%s:%d %s macro is used without first including build/'
6140 'build_config.h.' %
6141 (f.LocalPath(), found_line_number, found_macro))
6142 if errors:
6143 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
6144 return []
Kent Tamura5a8755d2017-06-29 23:37:076145
6146
Lei Zhang1c12a22f2021-05-12 11:28:456147def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506148 stl_include_re = input_api.re.compile(r'^#include\s+<('
6149 r'algorithm|'
6150 r'array|'
6151 r'limits|'
6152 r'list|'
6153 r'map|'
6154 r'memory|'
6155 r'queue|'
6156 r'set|'
6157 r'string|'
6158 r'unordered_map|'
6159 r'unordered_set|'
6160 r'utility|'
6161 r'vector)>')
6162 std_namespace_re = input_api.re.compile(r'std::')
6163 errors = []
6164 for f in input_api.AffectedFiles():
6165 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
6166 continue
Lei Zhang1c12a22f2021-05-12 11:28:456167
Sam Maiera6e76d72022-02-11 21:43:506168 uses_std_namespace = False
6169 has_stl_include = False
6170 for line in f.NewContents():
6171 if has_stl_include and uses_std_namespace:
6172 break
Lei Zhang1c12a22f2021-05-12 11:28:456173
Sam Maiera6e76d72022-02-11 21:43:506174 if not has_stl_include and stl_include_re.search(line):
6175 has_stl_include = True
6176 continue
Lei Zhang1c12a22f2021-05-12 11:28:456177
Bruce Dawson4a5579a2022-04-08 17:11:366178 if not uses_std_namespace and (std_namespace_re.search(line)
6179 or 'no-std-usage-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:506180 uses_std_namespace = True
6181 continue
Lei Zhang1c12a22f2021-05-12 11:28:456182
Sam Maiera6e76d72022-02-11 21:43:506183 if has_stl_include and not uses_std_namespace:
6184 errors.append(
6185 '%s: Includes STL header(s) but does not reference std::' %
6186 f.LocalPath())
6187 if errors:
6188 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
6189 return []
Lei Zhang1c12a22f2021-05-12 11:28:456190
6191
Xiaohan Wang42d96c22022-01-20 17:23:116192def _CheckForDeprecatedOSMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:506193 """Check for sensible looking, totally invalid OS macros."""
6194 preprocessor_statement = input_api.re.compile(r'^\s*#')
6195 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
6196 results = []
6197 for lnum, line in f.ChangedContents():
6198 if preprocessor_statement.search(line):
6199 for match in os_macro.finditer(line):
6200 results.append(
6201 ' %s:%d: %s' %
6202 (f.LocalPath(), lnum, 'defined(OS_' + match.group(1) +
6203 ') -> BUILDFLAG(IS_' + match.group(1) + ')'))
6204 return results
[email protected]b00342e7f2013-03-26 16:21:546205
6206
Xiaohan Wang42d96c22022-01-20 17:23:116207def CheckForDeprecatedOSMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506208 """Check all affected files for invalid OS macros."""
6209 bad_macros = []
Bruce Dawsonf7679202022-08-09 20:24:006210 # The OS_ macros are allowed to be used in build/build_config.h.
6211 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:506212 for f in input_api.AffectedSourceFiles(None):
Bruce Dawsonf7679202022-08-09 20:24:006213 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')) \
6214 and f.LocalPath() != config_h_file:
Sam Maiera6e76d72022-02-11 21:43:506215 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
[email protected]b00342e7f2013-03-26 16:21:546216
Sam Maiera6e76d72022-02-11 21:43:506217 if not bad_macros:
6218 return []
[email protected]b00342e7f2013-03-26 16:21:546219
Sam Maiera6e76d72022-02-11 21:43:506220 return [
6221 output_api.PresubmitError(
6222 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
6223 'defined in build_config.h):', bad_macros)
6224 ]
[email protected]b00342e7f2013-03-26 16:21:546225
lliabraa35bab3932014-10-01 12:16:446226
6227def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:506228 """Check all affected files for invalid "if defined" macros."""
6229 ALWAYS_DEFINED_MACROS = (
6230 "TARGET_CPU_PPC",
6231 "TARGET_CPU_PPC64",
6232 "TARGET_CPU_68K",
6233 "TARGET_CPU_X86",
6234 "TARGET_CPU_ARM",
6235 "TARGET_CPU_MIPS",
6236 "TARGET_CPU_SPARC",
6237 "TARGET_CPU_ALPHA",
6238 "TARGET_IPHONE_SIMULATOR",
6239 "TARGET_OS_EMBEDDED",
6240 "TARGET_OS_IPHONE",
6241 "TARGET_OS_MAC",
6242 "TARGET_OS_UNIX",
6243 "TARGET_OS_WIN32",
6244 )
6245 ifdef_macro = input_api.re.compile(
6246 r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
6247 results = []
6248 for lnum, line in f.ChangedContents():
6249 for match in ifdef_macro.finditer(line):
6250 if match.group(1) in ALWAYS_DEFINED_MACROS:
6251 always_defined = ' %s is always defined. ' % match.group(1)
6252 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
6253 results.append(
6254 ' %s:%d %s\n\t%s' %
6255 (f.LocalPath(), lnum, always_defined, did_you_mean))
6256 return results
lliabraa35bab3932014-10-01 12:16:446257
6258
Saagar Sanghavifceeaae2020-08-12 16:40:366259def CheckForInvalidIfDefinedMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506260 """Check all affected files for invalid "if defined" macros."""
Arthur Sonzogni4fd14fd2024-06-02 18:42:526261 SKIPPED_PATHS = [
6262 'base/allocator/partition_allocator/src/partition_alloc/build_config.h',
6263 'build/build_config.h',
6264 'third_party/abseil-cpp/',
6265 'third_party/sqlite/',
6266 ]
6267 def affected_files_filter(f):
6268 # Normalize the local path to Linux-style path separators so that the
6269 # path comparisons work on Windows as well.
Anton Bershanskyi4253349482025-02-11 21:01:276270 path = f.UnixLocalPath()
Arthur Sonzogni4fd14fd2024-06-02 18:42:526271
6272 for skipped_path in SKIPPED_PATHS:
6273 if path.startswith(skipped_path):
6274 return False
6275
6276 return path.endswith(('.h', '.c', '.cc', '.m', '.mm'))
6277
Sam Maiera6e76d72022-02-11 21:43:506278 bad_macros = []
Arthur Sonzogni4fd14fd2024-06-02 18:42:526279 for f in input_api.AffectedSourceFiles(affected_files_filter):
6280 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
lliabraa35bab3932014-10-01 12:16:446281
Sam Maiera6e76d72022-02-11 21:43:506282 if not bad_macros:
6283 return []
lliabraa35bab3932014-10-01 12:16:446284
Sam Maiera6e76d72022-02-11 21:43:506285 return [
6286 output_api.PresubmitError(
6287 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
6288 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
6289 bad_macros)
6290 ]
lliabraa35bab3932014-10-01 12:16:446291
Saagar Sanghavifceeaae2020-08-12 16:40:366292def CheckForIPCRules(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506293 """Check for same IPC rules described in
6294 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
6295 """
6296 base_pattern = r'IPC_ENUM_TRAITS\('
6297 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
6298 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
mlamouria82272622014-09-16 18:45:046299
Sam Maiera6e76d72022-02-11 21:43:506300 problems = []
6301 for f in input_api.AffectedSourceFiles(None):
6302 local_path = f.LocalPath()
6303 if not local_path.endswith('.h'):
6304 continue
6305 for line_number, line in f.ChangedContents():
6306 if inclusion_pattern.search(
6307 line) and not comment_pattern.search(line):
6308 problems.append('%s:%d\n %s' %
6309 (local_path, line_number, line.strip()))
mlamouria82272622014-09-16 18:45:046310
Sam Maiera6e76d72022-02-11 21:43:506311 if problems:
6312 return [
6313 output_api.PresubmitPromptWarning(_IPC_ENUM_TRAITS_DEPRECATED,
6314 problems)
6315 ]
6316 else:
6317 return []
mlamouria82272622014-09-16 18:45:046318
[email protected]b00342e7f2013-03-26 16:21:546319
Saagar Sanghavifceeaae2020-08-12 16:40:366320def CheckForLongPathnames(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506321 """Check to make sure no files being submitted have long paths.
6322 This causes issues on Windows.
6323 """
6324 problems = []
6325 for f in input_api.AffectedTestableFiles():
6326 local_path = f.LocalPath()
6327 # Windows has a path limit of 260 characters. Limit path length to 200 so
6328 # that we have some extra for the prefix on dev machines and the bots.
Weizhong Xia8b461f12024-06-21 21:46:336329 if (local_path.startswith('third_party/blink/web_tests/platform/') and
6330 not local_path.startswith('third_party/blink/web_tests/platform/win')):
6331 # Do not check length of the path for files not used by Windows
6332 continue
Sam Maiera6e76d72022-02-11 21:43:506333 if len(local_path) > 200:
6334 problems.append(local_path)
Stephen Martinis97a394142018-06-07 23:06:056335
Sam Maiera6e76d72022-02-11 21:43:506336 if problems:
6337 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
6338 else:
6339 return []
Stephen Martinis97a394142018-06-07 23:06:056340
6341
Saagar Sanghavifceeaae2020-08-12 16:40:366342def CheckForIncludeGuards(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506343 """Check that header files have proper guards against multiple inclusion.
6344 If a file should not have such guards (and it probably should) then it
Bruce Dawson4a5579a2022-04-08 17:11:366345 should include the string "no-include-guard-because-multiply-included" or
6346 "no-include-guard-because-pch-file".
Sam Maiera6e76d72022-02-11 21:43:506347 """
Daniel Bratell8ba52722018-03-02 16:06:146348
Sam Maiera6e76d72022-02-11 21:43:506349 def is_chromium_header_file(f):
6350 # We only check header files under the control of the Chromium
mikt84d6c712024-03-27 13:29:036351 # project. This excludes:
6352 # - third_party/*, except blink.
6353 # - base/allocator/partition_allocator/: PartitionAlloc is a standalone
6354 # library used outside of Chrome. Includes are referenced from its
6355 # own base directory. It has its own `CheckForIncludeGuards`
6356 # PRESUBMIT.py check.
6357 # - *_message_generator.h: They use include guards in a special,
6358 # non-typical way.
Sam Maiera6e76d72022-02-11 21:43:506359 file_with_path = input_api.os_path.normpath(f.LocalPath())
6360 return (file_with_path.endswith('.h')
6361 and not file_with_path.endswith('_message_generator.h')
Bruce Dawson4c4c2922022-05-02 18:07:336362 and not file_with_path.endswith('com_imported_mstscax.h')
Peter Kasting66c1f752024-12-02 15:28:376363 and not file_with_path.startswith(
6364 input_api.os_path.join('base', 'allocator',
6365 'partition_allocator'))
Sam Maiera6e76d72022-02-11 21:43:506366 and (not file_with_path.startswith('third_party')
6367 or file_with_path.startswith(
6368 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:146369
Sam Maiera6e76d72022-02-11 21:43:506370 def replace_special_with_underscore(string):
6371 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:146372
Sam Maiera6e76d72022-02-11 21:43:506373 errors = []
Daniel Bratell8ba52722018-03-02 16:06:146374
Sam Maiera6e76d72022-02-11 21:43:506375 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
6376 guard_name = None
6377 guard_line_number = None
6378 seen_guard_end = False
Lei Zhangd84f9512024-05-28 19:43:306379 bypass_checks_at_end_of_file = False
Daniel Bratell8ba52722018-03-02 16:06:146380
Sam Maiera6e76d72022-02-11 21:43:506381 file_with_path = input_api.os_path.normpath(f.LocalPath())
6382 base_file_name = input_api.os_path.splitext(
6383 input_api.os_path.basename(file_with_path))[0]
6384 upper_base_file_name = base_file_name.upper()
Daniel Bratell8ba52722018-03-02 16:06:146385
Sam Maiera6e76d72022-02-11 21:43:506386 expected_guard = replace_special_with_underscore(
6387 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:146388
Sam Maiera6e76d72022-02-11 21:43:506389 # For "path/elem/file_name.h" we should really only accept
6390 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
6391 # are too many (1000+) files with slight deviations from the
6392 # coding style. The most important part is that the include guard
6393 # is there, and that it's unique, not the name so this check is
6394 # forgiving for existing files.
6395 #
6396 # As code becomes more uniform, this could be made stricter.
Daniel Bratell8ba52722018-03-02 16:06:146397
Sam Maiera6e76d72022-02-11 21:43:506398 guard_name_pattern_list = [
6399 # Anything with the right suffix (maybe with an extra _).
6400 r'\w+_H__?',
Daniel Bratell8ba52722018-03-02 16:06:146401
Sam Maiera6e76d72022-02-11 21:43:506402 # To cover include guards with old Blink style.
6403 r'\w+_h',
Daniel Bratell8ba52722018-03-02 16:06:146404
Sam Maiera6e76d72022-02-11 21:43:506405 # Anything including the uppercase name of the file.
6406 r'\w*' + input_api.re.escape(
6407 replace_special_with_underscore(upper_base_file_name)) +
6408 r'\w*',
6409 ]
6410 guard_name_pattern = '|'.join(guard_name_pattern_list)
6411 guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
6412 guard_name_pattern + ')')
Daniel Bratell8ba52722018-03-02 16:06:146413
Sam Maiera6e76d72022-02-11 21:43:506414 for line_number, line in enumerate(f.NewContents()):
Bruce Dawson4a5579a2022-04-08 17:11:366415 if ('no-include-guard-because-multiply-included' in line
6416 or 'no-include-guard-because-pch-file' in line):
Lei Zhangd84f9512024-05-28 19:43:306417 bypass_checks_at_end_of_file = True
Sam Maiera6e76d72022-02-11 21:43:506418 break
Daniel Bratell8ba52722018-03-02 16:06:146419
Sam Maiera6e76d72022-02-11 21:43:506420 if guard_name is None:
6421 match = guard_pattern.match(line)
6422 if match:
6423 guard_name = match.group(1)
6424 guard_line_number = line_number
Daniel Bratell8ba52722018-03-02 16:06:146425
Sam Maiera6e76d72022-02-11 21:43:506426 # We allow existing files to use include guards whose names
6427 # don't match the chromium style guide, but new files should
6428 # get it right.
Bruce Dawson6cc154e2022-04-12 20:39:496429 if guard_name != expected_guard:
Bruce Dawson95eb7562022-09-14 15:27:166430 if f.Action() == 'A': # If file was just 'A'dded
Sam Maiera6e76d72022-02-11 21:43:506431 errors.append(
6432 output_api.PresubmitPromptWarning(
6433 'Header using the wrong include guard name %s'
6434 % guard_name, [
6435 '%s:%d' %
6436 (f.LocalPath(), line_number + 1)
6437 ], 'Expected: %r\nFound: %r' %
6438 (expected_guard, guard_name)))
6439 else:
6440 # The line after #ifndef should have a #define of the same name.
6441 if line_number == guard_line_number + 1:
6442 expected_line = '#define %s' % guard_name
6443 if line != expected_line:
6444 errors.append(
6445 output_api.PresubmitPromptWarning(
6446 'Missing "%s" for include guard' %
6447 expected_line,
6448 ['%s:%d' % (f.LocalPath(), line_number + 1)],
6449 'Expected: %r\nGot: %r' %
6450 (expected_line, line)))
Daniel Bratell8ba52722018-03-02 16:06:146451
Sam Maiera6e76d72022-02-11 21:43:506452 if not seen_guard_end and line == '#endif // %s' % guard_name:
6453 seen_guard_end = True
6454 elif seen_guard_end:
6455 if line.strip() != '':
6456 errors.append(
6457 output_api.PresubmitPromptWarning(
6458 'Include guard %s not covering the whole file'
6459 % (guard_name), [f.LocalPath()]))
6460 break # Nothing else to check and enough to warn once.
Daniel Bratell8ba52722018-03-02 16:06:146461
Lei Zhangd84f9512024-05-28 19:43:306462 if bypass_checks_at_end_of_file:
6463 continue
6464
Sam Maiera6e76d72022-02-11 21:43:506465 if guard_name is None:
6466 errors.append(
6467 output_api.PresubmitPromptWarning(
Bruce Dawson32114b62022-04-11 16:45:496468 'Missing include guard in %s\n'
Sam Maiera6e76d72022-02-11 21:43:506469 'Recommended name: %s\n'
6470 'This check can be disabled by having the string\n'
Bruce Dawson4a5579a2022-04-08 17:11:366471 '"no-include-guard-because-multiply-included" or\n'
6472 '"no-include-guard-because-pch-file" in the header.'
Sam Maiera6e76d72022-02-11 21:43:506473 % (f.LocalPath(), expected_guard)))
Lei Zhangd84f9512024-05-28 19:43:306474 elif not seen_guard_end:
6475 errors.append(
6476 output_api.PresubmitPromptWarning(
6477 'Incorrect or missing include guard #endif in %s\n'
6478 'Recommended #endif comment: // %s'
6479 % (f.LocalPath(), expected_guard)))
Sam Maiera6e76d72022-02-11 21:43:506480
6481 return errors
Daniel Bratell8ba52722018-03-02 16:06:146482
6483
Saagar Sanghavifceeaae2020-08-12 16:40:366484def CheckForWindowsLineEndings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506485 """Check source code and known ascii text files for Windows style line
6486 endings.
6487 """
Bruce Dawson5efbdc652022-04-11 19:29:516488 known_text_files = r'.*\.(txt|html|htm|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:236489
dpapadfd421fb2025-02-13 00:47:326490 _WEBUI_FILES_EXTENSIONS = r'\.(css|html|js|ts|svg)$'
6491
Sam Maiera6e76d72022-02-11 21:43:506492 file_inclusion_pattern = (known_text_files,
6493 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
dpapadfd421fb2025-02-13 00:47:326494 r'.+%s' % _HEADER_EXTENSIONS,
6495 r'.+%s' % _WEBUI_FILES_EXTENSIONS)
6496
6497 # Exclude folder that contains .ts files that are actually binary video
6498 # format and not TypeScript.
6499 file_exclusion_pattern = (r'media/test/data/')
mostynbb639aca52015-01-07 20:31:236500
Sam Maiera6e76d72022-02-11 21:43:506501 problems = []
6502 source_file_filter = lambda f: input_api.FilterSourceFile(
dpapadfd421fb2025-02-13 00:47:326503 f, files_to_check=file_inclusion_pattern,
6504 files_to_skip=file_exclusion_pattern)
Sam Maiera6e76d72022-02-11 21:43:506505 for f in input_api.AffectedSourceFiles(source_file_filter):
Bruce Dawson5efbdc652022-04-11 19:29:516506 # Ignore test files that contain crlf intentionally.
6507 if f.LocalPath().endswith('crlf.txt'):
Daniel Chenga37c03db2022-05-12 17:20:346508 continue
Sam Maiera6e76d72022-02-11 21:43:506509 include_file = False
6510 for line in input_api.ReadFile(f, 'r').splitlines(True):
6511 if line.endswith('\r\n'):
6512 include_file = True
6513 if include_file:
6514 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:236515
Sam Maiera6e76d72022-02-11 21:43:506516 if problems:
6517 return [
6518 output_api.PresubmitPromptWarning(
6519 'Are you sure that you want '
6520 'these files to contain Windows style line endings?\n' +
6521 '\n'.join(problems))
6522 ]
mostynbb639aca52015-01-07 20:31:236523
Sam Maiera6e76d72022-02-11 21:43:506524 return []
6525
mostynbb639aca52015-01-07 20:31:236526
Evan Stade6cfc964c12021-05-18 20:21:166527def CheckIconFilesForLicenseHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506528 """Check that .icon files (which are fragments of C++) have license headers.
6529 """
Evan Stade6cfc964c12021-05-18 20:21:166530
Sam Maiera6e76d72022-02-11 21:43:506531 icon_files = (r'.*\.icon$', )
Evan Stade6cfc964c12021-05-18 20:21:166532
Sam Maiera6e76d72022-02-11 21:43:506533 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
6534 return input_api.canned_checks.CheckLicense(input_api,
6535 output_api,
6536 source_file_filter=icons)
6537
Evan Stade6cfc964c12021-05-18 20:21:166538
Jose Magana2b456f22021-03-09 23:26:406539def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506540 """Check source code for use of Chrome App technologies being
6541 deprecated.
6542 """
Jose Magana2b456f22021-03-09 23:26:406543
Sam Maiera6e76d72022-02-11 21:43:506544 def _CheckForDeprecatedTech(input_api,
6545 output_api,
6546 detection_list,
6547 files_to_check=None,
6548 files_to_skip=None):
Jose Magana2b456f22021-03-09 23:26:406549
Sam Maiera6e76d72022-02-11 21:43:506550 if (files_to_check or files_to_skip):
6551 source_file_filter = lambda f: input_api.FilterSourceFile(
6552 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
6553 else:
6554 source_file_filter = None
6555
6556 problems = []
6557
6558 for f in input_api.AffectedSourceFiles(source_file_filter):
6559 if f.Action() == 'D':
6560 continue
6561 for _, line in f.ChangedContents():
6562 if any(detect in line for detect in detection_list):
6563 problems.append(f.LocalPath())
6564
6565 return problems
6566
6567 # to avoid this presubmit script triggering warnings
6568 files_to_skip = ['PRESUBMIT.py', 'PRESUBMIT_test.py']
Jose Magana2b456f22021-03-09 23:26:406569
6570 problems = []
6571
Sam Maiera6e76d72022-02-11 21:43:506572 # NMF: any files with extensions .nmf or NMF
6573 _NMF_FILES = r'\.(nmf|NMF)$'
6574 problems += _CheckForDeprecatedTech(
6575 input_api,
6576 output_api,
6577 detection_list=[''], # any change to the file will trigger warning
6578 files_to_check=[r'.+%s' % _NMF_FILES])
Jose Magana2b456f22021-03-09 23:26:406579
Sam Maiera6e76d72022-02-11 21:43:506580 # MANIFEST: any manifest.json that in its diff includes "app":
6581 _MANIFEST_FILES = r'(manifest\.json)$'
6582 problems += _CheckForDeprecatedTech(
6583 input_api,
6584 output_api,
6585 detection_list=['"app":'],
6586 files_to_check=[r'.*%s' % _MANIFEST_FILES])
Jose Magana2b456f22021-03-09 23:26:406587
Sam Maiera6e76d72022-02-11 21:43:506588 # NaCl / PNaCl: any file that in its diff contains the strings in the list
6589 problems += _CheckForDeprecatedTech(
6590 input_api,
6591 output_api,
6592 detection_list=['config=nacl', 'enable-nacl', 'cpu=pnacl', 'nacl_io'],
Bruce Dawson40fece62022-09-16 19:58:316593 files_to_skip=files_to_skip + [r"^native_client_sdk/"])
Jose Magana2b456f22021-03-09 23:26:406594
Gao Shenga79ebd42022-08-08 17:25:596595 # PPAPI: any C/C++ file that in its diff includes a ppapi library
Sam Maiera6e76d72022-02-11 21:43:506596 problems += _CheckForDeprecatedTech(
6597 input_api,
6598 output_api,
6599 detection_list=['#include "ppapi', '#include <ppapi'],
6600 files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,
6601 r'.+%s' % _IMPLEMENTATION_EXTENSIONS),
Bruce Dawson40fece62022-09-16 19:58:316602 files_to_skip=[r"^ppapi/"])
Jose Magana2b456f22021-03-09 23:26:406603
Sam Maiera6e76d72022-02-11 21:43:506604 if problems:
6605 return [
6606 output_api.PresubmitPromptWarning(
6607 'You are adding/modifying code'
6608 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
6609 ' PNaCl, PPAPI). See this blog post for more details:\n'
6610 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
6611 'and this documentation for options to replace these technologies:\n'
6612 'https://developer.chrome.com/docs/apps/migration/\n' +
6613 '\n'.join(problems))
6614 ]
Jose Magana2b456f22021-03-09 23:26:406615
Sam Maiera6e76d72022-02-11 21:43:506616 return []
Jose Magana2b456f22021-03-09 23:26:406617
mostynbb639aca52015-01-07 20:31:236618
Saagar Sanghavifceeaae2020-08-12 16:40:366619def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
Sam Maiera6e76d72022-02-11 21:43:506620 """Checks that all source files use SYSLOG properly."""
6621 syslog_files = []
6622 for f in input_api.AffectedSourceFiles(src_file_filter):
6623 for line_number, line in f.ChangedContents():
6624 if 'SYSLOG' in line:
6625 syslog_files.append(f.LocalPath() + ':' + str(line_number))
pastarmovj032ba5bc2017-01-12 10:41:566626
Sam Maiera6e76d72022-02-11 21:43:506627 if syslog_files:
6628 return [
6629 output_api.PresubmitPromptWarning(
6630 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
6631 ' calls.\nFiles to check:\n',
6632 items=syslog_files)
6633 ]
6634 return []
pastarmovj89f7ee12016-09-20 14:58:136635
6636
[email protected]1f7b4172010-01-28 01:17:346637def CheckChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506638 if input_api.version < [2, 0, 0]:
6639 return [
6640 output_api.PresubmitError(
6641 "Your depot_tools is out of date. "
6642 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
6643 "but your version is %d.%d.%d" % tuple(input_api.version))
6644 ]
6645 results = []
6646 results.extend(
6647 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
6648 return results
[email protected]ca8d1982009-02-19 16:33:126649
6650
6651def CheckChangeOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506652 if input_api.version < [2, 0, 0]:
6653 return [
6654 output_api.PresubmitError(
6655 "Your depot_tools is out of date. "
6656 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
6657 "but your version is %d.%d.%d" % tuple(input_api.version))
6658 ]
Saagar Sanghavifceeaae2020-08-12 16:40:366659
Sam Maiera6e76d72022-02-11 21:43:506660 results = []
6661 # Make sure the tree is 'open'.
6662 results.extend(
6663 input_api.canned_checks.CheckTreeIsOpen(
6664 input_api,
6665 output_api,
6666 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:276667
Sam Maiera6e76d72022-02-11 21:43:506668 results.extend(
6669 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
6670 results.extend(
6671 input_api.canned_checks.CheckChangeHasBugField(input_api, output_api))
6672 results.extend(
6673 input_api.canned_checks.CheckChangeHasNoUnwantedTags(
6674 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:506675 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146676
6677
Saagar Sanghavifceeaae2020-08-12 16:40:366678def CheckStrings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506679 """Check string ICU syntax validity and if translation screenshots exist."""
6680 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
6681 # footer is set to true.
6682 git_footers = input_api.change.GitFootersFromDescription()
6683 skip_screenshot_check_footer = [
6684 footer.lower() for footer in git_footers.get(
6685 u'Skip-Translation-Screenshots-Check', [])
6686 ]
6687 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:026688
Sam Maiera6e76d72022-02-11 21:43:506689 import os
6690 import re
6691 import sys
6692 from io import StringIO
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146693
Sam Maiera6e76d72022-02-11 21:43:506694 new_or_added_paths = set(f.LocalPath() for f in input_api.AffectedFiles()
6695 if (f.Action() == 'A' or f.Action() == 'M'))
6696 removed_paths = set(f.LocalPath()
6697 for f in input_api.AffectedFiles(include_deletes=True)
6698 if f.Action() == 'D')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146699
Sam Maiera6e76d72022-02-11 21:43:506700 affected_grds = [
6701 f for f in input_api.AffectedFiles()
6702 if f.LocalPath().endswith(('.grd', '.grdp'))
6703 ]
6704 affected_grds = [
6705 f for f in affected_grds if not 'testdata' in f.LocalPath()
6706 ]
6707 if not affected_grds:
6708 return []
meacer8c0d3832019-12-26 21:46:166709
Sam Maiera6e76d72022-02-11 21:43:506710 affected_png_paths = [
Andrew Grieve713b89b2024-10-15 20:20:086711 f.LocalPath() for f in input_api.AffectedFiles()
6712 if f.LocalPath().endswith('.png')
Sam Maiera6e76d72022-02-11 21:43:506713 ]
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146714
Sam Maiera6e76d72022-02-11 21:43:506715 # Check for screenshots. Developers can upload screenshots using
6716 # tools/translation/upload_screenshots.py which finds and uploads
6717 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
6718 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
6719 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
6720 #
6721 # The logic here is as follows:
6722 #
6723 # - If the CL has a .png file under the screenshots directory for a grd
6724 # file, warn the developer. Actual images should never be checked into the
6725 # Chrome repo.
6726 #
6727 # - If the CL contains modified or new messages in grd files and doesn't
6728 # contain the corresponding .sha1 files, warn the developer to add images
6729 # and upload them via tools/translation/upload_screenshots.py.
6730 #
6731 # - If the CL contains modified or new messages in grd files and the
6732 # corresponding .sha1 files, everything looks good.
6733 #
6734 # - If the CL contains removed messages in grd files but the corresponding
6735 # .sha1 files aren't removed, warn the developer to remove them.
6736 unnecessary_screenshots = []
Jens Mueller054652c2023-05-10 15:12:306737 invalid_sha1 = []
Sam Maiera6e76d72022-02-11 21:43:506738 missing_sha1 = []
Bruce Dawson55776c42022-12-09 17:23:476739 missing_sha1_modified = []
Sam Maiera6e76d72022-02-11 21:43:506740 unnecessary_sha1_files = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146741
Sam Maiera6e76d72022-02-11 21:43:506742 # This checks verifies that the ICU syntax of messages this CL touched is
6743 # valid, and reports any found syntax errors.
6744 # Without this presubmit check, ICU syntax errors in Chromium strings can land
6745 # without developers being aware of them. Later on, such ICU syntax errors
6746 # break message extraction for translation, hence would block Chromium
6747 # translations until they are fixed.
6748 icu_syntax_errors = []
Jens Mueller054652c2023-05-10 15:12:306749 sha1_pattern = input_api.re.compile(r'^[a-fA-F0-9]{40}$',
6750 input_api.re.MULTILINE)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146751
Sam Maiera6e76d72022-02-11 21:43:506752 def _CheckScreenshotAdded(screenshots_dir, message_id):
6753 sha1_path = input_api.os_path.join(screenshots_dir,
6754 message_id + '.png.sha1')
6755 if sha1_path not in new_or_added_paths:
6756 missing_sha1.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306757 elif not _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256758 invalid_sha1.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146759
Bruce Dawson55776c42022-12-09 17:23:476760 def _CheckScreenshotModified(screenshots_dir, message_id):
6761 sha1_path = input_api.os_path.join(screenshots_dir,
6762 message_id + '.png.sha1')
6763 if sha1_path not in new_or_added_paths:
6764 missing_sha1_modified.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306765 elif not _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256766 invalid_sha1.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306767
6768 def _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256769 return sha1_pattern.search(
6770 next("\n".join(f.NewContents()) for f in input_api.AffectedFiles()
6771 if f.LocalPath() == sha1_path))
Bruce Dawson55776c42022-12-09 17:23:476772
Sam Maiera6e76d72022-02-11 21:43:506773 def _CheckScreenshotRemoved(screenshots_dir, message_id):
6774 sha1_path = input_api.os_path.join(screenshots_dir,
6775 message_id + '.png.sha1')
6776 if input_api.os_path.exists(
6777 sha1_path) and sha1_path not in removed_paths:
6778 unnecessary_sha1_files.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146779
Sam Maiera6e76d72022-02-11 21:43:506780 def _ValidateIcuSyntax(text, level, signatures):
6781 """Validates ICU syntax of a text string.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146782
Sam Maiera6e76d72022-02-11 21:43:506783 Check if text looks similar to ICU and checks for ICU syntax correctness
6784 in this case. Reports various issues with ICU syntax and values of
6785 variants. Supports checking of nested messages. Accumulate information of
6786 each ICU messages found in the text for further checking.
Rainhard Findlingfc31844c52020-05-15 09:58:266787
Sam Maiera6e76d72022-02-11 21:43:506788 Args:
6789 text: a string to check.
6790 level: a number of current nesting level.
6791 signatures: an accumulator, a list of tuple of (level, variable,
6792 kind, variants).
Rainhard Findlingfc31844c52020-05-15 09:58:266793
Sam Maiera6e76d72022-02-11 21:43:506794 Returns:
6795 None if a string is not ICU or no issue detected.
6796 A tuple of (message, start index, end index) if an issue detected.
6797 """
6798 valid_types = {
6799 'plural': (frozenset(
Rainhard Findling3cde3ef02024-02-05 18:40:326800 ['=0', '=1', '=2', '=3', 'zero', 'one', 'two', 'few', 'many',
Sam Maiera6e76d72022-02-11 21:43:506801 'other']), frozenset(['=1', 'other'])),
6802 'selectordinal': (frozenset(
Rainhard Findling3cde3ef02024-02-05 18:40:326803 ['=0', '=1', '=2', '=3', 'zero', 'one', 'two', 'few', 'many',
Sam Maiera6e76d72022-02-11 21:43:506804 'other']), frozenset(['one', 'other'])),
6805 'select': (frozenset(), frozenset(['other'])),
6806 }
Rainhard Findlingfc31844c52020-05-15 09:58:266807
Sam Maiera6e76d72022-02-11 21:43:506808 # Check if the message looks like an attempt to use ICU
6809 # plural. If yes - check if its syntax strictly matches ICU format.
6810 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b',
6811 text)
6812 if not like:
6813 signatures.append((level, None, None, None))
6814 return
Rainhard Findlingfc31844c52020-05-15 09:58:266815
Sam Maiera6e76d72022-02-11 21:43:506816 # Check for valid prefix and suffix
6817 m = re.match(
6818 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
6819 r'(plural|selectordinal|select),\s*'
6820 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
6821 if not m:
6822 return (('This message looks like an ICU plural, '
6823 'but does not follow ICU syntax.'), like.start(),
6824 like.end())
6825 starting, variable, kind, variant_pairs = m.groups()
6826 variants, depth, last_pos = _ParseIcuVariants(variant_pairs,
6827 m.start(4))
6828 if depth:
6829 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
6830 len(text))
6831 first = text[0]
6832 ending = text[last_pos:]
6833 if not starting:
6834 return ('Invalid ICU format. No initial opening bracket',
6835 last_pos - 1, last_pos)
6836 if not ending or '}' not in ending:
6837 return ('Invalid ICU format. No final closing bracket',
6838 last_pos - 1, last_pos)
6839 elif first != '{':
6840 return ((
6841 'Invalid ICU format. Extra characters at the start of a complex '
6842 'message (go/icu-message-migration): "%s"') % starting, 0,
6843 len(starting))
6844 elif ending != '}':
6845 return ((
6846 'Invalid ICU format. Extra characters at the end of a complex '
6847 'message (go/icu-message-migration): "%s"') % ending,
6848 last_pos - 1, len(text) - 1)
6849 if kind not in valid_types:
6850 return (('Unknown ICU message type %s. '
6851 'Valid types are: plural, select, selectordinal') % kind,
6852 0, 0)
6853 known, required = valid_types[kind]
6854 defined_variants = set()
6855 for variant, variant_range, value, value_range in variants:
6856 start, end = variant_range
6857 if variant in defined_variants:
6858 return ('Variant "%s" is defined more than once' % variant,
6859 start, end)
6860 elif known and variant not in known:
6861 return ('Variant "%s" is not valid for %s message' %
6862 (variant, kind), start, end)
6863 defined_variants.add(variant)
6864 # Check for nested structure
6865 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
6866 if res:
6867 return (res[0], res[1] + value_range[0] + 1,
6868 res[2] + value_range[0] + 1)
6869 missing = required - defined_variants
6870 if missing:
6871 return ('Required variants missing: %s' % ', '.join(missing), 0,
6872 len(text))
6873 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:266874
Sam Maiera6e76d72022-02-11 21:43:506875 def _ParseIcuVariants(text, offset=0):
6876 """Parse variants part of ICU complex message.
Rainhard Findlingfc31844c52020-05-15 09:58:266877
Sam Maiera6e76d72022-02-11 21:43:506878 Builds a tuple of variant names and values, as well as
6879 their offsets in the input string.
Rainhard Findlingfc31844c52020-05-15 09:58:266880
Sam Maiera6e76d72022-02-11 21:43:506881 Args:
6882 text: a string to parse
6883 offset: additional offset to add to positions in the text to get correct
6884 position in the complete ICU string.
Rainhard Findlingfc31844c52020-05-15 09:58:266885
Sam Maiera6e76d72022-02-11 21:43:506886 Returns:
6887 List of tuples, each tuple consist of four fields: variant name,
6888 variant name span (tuple of two integers), variant value, value
6889 span (tuple of two integers).
6890 """
6891 depth, start, end = 0, -1, -1
6892 variants = []
6893 key = None
6894 for idx, char in enumerate(text):
6895 if char == '{':
6896 if not depth:
6897 start = idx
6898 chunk = text[end + 1:start]
6899 key = chunk.strip()
6900 pos = offset + end + 1 + chunk.find(key)
6901 span = (pos, pos + len(key))
6902 depth += 1
6903 elif char == '}':
6904 if not depth:
6905 return variants, depth, offset + idx
6906 depth -= 1
6907 if not depth:
6908 end = idx
6909 variants.append((key, span, text[start:end + 1],
6910 (offset + start, offset + end + 1)))
6911 return variants, depth, offset + end + 1
Rainhard Findlingfc31844c52020-05-15 09:58:266912
Terrence Reilly313f44ff2025-01-22 15:10:146913 old_sys_path = sys.path
Sam Maiera6e76d72022-02-11 21:43:506914 try:
Sam Maiera6e76d72022-02-11 21:43:506915 sys.path = sys.path + [
6916 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
6917 'translation')
6918 ]
6919 from helper import grd_helper
6920 finally:
6921 sys.path = old_sys_path
Rainhard Findlingfc31844c52020-05-15 09:58:266922
Sam Maiera6e76d72022-02-11 21:43:506923 for f in affected_grds:
6924 file_path = f.LocalPath()
6925 old_id_to_msg_map = {}
6926 new_id_to_msg_map = {}
6927 # Note that this code doesn't check if the file has been deleted. This is
6928 # OK because it only uses the old and new file contents and doesn't load
6929 # the file via its path.
6930 # It's also possible that a file's content refers to a renamed or deleted
6931 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
6932 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
6933 # .grdp files.
6934 if file_path.endswith('.grdp'):
6935 if f.OldContents():
6936 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6937 '\n'.join(f.OldContents()))
6938 if f.NewContents():
6939 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6940 '\n'.join(f.NewContents()))
6941 else:
6942 file_dir = input_api.os_path.dirname(file_path) or '.'
6943 if f.OldContents():
6944 old_id_to_msg_map = grd_helper.GetGrdMessages(
6945 StringIO('\n'.join(f.OldContents())), file_dir)
6946 if f.NewContents():
6947 new_id_to_msg_map = grd_helper.GetGrdMessages(
6948 StringIO('\n'.join(f.NewContents())), file_dir)
Rainhard Findlingfc31844c52020-05-15 09:58:266949
Sam Maiera6e76d72022-02-11 21:43:506950 grd_name, ext = input_api.os_path.splitext(
6951 input_api.os_path.basename(file_path))
6952 screenshots_dir = input_api.os_path.join(
6953 input_api.os_path.dirname(file_path),
6954 grd_name + ext.replace('.', '_'))
Rainhard Findlingfc31844c52020-05-15 09:58:266955
Sam Maiera6e76d72022-02-11 21:43:506956 # Compute added, removed and modified message IDs.
6957 old_ids = set(old_id_to_msg_map)
6958 new_ids = set(new_id_to_msg_map)
6959 added_ids = new_ids - old_ids
6960 removed_ids = old_ids - new_ids
6961 modified_ids = set([])
6962 for key in old_ids.intersection(new_ids):
6963 if (old_id_to_msg_map[key].ContentsAsXml('', True) !=
6964 new_id_to_msg_map[key].ContentsAsXml('', True)):
6965 # The message content itself changed. Require an updated screenshot.
6966 modified_ids.add(key)
6967 elif old_id_to_msg_map[key].attrs['meaning'] != \
6968 new_id_to_msg_map[key].attrs['meaning']:
Jens Mueller054652c2023-05-10 15:12:306969 # The message meaning changed. We later check for a screenshot.
6970 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146971
Sam Maiera6e76d72022-02-11 21:43:506972 if run_screenshot_check:
6973 # Check the screenshot directory for .png files. Warn if there is any.
6974 for png_path in affected_png_paths:
6975 if png_path.startswith(screenshots_dir):
6976 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146977
Sam Maiera6e76d72022-02-11 21:43:506978 for added_id in added_ids:
6979 _CheckScreenshotAdded(screenshots_dir, added_id)
Rainhard Findlingd8d04372020-08-13 13:30:096980
Sam Maiera6e76d72022-02-11 21:43:506981 for modified_id in modified_ids:
Bruce Dawson55776c42022-12-09 17:23:476982 _CheckScreenshotModified(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146983
Sam Maiera6e76d72022-02-11 21:43:506984 for removed_id in removed_ids:
6985 _CheckScreenshotRemoved(screenshots_dir, removed_id)
6986
6987 # Check new and changed strings for ICU syntax errors.
6988 for key in added_ids.union(modified_ids):
6989 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
6990 err = _ValidateIcuSyntax(msg, 0, [])
6991 if err is not None:
6992 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
6993
6994 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:266995 if run_screenshot_check:
Sam Maiera6e76d72022-02-11 21:43:506996 if unnecessary_screenshots:
6997 results.append(
6998 output_api.PresubmitError(
6999 'Do not include actual screenshots in the changelist. Run '
7000 'tools/translate/upload_screenshots.py to upload them instead:',
7001 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147002
Sam Maiera6e76d72022-02-11 21:43:507003 if missing_sha1:
7004 results.append(
7005 output_api.PresubmitError(
Bruce Dawson55776c42022-12-09 17:23:477006 'You are adding UI strings.\n'
Sam Maiera6e76d72022-02-11 21:43:507007 'To ensure the best translations, take screenshots of the relevant UI '
7008 '(https://g.co/chrome/translation) and add these files to your '
7009 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147010
Jens Mueller054652c2023-05-10 15:12:307011 if invalid_sha1:
7012 results.append(
7013 output_api.PresubmitError(
7014 'The following files do not seem to contain valid sha1 hashes. '
7015 'Make sure they contain hashes created by '
7016 'tools/translate/upload_screenshots.py:', sorted(invalid_sha1)))
7017
Bruce Dawson55776c42022-12-09 17:23:477018 if missing_sha1_modified:
7019 results.append(
7020 output_api.PresubmitError(
7021 'You are modifying UI strings or their meanings.\n'
7022 'To ensure the best translations, take screenshots of the relevant UI '
7023 '(https://g.co/chrome/translation) and add these files to your '
7024 'changelist:', sorted(missing_sha1_modified)))
7025
Sam Maiera6e76d72022-02-11 21:43:507026 if unnecessary_sha1_files:
7027 results.append(
7028 output_api.PresubmitError(
7029 'You removed strings associated with these files. Remove:',
7030 sorted(unnecessary_sha1_files)))
7031 else:
7032 results.append(
7033 output_api.PresubmitPromptOrNotify('Skipping translation '
7034 'screenshots check.'))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147035
Sam Maiera6e76d72022-02-11 21:43:507036 if icu_syntax_errors:
7037 results.append(
7038 output_api.PresubmitPromptWarning(
7039 'ICU syntax errors were found in the following strings (problems or '
7040 'feedback? Contact [email protected]):',
7041 items=icu_syntax_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:267042
Sam Maiera6e76d72022-02-11 21:43:507043 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:127044
7045
Saagar Sanghavifceeaae2020-08-12 16:40:367046def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:127047 repo_root=None,
7048 translation_expectations_path=None,
7049 grd_files=None):
Sam Maiera6e76d72022-02-11 21:43:507050 import sys
7051 affected_grds = [
7052 f for f in input_api.AffectedFiles()
7053 if (f.LocalPath().endswith('.grd') or f.LocalPath().endswith('.grdp'))
7054 ]
7055 if not affected_grds:
7056 return []
7057
Terrence Reilly313f44ff2025-01-22 15:10:147058 old_sys_path = sys.path
Sam Maiera6e76d72022-02-11 21:43:507059 try:
Sam Maiera6e76d72022-02-11 21:43:507060 sys.path = sys.path + [
7061 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
7062 'translation')
7063 ]
Terrence Reilly313f44ff2025-01-22 15:10:147064 sys.path = sys.path + [
7065 input_api.os_path.join(input_api.PresubmitLocalPath(),
7066 'third_party', 'depot_tools')
7067 ]
Sam Maiera6e76d72022-02-11 21:43:507068 from helper import git_helper
7069 from helper import translation_helper
Terrence Reilly313f44ff2025-01-22 15:10:147070 import gclient_utils
Sam Maiera6e76d72022-02-11 21:43:507071 finally:
7072 sys.path = old_sys_path
7073
7074 # Check that translation expectations can be parsed and we can get a list of
7075 # translatable grd files. |repo_root| and |translation_expectations_path| are
7076 # only passed by tests.
7077 if not repo_root:
7078 repo_root = input_api.PresubmitLocalPath()
7079 if not translation_expectations_path:
7080 translation_expectations_path = input_api.os_path.join(
7081 repo_root, 'tools', 'gritsettings', 'translation_expectations.pyl')
Terrence Reilly313f44ff2025-01-22 15:10:147082 is_cog = gclient_utils.IsEnvCog()
7083 # Git is not available in cog workspaces.
7084 if not grd_files and not is_cog:
Sam Maiera6e76d72022-02-11 21:43:507085 grd_files = git_helper.list_grds_in_repository(repo_root)
Terrence Reilly313f44ff2025-01-22 15:10:147086 if not grd_files:
7087 grd_files = []
Sam Maiera6e76d72022-02-11 21:43:507088
7089 # Ignore bogus grd files used only for testing
Gao Shenga79ebd42022-08-08 17:25:597090 # ui/webui/resources/tools/generate_grd.py.
Sam Maiera6e76d72022-02-11 21:43:507091 ignore_path = input_api.os_path.join('ui', 'webui', 'resources', 'tools',
7092 'tests')
7093 grd_files = [p for p in grd_files if ignore_path not in p]
7094
7095 try:
7096 translation_helper.get_translatable_grds(
Terrence Reilly313f44ff2025-01-22 15:10:147097 repo_root, grd_files, translation_expectations_path, is_cog)
Sam Maiera6e76d72022-02-11 21:43:507098 except Exception as e:
7099 return [
7100 output_api.PresubmitNotifyResult(
7101 'Failed to get a list of translatable grd files. This happens when:\n'
7102 ' - One of the modified grd or grdp files cannot be parsed or\n'
7103 ' - %s is not updated.\n'
7104 'Stack:\n%s' % (translation_expectations_path, str(e)))
7105 ]
Mustafa Emre Acer51f2f742020-03-09 19:41:127106 return []
7107
Ken Rockotc31f4832020-05-29 18:58:517108
Saagar Sanghavifceeaae2020-08-12 16:40:367109def CheckStableMojomChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507110 """Changes to [Stable] mojom types must preserve backward-compatibility."""
7111 changed_mojoms = input_api.AffectedFiles(
7112 include_deletes=True,
7113 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:527114
Bruce Dawson344ab262022-06-04 11:35:107115 if not changed_mojoms or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:507116 return []
7117
7118 delta = []
7119 for mojom in changed_mojoms:
Sam Maiera6e76d72022-02-11 21:43:507120 delta.append({
7121 'filename': mojom.LocalPath(),
7122 'old': '\n'.join(mojom.OldContents()) or None,
7123 'new': '\n'.join(mojom.NewContents()) or None,
7124 })
7125
7126 process = input_api.subprocess.Popen([
Takuto Ikutadca10222022-04-13 02:51:217127 input_api.python3_executable,
Sam Maiera6e76d72022-02-11 21:43:507128 input_api.os_path.join(
7129 input_api.PresubmitLocalPath(), 'mojo', 'public', 'tools', 'mojom',
7130 'check_stable_mojom_compatibility.py'), '--src-root',
7131 input_api.PresubmitLocalPath()
7132 ],
7133 stdin=input_api.subprocess.PIPE,
7134 stdout=input_api.subprocess.PIPE,
7135 stderr=input_api.subprocess.PIPE,
7136 universal_newlines=True)
7137 (x, error) = process.communicate(input=input_api.json.dumps(delta))
7138 if process.returncode:
7139 return [
7140 output_api.PresubmitError(
7141 'One or more [Stable] mojom definitions appears to have been changed '
Alex Goughc99921652024-02-15 22:59:127142 'in a way that is not backward-compatible. See '
7143 'https://chromium.googlesource.com/chromium/src/+/HEAD/mojo/public/tools/bindings/README.md#versioning'
7144 ' for details.',
Sam Maiera6e76d72022-02-11 21:43:507145 long_text=error)
7146 ]
Erik Staabc734cd7a2021-11-23 03:11:527147 return []
7148
Dominic Battre645d42342020-12-04 16:14:107149def CheckDeprecationOfPreferences(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507150 """Removing a preference should come with a deprecation."""
Dominic Battre645d42342020-12-04 16:14:107151
Sam Maiera6e76d72022-02-11 21:43:507152 def FilterFile(affected_file):
7153 """Accept only .cc files and the like."""
7154 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
7155 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
7156 input_api.DEFAULT_FILES_TO_SKIP)
7157 return input_api.FilterSourceFile(
7158 affected_file,
7159 files_to_check=file_inclusion_pattern,
7160 files_to_skip=files_to_skip)
Dominic Battre645d42342020-12-04 16:14:107161
Sam Maiera6e76d72022-02-11 21:43:507162 def ModifiedLines(affected_file):
7163 """Returns a list of tuples (line number, line text) of added and removed
7164 lines.
Dominic Battre645d42342020-12-04 16:14:107165
Sam Maiera6e76d72022-02-11 21:43:507166 Deleted lines share the same line number as the previous line.
Dominic Battre645d42342020-12-04 16:14:107167
Sam Maiera6e76d72022-02-11 21:43:507168 This relies on the scm diff output describing each changed code section
7169 with a line of the form
Dominic Battre645d42342020-12-04 16:14:107170
Sam Maiera6e76d72022-02-11 21:43:507171 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
7172 """
7173 line_num = 0
7174 modified_lines = []
7175 for line in affected_file.GenerateScmDiff().splitlines():
7176 # Extract <new line num> of the patch fragment (see format above).
7177 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@',
7178 line)
7179 if m:
7180 line_num = int(m.groups(1)[0])
7181 continue
7182 if ((line.startswith('+') and not line.startswith('++'))
7183 or (line.startswith('-') and not line.startswith('--'))):
7184 modified_lines.append((line_num, line))
Dominic Battre645d42342020-12-04 16:14:107185
Sam Maiera6e76d72022-02-11 21:43:507186 if not line.startswith('-'):
7187 line_num += 1
7188 return modified_lines
Dominic Battre645d42342020-12-04 16:14:107189
Sam Maiera6e76d72022-02-11 21:43:507190 def FindLineWith(lines, needle):
7191 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
Dominic Battre645d42342020-12-04 16:14:107192
Sam Maiera6e76d72022-02-11 21:43:507193 If 0 or >1 lines contain `needle`, -1 is returned.
7194 """
7195 matching_line_numbers = [
7196 # + 1 for 1-based counting of line numbers.
7197 i + 1 for i, line in enumerate(lines) if needle in line
7198 ]
7199 return matching_line_numbers[0] if len(
7200 matching_line_numbers) == 1 else -1
Dominic Battre645d42342020-12-04 16:14:107201
Sam Maiera6e76d72022-02-11 21:43:507202 def ModifiedPrefMigration(affected_file):
7203 """Returns whether the MigrateObsolete.*Pref functions were modified."""
7204 # Determine first and last lines of MigrateObsolete.*Pref functions.
7205 new_contents = affected_file.NewContents()
7206 range_1 = (FindLineWith(new_contents,
7207 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
7208 FindLineWith(new_contents,
7209 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
7210 range_2 = (FindLineWith(new_contents,
7211 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
7212 FindLineWith(new_contents,
7213 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
7214 if (-1 in range_1 + range_2):
7215 raise Exception(
7216 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.'
7217 )
Dominic Battre645d42342020-12-04 16:14:107218
Sam Maiera6e76d72022-02-11 21:43:507219 # Check whether any of the modified lines are part of the
7220 # MigrateObsolete.*Pref functions.
7221 for line_nr, line in ModifiedLines(affected_file):
7222 if (range_1[0] <= line_nr <= range_1[1]
7223 or range_2[0] <= line_nr <= range_2[1]):
7224 return True
7225 return False
Dominic Battre645d42342020-12-04 16:14:107226
Sam Maiera6e76d72022-02-11 21:43:507227 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
7228 browser_prefs_file_pattern = input_api.re.compile(
7229 r'chrome/browser/prefs/browser_prefs.cc')
Dominic Battre645d42342020-12-04 16:14:107230
Sam Maiera6e76d72022-02-11 21:43:507231 changes = input_api.AffectedFiles(include_deletes=True,
7232 file_filter=FilterFile)
7233 potential_problems = []
7234 for f in changes:
7235 for line in f.GenerateScmDiff().splitlines():
7236 # Check deleted lines for pref registrations.
7237 if (line.startswith('-') and not line.startswith('--')
7238 and register_pref_pattern.search(line)):
7239 potential_problems.append('%s: %s' % (f.LocalPath(), line))
Dominic Battre645d42342020-12-04 16:14:107240
Sam Maiera6e76d72022-02-11 21:43:507241 if browser_prefs_file_pattern.search(f.LocalPath()):
7242 # If the developer modified the MigrateObsolete.*Prefs() functions, we
7243 # assume that they knew that they have to deprecate preferences and don't
7244 # warn.
7245 try:
7246 if ModifiedPrefMigration(f):
7247 return []
7248 except Exception as e:
7249 return [output_api.PresubmitError(str(e))]
Dominic Battre645d42342020-12-04 16:14:107250
Sam Maiera6e76d72022-02-11 21:43:507251 if potential_problems:
7252 return [
7253 output_api.PresubmitPromptWarning(
7254 'Discovered possible removal of preference registrations.\n\n'
7255 'Please make sure to properly deprecate preferences by clearing their\n'
7256 'value for a couple of milestones before finally removing the code.\n'
7257 'Otherwise data may stay in the preferences files forever. See\n'
7258 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
7259 'chrome/browser/prefs/README.md for examples.\n'
7260 'This may be a false positive warning (e.g. if you move preference\n'
7261 'registrations to a different place).\n', potential_problems)
7262 ]
7263 return []
7264
Matt Stark6ef08872021-07-29 01:21:467265
7266def CheckConsistentGrdChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507267 """Changes to GRD files must be consistent for tools to read them."""
7268 changed_grds = input_api.AffectedFiles(
7269 include_deletes=False,
7270 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
7271 errors = []
7272 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
7273 for matcher, msg in _INVALID_GRD_FILE_LINE]
7274 for grd in changed_grds:
7275 for i, line in enumerate(grd.NewContents()):
7276 for matcher, msg in invalid_file_regexes:
7277 if matcher.search(line):
7278 errors.append(
7279 output_api.PresubmitError(
7280 'Problem on {grd}:{i} - {msg}'.format(
7281 grd=grd.LocalPath(), i=i + 1, msg=msg)))
7282 return errors
7283
Kevin McNee967dd2d22021-11-15 16:09:297284
Henrique Ferreiro2a4b55942021-11-29 23:45:367285def CheckAssertAshOnlyCode(input_api, output_api):
7286 """Errors if a BUILD.gn file in an ash/ directory doesn't include
Georg Neis94f87f02024-10-22 08:20:137287 assert(is_chromeos).
7288 For a transition period, assert(is_chromeos_ash) is also accepted.
Henrique Ferreiro2a4b55942021-11-29 23:45:367289 """
7290
7291 def FileFilter(affected_file):
7292 """Includes directories known to be Ash only."""
7293 return input_api.FilterSourceFile(
7294 affected_file,
7295 files_to_check=(
7296 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
7297 r'.*/ash/.*BUILD\.gn'), # Any path component.
7298 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
7299
7300 errors = []
Georg Neis94f87f02024-10-22 08:20:137301 pattern = input_api.re.compile(r'assert\(is_chromeos(_ash)?\b')
Jameson Thies0ce669f2021-12-09 15:56:567302 for f in input_api.AffectedFiles(include_deletes=False,
7303 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:367304 if (not pattern.search(input_api.ReadFile(f))):
7305 errors.append(
7306 output_api.PresubmitError(
Georg Neis94f87f02024-10-22 08:20:137307 'Please add assert(is_chromeos) to %s. If that\'s not '
7308 'possible, please create an issue and add a comment such '
Alison Galed6b25fe2024-04-17 13:59:047309 'as:\n # TODO(crbug.com/XXX): add '
Georg Neis94f87f02024-10-22 08:20:137310 'assert(is_chromeos) when ...' % f.LocalPath()))
Henrique Ferreiro2a4b55942021-11-29 23:45:367311 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:277312
7313
Kalvin Lee84ad17a2023-09-25 11:14:417314def _IsMiraclePtrDisallowed(input_api, affected_file):
Anton Bershanskyi4253349482025-02-11 21:01:277315 path = affected_file.UnixLocalPath()
Sam Maiera6e76d72022-02-11 21:43:507316 if not _IsCPlusPlusFile(input_api, path):
7317 return False
7318
Bartek Nowierski49b1a452024-06-08 00:24:357319 # Renderer-only code is generally allowed to use MiraclePtr. These
7320 # directories, however, are specifically disallowed, for perf reasons.
Kalvin Lee84ad17a2023-09-25 11:14:417321 if ("third_party/blink/renderer/core/" in path
7322 or "third_party/blink/renderer/platform/heap/" in path
Bartek Nowierski49b1a452024-06-08 00:24:357323 or "third_party/blink/renderer/platform/wtf/" in path
7324 or "third_party/blink/renderer/platform/fonts/" in path):
7325 return True
7326
7327 # The below paths are an explicitly listed subset of Renderer-only code,
7328 # because the plan is to Oilpanize it.
7329 # TODO(crbug.com/330759291): Remove once Oilpanization is completed or
7330 # abandoned.
7331 if ("third_party/blink/renderer/core/paint/" in path
7332 or "third_party/blink/renderer/platform/graphics/compositing/" in path
7333 or "third_party/blink/renderer/platform/graphics/paint/" in path):
Sam Maiera6e76d72022-02-11 21:43:507334 return True
7335
Sam Maiera6e76d72022-02-11 21:43:507336 # We assume that everything else may be used outside of Renderer processes.
Lukasz Anforowicz7016d05e2021-11-30 03:56:277337 return False
7338
Alison Galed6b25fe2024-04-17 13:59:047339# TODO(crbug.com/40206238): Remove these checks, once they are replaced
Lukasz Anforowicz7016d05e2021-11-30 03:56:277340# by the Chromium Clang Plugin (which will be preferable because it will
7341# 1) report errors earlier - at compile-time and 2) cover more rules).
7342def CheckRawPtrUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507343 """Rough checks that raw_ptr<T> usage guidelines are followed."""
7344 errors = []
7345 # The regex below matches "raw_ptr<" following a word boundary, but not in a
7346 # C++ comment.
7347 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
Kalvin Lee84ad17a2023-09-25 11:14:417348 file_filter = lambda f: _IsMiraclePtrDisallowed(input_api, f)
Sam Maiera6e76d72022-02-11 21:43:507349 for f, line_num, line in input_api.RightHandSideLines(file_filter):
7350 if raw_ptr_matcher.search(line):
7351 errors.append(
7352 output_api.PresubmitError(
7353 'Problem on {path}:{line} - '\
Kalvin Lee84ad17a2023-09-25 11:14:417354 'raw_ptr<T> should not be used in this renderer code '\
Sam Maiera6e76d72022-02-11 21:43:507355 '(as documented in the "Pointers to unprotected memory" '\
7356 'section in //base/memory/raw_ptr.md)'.format(
7357 path=f.LocalPath(), line=line_num)))
7358 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:567359
mikt9337567c2023-09-08 18:38:177360def CheckAdvancedMemorySafetyChecksUsage(input_api, output_api):
7361 """Checks that ADVANCED_MEMORY_SAFETY_CHECKS() macro is neither added nor
7362 removed as it is managed by the memory safety team internally.
7363 Do not add / remove it manually."""
7364 paths = set([])
7365 # The regex below matches "ADVANCED_MEMORY_SAFETY_CHECKS(" following a word
7366 # boundary, but not in a C++ comment.
7367 macro_matcher = input_api.re.compile(
7368 r'^((?!//).)*\bADVANCED_MEMORY_SAFETY_CHECKS\(', input_api.re.MULTILINE)
7369 for f in input_api.AffectedFiles():
7370 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
7371 continue
7372 if macro_matcher.search(f.GenerateScmDiff()):
7373 paths.add(f.LocalPath())
7374 if not paths:
7375 return []
7376 return [output_api.PresubmitPromptWarning(
7377 'ADVANCED_MEMORY_SAFETY_CHECKS() macro is managed by ' \
7378 'the memory safety team (chrome-memory-safety@). ' \
7379 'Please contact us to add/delete the uses of the macro.',
7380 paths)]
Henrique Ferreirof9819f2e32021-11-30 13:31:567381
7382def CheckPythonShebang(input_api, output_api):
7383 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
7384 system-wide python.
7385 """
7386 errors = []
7387 sources = lambda affected_file: input_api.FilterSourceFile(
7388 affected_file,
7389 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
7390 r'third_party/blink/web_tests/external/') + input_api.
7391 DEFAULT_FILES_TO_SKIP),
7392 files_to_check=[r'.*\.py$'])
7393 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:277394 for line_num, line in f.ChangedContents():
7395 if line_num == 1 and line.startswith('#!/usr/bin/python'):
7396 errors.append(f.LocalPath())
7397 break
Henrique Ferreirof9819f2e32021-11-30 13:31:567398
7399 result = []
7400 for file in errors:
7401 result.append(
7402 output_api.PresubmitError(
7403 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
7404 file))
7405 return result
James Shen81cc0e22022-06-15 21:10:457406
7407
Andrew Grieve5a66ae72024-12-13 15:21:537408def CheckAndroidTestAnnotations(input_api, output_api):
James Shen81cc0e22022-06-15 21:10:457409 """Checks that tests have either @Batch or @DoNotBatch annotation. If this
7410 is not an instrumentation test, disregard."""
7411
7412 batch_annotation = input_api.re.compile(r'^\s*@Batch')
7413 do_not_batch_annotation = input_api.re.compile(r'^\s*@DoNotBatch')
Andrew Grieve5a66ae72024-12-13 15:21:537414 robolectric_test = input_api.re.compile(r'@RunWith\((.*?)RobolectricTestRunner')
James Shen81cc0e22022-06-15 21:10:457415 test_class_declaration = input_api.re.compile(r'^\s*public\sclass.*Test')
7416 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
Mark Schillaci8ef0d872023-07-18 22:07:597417 test_annotation_declaration = input_api.re.compile(r'^\s*public\s@interface\s.*{')
James Shen81cc0e22022-06-15 21:10:457418
ckitagawae8fd23b2022-06-17 15:29:387419 missing_annotation_errors = []
7420 extra_annotation_errors = []
Andrew Grieve5a66ae72024-12-13 15:21:537421 wrong_robolectric_test_runner_errors = []
James Shen81cc0e22022-06-15 21:10:457422
7423 def _FilterFile(affected_file):
7424 return input_api.FilterSourceFile(
7425 affected_file,
7426 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
7427 files_to_check=[r'.*Test\.java$'])
7428
7429 for f in input_api.AffectedSourceFiles(_FilterFile):
7430 batch_matched = None
7431 do_not_batch_matched = None
7432 is_instrumentation_test = True
Mark Schillaci8ef0d872023-07-18 22:07:597433 test_annotation_declaration_matched = None
Andrew Grieve5a66ae72024-12-13 15:21:537434 has_base_robolectric_rule = False
James Shen81cc0e22022-06-15 21:10:457435 for line in f.NewContents():
Andrew Grieve5a66ae72024-12-13 15:21:537436 if 'BaseRobolectricTestRule' in line:
7437 has_base_robolectric_rule = True
7438 continue
7439 if m := robolectric_test.search(line):
7440 is_instrumentation_test = False
7441 if m.group(1) == '' and not has_base_robolectric_rule:
7442 path = str(f.LocalPath())
7443 # These two spots cannot use it.
7444 if 'webapk' not in path and 'build' not in path:
7445 wrong_robolectric_test_runner_errors.append(path)
7446 break
7447 if uiautomator_test.search(line):
James Shen81cc0e22022-06-15 21:10:457448 is_instrumentation_test = False
7449 break
7450 if not batch_matched:
7451 batch_matched = batch_annotation.search(line)
7452 if not do_not_batch_matched:
7453 do_not_batch_matched = do_not_batch_annotation.search(line)
7454 test_class_declaration_matched = test_class_declaration.search(
7455 line)
Mark Schillaci8ef0d872023-07-18 22:07:597456 test_annotation_declaration_matched = test_annotation_declaration.search(line)
7457 if test_class_declaration_matched or test_annotation_declaration_matched:
James Shen81cc0e22022-06-15 21:10:457458 break
Mark Schillaci8ef0d872023-07-18 22:07:597459 if test_annotation_declaration_matched:
7460 continue
James Shen81cc0e22022-06-15 21:10:457461 if (is_instrumentation_test and
7462 not batch_matched and
7463 not do_not_batch_matched):
Sam Maier4cef9242022-10-03 14:21:247464 missing_annotation_errors.append(str(f.LocalPath()))
ckitagawae8fd23b2022-06-17 15:29:387465 if (not is_instrumentation_test and
7466 (batch_matched or
7467 do_not_batch_matched)):
Sam Maier4cef9242022-10-03 14:21:247468 extra_annotation_errors.append(str(f.LocalPath()))
James Shen81cc0e22022-06-15 21:10:457469
7470 results = []
7471
ckitagawae8fd23b2022-06-17 15:29:387472 if missing_annotation_errors:
James Shen81cc0e22022-06-15 21:10:457473 results.append(
7474 output_api.PresubmitPromptWarning(
7475 """
Andrew Grieve43a5cf82023-09-08 15:09:467476A change was made to an on-device test that has neither been annotated with
7477@Batch nor @DoNotBatch. If this is a new test, please add the annotation. If
7478this is an existing test, please consider adding it if you are sufficiently
7479familiar with the test (but do so as a separate change).
7480
Jens Mueller2085ff82023-02-27 11:54:497481See https://source.chromium.org/chromium/chromium/src/+/main:docs/testing/batching_instrumentation_tests.md
ckitagawae8fd23b2022-06-17 15:29:387482""", missing_annotation_errors))
7483 if extra_annotation_errors:
7484 results.append(
7485 output_api.PresubmitPromptWarning(
7486 """
7487Robolectric tests do not need a @Batch or @DoNotBatch annotations.
7488""", extra_annotation_errors))
Andrew Grieve5a66ae72024-12-13 15:21:537489 if wrong_robolectric_test_runner_errors:
7490 results.append(
7491 output_api.PresubmitPromptWarning(
7492 """
Wenyu Fu0005ab82025-01-03 18:13:267493Robolectric tests should use either @RunWith(BaseRobolectricTestRunner.class) (or
Andrew Grieve5a66ae72024-12-13 15:21:537494a subclass of it), or use "@Rule BaseRobolectricTestRule".
7495""", wrong_robolectric_test_runner_errors))
James Shen81cc0e22022-06-15 21:10:457496
7497 return results
Sam Maier4cef9242022-10-03 14:21:247498
7499
Mike Dougherty1b8be712022-10-20 00:15:137500def CheckNoJsInIos(input_api, output_api):
7501 """Checks to make sure that JavaScript files are not used on iOS."""
7502
7503 def _FilterFile(affected_file):
7504 return input_api.FilterSourceFile(
7505 affected_file,
7506 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP +
Daniel White44b8bd02023-08-22 16:20:367507 (r'^ios/third_party/*', r'^ios/tools/*', r'^third_party/*',
7508 r'^components/autofill/ios/form_util/resources/*'),
Mike Dougherty1b8be712022-10-20 00:15:137509 files_to_check=[r'^ios/.*\.js$', r'.*/ios/.*\.js$'])
7510
Mike Dougherty4d1050b2023-03-14 15:59:537511 deleted_files = []
7512
7513 # Collect filenames of all removed JS files.
Arthur Sonzognic66e9c82024-04-23 07:53:047514 for f in input_api.AffectedFiles(file_filter=_FilterFile):
Mike Dougherty4d1050b2023-03-14 15:59:537515 local_path = f.LocalPath()
7516
7517 if input_api.os_path.splitext(local_path)[1] == '.js' and f.Action() == 'D':
7518 deleted_files.append(input_api.os_path.basename(local_path))
7519
Mike Dougherty1b8be712022-10-20 00:15:137520 error_paths = []
Mike Dougherty4d1050b2023-03-14 15:59:537521 moved_paths = []
Mike Dougherty1b8be712022-10-20 00:15:137522 warning_paths = []
7523
7524 for f in input_api.AffectedSourceFiles(_FilterFile):
7525 local_path = f.LocalPath()
7526
7527 if input_api.os_path.splitext(local_path)[1] == '.js':
7528 if f.Action() == 'A':
Mike Dougherty4d1050b2023-03-14 15:59:537529 if input_api.os_path.basename(local_path) in deleted_files:
7530 # This script was probably moved rather than newly created.
7531 # Present a warning instead of an error for these cases.
7532 moved_paths.append(local_path)
7533 else:
7534 error_paths.append(local_path)
Mike Dougherty1b8be712022-10-20 00:15:137535 elif f.Action() != 'D':
7536 warning_paths.append(local_path)
7537
7538 results = []
7539
7540 if warning_paths:
7541 results.append(output_api.PresubmitPromptWarning(
7542 'TypeScript is now fully supported for iOS feature scripts. '
7543 'Consider converting JavaScript files to TypeScript. See '
7544 '//ios/web/public/js_messaging/README.md for more details.',
7545 warning_paths))
7546
Mike Dougherty4d1050b2023-03-14 15:59:537547 if moved_paths:
7548 results.append(output_api.PresubmitPromptWarning(
7549 'Do not use JavaScript on iOS for new files as TypeScript is '
7550 'fully supported. (If this is a moved file, you may leave the '
7551 'script unconverted.) See //ios/web/public/js_messaging/README.md '
7552 'for help using scripts on iOS.', moved_paths))
7553
Mike Dougherty1b8be712022-10-20 00:15:137554 if error_paths:
7555 results.append(output_api.PresubmitError(
7556 'Do not use JavaScript on iOS as TypeScript is fully supported. '
7557 'See //ios/web/public/js_messaging/README.md for help using '
7558 'scripts on iOS.', error_paths))
7559
7560 return results
Hans Wennborg23a81d52023-03-24 16:38:137561
7562def CheckLibcxxRevisionsMatch(input_api, output_api):
7563 """Check to make sure the libc++ version matches across deps files."""
Andrew Grieve21bb6792023-03-27 19:06:487564 # Disable check for changes to sub-repositories.
7565 if input_api.PresubmitLocalPath() != input_api.change.RepositoryRoot():
Sam Maierb926c58c2023-08-08 19:58:257566 return []
Hans Wennborg23a81d52023-03-24 16:38:137567
7568 DEPS_FILES = [ 'DEPS', 'buildtools/deps_revisions.gni' ]
7569
Anton Bershanskyi4253349482025-02-11 21:01:277570 file_filter = lambda f: f.UnixLocalPath() in DEPS_FILES
Hans Wennborg23a81d52023-03-24 16:38:137571 changed_deps_files = input_api.AffectedFiles(file_filter=file_filter)
7572 if not changed_deps_files:
7573 return []
7574
7575 def LibcxxRevision(file):
7576 file = input_api.os_path.join(input_api.PresubmitLocalPath(),
7577 *file.split('/'))
7578 return input_api.re.search(
7579 r'libcxx_revision.*[:=].*[\'"](\w+)[\'"]',
7580 input_api.ReadFile(file)).group(1)
7581
7582 if len(set([LibcxxRevision(f) for f in DEPS_FILES])) == 1:
7583 return []
7584
7585 return [output_api.PresubmitError(
7586 'libcxx_revision not equal across %s' % ', '.join(DEPS_FILES),
7587 changed_deps_files)]
Arthur Sonzogni7109bd32023-10-03 10:34:427588
7589
7590def CheckDanglingUntriaged(input_api, output_api):
7591 """Warn developers adding DanglingUntriaged raw_ptr."""
7592
7593 # Ignore during git presubmit --all.
7594 #
7595 # This would be too costly, because this would check every lines of every
7596 # C++ files. Check from _BANNED_CPP_FUNCTIONS are also reading the whole
7597 # source code, but only once to apply every checks. It seems the bots like
7598 # `win-presubmit` are particularly sensitive to reading the files. Adding
7599 # this check caused the bot to run 2x longer. See https://crbug.com/1486612.
7600 if input_api.no_diffs:
Arthur Sonzogni9eafd222023-11-10 08:50:397601 return []
Arthur Sonzogni7109bd32023-10-03 10:34:427602
7603 def FilterFile(file):
7604 return input_api.FilterSourceFile(
7605 file,
7606 files_to_check=[r".*\.(h|cc|cpp|cxx|m|mm)$"],
7607 files_to_skip=[r"^base/allocator.*"],
7608 )
7609
7610 count = 0
Arthur Sonzognic66e9c82024-04-23 07:53:047611 for f in input_api.AffectedFiles(file_filter=FilterFile):
Arthur Sonzogni9eafd222023-11-10 08:50:397612 count -= sum([l.count("DanglingUntriaged") for l in f.OldContents()])
7613 count += sum([l.count("DanglingUntriaged") for l in f.NewContents()])
Arthur Sonzogni7109bd32023-10-03 10:34:427614
7615 # Most likely, nothing changed:
7616 if count == 0:
7617 return []
7618
7619 # Congrats developers for improving it:
7620 if count < 0:
Arthur Sonzogni9eafd222023-11-10 08:50:397621 message = f"DanglingUntriaged pointers removed: {-count}\nThank you!"
Arthur Sonzogni7109bd32023-10-03 10:34:427622 return [output_api.PresubmitNotifyResult(message)]
7623
7624 # Check for 'DanglingUntriaged-notes' in the description:
7625 notes_regex = input_api.re.compile("DanglingUntriaged-notes[:=]")
7626 if any(
7627 notes_regex.match(line)
7628 for line in input_api.change.DescriptionText().splitlines()):
7629 return []
7630
7631 # Check for DanglingUntriaged-notes in the git footer:
7632 if input_api.change.GitFootersFromDescription().get(
7633 "DanglingUntriaged-notes", []):
7634 return []
7635
7636 message = (
Arthur Sonzogni9eafd222023-11-10 08:50:397637 "Unexpected new occurrences of `DanglingUntriaged` detected. Please\n" +
7638 "avoid adding new ones\n" +
7639 "\n" +
7640 "See documentation:\n" +
7641 "https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr.md\n" +
7642 "\n" +
7643 "See also the guide to fix dangling pointers:\n" +
7644 "https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr_guide.md\n" +
7645 "\n" +
7646 "To disable this warning, please add in the commit description:\n" +
Alex Gough26dcd852023-12-22 16:47:197647 "DanglingUntriaged-notes: <rationale for new untriaged dangling " +
Arthur Sonzogni9eafd222023-11-10 08:50:397648 "pointers>"
Arthur Sonzogni7109bd32023-10-03 10:34:427649 )
7650 return [output_api.PresubmitPromptWarning(message)]
Jan Keitel77be7522023-10-12 20:40:497651
7652def CheckInlineConstexprDefinitionsInHeaders(input_api, output_api):
7653 """Checks that non-static constexpr definitions in headers are inline."""
7654 # In a properly formatted file, constexpr definitions inside classes or
7655 # structs will have additional whitespace at the beginning of the line.
7656 # The pattern looks for variables initialized as constexpr kVar = ...; or
7657 # constexpr kVar{...};
7658 # The pattern does not match expressions that have braces in kVar to avoid
7659 # matching constexpr functions.
7660 pattern = input_api.re.compile(r'^constexpr (?!inline )[^\(\)]*[={]')
7661 attribute_pattern = input_api.re.compile(r'(\[\[[a-zA-Z_:]+\]\]|[A-Z]+[A-Z_]+) ')
7662 problems = []
7663 for f in input_api.AffectedFiles():
7664 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
7665 continue
7666
7667 for line_number, line in f.ChangedContents():
7668 line = attribute_pattern.sub('', line)
7669 if pattern.search(line):
7670 problems.append(
7671 f"{f.LocalPath()}: {line_number}\n {line}")
7672
7673 if problems:
7674 return [
7675 output_api.PresubmitPromptWarning(
7676 'Consider inlining constexpr variable definitions in headers '
7677 'outside of classes to avoid unnecessary copies of the '
7678 'constant. See https://abseil.io/tips/168 for more details.',
7679 problems)
7680 ]
7681 else:
7682 return []
Alison Galed6b25fe2024-04-17 13:59:047683
7684def CheckTodoBugReferences(input_api, output_api):
7685 """Checks that bugs in TODOs use updated issue tracker IDs."""
7686
Manish Goregaokardc9e3512025-02-03 15:30:587687 files_to_skip = ['PRESUBMIT_test.py', r"^third_party/rust/chromium_crates_io/vendor/.*"]
Alison Galed6b25fe2024-04-17 13:59:047688
7689 def _FilterFile(affected_file):
7690 return input_api.FilterSourceFile(
7691 affected_file,
7692 files_to_skip=files_to_skip)
7693
7694 # Monorail bug IDs are all less than or equal to 1524553 so check that all
7695 # bugs in TODOs are greater than that value.
Tom Sepez8e628582025-02-14 02:18:557696 pattern = input_api.re.compile(r'.*\bTODO\([^\)0-9]*([0-9]+)\).*')
Alison Galed6b25fe2024-04-17 13:59:047697 problems = []
7698 for f in input_api.AffectedSourceFiles(_FilterFile):
7699 for line_number, line in f.ChangedContents():
7700 match = pattern.match(line)
7701 if match and int(match.group(1)) <= 1524553:
7702 problems.append(
7703 f"{f.LocalPath()}: {line_number}\n {line}")
7704
7705 if problems:
7706 return [
7707 output_api.PresubmitPromptWarning(
Alison Galecb598de52024-04-26 17:03:257708 'TODOs should use the new Chromium Issue Tracker IDs which can '
7709 'be found by navigating to the bug. See '
7710 'https://crbug.com/336778624 for more details.',
Alison Galed6b25fe2024-04-17 13:59:047711 problems)
7712 ]
7713 else:
7714 return []