blob: f6463a42e0818788e979ba6c12667b677f7128d1 [file] [log] [blame]
Avi Drissman24976592022-09-12 15:24:311# Copyright 2012 The Chromium Authors
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
Daniel Chengd88244472022-05-16 09:08:477See https://www.chromium.org/developers/how-tos/depottools/presubmit-scripts/
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d1982009-02-19 16:33:129"""
Daniel Chenga44a1bcd2022-03-15 20:00:1510
Daniel Chenga37c03db2022-05-12 17:20:3411from typing import Callable
Daniel Chenga44a1bcd2022-03-15 20:00:1512from typing import Optional
13from typing import Sequence
mikt19226ff22024-08-27 05:28:2114from typing import Tuple
Daniel Chenga44a1bcd2022-03-15 20:00:1515from dataclasses import dataclass
16
Saagar Sanghavifceeaae2020-08-12 16:40:3617PRESUBMIT_VERSION = '2.0.0'
[email protected]eea609a2011-11-18 13:10:1218
Dirk Prankee3c9c62d2021-05-18 18:35:5919
[email protected]379e7dd2010-01-28 17:39:2120_EXCLUDED_PATHS = (
Bruce Dawson7f8566b2022-05-06 16:22:1821 # Generated file
Bruce Dawson40fece62022-09-16 19:58:3122 (r"chrome/android/webapk/shell_apk/src/org/chromium"
23 r"/webapk/lib/runtime_library/IWebApkApi.java"),
Mila Greene3aa7222021-09-07 16:34:0824 # File needs to write to stdout to emulate a tool it's replacing.
Bruce Dawson40fece62022-09-16 19:58:3125 r"chrome/updater/mac/keystone/ksadmin.mm",
Ilya Shermane8a7d2d2020-07-25 04:33:4726 # Generated file.
Bruce Dawson40fece62022-09-16 19:58:3127 (r"^components/variations/proto/devtools/"
Ilya Shermanc167a962020-08-18 18:40:2628 r"client_variations.js"),
Bruce Dawson3bd976c2022-05-06 22:47:5229 # These are video files, not typescript.
Bruce Dawson40fece62022-09-16 19:58:3130 r"^media/test/data/.*.ts",
31 r"^native_client_sdksrc/build_tools/make_rules.py",
32 r"^native_client_sdk/src/build_tools/make_simple.py",
33 r"^native_client_sdk/src/tools/.*.mk",
34 r"^net/tools/spdyshark/.*",
35 r"^skia/.*",
36 r"^third_party/blink/.*",
37 r"^third_party/breakpad/.*",
Darwin Huangd74a9d32019-07-17 17:58:4638 # sqlite is an imported third party dependency.
Bruce Dawson40fece62022-09-16 19:58:3139 r"^third_party/sqlite/.*",
40 r"^v8/.*",
[email protected]3e4eb112011-01-18 03:29:5441 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5342 r".+_autogen\.h$",
Yue Shecf1380552022-08-23 20:59:2043 r".+_pb2(_grpc)?\.py$",
Bruce Dawson40fece62022-09-16 19:58:3144 r".+/pnacl_shim\.c$",
45 r"^gpu/config/.*_list_json\.cc$",
46 r"tools/md_browser/.*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1447 # Test pages for Maps telemetry tests.
Bruce Dawson40fece62022-09-16 19:58:3148 r"tools/perf/page_sets/maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5449 # Test pages for WebRTC telemetry tests.
Bruce Dawson40fece62022-09-16 19:58:3150 r"tools/perf/page_sets/webrtc_cases.*",
dpapad2efd4452023-04-06 01:43:4551 # Test file compared with generated output.
52 r"tools/polymer/tests/html_to_wrapper/.*.html.ts$",
dpapada45be36c2024-08-07 20:19:3553 # Third-party dependency frozen at a fixed version.
54 r"chrome/test/data/webui/chromeos/chai_v4.js$",
[email protected]4306417642009-06-11 00:33:4055)
[email protected]ca8d1982009-02-19 16:33:1256
John Abd-El-Malek759fea62021-03-13 03:41:1457_EXCLUDED_SET_NO_PARENT_PATHS = (
58 # It's for historical reasons that blink isn't a top level directory, where
59 # it would be allowed to have "set noparent" to avoid top level owners
60 # accidentally +1ing changes.
61 'third_party/blink/OWNERS',
62)
63
wnwenbdc444e2016-05-25 13:44:1564
[email protected]06e6d0ff2012-12-11 01:36:4465# Fragment of a regular expression that matches C++ and Objective-C++
66# implementation files.
67_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
68
wnwenbdc444e2016-05-25 13:44:1569
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1970# Fragment of a regular expression that matches C++ and Objective-C++
71# header files.
72_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
73
74
Aleksey Khoroshilov9b28c032022-06-03 16:35:3275# Paths with sources that don't use //base.
76_NON_BASE_DEPENDENT_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:3177 r"^chrome/browser/browser_switcher/bho/",
78 r"^tools/win/",
Aleksey Khoroshilov9b28c032022-06-03 16:35:3279)
80
81
[email protected]06e6d0ff2012-12-11 01:36:4482# Regular expression that matches code only used for test binaries
83# (best effort).
84_TEST_CODE_EXCLUDED_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:3185 r'.*/(fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
Marijn Kruisselbrink2a2d5fc2024-05-15 15:23:4986 # Test support files, like:
87 # foo_test_support.cc
88 # bar_test_util_linux.cc (suffix)
89 # baz_test_base.cc
90 r'.+_test_(base|support|util)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
James Cook1b4dc132021-03-09 22:45:1391 # Test suite files, like:
92 # foo_browsertest.cc
93 # bar_unittest_mac.cc (suffix)
94 # baz_unittests.cc (plural)
95 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(s)?(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1296 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1897 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
Victor Hugo Vianna Silvac22e0202021-06-09 19:46:2198 r'.+sync_service_impl_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Bruce Dawson40fece62022-09-16 19:58:3199 r'.*/(test|tool(s)?)/.*',
danakj89f47082020-09-02 17:53:43100 # content_shell is used for running content_browsertests.
Bruce Dawson40fece62022-09-16 19:58:31101 r'content/shell/.*',
danakj89f47082020-09-02 17:53:43102 # Web test harness.
Bruce Dawson40fece62022-09-16 19:58:31103 r'content/web_test/.*',
[email protected]7b054982013-11-27 00:44:47104 # Non-production example code.
Bruce Dawson40fece62022-09-16 19:58:31105 r'mojo/examples/.*',
[email protected]8176de12014-06-20 19:07:08106 # Launcher for running iOS tests on the simulator.
Bruce Dawson40fece62022-09-16 19:58:31107 r'testing/iossim/iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:41108 # EarlGrey app side code for tests.
Bruce Dawson40fece62022-09-16 19:58:31109 r'ios/.*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:17110 # Views Examples code
Bruce Dawson40fece62022-09-16 19:58:31111 r'ui/views/examples/.*',
Austin Sullivan33da70a2020-10-07 15:39:41112 # Chromium Codelab
Bruce Dawson40fece62022-09-16 19:58:31113 r'codelabs/*'
[email protected]06e6d0ff2012-12-11 01:36:44114)
[email protected]ca8d1982009-02-19 16:33:12115
Daniel Bratell609102be2019-03-27 20:53:21116_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:15117
[email protected]eea609a2011-11-18 13:10:12118_TEST_ONLY_WARNING = (
119 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:55120 'production code. If you are doing this from inside another method\n'
121 'named as *ForTesting(), then consider exposing things to have tests\n'
122 'make that same call directly.\n'
123 'If that is not possible, you may put a comment on the same line with\n'
124 ' // IN-TEST \n'
125 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
126 'method and can be ignored. Do not do this inside production code.\n'
127 'The android-binary-size trybot will block if the method exists in the\n'
Yulun Zeng08d7d8c2024-02-01 18:46:54128 'release apk.\n'
129 'Note: this warning might be a false positive (crbug.com/1196548).')
[email protected]eea609a2011-11-18 13:10:12130
131
Daniel Chenga44a1bcd2022-03-15 20:00:15132@dataclass
133class BanRule:
Daniel Chenga37c03db2022-05-12 17:20:34134 # String pattern. If the pattern begins with a slash, the pattern will be
135 # treated as a regular expression instead.
136 pattern: str
137 # Explanation as a sequence of strings. Each string in the sequence will be
138 # printed on its own line.
mikt19226ff22024-08-27 05:28:21139 explanation: Tuple[str, ...]
Daniel Chenga37c03db2022-05-12 17:20:34140 # Whether or not to treat this ban as a fatal error. If unspecified,
141 # defaults to true.
142 treat_as_error: Optional[bool] = None
143 # Paths that should be excluded from the ban check. Each string is a regular
144 # expression that will be matched against the path of the file being checked
145 # relative to the root of the source tree.
146 excluded_paths: Optional[Sequence[str]] = None
[email protected]cf9b78f2012-11-14 11:40:28147
Daniel Chenga44a1bcd2022-03-15 20:00:15148
Daniel Cheng917ce542022-03-15 20:46:57149_BANNED_JAVA_IMPORTS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15150 BanRule(
151 'import java.net.URI;',
152 (
153 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
154 ),
155 excluded_paths=(
156 (r'net/android/javatests/src/org/chromium/net/'
Dirk Prankee4df27972025-02-26 18:39:35157 r'AndroidProxySelectorTest\.java'),
Daniel Chenga44a1bcd2022-03-15 20:00:15158 r'components/cronet/',
159 r'third_party/robolectric/local/',
160 ),
Michael Thiessen44457642020-02-06 00:24:15161 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15162 BanRule(
163 'import android.annotation.TargetApi;',
164 (
165 'Do not use TargetApi, use @androidx.annotation.RequiresApi instead. '
166 'RequiresApi ensures that any calls are guarded by the appropriate '
167 'SDK_INT check. See https://crbug.com/1116486.',
168 ),
169 ),
170 BanRule(
Mohamed Heikal3d7a94c2023-03-28 16:55:24171 'import androidx.test.rule.ActivityTestRule;',
Daniel Chenga44a1bcd2022-03-15 20:00:15172 (
173 'Do not use ActivityTestRule, use '
174 'org.chromium.base.test.BaseActivityTestRule instead.',
175 ),
176 excluded_paths=(
177 'components/cronet/',
178 ),
179 ),
Min Qinbc44383c2023-02-22 17:25:26180 BanRule(
181 'import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;',
182 (
183 'Do not use VectorDrawableCompat, use getResources().getDrawable() to '
184 'avoid extra indirections. Please also add trace event as the call '
185 'might take more than 20 ms to complete.',
186 ),
187 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15188)
wnwenbdc444e2016-05-25 13:44:15189
Daniel Cheng917ce542022-03-15 20:46:57190_BANNED_JAVA_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15191 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41192 'StrictMode.allowThreadDiskReads()',
193 (
194 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
195 'directly.',
196 ),
197 False,
198 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15199 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41200 'StrictMode.allowThreadDiskWrites()',
201 (
202 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
203 'directly.',
204 ),
205 False,
206 ),
Daniel Cheng917ce542022-03-15 20:46:57207 BanRule(
Michael Thiessen0f2547e2020-07-27 21:55:36208 '.waitForIdleSync()',
209 (
210 'Do not use waitForIdleSync as it masks underlying issues. There is '
211 'almost always something else you should wait on instead.',
212 ),
213 False,
214 ),
Ashley Newson09cbd602022-10-26 11:40:14215 BanRule(
Ashley Newsoneb6f5ce2022-10-26 14:45:42216 r'/(?<!\bsuper\.)(?<!\bIntent )\bregisterReceiver\(',
Ashley Newson09cbd602022-10-26 11:40:14217 (
218 'Do not call android.content.Context.registerReceiver (or an override) '
219 'directly. Use one of the wrapper methods defined in '
220 'org.chromium.base.ContextUtils, such as '
221 'registerProtectedBroadcastReceiver, '
222 'registerExportedBroadcastReceiver, or '
223 'registerNonExportedBroadcastReceiver. See their documentation for '
224 'which one to use.',
225 ),
226 True,
227 excluded_paths=(
Ashley Newson22bc26d2022-11-01 20:30:57228 r'.*Test[^a-z]',
229 r'third_party/',
Ashley Newson09cbd602022-10-26 11:40:14230 'base/android/java/src/org/chromium/base/ContextUtils.java',
Brandon Mousseau7e76a9c2022-12-08 22:08:38231 'chromecast/browser/android/apk/src/org/chromium/chromecast/shell/BroadcastReceiverScope.java',
Ashley Newson09cbd602022-10-26 11:40:14232 ),
233 ),
Ted Chocd5b327b12022-11-05 02:13:22234 BanRule(
235 r'/(?:extends|new)\s*(?:android.util.)?Property<[A-Za-z.]+,\s*(?:Integer|Float)>',
236 (
237 'Do not use Property<..., Integer|Float>, but use FloatProperty or '
238 'IntProperty because it will avoid unnecessary autoboxing of '
239 'primitives.',
240 ),
241 ),
Peilin Wangbba4a8652022-11-10 16:33:57242 BanRule(
243 'requestLayout()',
244 (
245 'Layouts can be expensive. Prefer using ViewUtils.requestLayout(), '
246 'which emits a trace event with additional information to help with '
247 'scroll jank investigations. See http://crbug.com/1354176.',
248 ),
249 False,
250 excluded_paths=(
251 'ui/android/java/src/org/chromium/ui/base/ViewUtils.java',
252 ),
253 ),
Ted Chocf40ea9152023-02-14 19:02:39254 BanRule(
Ted Chocf486e3f2024-02-17 05:37:03255 'ProfileManager.getLastUsedRegularProfile()',
Ted Chocf40ea9152023-02-14 19:02:39256 (
257 'Prefer passing in the Profile reference instead of relying on the '
258 'static getLastUsedRegularProfile() call. Only top level entry points '
259 '(e.g. Activities) should call this method. Otherwise, the Profile '
260 'should either be passed in explicitly or retreived from an existing '
261 'entity with a reference to the Profile (e.g. WebContents).',
262 ),
263 False,
264 excluded_paths=(
265 r'.*Test[A-Z]?.*\.java',
266 ),
267 ),
Min Qinbc44383c2023-02-22 17:25:26268 BanRule(
269 r'/(ResourcesCompat|getResources\(\))\.getDrawable\(\)',
270 (
271 'getDrawable() can be expensive. If you have a lot of calls to '
272 'GetDrawable() or your code may introduce janks, please put your calls '
273 'inside a trace().',
274 ),
275 False,
276 excluded_paths=(
277 r'.*Test[A-Z]?.*\.java',
278 ),
279 ),
Henrique Nakashimabbf2b262023-03-10 17:21:39280 BanRule(
281 r'/RecordHistogram\.getHistogram(ValueCount|TotalCount|Samples)ForTesting\(',
282 (
283 'Raw histogram counts are easy to misuse; for example they don\'t reset '
Thiago Perrotta099034f2023-06-05 18:10:20284 'between batched tests. Use HistogramWatcher to check histogram records '
285 'instead.',
Henrique Nakashimabbf2b262023-03-10 17:21:39286 ),
287 False,
288 excluded_paths=(
289 'base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java',
290 'base/test/android/javatests/src/org/chromium/base/test/util/HistogramWatcher.java',
291 ),
292 ),
Jenna Himawan859865d2025-02-25 22:22:31293 BanRule(
294 r'/((announceForAccessibility\()|TYPE_ANNOUNCEMENT)',
295 ('Android 16 deprecates accessibility announcements, characterized by '
296 'the use of announceForAccessibility or the dispatch of '
297 'TYPE_ANNOUNCEMENT accessibility events. See '
298 'https://developer.android.com/about/versions/16/behavior-changes-all#disruptive-a11y'
299 ' for more details and suggested replacements.', ),
300 False,
301 ),
Nate Fischerd541ff82025-03-11 21:34:19302 BanRule(
303 pattern=(r'IS_DESKTOP_ANDROID'),
304 explanation=(
305 'Features which depend on IS_DESKTOP_ANDROID should only exist in '
306 'chrome/ layer and similar layers. Lower layers such as content/ '
307 'should not have features which are only designed for '
308 'desktop-android builds. See https://crbug.com/401628399.', ),
309 treat_as_error=False,
310 excluded_paths=[
311 _THIRD_PARTY_EXCEPT_BLINK, # Don't warn in third_party folders.
312 r'^build/', # This is permitted in build/ folder.
313 r'^chrome/', # This is permitted in chrome/ folder.
314 r'^components/', # This is permitted only for components/ that are not shared by WebView.
315 r'^extensions/', # This is permitted in chrome/ folder.
316 r'^infra/', # This is permitted in infra/ folder.
317 r'^tools/', # This is permitted in tools/ folder.
318 ],
319 ),
Eric Stevensona9a980972017-09-23 00:04:41320)
321
Clement Yan9b330cb2022-11-17 05:25:29322_BANNED_JAVASCRIPT_FUNCTIONS : Sequence [BanRule] = (
323 BanRule(
324 r'/\bchrome\.send\b',
325 (
326 'The use of chrome.send is disallowed in Chrome (context: https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/security/handling-messages-from-web-content.md).',
327 'Please use mojo instead for new webuis. https://docs.google.com/document/d/1RF-GSUoveYa37eoyZ9EhwMtaIwoW7Z88pIgNZ9YzQi4/edit#heading=h.gkk22wgk6wff',
328 ),
329 True,
330 (
331 r'^(?!ash\/webui).+',
332 # TODO(crbug.com/1385601): pre-existing violations still need to be
333 # cleaned up.
Rebekah Potter57aa94df2022-12-13 20:30:58334 'ash/webui/common/resources/cr.m.js',
Clement Yan9b330cb2022-11-17 05:25:29335 'ash/webui/common/resources/multidevice_setup/multidevice_setup_browser_proxy.js',
Martin Bidlingmaiera921fee72023-06-03 07:52:22336 'ash/webui/common/resources/quick_unlock/lock_screen_constants.ts',
Clement Yan9b330cb2022-11-17 05:25:29337 'ash/webui/common/resources/smb_shares/smb_browser_proxy.js',
Chad Duffin06e47de2023-12-14 18:04:13338 'ash/webui/connectivity_diagnostics/resources/connectivity_diagnostics.ts',
Clement Yan9b330cb2022-11-17 05:25:29339 'ash/webui/diagnostics_ui/resources/diagnostics_browser_proxy.ts',
340 'ash/webui/multidevice_debug/resources/logs.js',
341 'ash/webui/multidevice_debug/resources/webui.js',
342 'ash/webui/projector_app/resources/annotator/trusted/annotator_browser_proxy.js',
343 'ash/webui/projector_app/resources/app/trusted/projector_browser_proxy.js',
Ashley Prasad71f9024e2023-09-25 22:33:55344 # TODO(b/301634378): Remove violation exception once Scanning App
345 # migrated off usage of `chrome.send`.
346 'ash/webui/scanning/resources/scanning_browser_proxy.ts',
Clement Yan9b330cb2022-11-17 05:25:29347 ),
348 ),
349)
350
Daniel Cheng917ce542022-03-15 20:46:57351_BANNED_OBJC_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15352 BanRule(
[email protected]127f18ec2012-06-16 05:05:59353 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20354 (
355 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59356 'prohibited. Please use CrTrackingArea instead.',
357 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
358 ),
359 False,
360 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15361 BanRule(
[email protected]eaae1972014-04-16 04:17:26362 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20363 (
364 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59365 'instead.',
366 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
367 ),
368 False,
369 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15370 BanRule(
[email protected]127f18ec2012-06-16 05:05:59371 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20372 (
373 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59374 'Please use |convertPoint:(point) fromView:nil| instead.',
375 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
376 ),
377 True,
378 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15379 BanRule(
[email protected]127f18ec2012-06-16 05:05:59380 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20381 (
382 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59383 'Please use |convertPoint:(point) toView:nil| instead.',
384 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
385 ),
386 True,
387 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15388 BanRule(
[email protected]127f18ec2012-06-16 05:05:59389 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20390 (
391 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59392 'Please use |convertRect:(point) fromView:nil| instead.',
393 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
394 ),
395 True,
396 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15397 BanRule(
[email protected]127f18ec2012-06-16 05:05:59398 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20399 (
400 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59401 'Please use |convertRect:(point) toView:nil| instead.',
402 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
403 ),
404 True,
405 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15406 BanRule(
[email protected]127f18ec2012-06-16 05:05:59407 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20408 (
409 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59410 'Please use |convertSize:(point) fromView:nil| instead.',
411 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
412 ),
413 True,
414 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15415 BanRule(
[email protected]127f18ec2012-06-16 05:05:59416 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20417 (
418 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59419 'Please use |convertSize:(point) toView:nil| instead.',
420 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
421 ),
422 True,
423 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15424 BanRule(
jif65398702016-10-27 10:19:48425 r"/\s+UTF8String\s*]",
426 (
427 'The use of -[NSString UTF8String] is dangerous as it can return null',
428 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
429 'Please use |SysNSStringToUTF8| instead.',
430 ),
431 True,
Marijn Kruisselbrink1b7c48952023-08-31 16:58:34432 excluded_paths = (
433 '^third_party/ocmock/OCMock/',
434 ),
jif65398702016-10-27 10:19:48435 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15436 BanRule(
Sylvain Defresne4cf1d182017-09-18 14:16:34437 r'__unsafe_unretained',
438 (
439 'The use of __unsafe_unretained is almost certainly wrong, unless',
440 'when interacting with NSFastEnumeration or NSInvocation.',
441 'Please use __weak in files build with ARC, nothing otherwise.',
442 ),
443 False,
444 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15445 BanRule(
Avi Drissman7382afa02019-04-29 23:27:13446 'freeWhenDone:NO',
447 (
448 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
449 'Foundation types is prohibited.',
450 ),
451 True,
452 ),
Avi Drissman3d243a42023-08-01 16:53:59453 BanRule(
454 'This file requires ARC support.',
455 (
456 'ARC compilation is default in Chromium; do not add boilerplate to ',
457 'files that require ARC.',
458 ),
459 True,
460 ),
[email protected]127f18ec2012-06-16 05:05:59461)
462
Sylvain Defresnea8b73d252018-02-28 15:45:54463_BANNED_IOS_OBJC_FUNCTIONS = (
Daniel Chenga44a1bcd2022-03-15 20:00:15464 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54465 r'/\bTEST[(]',
466 (
467 'TEST() macro should not be used in Objective-C++ code as it does not ',
468 'drain the autorelease pool at the end of the test. Use TEST_F() ',
469 'macro instead with a fixture inheriting from PlatformTest (or a ',
470 'typedef).'
471 ),
472 True,
473 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15474 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54475 r'/\btesting::Test\b',
476 (
477 'testing::Test should not be used in Objective-C++ code as it does ',
478 'not drain the autorelease pool at the end of the test. Use ',
479 'PlatformTest instead.'
480 ),
481 True,
482 ),
Ewann2ecc8d72022-07-18 07:41:23483 BanRule(
484 ' systemImageNamed:',
485 (
486 '+[UIImage systemImageNamed:] should not be used to create symbols.',
487 'Instead use a wrapper defined in:',
Slobodan Pejic8ef56c702024-07-12 18:21:26488 'ios/chrome/browser/shared/ui/symbols/symbol_helpers.h'
Ewann2ecc8d72022-07-18 07:41:23489 ),
490 True,
Ewann450a2ef2022-07-19 14:38:23491 excluded_paths=(
Gauthier Ambard4d8756b2023-04-07 17:26:41492 'ios/chrome/browser/shared/ui/symbols/symbol_helpers.mm',
Slobodan Pejic8ef56c702024-07-12 18:21:26493 'ios/chrome/common',
Tommy Martino2a1182dc2024-11-20 19:34:42494 # App extensions have restricted dependencies and thus can't use the
495 # wrappers.
Riley Wong49be8a882025-02-27 00:38:23496 r'^ios/chrome/\w+_extension/',
Ewann450a2ef2022-07-19 14:38:23497 ),
Ewann2ecc8d72022-07-18 07:41:23498 ),
Sylvain Defresne781b9f92024-12-11 09:36:18499 BanRule(
500 r'public (RefCounted)?BrowserStateKeyedServiceFactory',
501 (
502 'KeyedService factories in //ios/chrome/browser should inherit from',
503 '(Refcounted)?ProfileKeyedServieFactoryIOS, not directory from',
504 '(Refcounted)?BrowserStateKeyedServiceFactory.'
505 ),
506 treat_as_error=True,
507 excluded_paths=(
508 'ios/components',
509 'ios/web_view',
510 ),
511 ),
Sylvain Defresnea8b73d252018-02-28 15:45:54512)
513
Daniel Cheng917ce542022-03-15 20:46:57514_BANNED_IOS_EGTEST_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15515 BanRule(
Peter K. Lee6c03ccff2019-07-15 14:40:05516 r'/\bEXPECT_OCMOCK_VERIFY\b',
517 (
518 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
519 'it is meant for GTests. Use [mock verify] instead.'
520 ),
521 True,
522 ),
523)
524
Daniel Cheng566634ff2024-06-29 14:56:53525_BANNED_CPP_FUNCTIONS: Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15526 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53527 '%#0',
528 (
529 'Zero-padded values that use "#" to add prefixes don\'t exhibit ',
530 'consistent behavior, since the prefix is not prepended for zero ',
531 'values. Use "0x%0..." instead.',
532 ),
533 False,
534 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting7c0d98a2023-10-06 15:42:39535 ),
536 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53537 r'/\busing namespace ',
538 (
539 'Using directives ("using namespace x") are banned by the Google Style',
540 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
541 'Explicitly qualify symbols or use using declarations ("using x::foo").',
542 ),
543 True,
544 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting94a56c42019-10-25 21:54:04545 ),
Antonio Gomes07300d02019-03-13 20:59:57546 # Make sure that gtest's FRIEND_TEST() macro is not used; the
547 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
548 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
Daniel Chenga44a1bcd2022-03-15 20:00:15549 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53550 'FRIEND_TEST(',
551 (
552 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
553 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
554 ),
555 False,
556 excluded_paths=(
557 "base/gtest_prod_util.h",
558 "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/gtest_prod_util.h",
559 ),
[email protected]23e6cbc2012-06-16 18:51:20560 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15561 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53562 'setMatrixClip',
563 (
564 'Overriding setMatrixClip() is prohibited; ',
565 'the base function is deprecated. ',
566 ),
567 True,
568 (),
tomhudsone2c14d552016-05-26 17:07:46569 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15570 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53571 'SkRefPtr',
572 ('The use of SkRefPtr is prohibited. ', 'Please use sk_sp<> instead.'),
573 True,
574 (),
[email protected]52657f62013-05-20 05:30:31575 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15576 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53577 'SkAutoRef',
578 ('The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
579 'Please use sk_sp<> instead.'),
580 True,
581 (),
[email protected]52657f62013-05-20 05:30:31582 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15583 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53584 'SkAutoTUnref',
585 ('The use of SkAutoTUnref is dangerous because it implicitly ',
586 'converts to a raw pointer. Please use sk_sp<> instead.'),
587 True,
588 (),
[email protected]52657f62013-05-20 05:30:31589 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15590 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53591 'SkAutoUnref',
592 ('The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
593 'because it implicitly converts to a raw pointer. ',
594 'Please use sk_sp<> instead.'),
595 True,
596 (),
[email protected]52657f62013-05-20 05:30:31597 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15598 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53599 r'/HANDLE_EINTR\(.*close',
600 ('HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
601 'descriptor will be closed, and it is incorrect to retry the close.',
602 'Either call close directly and ignore its return value, or wrap close',
603 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
604 ),
605 True,
606 (),
[email protected]d89eec82013-12-03 14:10:59607 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15608 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53609 r'/IGNORE_EINTR\((?!.*close)',
610 (
611 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
612 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
613 ),
614 True,
615 (
616 # Files that #define IGNORE_EINTR.
617 r'^base/posix/eintr_wrapper\.h$',
618 r'^ppapi/tests/test_broker\.cc$',
619 ),
[email protected]d89eec82013-12-03 14:10:59620 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15621 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53622 r'/v8::Extension\(',
623 (
624 'Do not introduce new v8::Extensions into the code base, use',
625 'gin::Wrappable instead. See http://crbug.com/334679',
626 ),
627 True,
628 (r'extensions/renderer/safe_builtins\.*', ),
[email protected]ec5b3f02014-04-04 18:43:43629 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15630 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53631 '#pragma comment(lib,',
632 ('Specify libraries to link with in build files and not in the source.',
633 ),
634 True,
635 (
636 r'^base/third_party/symbolize/.*',
637 r'^third_party/abseil-cpp/.*',
Victor Hugo Vianna Silvac86846c02025-03-07 06:56:37638 r'^third_party/grpc/source/.*',
Daniel Cheng566634ff2024-06-29 14:56:53639 ),
jame2d1a952016-04-02 00:27:10640 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15641 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53642 r'/base::SequenceChecker\b',
643 ('Consider using SEQUENCE_CHECKER macros instead of the class directly.',
644 ),
645 False,
646 (),
gabd52c912a2017-05-11 04:15:59647 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15648 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53649 r'/base::ThreadChecker\b',
650 ('Consider using THREAD_CHECKER macros instead of the class directly.',
651 ),
652 False,
653 (),
gabd52c912a2017-05-11 04:15:59654 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15655 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53656 r'/\b(?!(Sequenced|SingleThread))\w*TaskRunner::(GetCurrentDefault|CurrentDefaultHandle)',
657 (
658 'It is not allowed to call these methods from the subclasses ',
659 'of Sequenced or SingleThread task runners.',
660 ),
661 True,
662 (),
Sean Maher03efef12022-09-23 22:43:13663 ),
664 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53665 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
666 (
667 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
668 'deprecated (http://crbug.com/634507). Please avoid converting away',
669 'from the Time types in Chromium code, especially if any math is',
670 'being done on time values. For interfacing with platform/library',
671 'APIs, use base::Time::(From,To)DeltaSinceWindowsEpoch() or',
672 'base::{TimeDelta::In}Microseconds(), or one of the other type',
673 'converter methods instead. For faking TimeXXX values (for unit',
674 'testing only), use TimeXXX() + Microseconds(N). For',
675 'other use cases, please contact base/time/OWNERS.',
676 ),
677 False,
678 excluded_paths=(
679 "base/time/time.h",
680 "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/time/time.h",
681 ),
Yuri Wiitala2f8de5c2017-07-21 00:11:06682 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15683 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53684 'CallJavascriptFunctionUnsafe',
685 (
686 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
687 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
688 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
689 ),
690 False,
691 (
692 r'^content/browser/webui/web_ui_impl\.(cc|h)$',
693 r'^content/public/browser/web_ui\.h$',
694 r'^content/public/test/test_web_ui\.(cc|h)$',
695 ),
dbeamb6f4fde2017-06-15 04:03:06696 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15697 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53698 'leveldb::DB::Open',
699 (
700 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
701 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
702 "Chrome's tracing, making their memory usage visible.",
703 ),
704 True,
705 (r'^third_party/leveldatabase/.*\.(cc|h)$', ),
Gabriel Charette0592c3a2017-07-26 12:02:04706 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15707 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53708 'leveldb::NewMemEnv',
709 (
710 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
711 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
712 "to Chrome's tracing, making their memory usage visible.",
713 ),
714 True,
715 (r'^third_party/leveldatabase/.*\.(cc|h)$', ),
Chris Mumfordc38afb62017-10-09 17:55:08716 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15717 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53718 'base::ScopedMockTimeMessageLoopTaskRunner',
719 (
720 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
721 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
722 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
723 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
724 'with gab@ first if you think you need it)',
725 ),
726 False,
727 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57728 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15729 BanRule(
Peter Kasting5fdcd782025-01-13 14:57:07730 '\bstd::aligned_(storage|union)\b',
731 (
732 'std::aligned_storage and std::aligned_union are deprecated in',
733 'C++23. Use an aligned char array instead.'
734 ),
735 True,
736 (),
737 ),
738 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53739 'std::regex',
740 (
741 'Using std::regex adds unnecessary binary size to Chrome. Please use',
742 're2::RE2 instead (crbug.com/755321)',
743 ),
744 True,
745 [
746 # Abseil's benchmarks never linked into chrome.
747 'third_party/abseil-cpp/.*_benchmark.cc',
748 ],
Francois Doray43670e32017-09-27 12:40:38749 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15750 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53751 r'/\bstd::sto(i|l|ul|ll|ull)\b',
752 (
753 'std::sto{i,l,ul,ll,ull}() use exceptions to communicate results. ',
754 'Use base::StringTo[U]Int[64]() instead.',
755 ),
756 True,
757 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting991618a62019-06-17 22:00:09758 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15759 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53760 r'/\bstd::sto(f|d|ld)\b',
761 (
762 'std::sto{f,d,ld}() use exceptions to communicate results. ',
763 'For locale-independent values, e.g. reading numbers from disk',
764 'profiles, use base::StringToDouble().',
765 'For user-visible values, parse using ICU.',
766 ),
767 True,
768 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting991618a62019-06-17 22:00:09769 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15770 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53771 r'/\bstd::to_string\b',
772 (
773 'std::to_string() is locale dependent and slower than alternatives.',
774 'For locale-independent strings, e.g. writing numbers to disk',
775 'profiles, use base::NumberToString().',
776 'For user-visible strings, use base::FormatNumber() and',
777 'the related functions in base/i18n/number_formatting.h.',
778 ),
779 True,
780 [
781 # TODO(crbug.com/335672557): Please do not add to this list. Existing
782 # uses should removed.
Daniel Cheng566634ff2024-06-29 14:56:53783 "third_party/blink/renderer/core/css/parser/css_proto_converter.cc",
784 "third_party/blink/renderer/core/editing/ime/edit_context.cc",
785 "third_party/blink/renderer/platform/graphics/bitmap_image_test.cc",
Daniel Cheng566634ff2024-06-29 14:56:53786 _THIRD_PARTY_EXCEPT_BLINK
787 ],
Daniel Bratell69334cc2019-03-26 11:07:45788 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15789 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53790 r'/#include <(cctype|ctype\.h|cwctype|wctype.h)>',
791 (
792 '<cctype>/<ctype.h>/<cwctype>/<wctype.h> are banned. Use',
793 '"third_party/abseil-cpp/absl/strings/ascii.h" instead.',
794 ),
795 True,
796 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting6f79b202023-08-09 21:25:41797 ),
798 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53799 r'/\bstd::shared_ptr\b',
800 ('std::shared_ptr is banned. Use scoped_refptr instead.', ),
801 True,
802 [
803 # Needed for interop with third-party library.
Dirk Prankee4df27972025-02-26 18:39:35804 r'^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
805 r'array_buffer_contents\.(cc|h)',
806 r'^third_party/blink/renderer/core/typed_arrays/dom_array_buffer\.cc',
Daniel Cheng566634ff2024-06-29 14:56:53807 '^third_party/blink/renderer/bindings/core/v8/' +
808 'v8_wasm_response_extensions.cc',
Dirk Prankee4df27972025-02-26 18:39:35809 r'^gin/array_buffer\.(cc|h)',
810 r'^gin/per_isolate_data\.(cc|h)',
Daniel Cheng566634ff2024-06-29 14:56:53811 '^chrome/services/sharing/nearby/',
812 # Needed for interop with third-party library libunwindstack.
Dirk Prankee4df27972025-02-26 18:39:35813 r'^base/profiler/libunwindstack_unwinder_android\.(cc|h)',
814 r'^base/profiler/native_unwinder_android_memory_regions_map_impl.(cc|h)',
Daniel Cheng566634ff2024-06-29 14:56:53815 # Needed for interop with third-party boringssl cert verifier
816 '^third_party/boringssl/',
817 '^net/cert/',
818 '^net/tools/cert_verify_tool/',
819 '^services/cert_verifier/',
820 '^components/certificate_transparency/',
821 '^components/media_router/common/providers/cast/certificate/',
822 # gRPC provides some C++ libraries that use std::shared_ptr<>.
823 '^chromeos/ash/services/libassistant/grpc/',
824 '^chromecast/cast_core/grpc',
825 '^chromecast/cast_core/runtime/browser',
Dirk Prankee4df27972025-02-26 18:39:35826 r'^ios/chrome/test/earl_grey/chrome_egtest_plugin_client\.(mm|h)',
Daniel Cheng566634ff2024-06-29 14:56:53827 # Fuchsia provides C++ libraries that use std::shared_ptr<>.
Dirk Prankee4df27972025-02-26 18:39:35828 r'^base/fuchsia/.*\.(cc|h)',
829 r'.*fuchsia.*test\.(cc|h)',
Daniel Cheng566634ff2024-06-29 14:56:53830 # Clang plugins have different build config.
831 '^tools/clang/plugins/',
832 _THIRD_PARTY_EXCEPT_BLINK
833 ], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21834 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15835 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53836 r'/\bstd::weak_ptr\b',
837 ('std::weak_ptr is banned. Use base::WeakPtr instead.', ),
838 True,
839 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting991618a62019-06-17 22:00:09840 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15841 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53842 r'/\blong long\b',
843 ('long long is banned. Use [u]int64_t instead.', ),
844 False, # Only a warning since it is already used.
845 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21846 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15847 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53848 r'/\b(absl|std)::any\b',
849 (
850 '{absl,std}::any are banned due to incompatibility with the component ',
851 'build.',
852 ),
853 True,
854 # Not an error in third party folders, though it probably should be :)
855 [_THIRD_PARTY_EXCEPT_BLINK],
Daniel Chengc05fcc62022-01-12 16:54:29856 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15857 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53858 r'/\bstd::bind\b',
859 (
860 'std::bind() is banned because of lifetime risks. Use ',
861 'base::Bind{Once,Repeating}() instead.',
862 ),
863 True,
864 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21865 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15866 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53867 (r'/\bstd::(?:'
868 r'linear_congruential_engine|mersenne_twister_engine|'
869 r'subtract_with_carry_engine|discard_block_engine|'
870 r'independent_bits_engine|shuffle_order_engine|'
871 r'minstd_rand0?|mt19937(_64)?|ranlux(24|48)(_base)?|knuth_b|'
872 r'default_random_engine|'
873 r'random_device|'
874 r'seed_seq'
875 r')\b'),
876 (
877 'STL random number engines and generators are banned. Use the ',
878 'helpers in base/rand_util.h instead, e.g. base::RandBytes() or ',
879 'base::RandomBitGenerator.'
880 '',
881 'Please reach out to [email protected] if the base APIs are ',
882 'insufficient for your needs.',
883 ),
884 True,
885 [
886 # Not an error in third_party folders.
887 _THIRD_PARTY_EXCEPT_BLINK,
888 # Various tools which build outside of Chrome.
889 r'testing/libfuzzer',
Steinar H. Gundersone5689e42024-08-07 18:17:19890 r'testing/perf/confidence',
Daniel Cheng566634ff2024-06-29 14:56:53891 r'tools/android/io_benchmark/',
892 # Fuzzers are allowed to use standard library random number generators
893 # since fuzzing speed + reproducibility is important.
894 r'tools/ipc_fuzzer/',
895 r'.+_fuzzer\.cc$',
896 r'.+_fuzzertest\.cc$',
897 # TODO(https://crbug.com/1380528): These are all unsanctioned uses of
898 # the standard library's random number generators, and should be
899 # migrated to the //base equivalent.
900 r'ash/ambient/model/ambient_topic_queue\.cc',
901 r'base/allocator/partition_allocator/src/partition_alloc/partition_alloc_unittest\.cc',
Daniel Cheng566634ff2024-06-29 14:56:53902 r'base/test/launcher/test_launcher\.cc',
903 r'cc/metrics/video_playback_roughness_reporter_unittest\.cc',
904 r'chrome/browser/apps/app_service/metrics/website_metrics\.cc',
905 r'chrome/browser/ash/power/auto_screen_brightness/monotone_cubic_spline_unittest\.cc',
906 r'chrome/browser/ash/printing/zeroconf_printer_detector_unittest\.cc',
907 r'chrome/browser/nearby_sharing/contacts/nearby_share_contact_manager_impl_unittest\.cc',
908 r'chrome/browser/nearby_sharing/contacts/nearby_share_contacts_sorter_unittest\.cc',
909 r'chrome/browser/privacy_budget/mesa_distribution_unittest\.cc',
910 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
911 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
912 r'chrome/browser/win/conflicts/module_blocklist_cache_util_unittest\.cc',
913 r'chromeos/ash/components/memory/userspace_swap/swap_storage_unittest\.cc',
914 r'chromeos/ash/components/memory/userspace_swap/userspace_swap\.cc',
915 r'components/metrics/metrics_state_manager\.cc',
916 r'components/omnibox/browser/history_quick_provider_performance_unittest\.cc',
917 r'components/zucchini/disassembler_elf_unittest\.cc',
918 r'content/browser/webid/federated_auth_request_impl\.cc',
919 r'content/browser/webid/federated_auth_request_impl\.cc',
920 r'media/cast/test/utility/udp_proxy\.h',
921 r'sql/recover_module/module_unittest\.cc',
922 r'components/search_engines/template_url_prepopulate_data.cc',
923 # Do not add new entries to this list. If you have a use case which is
924 # not satisfied by the current APIs (i.e. you need an explicitly-seeded
925 # sequence, or stability of some sort is required), please contact
926 # [email protected].
927 ],
Daniel Cheng192683f2022-11-01 20:52:44928 ),
929 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53930 r'/\b(absl,std)::bind_front\b',
931 ('{absl,std}::bind_front() are banned. Use base::Bind{Once,Repeating}() '
932 'instead.', ),
933 True,
934 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12935 ),
936 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53937 r'/\bABSL_FLAG\b',
938 ('ABSL_FLAG is banned. Use base::CommandLine instead.', ),
939 True,
940 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12941 ),
942 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53943 r'/\babsl::c_',
944 (
Peter Kasting3b811ffd2025-01-29 22:20:16945 'Abseil container utilities are banned. Use std::ranges:: instead.',
Daniel Cheng566634ff2024-06-29 14:56:53946 ),
947 True,
948 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12949 ),
950 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53951 r'/\babsl::FixedArray\b',
952 ('absl::FixedArray is banned. Use base::FixedArray instead.', ),
953 True,
954 [
955 # base::FixedArray provides canonical access.
956 r'^base/types/fixed_array.h',
957 # Not an error in third_party folders.
958 _THIRD_PARTY_EXCEPT_BLINK,
959 ],
Peter Kasting431239a2023-09-29 03:11:44960 ),
961 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53962 r'/\babsl::FunctionRef\b',
963 ('absl::FunctionRef is banned. Use base::FunctionRef instead.', ),
964 True,
965 [
966 # base::Bind{Once,Repeating} references absl::FunctionRef to disallow
967 # interoperability.
968 r'^base/functional/bind_internal\.h',
969 # base::FunctionRef is implemented on top of absl::FunctionRef.
970 r'^base/functional/function_ref.*\..+',
971 # Not an error in third_party folders.
972 _THIRD_PARTY_EXCEPT_BLINK,
973 ],
Peter Kasting4f35bfc2022-10-18 18:39:12974 ),
975 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53976 r'/\babsl::(Insecure)?BitGen\b',
977 ('absl random number generators are banned. Use the helpers in '
978 'base/rand_util.h instead, e.g. base::RandBytes() or ',
979 'base::RandomBitGenerator.'),
980 True,
981 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12982 ),
983 BanRule(
Peter Kasting3b77a0c2024-08-22 00:22:26984 pattern=
985 r'/\babsl::(optional|nullopt|make_optional)\b',
986 explanation=('absl::optional is banned. Use std::optional instead.', ),
987 treat_as_error=True,
988 excluded_paths=[
989 _THIRD_PARTY_EXCEPT_BLINK,
990 ]),
991 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53992 r'/(\babsl::Span\b|#include <span>|\bstd::span\b)',
993 (
Peter Kastinge73b89d2024-11-26 19:35:52994 'absl::Span and std::span are banned. Use base::span instead.',
Daniel Cheng566634ff2024-06-29 14:56:53995 ),
996 True,
997 [
998 # Included for conversions between base and std.
999 r'base/containers/span.h',
1000 # Test base::span<> compatibility against std::span<>.
1001 r'base/containers/span_unittest.cc',
1002 # //base/numerics can't use base or absl. So it uses std.
1003 r'base/numerics/.*'
Lei Zhang1f9d9ec42024-06-20 18:42:271004
Daniel Cheng566634ff2024-06-29 14:56:531005 # Needed to use QUICHE API.
Ciara McMullinc029c8e2024-08-21 14:22:321006 r'android_webview/browser/ip_protection/.*',
Daniel Cheng566634ff2024-06-29 14:56:531007 r'chrome/browser/ip_protection/.*',
1008 r'components/ip_protection/.*',
1009 r'net/third_party/quiche/overrides/quiche_platform_impl/quiche_stack_trace_impl\.*',
1010 r'services/network/web_transport\.cc',
Lei Zhang1f9d9ec42024-06-20 18:42:271011
Daniel Cheng566634ff2024-06-29 14:56:531012 # Not an error in third_party folders.
1013 _THIRD_PARTY_EXCEPT_BLINK,
1014 ],
Peter Kasting4f35bfc2022-10-18 18:39:121015 ),
1016 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531017 r'/\babsl::StatusOr\b',
1018 ('absl::StatusOr is banned. Use base::expected instead.', ),
1019 True,
1020 [
1021 # Needed to use liburlpattern API.
1022 r'components/url_pattern/.*',
1023 r'services/network/shared_dictionary/simple_url_pattern_matcher\.cc',
1024 r'third_party/blink/renderer/core/url_pattern/.*',
1025 r'third_party/blink/renderer/modules/manifest/manifest_parser\.cc',
Lei Zhang1f9d9ec42024-06-20 18:42:271026
Daniel Cheng566634ff2024-06-29 14:56:531027 # Needed to use QUICHE API.
Ciara McMullinc029c8e2024-08-21 14:22:321028 r'android_webview/browser/ip_protection/.*',
Daniel Cheng566634ff2024-06-29 14:56:531029 r'chrome/browser/ip_protection/.*',
1030 r'components/ip_protection/.*',
Lei Zhang1f9d9ec42024-06-20 18:42:271031
Daniel Cheng566634ff2024-06-29 14:56:531032 # Needed to use MediaPipe API.
1033 r'components/media_effects/.*\.cc',
1034 # Not an error in third_party folders.
1035 _THIRD_PARTY_EXCEPT_BLINK
1036 ],
Peter Kasting4f35bfc2022-10-18 18:39:121037 ),
1038 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531039 r'/\babsl::(StrSplit|StrJoin|StrCat|StrAppend|Substitute|StrContains)\b',
1040 ('Abseil string utilities are banned. Use base/strings instead.', ),
1041 True,
1042 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:121043 ),
1044 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531045 r'/\babsl::(Mutex|CondVar|Notification|Barrier|BlockingCounter)\b',
1046 (
1047 'Abseil synchronization primitives are banned. Use',
1048 'base/synchronization instead.',
1049 ),
1050 True,
1051 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:121052 ),
1053 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531054 r'/\babsl::(Duration|Time|TimeZone|CivilDay)\b',
1055 ('Abseil\'s time library is banned. Use base/time instead.', ),
1056 True,
1057 [
1058 # Needed to use QUICHE API.
Ciara McMullinc029c8e2024-08-21 14:22:321059 r'android_webview/browser/ip_protection/.*',
Daniel Cheng566634ff2024-06-29 14:56:531060 r'chrome/browser/ip_protection/.*',
1061 r'components/ip_protection/.*',
Lei Zhang1f9d9ec42024-06-20 18:42:271062
Daniel Cheng566634ff2024-06-29 14:56:531063 # Needed to integrate with //third_party/nearby
1064 r'components/cross_device/nearby/system_clock.cc',
1065 _THIRD_PARTY_EXCEPT_BLINK # Not an error in third_party folders.
1066 ],
1067 ),
1068 BanRule(
Victor Hugo Vianna Silva6e84e8d42025-03-19 00:32:001069 r'/absl::(bad_variant_access|get|holds_alternative|monostate|variant|'
1070 r'visit)',
1071 ('Abseil\'s variant library is banned, use std.', ),
1072 # TODO(crbug.com/40242126): Make it an error once we're sure it works.
1073 False,
1074 [
1075 _THIRD_PARTY_EXCEPT_BLINK
1076 ],
1077 ),
1078 BanRule(
1079 r'/absl::(apply|exchange|forward|in_place|index_sequence|'
1080 r'integer_sequence|make_from_tuple|make_index_sequence|'
1081 r'make_integer_sequence|move)',
1082 ('Abseil\'s util library is banned, use std.', ),
1083 # TODO(crbug.com/40242126): Make it an error once we're sure it works.
1084 False,
1085 [
1086 _THIRD_PARTY_EXCEPT_BLINK
1087 ],
1088 ),
1089 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531090 r'/#include <chrono>',
1091 ('<chrono> is banned. Use base/time instead.', ),
1092 True,
1093 [
1094 # Not an error in third_party folders:
1095 _THIRD_PARTY_EXCEPT_BLINK,
Daniel Cheng566634ff2024-06-29 14:56:531096 # This uses openscreen API depending on std::chrono.
1097 "components/openscreen_platform/task_runner.cc",
1098 ]),
1099 BanRule(
1100 r'/#include <exception>',
1101 ('Exceptions are banned and disabled in Chromium.', ),
1102 True,
1103 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1104 ),
1105 BanRule(
1106 r'/\bstd::function\b',
1107 ('std::function is banned. Use base::{Once,Repeating}Callback instead.',
1108 ),
1109 True,
1110 [
1111 # Has tests that template trait helpers don't unintentionally match
1112 # std::function.
1113 r'base/functional/callback_helpers_unittest\.cc',
1114 # Required to implement interfaces from the third-party perfetto
1115 # library.
1116 r'base/tracing/perfetto_task_runner\.cc',
1117 r'base/tracing/perfetto_task_runner\.h',
1118 # Needed for interop with the third-party nearby library type
1119 # location::nearby::connections::ResultCallback.
Dirk Prankee4df27972025-02-26 18:39:351120 r'chrome/services/sharing/nearby/nearby_connections_conversions\.cc'
Daniel Cheng566634ff2024-06-29 14:56:531121 # Needed for interop with the internal libassistant library.
Dirk Prankee4df27972025-02-26 18:39:351122 r'chromeos/ash/services/libassistant/callback_utils\.h',
Daniel Cheng566634ff2024-06-29 14:56:531123 # Needed for interop with Fuchsia fidl APIs.
Dirk Prankee4df27972025-02-26 18:39:351124 r'fuchsia_web/webengine/browser/context_impl_browsertest\.cc',
1125 r'fuchsia_web/webengine/browser/cookie_manager_impl_unittest\.cc',
1126 r'fuchsia_web/webengine/browser/media_player_impl_unittest\.cc',
Daniel Cheng566634ff2024-06-29 14:56:531127 # Required to interop with interfaces from the third-party ChromeML
1128 # library API.
Dirk Prankee4df27972025-02-26 18:39:351129 r'services/on_device_model/ml/chrome_ml_api\.h',
1130 r'services/on_device_model/ml/on_device_model_executor\.cc',
1131 r'services/on_device_model/ml/on_device_model_executor\.h',
Daniel Cheng566634ff2024-06-29 14:56:531132 # Required to interop with interfaces from the third-party perfetto
1133 # library.
Dirk Prankee4df27972025-02-26 18:39:351134 r'components/tracing/common/etw_consumer_win_unittest\.cc',
1135 r'services/tracing/public/cpp/perfetto/custom_event_recorder\.cc',
1136 r'services/tracing/public/cpp/perfetto/perfetto_traced_process\.cc',
1137 r'services/tracing/public/cpp/perfetto/perfetto_traced_process\.h',
1138 r'services/tracing/public/cpp/perfetto/perfetto_tracing_backend\.cc',
1139 r'services/tracing/public/cpp/perfetto/producer_client\.cc',
1140 r'services/tracing/public/cpp/perfetto/producer_client\.h',
1141 r'services/tracing/public/cpp/perfetto/producer_test_utils\.cc',
1142 r'services/tracing/public/cpp/perfetto/producer_test_utils\.h',
Daniel Cheng566634ff2024-06-29 14:56:531143 # Required for interop with the third-party webrtc library.
Dirk Prankee4df27972025-02-26 18:39:351144 r'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.cc',
1145 r'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.h',
Daniel Cheng566634ff2024-06-29 14:56:531146 # TODO(https://crbug.com/1364577): Various uses that should be
1147 # migrated to something else.
1148 # Should use base::OnceCallback or base::RepeatingCallback.
Dirk Prankee4df27972025-02-26 18:39:351149 r'base/allocator/dispatcher/initializer_unittest\.cc',
1150 r'chrome/browser/ash/accessibility/speech_monitor\.cc',
1151 r'chrome/browser/ash/accessibility/speech_monitor\.h',
1152 r'chrome/browser/ash/login/ash_hud_login_browsertest\.cc',
1153 r'chromecast/base/observer_unittest\.cc',
1154 r'chromecast/browser/cast_web_view\.h',
1155 r'chromecast/public/cast_media_shlib\.h',
1156 r'device/bluetooth/floss/exported_callback_manager\.h',
1157 r'device/bluetooth/floss/floss_dbus_client\.h',
1158 r'device/fido/cable/v2_handshake_unittest\.cc',
1159 r'device/fido/pin\.cc',
1160 r'services/tracing/perfetto/test_utils\.h',
Daniel Cheng566634ff2024-06-29 14:56:531161 # Should use base::FunctionRef.
Dirk Prankee4df27972025-02-26 18:39:351162 r'chrome/browser/media/webrtc/test_stats_dictionary\.cc',
1163 r'chrome/browser/media/webrtc/test_stats_dictionary\.h',
1164 r'chromeos/ash/services/libassistant/device_settings_controller\.cc',
1165 r'components/browser_ui/client_certificate/android/ssl_client_certificate_request\.cc',
1166 r'components/gwp_asan/client/sampling_malloc_shims_unittest\.cc',
1167 r'content/browser/font_unique_name_lookup/font_unique_name_lookup_unittest\.cc',
Daniel Cheng566634ff2024-06-29 14:56:531168 # Does not need std::function at all.
Dirk Prankee4df27972025-02-26 18:39:351169 r'components/omnibox/browser/autocomplete_result\.cc',
1170 r'device/fido/win/webauthn_api\.cc',
1171 r'media/audio/alsa/alsa_util\.cc',
1172 r'media/remoting/stream_provider\.h',
1173 r'sql/vfs_wrapper\.cc',
Daniel Cheng566634ff2024-06-29 14:56:531174 # TODO(https://crbug.com/1364585): Remove usage and exception list
1175 # entries.
Dirk Prankee4df27972025-02-26 18:39:351176 r'extensions/renderer/api/automation/automation_internal_custom_bindings\.cc',
1177 r'extensions/renderer/api/automation/automation_internal_custom_bindings\.h',
Daniel Cheng566634ff2024-06-29 14:56:531178 # TODO(https://crbug.com/1364579): Remove usage and exception list
1179 # entry.
Dirk Prankee4df27972025-02-26 18:39:351180 r'ui/views/controls/focus_ring\.h',
Lei Zhang1f9d9ec42024-06-20 18:42:271181
Daniel Cheng566634ff2024-06-29 14:56:531182 # Various pre-existing uses in //tools that is low-priority to fix.
Dirk Prankee4df27972025-02-26 18:39:351183 r'tools/binary_size/libsupersize/viewer/caspian/diff\.cc',
1184 r'tools/binary_size/libsupersize/viewer/caspian/model\.cc',
1185 r'tools/binary_size/libsupersize/viewer/caspian/model\.h',
1186 r'tools/binary_size/libsupersize/viewer/caspian/tree_builder\.h',
1187 r'tools/clang/base_bind_rewriters/BaseBindRewriters\.cpp',
Daniel Chenge5583e3c2022-09-22 00:19:411188
Daniel Cheng566634ff2024-06-29 14:56:531189 # Not an error in third_party folders.
1190 _THIRD_PARTY_EXCEPT_BLINK
1191 ],
Daniel Bratell609102be2019-03-27 20:53:211192 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151193 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531194 r'/#include <X11/',
1195 ('Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.', ),
1196 True,
1197 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Tom Andersona95e12042020-09-09 23:08:001198 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151199 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531200 r'/\bstd::ratio\b',
1201 ('std::ratio is banned by the Google Style Guide.', ),
1202 True,
1203 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:451204 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151205 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531206 r'/\bstd::aligned_alloc\b',
1207 (
1208 'std::aligned_alloc() is not yet allowed (crbug.com/1412818). Use ',
1209 'base::AlignedAlloc() instead.',
1210 ),
1211 True,
1212 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181213 ),
1214 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531215 r'/#include <(barrier|latch|semaphore|stop_token)>',
1216 ('The thread support library is banned. Use base/synchronization '
1217 'instead.', ),
1218 True,
1219 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181220 ),
1221 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531222 r'/\bstd::execution::(par|seq)\b',
1223 ('std::execution::(par|seq) is banned; they do not fit into '
1224 ' Chrome\'s threading model, and libc++ doesn\'t have full '
mikt19226ff22024-08-27 05:28:211225 'support.', ),
Daniel Cheng566634ff2024-06-29 14:56:531226 True,
1227 [_THIRD_PARTY_EXCEPT_BLINK],
Helmut Januschka7cc8a84f2024-02-07 22:50:411228 ),
1229 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531230 r'/\bstd::bit_cast\b',
1231 ('std::bit_cast is banned; use base::bit_cast instead for values and '
1232 'standard C++ casting when pointers are involved.', ),
1233 True,
1234 [
1235 # Don't warn in third_party folders.
1236 _THIRD_PARTY_EXCEPT_BLINK,
1237 # //base/numerics can't use base or absl.
1238 r'base/numerics/.*'
1239 ],
Avi Drissman70cb7f72023-12-12 17:44:371240 ),
1241 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531242 r'/\bstd::(c8rtomb|mbrtoc8)\b',
1243 ('std::c8rtomb() and std::mbrtoc8() are banned.', ),
1244 True,
1245 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181246 ),
1247 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531248 r'/\bchar8_t|std::u8string\b',
1249 (
1250 'char8_t and std::u8string are not yet allowed. Can you use [unsigned]',
1251 ' char and std::string instead?',
1252 ),
1253 True,
1254 [
1255 # The demangler does not use this type but needs to know about it.
Dirk Prankee4df27972025-02-26 18:39:351256 r'base/third_party/symbolize/demangle\.cc',
Daniel Cheng566634ff2024-06-29 14:56:531257 # Don't warn in third_party folders.
1258 _THIRD_PARTY_EXCEPT_BLINK
1259 ],
Peter Kastinge2c5ee82023-02-15 17:23:081260 ),
1261 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531262 r'/(\b(co_await|co_return|co_yield)\b|#include <coroutine>)',
1263 ('Coroutines are not yet allowed (https://crbug.com/1403840).', ),
1264 True,
1265 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081266 ),
1267 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531268 r'/^\s*(export\s|import\s+["<:\w]|module(;|\s+[:\w]))',
1269 ('Modules are disallowed for now due to lack of toolchain support.', ),
1270 True,
1271 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting69357dc2023-03-14 01:34:291272 ),
1273 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531274 r'/\[\[(\w*::)?no_unique_address\]\]',
1275 (
1276 '[[no_unique_address]] does not work as expected on Windows ',
1277 '(https://crbug.com/1414621). Use NO_UNIQUE_ADDRESS instead.',
1278 ),
1279 True,
1280 [
1281 # NO_UNIQUE_ADDRESS / PA_NO_UNIQUE_ADDRESS provide canonical access.
1282 r'^base/compiler_specific\.h',
1283 r'^base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/compiler_specific\.h',
1284 # Not an error in third_party folders.
1285 _THIRD_PARTY_EXCEPT_BLINK,
1286 ],
Peter Kasting8bc046d22023-11-14 00:38:031287 ),
1288 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531289 r'/#include <format>',
1290 ('<format> is not yet allowed. Use base::StringPrintf() instead.', ),
1291 True,
1292 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081293 ),
1294 BanRule(
Daniel Cheng89719222024-07-04 04:59:291295 pattern='std::views',
1296 explanation=(
1297 'Use of std::views is banned in Chrome. If you need this '
1298 'functionality, please contact [email protected].',
1299 ),
1300 treat_as_error=True,
1301 excluded_paths=[
1302 # Don't warn in third_party folders.
1303 _THIRD_PARTY_EXCEPT_BLINK
1304 ],
1305 ),
1306 BanRule(
1307 # Ban everything except specifically allowlisted constructs.
1308 pattern=r'/std::ranges::(?!' + '|'.join((
1309 # From https://en.cppreference.com/w/cpp/ranges:
1310 # Range access
1311 'begin',
1312 'end',
1313 'cbegin',
1314 'cend',
1315 'rbegin',
1316 'rend',
1317 'crbegin',
1318 'crend',
1319 'size',
1320 'ssize',
1321 'empty',
1322 'data',
1323 'cdata',
1324 # Range primitives
1325 'iterator_t',
1326 'const_iterator_t',
1327 'sentinel_t',
1328 'const_sentinel_t',
1329 'range_difference_t',
1330 'range_size_t',
1331 'range_value_t',
1332 'range_reference_t',
1333 'range_const_reference_t',
1334 'range_rvalue_reference_t',
1335 'range_common_reference_t',
1336 # Dangling iterator handling
1337 'dangling',
1338 'borrowed_iterator_t',
1339 # Banned: borrowed_subrange_t
1340 # Range concepts
1341 'range',
1342 'borrowed_range',
1343 'sized_range',
1344 'view',
1345 'input_range',
1346 'output_range',
1347 'forward_range',
1348 'bidirectional_range',
1349 'random_access_range',
1350 'contiguous_range',
1351 'common_range',
1352 'viewable_range',
1353 'constant_range',
1354 # Banned: Views
1355 # Banned: Range factories
1356 # Banned: Range adaptors
Peter Kastinga7f93752024-10-24 22:15:401357 # Incidentally listed on
1358 # https://en.cppreference.com/w/cpp/header/ranges:
1359 'enable_borrowed_range',
1360 'enable_view',
Daniel Cheng89719222024-07-04 04:59:291361 # From https://en.cppreference.com/w/cpp/algorithm/ranges:
1362 # Constrained algorithms: non-modifying sequence operations
1363 'all_of',
1364 'any_of',
1365 'none_of',
1366 'for_each',
1367 'for_each_n',
1368 'count',
1369 'count_if',
1370 'mismatch',
1371 'equal',
1372 'lexicographical_compare',
1373 'find',
1374 'find_if',
1375 'find_if_not',
1376 'find_end',
1377 'find_first_of',
1378 'adjacent_find',
1379 'search',
1380 'search_n',
1381 # Constrained algorithms: modifying sequence operations
1382 'copy',
1383 'copy_if',
1384 'copy_n',
1385 'copy_backward',
1386 'move',
1387 'move_backward',
1388 'fill',
1389 'fill_n',
1390 'transform',
1391 'generate',
1392 'generate_n',
1393 'remove',
1394 'remove_if',
1395 'remove_copy',
1396 'remove_copy_if',
1397 'replace',
1398 'replace_if',
1399 'replace_copy',
1400 'replace_copy_if',
1401 'swap_ranges',
1402 'reverse',
1403 'reverse_copy',
1404 'rotate',
1405 'rotate_copy',
1406 'shuffle',
1407 'sample',
1408 'unique',
1409 'unique_copy',
1410 # Constrained algorithms: partitioning operations
1411 'is_partitioned',
1412 'partition',
1413 'partition_copy',
1414 'stable_partition',
1415 'partition_point',
1416 # Constrained algorithms: sorting operations
1417 'is_sorted',
1418 'is_sorted_until',
1419 'sort',
1420 'partial_sort',
1421 'partial_sort_copy',
1422 'stable_sort',
1423 'nth_element',
1424 # Constrained algorithms: binary search operations (on sorted ranges)
1425 'lower_bound',
1426 'upper_bound',
1427 'binary_search',
1428 'equal_range',
1429 # Constrained algorithms: set operations (on sorted ranges)
1430 'merge',
1431 'inplace_merge',
1432 'includes',
1433 'set_difference',
1434 'set_intersection',
1435 'set_symmetric_difference',
1436 'set_union',
1437 # Constrained algorithms: heap operations
1438 'is_heap',
1439 'is_heap_until',
1440 'make_heap',
1441 'push_heap',
1442 'pop_heap',
1443 'sort_heap',
1444 # Constrained algorithms: minimum/maximum operations
1445 'max',
1446 'max_element',
1447 'min',
1448 'min_element',
1449 'minmax',
1450 'minmax_element',
1451 'clamp',
1452 # Constrained algorithms: permutation operations
1453 'is_permutation',
1454 'next_permutation',
1455 'prev_premutation',
1456 # Constrained uninitialized memory algorithms
1457 'uninitialized_copy',
1458 'uninitialized_copy_n',
1459 'uninitialized_fill',
1460 'uninitialized_fill_n',
1461 'uninitialized_move',
1462 'uninitialized_move_n',
1463 'uninitialized_default_construct',
1464 'uninitialized_default_construct_n',
1465 'uninitialized_value_construct',
1466 'uninitialized_value_construct_n',
1467 'destroy',
1468 'destroy_n',
1469 'destroy_at',
1470 'construct_at',
1471 # Return types
1472 'in_fun_result',
1473 'in_in_result',
1474 'in_out_result',
1475 'in_in_out_result',
1476 'in_out_out_result',
1477 'min_max_result',
1478 'in_found_result',
Peter Kastingf379c022025-01-13 14:01:001479 # From https://en.cppreference.com/w/cpp/header/functional
1480 'equal_to',
1481 'not_equal_to',
1482 'greater',
1483 'less',
1484 'greater_equal',
1485 'less_equal',
danakj91c715b2024-07-10 13:24:261486 # From https://en.cppreference.com/w/cpp/iterator
1487 'advance',
1488 'distance',
1489 'next',
1490 'prev',
Daniel Cheng89719222024-07-04 04:59:291491 )) + r')\w+',
1492 explanation=(
1493 'Use of range views and associated helpers is banned in Chrome. '
1494 'If you need this functionality, please contact [email protected].',
1495 ),
1496 treat_as_error=True,
1497 excluded_paths=[
1498 # Don't warn in third_party folders.
1499 _THIRD_PARTY_EXCEPT_BLINK
1500 ],
Peter Kastinge2c5ee82023-02-15 17:23:081501 ),
1502 BanRule(
Peter Kasting31879d82024-10-07 20:18:391503 r'/#include <regex>',
1504 ('<regex> is not allowed. Use third_party/re2 instead.',
1505 ),
1506 True,
1507 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1508 ),
1509 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531510 r'/#include <source_location>',
1511 ('<source_location> is not yet allowed. Use base/location.h instead.',
1512 ),
1513 True,
1514 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081515 ),
1516 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531517 r'/\bstd::to_address\b',
1518 (
1519 'std::to_address is banned because it is not guaranteed to be',
1520 'SFINAE-compatible. Use base::to_address from base/types/to_address.h',
1521 'instead.',
1522 ),
1523 True,
1524 [
1525 # Needed in base::to_address implementation.
1526 r'base/types/to_address.h',
1527 _THIRD_PARTY_EXCEPT_BLINK
1528 ], # Not an error in third_party folders.
Nick Diego Yamanee522ae82024-02-27 04:23:221529 ),
1530 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531531 r'/#include <syncstream>',
1532 ('<syncstream> is banned.', ),
1533 True,
1534 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181535 ),
1536 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531537 r'/\bRunMessageLoop\b',
1538 ('RunMessageLoop is deprecated, use RunLoop instead.', ),
1539 False,
1540 (),
Gabriel Charette147335ea2018-03-22 15:59:191541 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151542 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531543 'RunAllPendingInMessageLoop()',
1544 (
1545 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
1546 "if you're convinced you need this.",
1547 ),
1548 False,
1549 (),
Gabriel Charette147335ea2018-03-22 15:59:191550 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151551 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531552 'RunAllPendingInMessageLoop(BrowserThread',
1553 (
1554 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
1555 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
1556 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
1557 'async events instead of flushing threads.',
1558 ),
1559 False,
1560 (),
Gabriel Charette147335ea2018-03-22 15:59:191561 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151562 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531563 r'MessageLoopRunner',
1564 ('MessageLoopRunner is deprecated, use RunLoop instead.', ),
1565 False,
1566 (),
Gabriel Charette147335ea2018-03-22 15:59:191567 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151568 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531569 'GetDeferredQuitTaskForRunLoop',
1570 (
1571 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
1572 "gab@ if you found a use case where this is the only solution.",
1573 ),
1574 False,
1575 (),
Gabriel Charette147335ea2018-03-22 15:59:191576 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151577 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531578 'sqlite3_initialize(',
1579 (
1580 'Instead of calling sqlite3_initialize(), depend on //sql, ',
1581 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
1582 ),
1583 True,
1584 (
1585 r'^sql/initialization\.(cc|h)$',
1586 r'^third_party/sqlite/.*\.(c|cc|h)$',
1587 ),
Victor Costan3653df62018-02-08 21:38:161588 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151589 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531590 'CREATE VIEW',
1591 (
1592 'SQL views are disabled in Chromium feature code',
1593 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-views',
1594 ),
1595 True,
1596 (
1597 _THIRD_PARTY_EXCEPT_BLINK,
1598 # sql/ itself uses views when using memory-mapped IO.
1599 r'^sql/.*',
1600 # Various performance tools that do not build as part of Chrome.
1601 r'^infra/.*',
1602 r'^tools/perf.*',
1603 r'.*perfetto.*',
1604 ),
Austin Sullivand661ab52022-11-16 08:55:151605 ),
1606 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531607 'CREATE VIRTUAL TABLE',
1608 (
1609 'SQL virtual tables are disabled in Chromium feature code',
1610 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-virtual-tables',
1611 ),
1612 True,
1613 (
1614 _THIRD_PARTY_EXCEPT_BLINK,
1615 # sql/ itself uses virtual tables in the recovery module and tests.
1616 r'^sql/.*',
1617 # TODO(https://crbug.com/695592): Remove once WebSQL is deprecated.
1618 r'third_party/blink/web_tests/storage/websql/.*'
1619 # Various performance tools that do not build as part of Chrome.
1620 r'^tools/perf.*',
1621 r'.*perfetto.*',
1622 ),
Austin Sullivand661ab52022-11-16 08:55:151623 ),
1624 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531625 'std::random_shuffle',
1626 ('std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
1627 'base::RandomShuffle instead.'),
1628 True,
1629 (),
tzik5de2157f2018-05-08 03:42:471630 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151631 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531632 'ios/web/public/test/http_server',
1633 ('web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
1634 ),
1635 False,
1636 (),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:241637 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151638 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531639 'GetAddressOf',
1640 ('Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
1641 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
1642 'operator& is generally recommended. So always use operator& instead. ',
1643 'See http://crbug.com/914910 for more conversion guidance.'),
1644 True,
1645 (),
Robert Liao764c9492019-01-24 18:46:281646 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151647 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531648 'SHFileOperation',
1649 ('SHFileOperation was deprecated in Windows Vista, and there are less ',
1650 'complex functions to achieve the same goals. Use IFileOperation for ',
1651 'any esoteric actions instead.'),
1652 True,
1653 (),
Ben Lewisa9514602019-04-29 17:53:051654 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151655 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531656 'StringFromGUID2',
1657 ('StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
1658 'Use base::win::WStringFromGUID instead.'),
1659 True,
1660 (r'/base/win/win_util_unittest.cc', ),
Cliff Smolinsky81951642019-04-30 21:39:511661 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151662 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531663 'StringFromCLSID',
1664 ('StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
1665 'Use base::win::WStringFromGUID instead.'),
1666 True,
1667 (r'/base/win/win_util_unittest.cc', ),
Cliff Smolinsky81951642019-04-30 21:39:511668 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151669 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531670 'kCFAllocatorNull',
1671 (
1672 'The use of kCFAllocatorNull with the NoCopy creation of ',
1673 'CoreFoundation types is prohibited.',
1674 ),
1675 True,
1676 (),
Avi Drissman7382afa02019-04-29 23:27:131677 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151678 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531679 'mojo::ConvertTo',
1680 ('mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1681 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1682 'StringTraits if you would like to convert between custom types and',
1683 'the wire format of mojom types.'),
1684 False,
1685 (
1686 r'^fuchsia_web/webengine/browser/url_request_rewrite_rules_manager\.cc$',
1687 r'^fuchsia_web/webengine/url_request_rewrite_type_converters\.cc$',
1688 r'^third_party/blink/.*\.(cc|h)$',
1689 r'^content/renderer/.*\.(cc|h)$',
1690 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291691 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151692 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531693 'GetInterfaceProvider',
1694 ('InterfaceProvider is deprecated.',
1695 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1696 'or Platform::GetBrowserInterfaceBroker.'),
1697 False,
1698 (),
Oksana Zhuravlovac8222d22019-12-19 19:21:161699 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151700 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531701 'CComPtr',
1702 ('New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1703 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1704 'details.'),
1705 False,
1706 (),
Robert Liao1d78df52019-11-11 20:02:011707 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151708 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531709 r'/\b(IFACE|STD)METHOD_?\(',
1710 ('IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1711 'Instead, always use IFACEMETHODIMP in the declaration.'),
1712 False,
1713 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Xiaohan Wang72bd2ba2020-02-18 21:38:201714 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151715 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531716 'set_owned_by_client',
1717 ('set_owned_by_client is deprecated.',
1718 'views::View already owns the child views by default. This introduces ',
1719 'a competing ownership model which makes the code difficult to reason ',
1720 'about. See http://crbug.com/1044687 for more details.'),
1721 False,
1722 (),
Allen Bauer53b43fb12020-03-12 17:21:471723 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151724 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531725 'RemoveAllChildViewsWithoutDeleting',
1726 ('RemoveAllChildViewsWithoutDeleting is deprecated.',
1727 'This method is deemed dangerous as, unless raw pointers are re-added,',
1728 'calls to this method introduce memory leaks.'),
1729 False,
1730 (),
Peter Boström7ff41522021-07-29 03:43:271731 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151732 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531733 r'/\bTRACE_EVENT_ASYNC_',
1734 (
1735 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1736 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1737 ),
1738 False,
1739 (
1740 r'^base/trace_event/.*',
1741 r'^base/tracing/.*',
1742 ),
Eric Secklerbe6f48d2020-05-06 18:09:121743 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151744 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531745 'RoInitialize',
1746 ('Improper use of [base::win]::RoInitialize() has been implicated in a ',
1747 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
1748 'instead. See http://crbug.com/1197722 for more information.'),
1749 True,
1750 (
1751 r'^base/win/scoped_winrt_initializer\.cc$',
1752 r'^third_party/abseil-cpp/absl/.*',
1753 ),
Robert Liao22f66a52021-04-10 00:57:521754 ),
Patrick Monettec343bb982022-06-01 17:18:451755 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531756 r'base::Watchdog',
1757 (
1758 'base::Watchdog is deprecated because it creates its own thread.',
1759 'Instead, manually start a timer on a SequencedTaskRunner.',
1760 ),
1761 False,
1762 (),
Patrick Monettec343bb982022-06-01 17:18:451763 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091764 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531765 'base::Passed',
1766 ('Do not use base::Passed. It is a legacy helper for capturing ',
1767 'move-only types with base::BindRepeating, but invoking the ',
1768 'resulting RepeatingCallback moves the captured value out of ',
1769 'the callback storage, and subsequent invocations may pass the ',
1770 'value in a valid but undefined state. Prefer base::BindOnce().',
1771 'See http://crbug.com/1326449 for context.'),
1772 False,
1773 (
1774 # False positive, but it is also fine to let bind internals reference
1775 # base::Passed.
1776 r'^base[\\/]functional[\\/]bind\.h',
1777 r'^base[\\/]functional[\\/]bind_internal\.h',
1778 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091779 ),
Daniel Cheng2248b332022-07-27 06:16:591780 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531781 r'base::Feature k',
1782 ('Please use BASE_DECLARE_FEATURE() or BASE_FEATURE() instead of ',
1783 'directly declaring/defining features.'),
1784 True,
1785 [
1786 # Implements BASE_DECLARE_FEATURE().
1787 r'^base/feature_list\.h',
1788 ],
Daniel Chengba3bc2e2022-10-03 02:45:431789 ),
Robert Ogden92101dcb2022-10-19 23:49:361790 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531791 r'/\bchartorune\b',
1792 ('chartorune is not memory-safe, unless you can guarantee the input ',
1793 'string is always null-terminated. Otherwise, please use charntorune ',
1794 'from libphonenumber instead.'),
1795 True,
1796 [
1797 _THIRD_PARTY_EXCEPT_BLINK,
1798 # Exceptions to this rule should have a fuzzer.
1799 ],
Robert Ogden92101dcb2022-10-19 23:49:361800 ),
Arthur Sonzogni1da65fa2023-03-27 16:01:521801 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531802 r'/\b#include "base/atomicops\.h"\b',
1803 ('Do not use base::subtle atomics, but std::atomic, which are simpler '
1804 'to use, have better understood, clearer and richer semantics, and are '
1805 'harder to mis-use. See details in base/atomicops.h.', ),
1806 False,
1807 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Benoit Lize79cf0592023-01-27 10:01:571808 ),
Daniel Cheng566634ff2024-06-29 14:56:531809 BanRule(r'CrossThreadPersistent<', (
Arthur Sonzogni60348572e2023-04-07 10:22:521810 'Do not use blink::CrossThreadPersistent, but '
Daniel Cheng566634ff2024-06-29 14:56:531811 'blink::CrossThreadHandle. It is harder to mis-use.', 'More info: '
Arthur Sonzogni60348572e2023-04-07 10:22:521812 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1813 'Please contact platform-architecture-dev@ before adding new instances.'
Daniel Cheng566634ff2024-06-29 14:56:531814 ), False, []),
1815 BanRule(r'CrossThreadWeakPersistent<', (
Arthur Sonzogni60348572e2023-04-07 10:22:521816 'Do not use blink::CrossThreadWeakPersistent, but '
Daniel Cheng566634ff2024-06-29 14:56:531817 'blink::CrossThreadWeakHandle. It is harder to mis-use.', 'More info: '
Arthur Sonzogni60348572e2023-04-07 10:22:521818 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1819 'Please contact platform-architecture-dev@ before adding new instances.'
Daniel Cheng566634ff2024-06-29 14:56:531820 ), False, []),
1821 BanRule(r'objc/objc.h', (
Avi Drissman491617c2023-04-13 17:33:151822 'Do not include <objc/objc.h>. It defines away ARC lifetime '
1823 'annotations, and is thus dangerous.',
1824 'Please use the pimpl pattern; search for `ObjCStorage` for examples.',
1825 'For further reading on how to safely mix C++ and Obj-C, see',
1826 'https://chromium.googlesource.com/chromium/src/+/main/docs/mac/mixing_cpp_and_objc.md'
Daniel Cheng566634ff2024-06-29 14:56:531827 ), True, []),
1828 BanRule(
1829 r'/#include <filesystem>',
1830 ('libc++ <filesystem> is banned per the Google C++ styleguide.', ),
1831 True,
1832 # This fuzzing framework is a standalone open source project and
1833 # cannot rely on Chromium base.
1834 (r'third_party/centipede'),
Avi Drissman491617c2023-04-13 17:33:151835 ),
Grace Park8d59b54b2023-04-26 17:53:351836 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531837 r'TopDocument()',
1838 ('TopDocument() does not work correctly with out-of-process iframes. '
1839 'Please do not introduce new uses.', ),
1840 True,
1841 (
1842 # TODO(crbug.com/617677): Remove all remaining uses.
1843 r'^third_party/blink/renderer/core/dom/document\.cc',
1844 r'^third_party/blink/renderer/core/dom/document\.h',
1845 r'^third_party/blink/renderer/core/dom/element\.cc',
1846 r'^third_party/blink/renderer/core/exported/web_disallow_transition_scope_test\.cc',
1847 r'^third_party/blink/renderer/core/exported/web_document_test\.cc',
1848 r'^third_party/blink/renderer/core/html/html_anchor_element\.cc',
1849 r'^third_party/blink/renderer/core/html/html_dialog_element\.cc',
1850 r'^third_party/blink/renderer/core/html/html_element\.cc',
1851 r'^third_party/blink/renderer/core/html/html_frame_owner_element\.cc',
1852 r'^third_party/blink/renderer/core/html/media/video_wake_lock\.cc',
1853 r'^third_party/blink/renderer/core/loader/anchor_element_interaction_tracker\.cc',
1854 r'^third_party/blink/renderer/core/page/scrolling/root_scroller_controller\.cc',
1855 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.cc',
1856 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.h',
1857 r'^third_party/blink/renderer/core/script/classic_pending_script\.cc',
1858 r'^third_party/blink/renderer/core/script/script_loader\.cc',
1859 ),
Grace Park8d59b54b2023-04-26 17:53:351860 ),
Daniel Cheng72153e02023-05-18 21:18:141861 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531862 pattern=r'base::raw_ptr<',
1863 explanation=('Do not use base::raw_ptr, use raw_ptr.', ),
1864 treat_as_error=True,
1865 excluded_paths=(
1866 '^base/',
1867 '^tools/',
1868 ),
Daniel Cheng72153e02023-05-18 21:18:141869 ),
Arthur Sonzognif0eea302023-08-18 19:20:311870 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531871 pattern=r'base:raw_ref<',
1872 explanation=('Do not use base::raw_ref, use raw_ref.', ),
1873 treat_as_error=True,
1874 excluded_paths=(
1875 '^base/',
1876 '^tools/',
1877 ),
Arthur Sonzognif0eea302023-08-18 19:20:311878 ),
1879 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531880 pattern=r'/raw_ptr<[^;}]*\w{};',
1881 explanation=(
1882 'Do not use {} for raw_ptr initialization, use = nullptr instead.',
1883 ),
1884 treat_as_error=True,
1885 excluded_paths=(
1886 '^base/',
1887 '^tools/',
1888 ),
Arthur Sonzognif0eea302023-08-18 19:20:311889 ),
Anton Maliev66751812023-08-24 16:28:131890 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531891 pattern=r'/#include "base/allocator/.*/raw_'
1892 r'(ptr|ptr_cast|ptr_exclusion|ref).h"',
1893 explanation=(
1894 'Please include the corresponding facade headers:',
1895 '- #include "base/memory/raw_ptr.h"',
1896 '- #include "base/memory/raw_ptr_cast.h"',
1897 '- #include "base/memory/raw_ptr_exclusion.h"',
1898 '- #include "base/memory/raw_ref.h"',
1899 ),
1900 treat_as_error=True,
1901 excluded_paths=(
1902 '^base/',
1903 '^tools/',
1904 ),
Tom Sepez41eb158d2023-09-12 16:16:221905 ),
1906 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531907 pattern=r'ContentSettingsType::COOKIES',
1908 explanation=
1909 ('Do not use ContentSettingsType::COOKIES to check whether cookies are '
1910 'supported in the provided context. Instead rely on the '
1911 'content_settings::CookieSettings API. If you are using '
1912 'ContentSettingsType::COOKIES to check the user preference setting '
1913 'specifically, disregard this warning.', ),
1914 treat_as_error=False,
1915 excluded_paths=(
1916 '^chrome/browser/ui/content_settings/',
1917 '^components/content_settings/',
1918 '^services/network/cookie_settings.cc',
1919 '.*test.cc',
1920 ),
Arthur Sonzogni48c6aea22023-09-04 22:25:201921 ),
1922 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531923 pattern=r'ContentSettingsType::TRACKING_PROTECTION',
1924 explanation=
1925 ('Do not directly use ContentSettingsType::TRACKING_PROTECTION to check '
1926 'for tracking protection exceptions. Instead rely on the '
1927 'privacy_sandbox::TrackingProtectionSettings API.', ),
1928 treat_as_error=False,
1929 excluded_paths=(
1930 '^chrome/browser/ui/content_settings/',
1931 '^components/content_settings/',
1932 '^components/privacy_sandbox/tracking_protection_settings.cc',
1933 '.*test.cc',
1934 ),
Anton Maliev66751812023-08-24 16:28:131935 ),
Tom Andersoncd522072023-10-03 00:52:351936 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531937 pattern=r'/\bg_signal_connect',
1938 explanation=('Use ScopedGSignal instead of g_signal_connect*()', ),
1939 treat_as_error=True,
1940 excluded_paths=('^ui/base/glib/scoped_gsignal.h', ),
Michelle Abreo6b7437822024-04-26 17:29:041941 ),
1942 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531943 pattern=r'features::kIsolatedWebApps',
1944 explanation=(
1945 'Do not use `features::kIsolatedWebApps` directly to guard Isolated ',
1946 'Web App code. ',
Andrew Rayskiy7ae2b5d2025-02-28 16:59:381947 'Use `content::AreIsolatedWebAppsEnabled()` in the browser process '
1948 'or check the `kEnableIsolatedWebAppsInRenderer` command line flag '
1949 'in the renderer process.',
Daniel Cheng566634ff2024-06-29 14:56:531950 ),
1951 treat_as_error=True,
Andrew Rayskiy7ae2b5d2025-02-28 16:59:381952 excluded_paths=_TEST_CODE_EXCLUDED_PATHS + (
1953 '^chrome/browser/about_flags.cc',
1954 '^chrome/browser/component_updater/iwa_key_distribution_component_installer.cc',
1955 '^chrome/browser/web_applications/isolated_web_apps/chrome_content_browser_client_isolated_web_apps_part.cc',
1956 '^chrome/browser/ui/startup/bad_flags_prompt.cc',
1957 '^content/shell/browser/shell_content_browser_client.cc',
1958 )),
Daniel Cheng566634ff2024-06-29 14:56:531959 BanRule(
1960 pattern=r'features::kIsolatedWebAppDevMode',
1961 explanation=(
1962 'Do not use `features::kIsolatedWebAppDevMode` directly to guard code ',
1963 'related to Isolated Web App Developer Mode. ',
1964 'Use `web_app::IsIwaDevModeEnabled()` instead.',
1965 ),
1966 treat_as_error=True,
1967 excluded_paths=_TEST_CODE_EXCLUDED_PATHS + (
1968 '^chrome/browser/about_flags.cc',
1969 '^chrome/browser/web_applications/isolated_web_apps/isolated_web_app_features.cc',
1970 '^chrome/browser/ui/startup/bad_flags_prompt.cc',
1971 )),
1972 BanRule(
1973 pattern=r'features::kIsolatedWebAppUnmanagedInstall',
1974 explanation=(
1975 'Do not use `features::kIsolatedWebAppUnmanagedInstall` directly to ',
1976 'guard code related to unmanaged install flow for Isolated Web Apps. ',
1977 'Use `web_app::IsIwaUnmanagedInstallEnabled()` instead.',
1978 ),
1979 treat_as_error=True,
1980 excluded_paths=_TEST_CODE_EXCLUDED_PATHS + (
1981 '^chrome/browser/about_flags.cc',
1982 '^chrome/browser/web_applications/isolated_web_apps/isolated_web_app_features.cc',
1983 )),
1984 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531985 pattern='/(CUIAutomation|AccessibleObjectFromWindow)',
1986 explanation=
1987 ('Direct usage of UIAutomation or IAccessible2 in client code is '
1988 'discouraged in Chromium, as it is not an assistive technology and '
1989 'should not rely on accessibility APIs directly. These APIs can '
1990 'introduce significant performance overhead. However, if you believe '
1991 'your use case warrants an exception, please discuss it with an '
1992 'accessibility owner before proceeding. For more information on the '
1993 'performance implications, see https://docs.google.com/document/d/1jN4itpCe_bDXF0BhFaYwv4xVLsCWkL9eULdzjmLzkuk/edit#heading=h.pwth3nbwdub0.',
1994 ),
1995 treat_as_error=False,
Andrew Rayskiycdd45e732024-03-20 14:32:391996 ),
1997 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531998 pattern=r'/WIDGET_OWNS_NATIVE_WIDGET|'
1999 r'NATIVE_WIDGET_OWNS_WIDGET',
2000 explanation=
2001 ('WIDGET_OWNS_NATIVE_WIDGET and NATIVE_WIDGET_OWNS_WIDGET are in the '
2002 'process of being deprecated. Consider using the new '
2003 'CLIENT_OWNS_WIDGET ownership model. Eventually, this will be the only '
2004 'available ownership model available and the associated enumeration'
2005 'will be removed.', ),
2006 treat_as_error=False,
Andrew Rayskiycdd45e732024-03-20 14:32:392007 ),
2008 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:532009 pattern='ProfileManager::GetLastUsedProfile',
2010 explanation=
2011 ('Most code should already be scoped to a Profile. Pass in a Profile* '
2012 'or retreive from an existing entity with a reference to the Profile '
2013 '(e.g. WebContents).', ),
2014 treat_as_error=False,
Arthur Sonzogni5cbd3e32024-02-08 17:51:322015 ),
Helmut Januschkab3f71ab52024-03-12 02:48:052016 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:532017 pattern=(r'/FindBrowserWithUiElementContext|'
2018 r'FindBrowserWithTab|'
2019 r'FindBrowserWithGroup|'
2020 r'FindTabbedBrowser|'
2021 r'FindAnyBrowser|'
2022 r'FindBrowserWithProfile|'
Erik Chen5f02eb4c2024-08-23 06:30:442023 r'FindLastActive|'
Daniel Cheng566634ff2024-06-29 14:56:532024 r'FindBrowserWithActiveWindow'),
2025 explanation=
2026 ('Most code should already be scoped to a Browser. Pass in a Browser* '
2027 'or retreive from an existing entity with a reference to the Browser.',
2028 ),
2029 treat_as_error=False,
Helmut Januschkab3f71ab52024-03-12 02:48:052030 ),
2031 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:532032 pattern='BrowserUserData',
2033 explanation=
2034 ('Do not use BrowserUserData to store state on a Browser instance. '
2035 'Instead use BrowserWindowFeatures. BrowserWindowFeatures is '
2036 'functionally identical but has two benefits: it does not force a '
2037 'dependency onto class Browser, and lifetime semantics are explicit '
2038 'rather than implicit. See BrowserUserData header file for more '
2039 'details.', ),
2040 treat_as_error=False,
Mike Doughertyab1bdec2024-08-06 16:39:012041 excluded_paths=(
2042 # Exclude iOS as the iOS implementation of BrowserUserData is separate
2043 # and still in use.
2044 '^ios/',
2045 ),
Erik Chen87358e82024-06-04 02:13:122046 ),
Tom Sepezea67b6e2024-08-08 18:17:272047 BanRule(
Tom Sepezd3272cd2025-02-21 19:11:312048 pattern=r'subspan(0u,',
2049 explanation=
2050 ('Prefer first(n) over subspan(0u, n) as it is shorter, and the '
2051 'compiler may have to emit a branch for the n == dynamic_extent '
2052 'case of subspan().',
2053 ),
2054 treat_as_error=False,
2055 ),
2056 BanRule(
Tom Sepezea67b6e2024-08-08 18:17:272057 pattern=r'UNSAFE_TODO(',
2058 explanation=
2059 ('Do not use UNSAFE_TODO() to write new unsafe code. Use only when '
Tom Sepeza90f92b2024-08-15 16:01:352060 'removing a pre-existing file-wide allow_unsafe_buffers pragma, or '
2061 'when incrementally converting code off of unsafe interfaces',
Tom Sepezea67b6e2024-08-08 18:17:272062 ),
2063 treat_as_error=False,
2064 ),
2065 BanRule(
2066 pattern=r'UNSAFE_BUFFERS(',
2067 explanation=
Tom Sepeza90f92b2024-08-15 16:01:352068 ('Try to avoid using UNSAFE_BUFFERS() if at all possible. Otherwise, '
2069 'be sure to justify in a // SAFETY comment why other options are not '
2070 'available, and why the code is safe.',
Tom Sepezea67b6e2024-08-08 18:17:272071 ),
2072 treat_as_error=False,
2073 ),
Erik Chend086ae02024-08-20 22:53:332074 BanRule(
2075 pattern='BrowserWithTestWindowTest',
2076 explanation=
2077 ('Do not use BrowserWithTestWindowTest. By instantiating an instance '
2078 'of class Browser, the test is no longer a unit test but is instead a '
2079 'browser test. The class BrowserWithTestWindowTest forces production '
2080 'logic to take on test-only conditionals, which is an anti-pattern. '
2081 'Features should be performing dependency injection rather than '
2082 'directly using class Browser. See '
mikt19226ff22024-08-27 05:28:212083 'docs/chrome_browser_design_principles.md for more details.',
Erik Chend086ae02024-08-20 22:53:332084 ),
2085 treat_as_error=False,
2086 ),
Erik Chen8cf3a652024-08-23 17:13:302087 BanRule(
Erik Chen959cdd72024-08-29 02:11:212088 pattern='TestWithBrowserView',
2089 explanation=
2090 ('Do not use TestWithBrowserView. See '
2091 'docs/chrome_browser_design_principles.md for details. If you want '
2092 'to write a test that has both a Browser and a BrowserView, create '
2093 'a browser_test. If you want to write a unit_test, your code must '
Erik Chendba23692024-09-26 06:43:362094 'not reference Browser*.',
Erik Chen959cdd72024-08-29 02:11:212095 ),
2096 treat_as_error=False,
2097 ),
2098 BanRule(
Erik Chene89ebe32025-02-22 02:46:492099 pattern='CreateBrowserWithTestWindow',
2100 explanation=
2101 ('Do not use CreateBrowserWithTestWindow. See '
2102 'docs/chrome_browser_design_principles.md for details. If you want '
2103 'to write a test that has a Browser, create a browser_test. If you '
2104 'want to write a unit_test, your code must not reference Browser*.',
2105 ),
2106 treat_as_error=False,
2107 ),
2108 BanRule(
Erik Chenf12a06642025-03-13 23:30:342109 pattern='CreateBrowserWithTestWindowForParams',
2110 explanation=
2111 ('Do not use CreateBrowserWithTestWindowForParams. See '
2112 'docs/chrome_browser_design_principles.md for details. If you want '
2113 'to write a test that has a Browser, create a browser_test and use '
2114 'Browser::Browser. If you want to write a unit_test, your code must '
2115 'not reference Browser*.',
2116 ),
2117 treat_as_error=False,
2118 ),
2119 BanRule(
Erik Chen8cf3a652024-08-23 17:13:302120 pattern='RunUntilIdle',
2121 explanation=
2122 ('Do not RunUntilIdle. If possible, explicitly quit the run loop using '
2123 'run_loop.Quit() or run_loop.QuitClosure() if completion can be '
2124 'observed using a lambda or callback. Otherwise, wait for the '
mikt19226ff22024-08-27 05:28:212125 'condition to be true via base::test::RunUntil().',
Erik Chen8cf3a652024-08-23 17:13:302126 ),
2127 treat_as_error=False,
2128 ),
Daniel Chengddde13a2024-09-05 21:39:282129 BanRule(
2130 pattern=r'/\bstd::(literals|string_literals|string_view_literals)\b',
2131 explanation = (
2132 'User-defined literals are banned by the Google C++ style guide. '
2133 'Exceptions are provided in Chrome for string and string_view '
2134 'literals that embed \\0.',
2135 ),
2136 treat_as_error=True,
2137 excluded_paths=(
2138 # Various tests or test helpers that embed NUL in strings or
2139 # string_views.
Daniel Chengddde13a2024-09-05 21:39:282140 r'^base/strings/string_util_unittest\.cc',
2141 r'^base/strings/utf_string_conversions_unittest\.cc',
2142 r'^chrome/browser/ash/crosapi/browser_data_back_migrator_unittest\.cc',
2143 r'^chrome/browser/ash/crosapi/browser_data_migrator_util_unittest\.cc',
2144 r'^chrome/browser/ash/crosapi/move_migrator_unittest\.cc',
Hidehiko Abe51601812025-01-12 16:17:352145 r'^chromeos/ash/experiences/arc/session/serial_number_util_unittest\.cc',
Daniel Chengddde13a2024-09-05 21:39:282146 r'^components/history/core/browser/visit_annotations_database\.cc',
2147 r'^components/history/core/browser/visit_annotations_database_unittest\.cc',
2148 r'^components/os_crypt/sync/os_crypt_unittest\.cc',
2149 r'^components/password_manager/core/browser/credentials_cleaner_unittest\.cc',
2150 r'^content/browser/file_system_access/file_system_access_file_writer_impl_unittest\.cc',
2151 r'^net/cookies/parsed_cookie_unittest\.cc',
2152 r'^third_party/blink/renderer/modules/webcodecs/test_helpers\.cc',
2153 r'^third_party/blink/renderer/modules/websockets/websocket_channel_impl_test\.cc',
2154 ),
Erik Chenba8b0cd32024-10-01 08:36:362155 ),
2156 BanRule(
2157 pattern='BUILDFLAG(GOOGLE_CHROME_BRANDING)',
2158 explanation=
2159 ('Code gated by GOOGLE_CHROME_BRANDING is effectively untested. This '
2160 'is typically wrong. Valid use cases are glue for private modules '
2161 'shipped alongside Chrome, and installation-related logic.',
2162 ),
2163 treat_as_error=False,
2164 ),
2165 BanRule(
2166 pattern='defined(OFFICIAL_BUILD)',
2167 explanation=
2168 ('Code gated by OFFICIAL_BUILD is effectively untested. This '
2169 'is typically wrong. One valid use case is low-level code that '
2170 'handles subtleties related to high-levels of optimizations that come '
2171 'with OFFICIAL_BUILD.',
2172 ),
2173 treat_as_error=False,
2174 ),
Erik Chen95b9c782024-11-08 03:26:272175 BanRule(
2176 pattern='WebContentsDestroyed',
2177 explanation=
2178 ('Do not use this method. It is invoked half-way through the '
2179 'destructor of WebContentsImpl and using it often results in crashes '
2180 'or surprising behavior. Conceptually, this is only necessary by '
2181 'objects that depend on, but outlive the WebContents. These objects '
2182 'should instead coordinate with the owner of the WebContents which is '
2183 'responsible for destroying the WebContents.',
2184 ),
2185 treat_as_error=False,
2186 ),
Maksim Sisovc98fdfa2024-11-16 20:12:272187 BanRule(
Georg Neisa7f94e62025-02-28 07:01:482188 pattern='IS_CHROMEOS_ASH',
Maksim Sisovc98fdfa2024-11-16 20:12:272189 explanation=
Georg Neisa7f94e62025-02-28 07:01:482190 ('IS_CHROMEOS_ASH is deprecated. Please use the equivalent IS_CHROMEOS '
2191 'instead (Lacros is gone).',
Maksim Sisovc98fdfa2024-11-16 20:12:272192 ),
2193 treat_as_error=False,
2194 ),
Erik Chen1396bbe2025-01-27 23:39:362195 BanRule(
2196 pattern=(r'namespace {'),
2197 explanation=
2198 ('Anonymous namespaces are disallowed in C++ header files. See '
2199 'https://google.github.io/styleguide/cppguide.html#Internal_Linkage '
2200 ' for details.',
2201 ),
2202 treat_as_error=False,
2203 excluded_paths=[
2204 _THIRD_PARTY_EXCEPT_BLINK, # Don't warn in third_party folders.
2205 r'^(?!.*\.h$).*$', # Exclude all files except those that end in .h
2206 ],
2207 ),
Keren Zhuf06d757d2025-03-04 05:32:362208 BanRule(
2209 pattern=('AddChildViewRaw'),
2210 explanation=(
2211 'Do not use AddChildViewRaw. It is prone to memory leaks and '
2212 'use-after-free bugs. Instead, use AddChildView(std::unique_ptr). '
2213 'See https://crbug.com/40485510 for more details.', ),
2214 treat_as_error=False,
2215 ),
Nate Fischerd541ff82025-03-11 21:34:192216 BanRule(
2217 pattern=(r'IS_DESKTOP_ANDROID'),
2218 explanation=(
2219 'Features which depend on IS_DESKTOP_ANDROID should only exist in '
2220 'chrome/ layer and similar layers. Lower layers such as content/ '
2221 'should not have features which are only designed for '
2222 'desktop-android builds. See https://crbug.com/401628399.', ),
2223 treat_as_error=False,
2224 excluded_paths=[
2225 _THIRD_PARTY_EXCEPT_BLINK, # Don't warn in third_party folders.
2226 r'^build/', # This is permitted in build/ folder.
2227 r'^chrome/', # This is permitted in chrome/ folder.
2228 r'^components/', # This is permitted only for components/ that are not shared by WebView.
2229 r'^extensions/', # This is permitted in chrome/ folder.
2230 r'^infra/', # This is permitted in infra/ folder.
2231 r'^tools/', # This is permitted in tools/ folder.
2232 ],
2233 ),
[email protected]127f18ec2012-06-16 05:05:592234)
2235
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152236_DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING = (
2237 'Used a predicate related to signin::ConsentLevel::kSync which will always '
2238 'return false in the future (crbug.com/40066949). Prefer using a predicate '
2239 'that also supports signin::ConsentLevel::kSignin when appropriate. It is '
2240 'safe to ignore this warning if you are just moving an existing call, or if '
2241 'you want special handling for users in the legacy state. In doubt, reach '
Victor Hugo Vianna Silvae2292972024-06-04 17:11:552242 'out to //components/sync/OWNERS.',
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152243)
2244
2245# C++ functions related to signin::ConsentLevel::kSync which are deprecated.
2246_DEPRECATED_SYNC_CONSENT_CPP_FUNCTIONS : Sequence[BanRule] = (
2247 BanRule(
2248 'HasSyncConsent',
2249 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2250 False,
2251 ),
2252 BanRule(
2253 'CanSyncFeatureStart',
2254 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2255 False,
2256 ),
2257 BanRule(
2258 'IsSyncFeatureEnabled',
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152259 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152260 False,
2261 ),
2262 BanRule(
2263 'IsSyncFeatureActive',
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152264 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152265 False,
2266 ),
2267)
2268
2269# Java functions related to signin::ConsentLevel::kSync which are deprecated.
2270_DEPRECATED_SYNC_CONSENT_JAVA_FUNCTIONS : Sequence[BanRule] = (
2271 BanRule(
2272 'hasSyncConsent',
2273 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2274 False,
2275 ),
2276 BanRule(
2277 'canSyncFeatureStart',
2278 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2279 False,
2280 ),
2281 BanRule(
2282 'isSyncFeatureEnabled',
2283 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2284 False,
2285 ),
2286 BanRule(
2287 'isSyncFeatureActive',
2288 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2289 False,
2290 ),
2291)
2292
Daniel Cheng92c15e32022-03-16 17:48:222293_BANNED_MOJOM_PATTERNS : Sequence[BanRule] = (
2294 BanRule(
2295 'handle<shared_buffer>',
2296 (
2297 'Please use one of the more specific shared memory types instead:',
2298 ' mojo_base.mojom.ReadOnlySharedMemoryRegion',
2299 ' mojo_base.mojom.WritableSharedMemoryRegion',
2300 ' mojo_base.mojom.UnsafeSharedMemoryRegion',
2301 ),
2302 True,
2303 ),
2304)
2305
mlamouria82272622014-09-16 18:45:042306_IPC_ENUM_TRAITS_DEPRECATED = (
2307 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:502308 'See http://www.chromium.org/Home/chromium-security/education/'
2309 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:042310
Stephen Martinis97a394142018-06-07 23:06:052311_LONG_PATH_ERROR = (
2312 'Some files included in this CL have file names that are too long (> 200'
2313 ' characters). If committed, these files will cause issues on Windows. See'
2314 ' https://crbug.com/612667 for more details.'
2315)
2316
Shenghua Zhangbfaa38b82017-11-16 21:58:022317_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Bruce Dawson40fece62022-09-16 19:58:312318 r".*/BuildHooksAndroidImpl\.java",
2319 r".*/LicenseContentProvider\.java",
2320 r".*/PlatformServiceBridgeImpl.java",
2321 r".*chrome/android/feed/dummy/.*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:022322]
[email protected]127f18ec2012-06-16 05:05:592323
Mohamed Heikald048240a2019-11-12 16:57:372324# List of image extensions that are used as resources in chromium.
2325_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
2326
Sean Kau46e29bc2017-08-28 16:31:162327# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:402328_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Bruce Dawson40fece62022-09-16 19:58:312329 r'test/data/',
2330 r'testing/buildbot/',
2331 r'^components/policy/resources/policy_templates\.json$',
2332 r'^third_party/protobuf/',
Camillo Bruni1411a352023-05-24 12:39:032333 r'^third_party/blink/perf_tests/speedometer.*/resources/todomvc/learn\.json',
Bruce Dawson40fece62022-09-16 19:58:312334 r'^third_party/blink/renderer/devtools/protocol\.json$',
2335 r'^third_party/blink/web_tests/external/wpt/',
2336 r'^tools/perf/',
2337 r'^tools/traceline/svgui/startup-release.json',
Daniel Cheng2d4c2d192022-07-01 01:38:312338 # vscode configuration files allow comments
Bruce Dawson40fece62022-09-16 19:58:312339 r'^tools/vscode/',
Sean Kau46e29bc2017-08-28 16:31:162340]
2341
Andrew Grieveb773bad2020-06-05 18:00:382342# These are not checked on the public chromium-presubmit trybot.
2343# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:042344# checkouts.
agrievef32bcc72016-04-04 14:57:402345_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:382346 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382347]
2348
2349
2350_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:042351 'android_webview/tools/run_cts.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:362352 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042353 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362354 'build/android/gyp/aar.pydeps',
2355 'build/android/gyp/aidl.pydeps',
2356 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:382357 'build/android/gyp/assert_static_initializers.pydeps',
Mohamed Heikal133e1f22023-04-18 20:04:372358 'build/android/gyp/binary_baseline_profile.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:022359 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:222360 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieveacac4242024-12-20 19:39:422361 'build/android/gyp/check_for_missing_direct_deps.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:112362 'build/android/gyp/compile_java.pydeps',
Peter Weneaa963f2023-01-20 19:40:302363 'build/android/gyp/compile_kt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362364 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362365 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362366 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:112367 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042368 'build/android/gyp/create_app_bundle_apks.pydeps',
2369 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362370 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:122371 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:092372 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:222373 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve2d972e5f2025-01-28 18:28:142374 'build/android/gyp/create_stub_manifest.pydeps',
Peter Wene6e017e2022-07-27 21:40:402375 'build/android/gyp/create_test_apk_wrapper_script.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002376 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362377 'build/android/gyp/dex.pydeps',
2378 'build/android/gyp/dist_aar.pydeps',
Andrew Grieve651ddb32025-01-23 03:27:342379 'build/android/gyp/errorprone.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362380 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:212381 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362382 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:362383 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362384 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:582385 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362386 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:142387 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:262388 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:472389 'build/android/gyp/java_google_api_keys.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042390 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362391 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362392 'build/android/gyp/merge_manifest.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:102393 'build/android/gyp/optimize_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362394 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:222395 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362396 'build/android/gyp/proguard.pydeps',
Mohamed Heikaldd52b452024-09-10 17:10:502397 'build/android/gyp/rename_java_classes.pydeps',
Andrew Grievee3a775ab2022-05-16 15:59:222398 'build/android/gyp/system_image_apks.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:102399 'build/android/gyp/trace_event_bytecode_rewriter.pydeps',
Andrew Grieve170b9782025-02-03 15:54:532400 'build/android/gyp/tracereferences.pydeps',
Peter Wen578730b2020-03-19 19:55:462401 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:302402 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:242403 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362404 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:462405 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:562406 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362407 'build/android/incremental_install/generate_android_manifest.pydeps',
2408 'build/android/incremental_install/write_installer_json.pydeps',
Stephanie Kim392913b452022-06-15 17:25:322409 'build/android/pylib/results/presentation/test_results_presentation.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042410 'build/android/resource_sizes.pydeps',
2411 'build/android/test_runner.pydeps',
2412 'build/android/test_wrapper/logdog_wrapper.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362413 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:322414 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:272415 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
2416 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:042417 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Mohannad Farrag19102742023-12-01 01:16:302418 'components/cronet/tools/check_combined_proguard_file.pydeps',
2419 'components/cronet/tools/generate_proguard_file.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002420 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382421 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002422 'content/public/android/generate_child_service.pydeps',
Hzj_jie77bdb802024-07-22 18:14:512423 'fuchsia_web/av_testing/av_sync_tests.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382424 'net/tools/testserver/testserver.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:182425 'testing/scripts/run_isolated_script_test.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:412426 'testing/merge_scripts/standard_isolated_script_merge.pydeps',
2427 'testing/merge_scripts/standard_gtest_merge.pydeps',
2428 'testing/merge_scripts/code_coverage/merge_results.pydeps',
2429 'testing/merge_scripts/code_coverage/merge_steps.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042430 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:422431 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
Yuki Shiino38eeaad12022-08-11 06:40:252432 'third_party/blink/renderer/bindings/scripts/check_generated_file_list.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:422433 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:132434 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Yuki Shiinoea477d32023-08-21 06:24:342435 'third_party/blink/renderer/bindings/scripts/generate_event_interface_names.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:502436 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:412437 'third_party/blink/tools/blinkpy/web_tests/merge_results.pydeps',
2438 'third_party/blink/tools/merge_web_test_results.pydeps',
John Budorickbc3571aa2019-04-25 02:20:062439 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:222440 'tools/binary_size/supersize.pydeps',
Peter Wen2dcfa6e2025-03-04 22:42:522441 'tools/cygprofile/generate_orderfile.pydeps',
Ben Pastene028104a2022-08-10 19:17:452442 'tools/perf/process_perf_results.pydeps',
Peter Wence103e12024-10-09 19:23:512443 'tools/pgo/generate_profile.pydeps',
agrievef32bcc72016-04-04 14:57:402444]
2445
wnwenbdc444e2016-05-25 13:44:152446
agrievef32bcc72016-04-04 14:57:402447_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
2448
2449
Eric Boren6fd2b932018-01-25 15:05:082450# Bypass the AUTHORS check for these accounts.
2451_KNOWN_ROBOTS = set(
Shuai Xia0d99ebf2025-02-11 23:47:592452 ) | set('%[email protected]' % s for s in ('findit-for-me',
2453 'luci-bisection',
2454 'predator-for-me-staging',
2455 'predator-for-me')
Achuith Bhandarkar35905562018-07-25 19:28:452456 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:592457 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:522458 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:232459 'wpt-autoroller', 'chrome-weblayer-builder',
Georg Neise5817eb2025-02-06 03:47:312460 'skylab-test-cros-roller', 'infra-try-recipes-tester',
2461 'chrome-automated-expectation',
Stephanie Kimb49bdd242023-04-28 16:46:042462 'chromium-automated-expectation', 'chrome-branch-day',
2463 'chromium-autosharder')
Eric Boren835d71f2018-09-07 21:09:042464 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:272465 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:042466 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:162467 for s in ('chromium-internal-autoroll',)
Kyungjun Lee3b7c9352024-04-02 23:59:142468 ) | set('%[email protected]' % s
2469 for s in ('chrome-screen-ai-releaser',)
Yulan Lineb0cfba2021-04-09 18:43:162470 ) | set('%[email protected]' % s
Chong Gub277e342022-10-15 03:30:552471 for s in ('swarming-tasks',)
2472 ) | set('%[email protected]' % s
2473 for s in ('global-integration-try-builder',
Joey Scarr1103c5d2023-09-14 01:17:552474 'global-integration-ci-builder')
Suma Kasa3b9cf7a2023-09-21 22:05:542475 ) | set('%[email protected]' % s
2476 for s in ('chops-security-borg',
2477 'chops-security-cronjobs-cpesuggest'))
Eric Boren6fd2b932018-01-25 15:05:082478
Matt Stark6ef08872021-07-29 01:21:462479_INVALID_GRD_FILE_LINE = [
2480 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
2481]
Eric Boren6fd2b932018-01-25 15:05:082482
Daniel Bratell65b033262019-04-23 08:17:062483def _IsCPlusPlusFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502484 """Returns True if this file contains C++-like code (and not Python,
2485 Go, Java, MarkDown, ...)"""
Daniel Bratell65b033262019-04-23 08:17:062486
Sam Maiera6e76d72022-02-11 21:43:502487 ext = input_api.os_path.splitext(file_path)[1]
2488 # This list is compatible with CppChecker.IsCppFile but we should
2489 # consider adding ".c" to it. If we do that we can use this function
2490 # at more places in the code.
2491 return ext in (
2492 '.h',
2493 '.cc',
2494 '.cpp',
2495 '.m',
2496 '.mm',
2497 )
2498
Daniel Bratell65b033262019-04-23 08:17:062499
2500def _IsCPlusPlusHeaderFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502501 return input_api.os_path.splitext(file_path)[1] == ".h"
Daniel Bratell65b033262019-04-23 08:17:062502
2503
2504def _IsJavaFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502505 return input_api.os_path.splitext(file_path)[1] == ".java"
Daniel Bratell65b033262019-04-23 08:17:062506
2507
2508def _IsProtoFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502509 return input_api.os_path.splitext(file_path)[1] == ".proto"
Daniel Bratell65b033262019-04-23 08:17:062510
Mohamed Heikal5e5b7922020-10-29 18:57:592511
Erik Staabc734cd7a2021-11-23 03:11:522512def _IsXmlOrGrdFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502513 ext = input_api.os_path.splitext(file_path)[1]
2514 return ext in ('.grd', '.xml')
Erik Staabc734cd7a2021-11-23 03:11:522515
2516
Sven Zheng76a79ea2022-12-21 21:25:242517def _IsMojomFile(input_api, file_path):
2518 return input_api.os_path.splitext(file_path)[1] == ".mojom"
2519
2520
Mohamed Heikal5e5b7922020-10-29 18:57:592521def CheckNoUpstreamDepsOnClank(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502522 """Prevent additions of dependencies from the upstream repo on //clank."""
2523 # clank can depend on clank
2524 if input_api.change.RepositoryRoot().endswith('clank'):
2525 return []
2526 build_file_patterns = [
2527 r'(.+/)?BUILD\.gn',
2528 r'.+\.gni',
2529 ]
2530 excluded_files = [r'build[/\\]config[/\\]android[/\\]config\.gni']
2531 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
Mohamed Heikal5e5b7922020-10-29 18:57:592532
Sam Maiera6e76d72022-02-11 21:43:502533 error_message = 'Disallowed import on //clank in an upstream build file:'
Mohamed Heikal5e5b7922020-10-29 18:57:592534
Sam Maiera6e76d72022-02-11 21:43:502535 def FilterFile(affected_file):
2536 return input_api.FilterSourceFile(affected_file,
2537 files_to_check=build_file_patterns,
2538 files_to_skip=excluded_files)
Mohamed Heikal5e5b7922020-10-29 18:57:592539
Sam Maiera6e76d72022-02-11 21:43:502540 problems = []
2541 for f in input_api.AffectedSourceFiles(FilterFile):
2542 local_path = f.LocalPath()
2543 for line_number, line in f.ChangedContents():
2544 if (bad_pattern.search(line)):
2545 problems.append('%s:%d\n %s' %
2546 (local_path, line_number, line.strip()))
2547 if problems:
2548 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
2549 else:
2550 return []
Mohamed Heikal5e5b7922020-10-29 18:57:592551
2552
Saagar Sanghavifceeaae2020-08-12 16:40:362553def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502554 """Attempts to prevent use of functions intended only for testing in
2555 non-testing code. For now this is just a best-effort implementation
2556 that ignores header files and may have some false positives. A
2557 better implementation would probably need a proper C++ parser.
2558 """
2559 # We only scan .cc files and the like, as the declaration of
2560 # for-testing functions in header files are hard to distinguish from
2561 # calls to such functions without a proper C++ parser.
2562 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:192563
Sam Maiera6e76d72022-02-11 21:43:502564 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
2565 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' %
2566 base_function_pattern)
2567 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
2568 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
2569 exclusion_pattern = input_api.re.compile(
2570 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' %
2571 (base_function_pattern, base_function_pattern))
2572 # Avoid a false positive in this case, where the method name, the ::, and
2573 # the closing { are all on different lines due to line wrapping.
2574 # HelperClassForTesting::
2575 # HelperClassForTesting(
2576 # args)
2577 # : member(0) {}
2578 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:192579
Sam Maiera6e76d72022-02-11 21:43:502580 def FilterFile(affected_file):
2581 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2582 input_api.DEFAULT_FILES_TO_SKIP)
2583 return input_api.FilterSourceFile(
2584 affected_file,
2585 files_to_check=file_inclusion_pattern,
2586 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:192587
Sam Maiera6e76d72022-02-11 21:43:502588 problems = []
2589 for f in input_api.AffectedSourceFiles(FilterFile):
2590 local_path = f.LocalPath()
2591 in_method_defn = False
2592 for line_number, line in f.ChangedContents():
2593 if (inclusion_pattern.search(line)
2594 and not comment_pattern.search(line)
2595 and not exclusion_pattern.search(line)
2596 and not allowlist_pattern.search(line)
2597 and not in_method_defn):
2598 problems.append('%s:%d\n %s' %
2599 (local_path, line_number, line.strip()))
2600 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:192601
Sam Maiera6e76d72022-02-11 21:43:502602 if problems:
2603 return [
2604 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
2605 ]
2606 else:
2607 return []
[email protected]55459852011-08-10 15:17:192608
2609
Saagar Sanghavifceeaae2020-08-12 16:40:362610def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502611 """This is a simplified version of
2612 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
2613 """
2614 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
2615 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
2616 name_pattern = r'ForTest(s|ing)?'
2617 # Describes an occurrence of "ForTest*" inside a // comment.
2618 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
2619 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
2620 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
2621 # Catch calls.
2622 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
2623 # Ignore definitions. (Comments are ignored separately.)
2624 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
Andrew Grieve40f451d2023-07-06 19:46:512625 allowlist_re = input_api.re.compile(r'// IN-TEST$')
Vaclav Brozek7dbc28c2018-03-27 08:35:232626
Sam Maiera6e76d72022-02-11 21:43:502627 problems = []
2628 sources = lambda x: input_api.FilterSourceFile(
2629 x,
2630 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
2631 DEFAULT_FILES_TO_SKIP),
2632 files_to_check=[r'.*\.java$'])
2633 for f in input_api.AffectedFiles(include_deletes=False,
2634 file_filter=sources):
2635 local_path = f.LocalPath()
Vaclav Brozek7dbc28c2018-03-27 08:35:232636 is_inside_javadoc = False
Sam Maiera6e76d72022-02-11 21:43:502637 for line_number, line in f.ChangedContents():
2638 if is_inside_javadoc and javadoc_end_re.search(line):
2639 is_inside_javadoc = False
2640 if not is_inside_javadoc and javadoc_start_re.search(line):
2641 is_inside_javadoc = True
2642 if is_inside_javadoc:
2643 continue
2644 if (inclusion_re.search(line) and not comment_re.search(line)
2645 and not annotation_re.search(line)
Andrew Grieve40f451d2023-07-06 19:46:512646 and not allowlist_re.search(line)
Sam Maiera6e76d72022-02-11 21:43:502647 and not exclusion_re.search(line)):
2648 problems.append('%s:%d\n %s' %
2649 (local_path, line_number, line.strip()))
Vaclav Brozek7dbc28c2018-03-27 08:35:232650
Sam Maiera6e76d72022-02-11 21:43:502651 if problems:
2652 return [
2653 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
2654 ]
2655 else:
2656 return []
Vaclav Brozek7dbc28c2018-03-27 08:35:232657
2658
Saagar Sanghavifceeaae2020-08-12 16:40:362659def CheckNoIOStreamInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502660 """Checks to make sure no .h files include <iostream>."""
2661 files = []
2662 pattern = input_api.re.compile(r'^#include\s*<iostream>',
2663 input_api.re.MULTILINE)
2664 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2665 if not f.LocalPath().endswith('.h'):
2666 continue
2667 contents = input_api.ReadFile(f)
2668 if pattern.search(contents):
2669 files.append(f)
[email protected]10689ca2011-09-02 02:31:542670
Sam Maiera6e76d72022-02-11 21:43:502671 if len(files):
2672 return [
2673 output_api.PresubmitError(
2674 'Do not #include <iostream> in header files, since it inserts static '
2675 'initialization into every file including the header. Instead, '
2676 '#include <ostream>. See http://crbug.com/94794', files)
2677 ]
2678 return []
2679
[email protected]10689ca2011-09-02 02:31:542680
Aleksey Khoroshilov9b28c032022-06-03 16:35:322681def CheckNoStrCatRedefines(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502682 """Checks no windows headers with StrCat redefined are included directly."""
2683 files = []
Aleksey Khoroshilov9b28c032022-06-03 16:35:322684 files_to_check = (r'.+%s' % _HEADER_EXTENSIONS,
2685 r'.+%s' % _IMPLEMENTATION_EXTENSIONS)
2686 files_to_skip = (input_api.DEFAULT_FILES_TO_SKIP +
2687 _NON_BASE_DEPENDENT_PATHS)
2688 sources_filter = lambda f: input_api.FilterSourceFile(
2689 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
2690
Sam Maiera6e76d72022-02-11 21:43:502691 pattern_deny = input_api.re.compile(
2692 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
2693 input_api.re.MULTILINE)
2694 pattern_allow = input_api.re.compile(
2695 r'^#include\s"base/win/windows_defines.inc"', input_api.re.MULTILINE)
Aleksey Khoroshilov9b28c032022-06-03 16:35:322696 for f in input_api.AffectedSourceFiles(sources_filter):
Sam Maiera6e76d72022-02-11 21:43:502697 contents = input_api.ReadFile(f)
2698 if pattern_deny.search(
2699 contents) and not pattern_allow.search(contents):
2700 files.append(f.LocalPath())
Danil Chapovalov3518f362018-08-11 16:13:432701
Sam Maiera6e76d72022-02-11 21:43:502702 if len(files):
2703 return [
2704 output_api.PresubmitError(
2705 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
2706 'directly since they pollute code with StrCat macro. Instead, '
2707 'include matching header from base/win. See http://crbug.com/856536',
2708 files)
2709 ]
2710 return []
Danil Chapovalov3518f362018-08-11 16:13:432711
[email protected]10689ca2011-09-02 02:31:542712
Andrew Williamsc9f69b482023-07-10 16:07:362713def _CheckNoUNIT_TESTInSourceFiles(input_api, f):
2714 problems = []
2715
2716 unit_test_macro = input_api.re.compile(
Riley Wong49be8a882025-02-27 00:38:232717 r'^\s*#.*(?:ifn?def\s+UNIT_TEST|defined\s*\(?\s*UNIT_TEST\s*\)?)(?:$|\s+)')
Andrew Williamsc9f69b482023-07-10 16:07:362718 for line_num, line in f.ChangedContents():
2719 if unit_test_macro.match(line):
2720 problems.append(' %s:%d' % (f.LocalPath(), line_num))
2721
2722 return problems
2723
2724
Saagar Sanghavifceeaae2020-08-12 16:40:362725def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502726 """Checks to make sure no source files use UNIT_TEST."""
2727 problems = []
2728 for f in input_api.AffectedFiles():
2729 if (not f.LocalPath().endswith(('.cc', '.mm'))):
2730 continue
Andrew Williamsc9f69b482023-07-10 16:07:362731 problems.extend(
2732 _CheckNoUNIT_TESTInSourceFiles(input_api, f))
[email protected]72df4e782012-06-21 16:28:182733
Sam Maiera6e76d72022-02-11 21:43:502734 if not problems:
2735 return []
2736 return [
2737 output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
2738 '\n'.join(problems))
2739 ]
2740
[email protected]72df4e782012-06-21 16:28:182741
Saagar Sanghavifceeaae2020-08-12 16:40:362742def CheckNoDISABLETypoInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502743 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
Dominic Battre033531052018-09-24 15:45:342744
Sam Maiera6e76d72022-02-11 21:43:502745 This test warns if somebody tries to disable a test with the DISABLE_ prefix
2746 instead of DISABLED_. To filter false positives, reports are only generated
2747 if a corresponding MAYBE_ line exists.
2748 """
2749 problems = []
Dominic Battre033531052018-09-24 15:45:342750
Sam Maiera6e76d72022-02-11 21:43:502751 # The following two patterns are looked for in tandem - is a test labeled
2752 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
2753 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
2754 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
Dominic Battre033531052018-09-24 15:45:342755
Sam Maiera6e76d72022-02-11 21:43:502756 # This is for the case that a test is disabled on all platforms.
2757 full_disable_pattern = input_api.re.compile(
2758 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
2759 input_api.re.MULTILINE)
Dominic Battre033531052018-09-24 15:45:342760
Arthur Sonzognic66e9c82024-04-23 07:53:042761 for f in input_api.AffectedFiles(include_deletes=False):
Sam Maiera6e76d72022-02-11 21:43:502762 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2763 continue
Dominic Battre033531052018-09-24 15:45:342764
Arthur Sonzognic66e9c82024-04-23 07:53:042765 # Search for MAYBE_, DISABLE_ pairs.
Sam Maiera6e76d72022-02-11 21:43:502766 disable_lines = {} # Maps of test name to line number.
2767 maybe_lines = {}
2768 for line_num, line in f.ChangedContents():
2769 disable_match = disable_pattern.search(line)
2770 if disable_match:
2771 disable_lines[disable_match.group(1)] = line_num
2772 maybe_match = maybe_pattern.search(line)
2773 if maybe_match:
2774 maybe_lines[maybe_match.group(1)] = line_num
Dominic Battre033531052018-09-24 15:45:342775
Sam Maiera6e76d72022-02-11 21:43:502776 # Search for DISABLE_ occurrences within a TEST() macro.
2777 disable_tests = set(disable_lines.keys())
2778 maybe_tests = set(maybe_lines.keys())
2779 for test in disable_tests.intersection(maybe_tests):
2780 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
Dominic Battre033531052018-09-24 15:45:342781
Sam Maiera6e76d72022-02-11 21:43:502782 contents = input_api.ReadFile(f)
2783 full_disable_match = full_disable_pattern.search(contents)
2784 if full_disable_match:
2785 problems.append(' %s' % f.LocalPath())
Dominic Battre033531052018-09-24 15:45:342786
Sam Maiera6e76d72022-02-11 21:43:502787 if not problems:
2788 return []
2789 return [
2790 output_api.PresubmitPromptWarning(
2791 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
2792 '\n'.join(problems))
2793 ]
2794
Dominic Battre033531052018-09-24 15:45:342795
Nina Satragnof7660532021-09-20 18:03:352796def CheckForgettingMAYBEInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502797 """Checks to make sure tests disabled conditionally are not missing a
2798 corresponding MAYBE_ prefix.
2799 """
2800 # Expect at least a lowercase character in the test name. This helps rule out
2801 # false positives with macros wrapping the actual tests name.
2802 define_maybe_pattern = input_api.re.compile(
2803 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
Bruce Dawsonffc55292022-04-20 04:18:192804 # The test_maybe_pattern needs to handle all of these forms. The standard:
2805 # IN_PROC_TEST_F(SyncTest, MAYBE_Start) {
2806 # With a wrapper macro around the test name:
2807 # IN_PROC_TEST_F(SyncTest, E2E_ENABLED(MAYBE_Start)) {
2808 # And the odd-ball NACL_BROWSER_TEST_f format:
2809 # NACL_BROWSER_TEST_F(NaClBrowserTest, SimpleLoad, {
2810 # The optional E2E_ENABLED-style is handled with (\w*\()?
2811 # The NACL_BROWSER_TEST_F pattern is handled by allowing a trailing comma or
2812 # trailing ')'.
2813 test_maybe_pattern = (
2814 r'^\s*\w*TEST[^(]*\(\s*\w+,\s*(\w*\()?MAYBE_{test_name}[\),]')
Sam Maiera6e76d72022-02-11 21:43:502815 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
2816 warnings = []
Nina Satragnof7660532021-09-20 18:03:352817
Sam Maiera6e76d72022-02-11 21:43:502818 # Read the entire files. We can't just read the affected lines, forgetting to
2819 # add MAYBE_ on a change would not show up otherwise.
Arthur Sonzognic66e9c82024-04-23 07:53:042820 for f in input_api.AffectedFiles(include_deletes=False):
Sam Maiera6e76d72022-02-11 21:43:502821 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2822 continue
2823 contents = input_api.ReadFile(f)
2824 lines = contents.splitlines(True)
2825 current_position = 0
2826 warning_test_names = set()
2827 for line_num, line in enumerate(lines, start=1):
2828 current_position += len(line)
2829 maybe_match = define_maybe_pattern.search(line)
2830 if maybe_match:
2831 test_name = maybe_match.group('test_name')
2832 # Do not warn twice for the same test.
2833 if (test_name in warning_test_names):
2834 continue
2835 warning_test_names.add(test_name)
Nina Satragnof7660532021-09-20 18:03:352836
Sam Maiera6e76d72022-02-11 21:43:502837 # Attempt to find the corresponding MAYBE_ test or suite, starting from
2838 # the current position.
2839 test_match = input_api.re.compile(
2840 test_maybe_pattern.format(test_name=test_name),
2841 input_api.re.MULTILINE).search(contents, current_position)
2842 suite_match = input_api.re.compile(
2843 suite_maybe_pattern.format(test_name=test_name),
2844 input_api.re.MULTILINE).search(contents, current_position)
2845 if not test_match and not suite_match:
2846 warnings.append(
2847 output_api.PresubmitPromptWarning(
2848 '%s:%d found MAYBE_ defined without corresponding test %s'
2849 % (f.LocalPath(), line_num, test_name)))
2850 return warnings
2851
[email protected]72df4e782012-06-21 16:28:182852
Saagar Sanghavifceeaae2020-08-12 16:40:362853def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502854 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
2855 errors = []
Kalvin Lee4a3b79de2022-05-26 16:00:162856 pattern = input_api.re.compile(r'\bDCHECK_IS_ON\b(?!\(\))',
Sam Maiera6e76d72022-02-11 21:43:502857 input_api.re.MULTILINE)
2858 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2859 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
2860 continue
2861 for lnum, line in f.ChangedContents():
2862 if input_api.re.search(pattern, line):
2863 errors.append(
2864 output_api.PresubmitError((
2865 '%s:%d: Use of DCHECK_IS_ON() must be written as "#if '
2866 + 'DCHECK_IS_ON()", not forgetting the parentheses.') %
2867 (f.LocalPath(), lnum)))
2868 return errors
danakj61c1aa22015-10-26 19:55:522869
2870
Weilun Shia487fad2020-10-28 00:10:342871# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
2872# more reliable way. See
2873# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:192874
wnwenbdc444e2016-05-25 13:44:152875
Saagar Sanghavifceeaae2020-08-12 16:40:362876def CheckFlakyTestUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502877 """Check that FlakyTest annotation is our own instead of the android one"""
2878 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
2879 files = []
2880 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2881 if f.LocalPath().endswith('Test.java'):
2882 if pattern.search(input_api.ReadFile(f)):
2883 files.append(f)
2884 if len(files):
2885 return [
2886 output_api.PresubmitError(
2887 'Use org.chromium.base.test.util.FlakyTest instead of '
2888 'android.test.FlakyTest', files)
2889 ]
2890 return []
mcasasb7440c282015-02-04 14:52:192891
wnwenbdc444e2016-05-25 13:44:152892
Saagar Sanghavifceeaae2020-08-12 16:40:362893def CheckNoDEPSGIT(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502894 """Make sure .DEPS.git is never modified manually."""
2895 if any(f.LocalPath().endswith('.DEPS.git')
2896 for f in input_api.AffectedFiles()):
2897 return [
2898 output_api.PresubmitError(
2899 'Never commit changes to .DEPS.git. This file is maintained by an\n'
2900 'automated system based on what\'s in DEPS and your changes will be\n'
2901 'overwritten.\n'
2902 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
2903 'get-the-code#Rolling_DEPS\n'
2904 'for more information')
2905 ]
2906 return []
[email protected]2a8ac9c2011-10-19 17:20:442907
2908
Sven Zheng76a79ea2022-12-21 21:25:242909def CheckCrosApiNeedBrowserTest(input_api, output_api):
2910 """Check new crosapi should add browser test."""
2911 has_new_crosapi = False
2912 has_browser_test = False
2913 for f in input_api.AffectedFiles():
Anton Bershanskyi4253349482025-02-11 21:01:272914 path = f.UnixLocalPath()
Sven Zheng76a79ea2022-12-21 21:25:242915 if (path.startswith('chromeos/crosapi/mojom') and
2916 _IsMojomFile(input_api, path) and f.Action() == 'A'):
2917 has_new_crosapi = True
2918 if path.endswith('browsertest.cc') or path.endswith('browser_test.cc'):
2919 has_browser_test = True
2920 if has_new_crosapi and not has_browser_test:
2921 return [
2922 output_api.PresubmitPromptWarning(
2923 'You are adding a new crosapi, but there is no file ends with '
2924 'browsertest.cc file being added or modified. It is important '
2925 'to add crosapi browser test coverage to avoid version '
2926 ' skew issues.\n'
2927 'Check //docs/lacros/test_instructions.md for more information.'
2928 )
2929 ]
2930 return []
2931
2932
Saagar Sanghavifceeaae2020-08-12 16:40:362933def CheckValidHostsInDEPSOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502934 """Checks that DEPS file deps are from allowed_hosts."""
2935 # Run only if DEPS file has been modified to annoy fewer bystanders.
2936 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
2937 return []
2938 # Outsource work to gclient verify
2939 try:
2940 gclient_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
2941 'third_party', 'depot_tools',
2942 'gclient.py')
2943 input_api.subprocess.check_output(
Bruce Dawson8a43cf72022-05-13 17:10:322944 [input_api.python3_executable, gclient_path, 'verify'],
Sam Maiera6e76d72022-02-11 21:43:502945 stderr=input_api.subprocess.STDOUT)
2946 return []
2947 except input_api.subprocess.CalledProcessError as error:
2948 return [
2949 output_api.PresubmitError(
2950 'DEPS file must have only git dependencies.',
2951 long_text=error.output)
2952 ]
tandriief664692014-09-23 14:51:472953
2954
Mario Sanchez Prada2472cab2019-09-18 10:58:312955def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152956 ban_rule):
Allen Bauer84778682022-09-22 16:28:562957 """Helper method for checking for banned constructs.
Mario Sanchez Prada2472cab2019-09-18 10:58:312958
Sam Maiera6e76d72022-02-11 21:43:502959 Returns an string composed of the name of the file, the line number where the
2960 match has been found and the additional text passed as |message| in case the
2961 target type name matches the text inside the line passed as parameter.
2962 """
2963 result = []
Peng Huang9c5949a02020-06-11 19:20:542964
Daniel Chenga44a1bcd2022-03-15 20:00:152965 # Ignore comments about banned types.
2966 if input_api.re.search(r"^ *//", line):
Sam Maiera6e76d72022-02-11 21:43:502967 return result
Daniel Chenga44a1bcd2022-03-15 20:00:152968 # A // nocheck comment will bypass this error.
2969 if line.endswith(" nocheck"):
Sam Maiera6e76d72022-02-11 21:43:502970 return result
2971
2972 matched = False
Daniel Chenga44a1bcd2022-03-15 20:00:152973 if ban_rule.pattern[0:1] == '/':
2974 regex = ban_rule.pattern[1:]
Sam Maiera6e76d72022-02-11 21:43:502975 if input_api.re.search(regex, line):
2976 matched = True
Daniel Chenga44a1bcd2022-03-15 20:00:152977 elif ban_rule.pattern in line:
Sam Maiera6e76d72022-02-11 21:43:502978 matched = True
2979
2980 if matched:
2981 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
Daniel Chenga44a1bcd2022-03-15 20:00:152982 for line in ban_rule.explanation:
2983 result.append(' %s' % line)
Sam Maiera6e76d72022-02-11 21:43:502984
danakjd18e8892020-12-17 17:42:012985 return result
Mario Sanchez Prada2472cab2019-09-18 10:58:312986
2987
Saagar Sanghavifceeaae2020-08-12 16:40:362988def CheckNoBannedFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502989 """Make sure that banned functions are not used."""
2990 warnings = []
2991 errors = []
[email protected]127f18ec2012-06-16 05:05:592992
Sam Maiera6e76d72022-02-11 21:43:502993 def IsExcludedFile(affected_file, excluded_paths):
Daniel Chenga44a1bcd2022-03-15 20:00:152994 if not excluded_paths:
2995 return False
2996
Anton Bershanskyi4253349482025-02-11 21:01:272997 local_path = affected_file.UnixLocalPath()
Sam Maiera6e76d72022-02-11 21:43:502998 for item in excluded_paths:
2999 if input_api.re.match(item, local_path):
3000 return True
3001 return False
wnwenbdc444e2016-05-25 13:44:153002
Sam Maiera6e76d72022-02-11 21:43:503003 def IsIosObjcFile(affected_file):
3004 local_path = affected_file.LocalPath()
3005 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m',
3006 '.h'):
3007 return False
3008 basename = input_api.os_path.basename(local_path)
3009 if 'ios' in basename.split('_'):
3010 return True
3011 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
3012 if sep and 'ios' in local_path.split(sep):
3013 return True
3014 return False
Sylvain Defresnea8b73d252018-02-28 15:45:543015
Daniel Chenga44a1bcd2022-03-15 20:00:153016 def CheckForMatch(affected_file, line_num: int, line: str,
3017 ban_rule: BanRule):
3018 if IsExcludedFile(affected_file, ban_rule.excluded_paths):
3019 return
3020
Sam Maiera6e76d72022-02-11 21:43:503021 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
Daniel Chenga44a1bcd2022-03-15 20:00:153022 ban_rule)
Sam Maiera6e76d72022-02-11 21:43:503023 if problems:
Daniel Chenga44a1bcd2022-03-15 20:00:153024 if ban_rule.treat_as_error is not None and ban_rule.treat_as_error:
Sam Maiera6e76d72022-02-11 21:43:503025 errors.extend(problems)
3026 else:
3027 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:153028
Sam Maiera6e76d72022-02-11 21:43:503029 file_filter = lambda f: f.LocalPath().endswith(('.java'))
3030 for f in input_api.AffectedFiles(file_filter=file_filter):
3031 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:153032 for ban_rule in _BANNED_JAVA_FUNCTIONS:
3033 CheckForMatch(f, line_num, line, ban_rule)
Eric Stevensona9a980972017-09-23 00:04:413034
Clement Yan9b330cb2022-11-17 05:25:293035 file_filter = lambda f: f.LocalPath().endswith(('.js', '.ts'))
3036 for f in input_api.AffectedFiles(file_filter=file_filter):
3037 for line_num, line in f.ChangedContents():
3038 for ban_rule in _BANNED_JAVASCRIPT_FUNCTIONS:
3039 CheckForMatch(f, line_num, line, ban_rule)
3040
Sam Maiera6e76d72022-02-11 21:43:503041 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
3042 for f in input_api.AffectedFiles(file_filter=file_filter):
3043 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:153044 for ban_rule in _BANNED_OBJC_FUNCTIONS:
3045 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:593046
Sam Maiera6e76d72022-02-11 21:43:503047 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
3048 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:153049 for ban_rule in _BANNED_IOS_OBJC_FUNCTIONS:
3050 CheckForMatch(f, line_num, line, ban_rule)
Sylvain Defresnea8b73d252018-02-28 15:45:543051
Sam Maiera6e76d72022-02-11 21:43:503052 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
3053 for f in input_api.AffectedFiles(file_filter=egtest_filter):
3054 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:153055 for ban_rule in _BANNED_IOS_EGTEST_FUNCTIONS:
3056 CheckForMatch(f, line_num, line, ban_rule)
Peter K. Lee6c03ccff2019-07-15 14:40:053057
Sam Maiera6e76d72022-02-11 21:43:503058 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
3059 for f in input_api.AffectedFiles(file_filter=file_filter):
3060 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:153061 for ban_rule in _BANNED_CPP_FUNCTIONS:
3062 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:593063
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:153064 # As of 05/2024, iOS fully migrated ConsentLevel::kSync to kSignin, and
3065 # Android is in the process of preventing new users from entering kSync.
3066 # So the warning is restricted to those platforms.
Riley Wong49be8a882025-02-27 00:38:233067 ios_pattern = input_api.re.compile(r'(^|[\W_])ios[\W_]')
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:153068 file_filter = lambda f: (f.LocalPath().endswith(('.cc', '.mm', '.h')) and
3069 ('android' in f.LocalPath() or
3070 # Simply checking for an 'ios' substring would
3071 # catch unrelated cases, use a regex.
3072 ios_pattern.search(f.LocalPath())))
3073 for f in input_api.AffectedFiles(file_filter=file_filter):
3074 for line_num, line in f.ChangedContents():
3075 for ban_rule in _DEPRECATED_SYNC_CONSENT_CPP_FUNCTIONS:
3076 CheckForMatch(f, line_num, line, ban_rule)
3077
3078 file_filter = lambda f: f.LocalPath().endswith(('.java'))
3079 for f in input_api.AffectedFiles(file_filter=file_filter):
3080 for line_num, line in f.ChangedContents():
3081 for ban_rule in _DEPRECATED_SYNC_CONSENT_JAVA_FUNCTIONS:
3082 CheckForMatch(f, line_num, line, ban_rule)
3083
Daniel Cheng92c15e32022-03-16 17:48:223084 file_filter = lambda f: f.LocalPath().endswith(('.mojom'))
3085 for f in input_api.AffectedFiles(file_filter=file_filter):
3086 for line_num, line in f.ChangedContents():
3087 for ban_rule in _BANNED_MOJOM_PATTERNS:
3088 CheckForMatch(f, line_num, line, ban_rule)
3089
3090
Sam Maiera6e76d72022-02-11 21:43:503091 result = []
3092 if (warnings):
3093 result.append(
3094 output_api.PresubmitPromptWarning('Banned functions were used.\n' +
3095 '\n'.join(warnings)))
3096 if (errors):
3097 result.append(
3098 output_api.PresubmitError('Banned functions were used.\n' +
3099 '\n'.join(errors)))
3100 return result
[email protected]127f18ec2012-06-16 05:05:593101
Michael Thiessen44457642020-02-06 00:24:153102def _CheckAndroidNoBannedImports(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503103 """Make sure that banned java imports are not used."""
3104 errors = []
Michael Thiessen44457642020-02-06 00:24:153105
Sam Maiera6e76d72022-02-11 21:43:503106 file_filter = lambda f: f.LocalPath().endswith(('.java'))
3107 for f in input_api.AffectedFiles(file_filter=file_filter):
3108 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:153109 for ban_rule in _BANNED_JAVA_IMPORTS:
3110 # Consider merging this into the above function. There is no
3111 # real difference anymore other than helping with a little
3112 # bit of boilerplate text. Doing so means things like
3113 # `treat_as_error` will also be uniformly handled.
Sam Maiera6e76d72022-02-11 21:43:503114 problems = _GetMessageForMatchingType(input_api, f, line_num,
Daniel Chenga44a1bcd2022-03-15 20:00:153115 line, ban_rule)
Sam Maiera6e76d72022-02-11 21:43:503116 if problems:
3117 errors.extend(problems)
3118 result = []
3119 if (errors):
3120 result.append(
3121 output_api.PresubmitError('Banned imports were used.\n' +
3122 '\n'.join(errors)))
3123 return result
Michael Thiessen44457642020-02-06 00:24:153124
3125
Saagar Sanghavifceeaae2020-08-12 16:40:363126def CheckNoPragmaOnce(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503127 """Make sure that banned functions are not used."""
3128 files = []
3129 pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
3130 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
3131 if not f.LocalPath().endswith('.h'):
3132 continue
Bruce Dawson4c4c2922022-05-02 18:07:333133 if f.LocalPath().endswith('com_imported_mstscax.h'):
3134 continue
Sam Maiera6e76d72022-02-11 21:43:503135 contents = input_api.ReadFile(f)
3136 if pattern.search(contents):
3137 files.append(f)
[email protected]6c063c62012-07-11 19:11:063138
Sam Maiera6e76d72022-02-11 21:43:503139 if files:
3140 return [
3141 output_api.PresubmitError(
3142 'Do not use #pragma once in header files.\n'
3143 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
3144 files)
3145 ]
3146 return []
[email protected]6c063c62012-07-11 19:11:063147
[email protected]127f18ec2012-06-16 05:05:593148
Saagar Sanghavifceeaae2020-08-12 16:40:363149def CheckNoTrinaryTrueFalse(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503150 """Checks to make sure we don't introduce use of foo ? true : false."""
3151 problems = []
3152 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
3153 for f in input_api.AffectedFiles():
3154 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
3155 continue
[email protected]e7479052012-09-19 00:26:123156
Sam Maiera6e76d72022-02-11 21:43:503157 for line_num, line in f.ChangedContents():
3158 if pattern.match(line):
3159 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]e7479052012-09-19 00:26:123160
Sam Maiera6e76d72022-02-11 21:43:503161 if not problems:
3162 return []
3163 return [
3164 output_api.PresubmitPromptWarning(
3165 'Please consider avoiding the "? true : false" pattern if possible.\n'
3166 + '\n'.join(problems))
3167 ]
[email protected]e7479052012-09-19 00:26:123168
3169
Saagar Sanghavifceeaae2020-08-12 16:40:363170def CheckUnwantedDependencies(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503171 """Runs checkdeps on #include and import statements added in this
3172 change. Breaking - rules is an error, breaking ! rules is a
3173 warning.
3174 """
3175 # Return early if no relevant file types were modified.
3176 for f in input_api.AffectedFiles():
3177 path = f.LocalPath()
3178 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path)
3179 or _IsJavaFile(input_api, path)):
3180 break
[email protected]55f9f382012-07-31 11:02:183181 else:
Sam Maiera6e76d72022-02-11 21:43:503182 return []
rhalavati08acd232017-04-03 07:23:283183
Sam Maiera6e76d72022-02-11 21:43:503184 import sys
3185 # We need to wait until we have an input_api object and use this
3186 # roundabout construct to import checkdeps because this file is
3187 # eval-ed and thus doesn't have __file__.
3188 original_sys_path = sys.path
3189 try:
3190 sys.path = sys.path + [
3191 input_api.os_path.join(input_api.PresubmitLocalPath(),
3192 'buildtools', 'checkdeps')
3193 ]
3194 import checkdeps
3195 from rules import Rule
3196 finally:
3197 # Restore sys.path to what it was before.
3198 sys.path = original_sys_path
[email protected]55f9f382012-07-31 11:02:183199
Sam Maiera6e76d72022-02-11 21:43:503200 added_includes = []
3201 added_imports = []
3202 added_java_imports = []
3203 for f in input_api.AffectedFiles():
3204 if _IsCPlusPlusFile(input_api, f.LocalPath()):
3205 changed_lines = [line for _, line in f.ChangedContents()]
3206 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
3207 elif _IsProtoFile(input_api, f.LocalPath()):
3208 changed_lines = [line for _, line in f.ChangedContents()]
3209 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
3210 elif _IsJavaFile(input_api, f.LocalPath()):
3211 changed_lines = [line for _, line in f.ChangedContents()]
3212 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:243213
Sam Maiera6e76d72022-02-11 21:43:503214 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
3215
3216 error_descriptions = []
3217 warning_descriptions = []
3218 error_subjects = set()
3219 warning_subjects = set()
3220
3221 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
3222 added_includes):
3223 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3224 description_with_path = '%s\n %s' % (path, rule_description)
3225 if rule_type == Rule.DISALLOW:
3226 error_descriptions.append(description_with_path)
3227 error_subjects.add("#includes")
3228 else:
3229 warning_descriptions.append(description_with_path)
3230 warning_subjects.add("#includes")
3231
3232 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
3233 added_imports):
3234 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3235 description_with_path = '%s\n %s' % (path, rule_description)
3236 if rule_type == Rule.DISALLOW:
3237 error_descriptions.append(description_with_path)
3238 error_subjects.add("imports")
3239 else:
3240 warning_descriptions.append(description_with_path)
3241 warning_subjects.add("imports")
3242
3243 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
3244 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
3245 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3246 description_with_path = '%s\n %s' % (path, rule_description)
3247 if rule_type == Rule.DISALLOW:
3248 error_descriptions.append(description_with_path)
3249 error_subjects.add("imports")
3250 else:
3251 warning_descriptions.append(description_with_path)
3252 warning_subjects.add("imports")
3253
3254 results = []
3255 if error_descriptions:
3256 results.append(
3257 output_api.PresubmitError(
3258 'You added one or more %s that violate checkdeps rules.' %
3259 " and ".join(error_subjects), error_descriptions))
3260 if warning_descriptions:
3261 results.append(
3262 output_api.PresubmitPromptOrNotify(
3263 'You added one or more %s of files that are temporarily\n'
3264 'allowed but being removed. Can you avoid introducing the\n'
3265 '%s? See relevant DEPS file(s) for details and contacts.' %
3266 (" and ".join(warning_subjects), "/".join(warning_subjects)),
3267 warning_descriptions))
3268 return results
[email protected]55f9f382012-07-31 11:02:183269
3270
Saagar Sanghavifceeaae2020-08-12 16:40:363271def CheckFilePermissions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503272 """Check that all files have their permissions properly set."""
3273 if input_api.platform == 'win32':
3274 return []
3275 checkperms_tool = input_api.os_path.join(input_api.PresubmitLocalPath(),
3276 'tools', 'checkperms',
3277 'checkperms.py')
3278 args = [
Bruce Dawson8a43cf72022-05-13 17:10:323279 input_api.python3_executable, checkperms_tool, '--root',
Sam Maiera6e76d72022-02-11 21:43:503280 input_api.change.RepositoryRoot()
3281 ]
3282 with input_api.CreateTemporaryFile() as file_list:
3283 for f in input_api.AffectedFiles():
3284 # checkperms.py file/directory arguments must be relative to the
3285 # repository.
3286 file_list.write((f.LocalPath() + '\n').encode('utf8'))
3287 file_list.close()
3288 args += ['--file-list', file_list.name]
3289 try:
3290 input_api.subprocess.check_output(args)
3291 return []
3292 except input_api.subprocess.CalledProcessError as error:
3293 return [
3294 output_api.PresubmitError('checkperms.py failed:',
3295 long_text=error.output.decode(
3296 'utf-8', 'ignore'))
3297 ]
[email protected]fbcafe5a2012-08-08 15:31:223298
3299
Saagar Sanghavifceeaae2020-08-12 16:40:363300def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503301 """Makes sure we don't include ui/aura/window_property.h
3302 in header files.
3303 """
3304 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
3305 errors = []
3306 for f in input_api.AffectedFiles():
3307 if not f.LocalPath().endswith('.h'):
3308 continue
3309 for line_num, line in f.ChangedContents():
3310 if pattern.match(line):
3311 errors.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]c8278b32012-10-30 20:35:493312
Sam Maiera6e76d72022-02-11 21:43:503313 results = []
3314 if errors:
3315 results.append(
3316 output_api.PresubmitError(
3317 'Header files should not include ui/aura/window_property.h',
3318 errors))
3319 return results
[email protected]c8278b32012-10-30 20:35:493320
3321
Omer Katzcc77ea92021-04-26 10:23:283322def CheckNoInternalHeapIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503323 """Makes sure we don't include any headers from
3324 third_party/blink/renderer/platform/heap/impl or
3325 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
3326 third_party/blink/renderer/platform/heap
3327 """
3328 impl_pattern = input_api.re.compile(
3329 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
3330 v8_wrapper_pattern = input_api.re.compile(
3331 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"'
3332 )
3333 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:313334 r"^third_party/blink/renderer/platform/heap/.*",
Anton Bershanskyi4253349482025-02-11 21:01:273335 f.UnixLocalPath())
Sam Maiera6e76d72022-02-11 21:43:503336 errors = []
Omer Katzcc77ea92021-04-26 10:23:283337
Sam Maiera6e76d72022-02-11 21:43:503338 for f in input_api.AffectedFiles(file_filter=file_filter):
3339 for line_num, line in f.ChangedContents():
3340 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
3341 errors.append(' %s:%d' % (f.LocalPath(), line_num))
Omer Katzcc77ea92021-04-26 10:23:283342
Sam Maiera6e76d72022-02-11 21:43:503343 results = []
3344 if errors:
3345 results.append(
3346 output_api.PresubmitError(
3347 'Do not include files from third_party/blink/renderer/platform/heap/impl'
3348 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
3349 'relevant counterparts from third_party/blink/renderer/platform/heap',
3350 errors))
3351 return results
Omer Katzcc77ea92021-04-26 10:23:283352
3353
[email protected]70ca77752012-11-20 03:45:033354def _CheckForVersionControlConflictsInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:503355 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
3356 errors = []
3357 for line_num, line in f.ChangedContents():
3358 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
3359 # First-level headers in markdown look a lot like version control
3360 # conflict markers. http://daringfireball.net/projects/markdown/basics
3361 continue
3362 if pattern.match(line):
3363 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
3364 return errors
[email protected]70ca77752012-11-20 03:45:033365
3366
Saagar Sanghavifceeaae2020-08-12 16:40:363367def CheckForVersionControlConflicts(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503368 """Usually this is not intentional and will cause a compile failure."""
3369 errors = []
3370 for f in input_api.AffectedFiles():
3371 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
[email protected]70ca77752012-11-20 03:45:033372
Sam Maiera6e76d72022-02-11 21:43:503373 results = []
3374 if errors:
3375 results.append(
3376 output_api.PresubmitError(
3377 'Version control conflict markers found, please resolve.',
3378 errors))
3379 return results
[email protected]70ca77752012-11-20 03:45:033380
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203381
Saagar Sanghavifceeaae2020-08-12 16:40:363382def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
Dirk Prankee4df27972025-02-26 18:39:353383 pattern = input_api.re.compile(r'support\.google\.com\/chrome.*/answer')
Sam Maiera6e76d72022-02-11 21:43:503384 errors = []
3385 for f in input_api.AffectedFiles():
3386 for line_num, line in f.ChangedContents():
3387 if pattern.search(line):
3388 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
estadee17314a02017-01-12 16:22:163389
Sam Maiera6e76d72022-02-11 21:43:503390 results = []
3391 if errors:
3392 results.append(
3393 output_api.PresubmitPromptWarning(
3394 'Found Google support URL addressed by answer number. Please replace '
3395 'with a p= identifier instead. See crbug.com/679462\n',
3396 errors))
3397 return results
estadee17314a02017-01-12 16:22:163398
[email protected]70ca77752012-11-20 03:45:033399
Saagar Sanghavifceeaae2020-08-12 16:40:363400def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503401 def FilterFile(affected_file):
3402 """Filter function for use with input_api.AffectedSourceFiles,
3403 below. This filters out everything except non-test files from
3404 top-level directories that generally speaking should not hard-code
3405 service URLs (e.g. src/android_webview/, src/content/ and others).
3406 """
3407 return input_api.FilterSourceFile(
3408 affected_file,
Bruce Dawson40fece62022-09-16 19:58:313409 files_to_check=[r'^(android_webview|base|content|net)/.*'],
Sam Maiera6e76d72022-02-11 21:43:503410 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3411 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:443412
Dirk Prankee4df27972025-02-26 18:39:353413 base_pattern = (r'"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
3414 r'\.(com|net)[^"]*"')
Sam Maiera6e76d72022-02-11 21:43:503415 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
3416 pattern = input_api.re.compile(base_pattern)
3417 problems = [] # items are (filename, line_number, line)
3418 for f in input_api.AffectedSourceFiles(FilterFile):
3419 for line_num, line in f.ChangedContents():
3420 if not comment_pattern.search(line) and pattern.search(line):
3421 problems.append((f.LocalPath(), line_num, line))
[email protected]06e6d0ff2012-12-11 01:36:443422
Sam Maiera6e76d72022-02-11 21:43:503423 if problems:
3424 return [
3425 output_api.PresubmitPromptOrNotify(
3426 'Most layers below src/chrome/ should not hardcode service URLs.\n'
3427 'Are you sure this is correct?', [
3428 ' %s:%d: %s' % (problem[0], problem[1], problem[2])
3429 for problem in problems
3430 ])
3431 ]
3432 else:
3433 return []
[email protected]06e6d0ff2012-12-11 01:36:443434
3435
Saagar Sanghavifceeaae2020-08-12 16:40:363436def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503437 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
James Cook6b6597c2019-11-06 22:05:293438
Sam Maiera6e76d72022-02-11 21:43:503439 def FileFilter(affected_file):
3440 """Includes directories known to be Chrome OS only."""
3441 return input_api.FilterSourceFile(
3442 affected_file,
3443 files_to_check=(
3444 '^ash/',
3445 '^chromeos/', # Top-level src/chromeos.
3446 '.*/chromeos/', # Any path component.
3447 '^components/arc',
3448 '^components/exo'),
3449 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:293450
Sam Maiera6e76d72022-02-11 21:43:503451 prefs = []
3452 priority_prefs = []
3453 for f in input_api.AffectedFiles(file_filter=FileFilter):
3454 for line_num, line in f.ChangedContents():
3455 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF',
3456 line):
3457 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
3458 prefs.append(' %s' % line)
3459 if input_api.re.search(
3460 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
3461 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
3462 priority_prefs.append(' %s' % line)
3463
3464 results = []
3465 if (prefs):
3466 results.append(
3467 output_api.PresubmitPromptWarning(
3468 'Preferences were registered as SYNCABLE_PREF and will be controlled '
3469 'by browser sync settings. If these prefs should be controlled by OS '
3470 'sync settings use SYNCABLE_OS_PREF instead.\n' +
3471 '\n'.join(prefs)))
3472 if (priority_prefs):
3473 results.append(
3474 output_api.PresubmitPromptWarning(
3475 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
3476 'controlled by browser sync settings. If these prefs should be '
3477 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
3478 'instead.\n' + '\n'.join(prefs)))
3479 return results
James Cook6b6597c2019-11-06 22:05:293480
3481
Saagar Sanghavifceeaae2020-08-12 16:40:363482def CheckNoAbbreviationInPngFileName(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503483 """Makes sure there are no abbreviations in the name of PNG files.
3484 The native_client_sdk directory is excluded because it has auto-generated PNG
3485 files for documentation.
3486 """
3487 errors = []
Yuanqing Zhu9eef02832022-12-04 14:42:173488 files_to_check = [r'.*\.png$']
Bruce Dawson40fece62022-09-16 19:58:313489 files_to_skip = [r'^native_client_sdk/',
3490 r'^services/test/',
3491 r'^third_party/blink/web_tests/',
Bruce Dawson3db456212022-05-02 05:34:183492 ]
Sam Maiera6e76d72022-02-11 21:43:503493 file_filter = lambda f: input_api.FilterSourceFile(
3494 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Dirk Prankee4df27972025-02-26 18:39:353495 abbreviation = input_api.re.compile(r'.+_[a-z]\.png|.+_[a-z]_.*\.png')
Sam Maiera6e76d72022-02-11 21:43:503496 for f in input_api.AffectedFiles(include_deletes=False,
3497 file_filter=file_filter):
Yuanqing Zhu9eef02832022-12-04 14:42:173498 file_name = input_api.os_path.split(f.LocalPath())[1]
3499 if abbreviation.search(file_name):
3500 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:273501
Sam Maiera6e76d72022-02-11 21:43:503502 results = []
3503 if errors:
3504 results.append(
3505 output_api.PresubmitError(
3506 'The name of PNG files should not have abbreviations. \n'
3507 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
3508 'Contact [email protected] if you have questions.', errors))
3509 return results
[email protected]d2530012013-01-25 16:39:273510
Evan Stade7cd4a2c2022-08-04 23:37:253511def CheckNoProductIconsAddedToPublicRepo(input_api, output_api):
3512 """Heuristically identifies product icons based on their file name and reminds
3513 contributors not to add them to the Chromium repository.
3514 """
3515 errors = []
3516 files_to_check = [r'.*google.*\.png$|.*google.*\.svg$|.*google.*\.icon$']
3517 file_filter = lambda f: input_api.FilterSourceFile(
3518 f, files_to_check=files_to_check)
3519 for f in input_api.AffectedFiles(include_deletes=False,
3520 file_filter=file_filter):
3521 errors.append(' %s' % f.LocalPath())
3522
3523 results = []
3524 if errors:
Bruce Dawson3bcf0c92022-08-12 00:03:083525 # Give warnings instead of errors on presubmit --all and presubmit
3526 # --files.
3527 message_type = (output_api.PresubmitNotifyResult if input_api.no_diffs
3528 else output_api.PresubmitError)
Evan Stade7cd4a2c2022-08-04 23:37:253529 results.append(
Bruce Dawson3bcf0c92022-08-12 00:03:083530 message_type(
Evan Stade7cd4a2c2022-08-04 23:37:253531 'Trademarked images should not be added to the public repo. '
3532 'See crbug.com/944754', errors))
3533 return results
3534
[email protected]d2530012013-01-25 16:39:273535
Daniel Cheng4dcdb6b2017-04-13 08:30:173536def _ExtractAddRulesFromParsedDeps(parsed_deps):
Sam Maiera6e76d72022-02-11 21:43:503537 """Extract the rules that add dependencies from a parsed DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:173538
Sam Maiera6e76d72022-02-11 21:43:503539 Args:
3540 parsed_deps: the locals dictionary from evaluating the DEPS file."""
3541 add_rules = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:173542 add_rules.update([
Sam Maiera6e76d72022-02-11 21:43:503543 rule[1:] for rule in parsed_deps.get('include_rules', [])
Daniel Cheng4dcdb6b2017-04-13 08:30:173544 if rule.startswith('+') or rule.startswith('!')
3545 ])
Sam Maiera6e76d72022-02-11 21:43:503546 for _, rules in parsed_deps.get('specific_include_rules', {}).items():
3547 add_rules.update([
3548 rule[1:] for rule in rules
3549 if rule.startswith('+') or rule.startswith('!')
3550 ])
3551 return add_rules
Daniel Cheng4dcdb6b2017-04-13 08:30:173552
3553
3554def _ParseDeps(contents):
Sam Maiera6e76d72022-02-11 21:43:503555 """Simple helper for parsing DEPS files."""
Daniel Cheng4dcdb6b2017-04-13 08:30:173556
Sam Maiera6e76d72022-02-11 21:43:503557 # Stubs for handling special syntax in the root DEPS file.
3558 class _VarImpl:
3559 def __init__(self, local_scope):
3560 self._local_scope = local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:173561
Sam Maiera6e76d72022-02-11 21:43:503562 def Lookup(self, var_name):
3563 """Implements the Var syntax."""
3564 try:
3565 return self._local_scope['vars'][var_name]
3566 except KeyError:
3567 raise Exception('Var is not defined: %s' % var_name)
Daniel Cheng4dcdb6b2017-04-13 08:30:173568
Sam Maiera6e76d72022-02-11 21:43:503569 local_scope = {}
3570 global_scope = {
3571 'Var': _VarImpl(local_scope).Lookup,
3572 'Str': str,
3573 }
Dirk Pranke1b9e06382021-05-14 01:16:223574
Sam Maiera6e76d72022-02-11 21:43:503575 exec(contents, global_scope, local_scope)
3576 return local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:173577
3578
Andrew Grieveb77ac762024-11-29 15:01:483579def _FindAllDepsFilesForSubpath(input_api, subpath):
3580 ret = []
3581 while subpath:
3582 cur = input_api.os_path.join(input_api.change.RepositoryRoot(), subpath, 'DEPS')
Joanna Wang130e7bdd2024-12-10 17:39:033583 if input_api.os_path.isfile(cur):
Andrew Grieveb77ac762024-11-29 15:01:483584 ret.append(cur)
3585 subpath = input_api.os_path.dirname(subpath)
3586 return ret
3587
3588
3589def _FindAddedDepsThatRequireReview(input_api, depended_on_paths):
3590 """Filters to those whose DEPS set new_usages_require_review=True"""
3591 ret = set()
3592 cache = {}
3593 for target_path in depended_on_paths:
3594 for subpath in _FindAllDepsFilesForSubpath(input_api, target_path):
3595 config = cache.get(subpath)
3596 if config is None:
3597 config = _ParseDeps(input_api.ReadFile(subpath))
3598 cache[subpath] = config
3599 if config.get('new_usages_require_review'):
3600 ret.add(target_path)
3601 break
3602 return ret
3603
3604
Daniel Cheng4dcdb6b2017-04-13 08:30:173605def _CalculateAddedDeps(os_path, old_contents, new_contents):
Sam Maiera6e76d72022-02-11 21:43:503606 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
3607 a set of DEPS entries that we should look up.
[email protected]14a6131c2014-01-08 01:15:413608
Sam Maiera6e76d72022-02-11 21:43:503609 For a directory (rather than a specific filename) we fake a path to
3610 a specific filename by adding /DEPS. This is chosen as a file that
3611 will seldom or never be subject to per-file include_rules.
3612 """
3613 # We ignore deps entries on auto-generated directories.
3614 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:083615
Sam Maiera6e76d72022-02-11 21:43:503616 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
3617 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
Daniel Cheng4dcdb6b2017-04-13 08:30:173618
Sam Maiera6e76d72022-02-11 21:43:503619 added_deps = new_deps.difference(old_deps)
Daniel Cheng4dcdb6b2017-04-13 08:30:173620
Sam Maiera6e76d72022-02-11 21:43:503621 results = set()
3622 for added_dep in added_deps:
3623 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
3624 continue
3625 # Assume that a rule that ends in .h is a rule for a specific file.
3626 if added_dep.endswith('.h'):
3627 results.add(added_dep)
3628 else:
3629 results.add(os_path.join(added_dep, 'DEPS'))
3630 return results
[email protected]f32e2d1e2013-07-26 21:39:083631
Stephanie Kimec4f55a2024-04-24 16:54:023632def CheckForNewDEPSDownloadFromGoogleStorageHooks(input_api, output_api):
3633 """Checks that there are no new download_from_google_storage hooks"""
3634 for f in input_api.AffectedFiles(include_deletes=False):
3635 if f.LocalPath() == 'DEPS':
3636 old_hooks = _ParseDeps('\n'.join(f.OldContents()))['hooks']
3637 new_hooks = _ParseDeps('\n'.join(f.NewContents()))['hooks']
3638 old_name_to_hook = {hook['name']: hook for hook in old_hooks}
3639 new_name_to_hook = {hook['name']: hook for hook in new_hooks}
3640 added_hook_names = set(new_name_to_hook.keys()) - set(
3641 old_name_to_hook.keys())
3642 if not added_hook_names:
3643 return []
3644 new_download_from_google_storage_hooks = []
3645 for new_hook in added_hook_names:
3646 hook = new_name_to_hook[new_hook]
3647 action_cmd = hook['action']
3648 if any('download_from_google_storage' in arg
3649 for arg in action_cmd):
3650 new_download_from_google_storage_hooks.append(new_hook)
3651 if new_download_from_google_storage_hooks:
3652 return [
3653 output_api.PresubmitError(
3654 'Please do not add new download_from_google_storage '
3655 'hooks. Instead, add a `gcs` dep_type entry to `deps`. '
3656 'See https://chromium.googlesource.com/chromium/src.git'
3657 '/+/refs/heads/main/docs/gcs_dependencies.md for more '
3658 'info. Added hooks:',
3659 items=new_download_from_google_storage_hooks)
3660 ]
3661 return []
3662
[email protected]f32e2d1e2013-07-26 21:39:083663
Rasika Navarangec2d33d22024-05-23 15:19:023664def CheckEachPerfettoTestDataFileHasDepsEntry(input_api, output_api):
3665 test_data_filter = lambda f: input_api.FilterSourceFile(
Rasika Navarange08e542162024-05-31 13:31:263666 f, files_to_check=[r'^base/tracing/test/data_sha256/.*\.sha256'])
Rasika Navarangec2d33d22024-05-23 15:19:023667 if not any(input_api.AffectedFiles(file_filter=test_data_filter)):
3668 return []
3669
3670 # Find DEPS entry
3671 deps_entry = []
Rasika Navarange277cd662024-06-04 10:14:593672 old_deps_entry = []
Rasika Navarangec2d33d22024-05-23 15:19:023673 for f in input_api.AffectedFiles(include_deletes=False):
3674 if f.LocalPath() == 'DEPS':
3675 new_deps = _ParseDeps('\n'.join(f.NewContents()))['deps']
3676 deps_entry = new_deps['src/base/tracing/test/data']
Rasika Navarange277cd662024-06-04 10:14:593677 old_deps = _ParseDeps('\n'.join(f.OldContents()))['deps']
3678 old_deps_entry = old_deps['src/base/tracing/test/data']
Rasika Navarangec2d33d22024-05-23 15:19:023679 if not deps_entry:
Rasika Navarange08e542162024-05-31 13:31:263680 # TODO(312895063):Add back error when .sha256 files have been moved.
Rasika Navaranged977df342024-06-05 10:01:273681 return [output_api.PresubmitError(
Rasika Navarangec2d33d22024-05-23 15:19:023682 'You must update the DEPS file when you update a '
Rasika Navarange08e542162024-05-31 13:31:263683 '.sha256 file in base/tracing/test/data_sha256'
Rasika Navarangec2d33d22024-05-23 15:19:023684 )]
3685
3686 output = []
3687 for f in input_api.AffectedFiles(file_filter=test_data_filter):
3688 objects = deps_entry['objects']
3689 if not f.NewContents():
3690 # Deleted file so check that DEPS entry removed
3691 sha256_from_file = f.OldContents()[0]
3692 object_entry = next(
3693 (item for item in objects if item["sha256sum"] == sha256_from_file),
3694 None)
Rasika Navarange277cd662024-06-04 10:14:593695 old_entry = next(
3696 (item for item in old_deps_entry['objects'] if item["sha256sum"] == sha256_from_file),
3697 None)
Rasika Navarangec2d33d22024-05-23 15:19:023698 if object_entry:
Rasika Navarange277cd662024-06-04 10:14:593699 # Allow renaming of objects with the same hash
3700 if object_entry['object_name'] != old_entry['object_name']:
3701 continue
Rasika Navarangec2d33d22024-05-23 15:19:023702 output.append(output_api.PresubmitError(
3703 'You deleted %s so you must also remove the corresponding DEPS entry.'
3704 % f.LocalPath()
3705 ))
3706 continue
3707
3708 sha256_from_file = f.NewContents()[0]
3709 object_entry = next(
3710 (item for item in objects if item["sha256sum"] == sha256_from_file),
3711 None)
3712 if not object_entry:
3713 output.append(output_api.PresubmitError(
3714 'No corresponding DEPS entry found for %s. '
3715 'Run `base/tracing/test/test_data.py get_deps --filepath %s` '
3716 'to generate the DEPS entry.'
3717 % (f.LocalPath(), f.LocalPath())
3718 ))
3719
3720 if output:
3721 output.append(output_api.PresubmitError(
3722 'The DEPS entry for `src/base/tracing/test/data` in the DEPS file has not been '
3723 'updated properly. Run `base/tracing/test/test_data.py get_all_deps` to see what '
3724 'the DEPS entry should look like.'
3725 ))
3726 return output
3727
3728
Saagar Sanghavifceeaae2020-08-12 16:40:363729def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503730 """When a dependency prefixed with + is added to a DEPS file, we
3731 want to make sure that the change is reviewed by an OWNER of the
3732 target file or directory, to avoid layering violations from being
3733 introduced. This check verifies that this happens.
3734 """
3735 # We rely on Gerrit's code-owners to check approvals.
3736 # input_api.gerrit is always set for Chromium, but other projects
3737 # might not use Gerrit.
Bruce Dawson344ab262022-06-04 11:35:103738 if not input_api.gerrit or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:503739 return []
Bruce Dawsonb357aeb2022-08-09 15:38:303740 if 'PRESUBMIT_SKIP_NETWORK' in input_api.environ:
Sam Maiera6e76d72022-02-11 21:43:503741 return []
Bruce Dawsonb357aeb2022-08-09 15:38:303742 try:
3743 if (input_api.change.issue and
3744 input_api.gerrit.IsOwnersOverrideApproved(
3745 input_api.change.issue)):
3746 # Skip OWNERS check when Owners-Override label is approved. This is
3747 # intended for global owners, trusted bots, and on-call sheriffs.
3748 # Review is still required for these changes.
3749 return []
3750 except Exception as e:
Sam Maier4cef9242022-10-03 14:21:243751 return [output_api.PresubmitPromptWarning(
3752 'Failed to retrieve owner override status - %s' % str(e))]
Edward Lesmes6fba51082021-01-20 04:20:233753
Andrew Grieveb77ac762024-11-29 15:01:483754 # A set of paths (that might not exist) that are being added as DEPS
3755 # (via lines like "+foo/bar/baz").
3756 depended_on_paths = set()
jochen53efcdd2016-01-29 05:09:243757
Sam Maiera6e76d72022-02-11 21:43:503758 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:313759 r"^third_party/blink/.*",
Anton Bershanskyi4253349482025-02-11 21:01:273760 f.UnixLocalPath())
Sam Maiera6e76d72022-02-11 21:43:503761 for f in input_api.AffectedFiles(include_deletes=False,
3762 file_filter=file_filter):
3763 filename = input_api.os_path.basename(f.LocalPath())
3764 if filename == 'DEPS':
Andrew Grieveb77ac762024-11-29 15:01:483765 depended_on_paths.update(
Sam Maiera6e76d72022-02-11 21:43:503766 _CalculateAddedDeps(input_api.os_path,
3767 '\n'.join(f.OldContents()),
3768 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:553769
Andrew Grieveb77ac762024-11-29 15:01:483770 # Requiring reviews is opt-in as of https://crbug.com/365797506
3771 depended_on_paths = _FindAddedDepsThatRequireReview(input_api, depended_on_paths)
3772 if not depended_on_paths:
Sam Maiera6e76d72022-02-11 21:43:503773 return []
[email protected]e871964c2013-05-13 14:14:553774
Sam Maiera6e76d72022-02-11 21:43:503775 if input_api.is_committing:
3776 if input_api.tbr:
3777 return [
3778 output_api.PresubmitNotifyResult(
3779 '--tbr was specified, skipping OWNERS check for DEPS additions'
3780 )
3781 ]
Daniel Cheng3008dc12022-05-13 04:02:113782 # TODO(dcheng): Make this generate an error on dry runs if the reviewer
3783 # is not added, to prevent review serialization.
Sam Maiera6e76d72022-02-11 21:43:503784 if input_api.dry_run:
3785 return [
3786 output_api.PresubmitNotifyResult(
3787 'This is a dry run, skipping OWNERS check for DEPS additions'
3788 )
3789 ]
3790 if not input_api.change.issue:
3791 return [
3792 output_api.PresubmitError(
3793 "DEPS approval by OWNERS check failed: this change has "
3794 "no change number, so we can't check it for approvals.")
3795 ]
3796 output = output_api.PresubmitError
[email protected]14a6131c2014-01-08 01:15:413797 else:
Sam Maiera6e76d72022-02-11 21:43:503798 output = output_api.PresubmitNotifyResult
[email protected]e871964c2013-05-13 14:14:553799
Sam Maiera6e76d72022-02-11 21:43:503800 owner_email, reviewers = (
3801 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3802 input_api, None, approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:553803
Sam Maiera6e76d72022-02-11 21:43:503804 owner_email = owner_email or input_api.change.author_email
3805
3806 approval_status = input_api.owners_client.GetFilesApprovalStatus(
Andrew Grieveb77ac762024-11-29 15:01:483807 depended_on_paths, reviewers.union([owner_email]), [])
Sam Maiera6e76d72022-02-11 21:43:503808 missing_files = [
Andrew Grieveb77ac762024-11-29 15:01:483809 p for p in depended_on_paths
3810 if approval_status[p] != input_api.owners_client.APPROVED
Sam Maiera6e76d72022-02-11 21:43:503811 ]
3812
3813 # We strip the /DEPS part that was added by
3814 # _FilesToCheckForIncomingDeps to fake a path to a file in a
3815 # directory.
3816 def StripDeps(path):
3817 start_deps = path.rfind('/DEPS')
3818 if start_deps != -1:
3819 return path[:start_deps]
3820 else:
3821 return path
3822
Scott Leebf6a0942024-06-26 22:59:393823 submodule_paths = set(input_api.ListSubmodules())
3824 def is_from_submodules(path, submodule_paths):
3825 path = input_api.os_path.normpath(path)
3826 while path:
3827 if path in submodule_paths:
3828 return True
3829
3830 # All deps should be a relative path from the checkout.
3831 # i.e., shouldn't start with "/" or "c:\", for example.
3832 #
3833 # That said, this is to prevent an infinite loop, just in case
3834 # an input dep path starts with "/", because
3835 # os.path.dirname("/") => "/"
3836 parent = input_api.os_path.dirname(path)
3837 if parent == path:
3838 break
3839 path = parent
3840
3841 return False
3842
Sam Maiera6e76d72022-02-11 21:43:503843 unapproved_dependencies = [
3844 "'+%s'," % StripDeps(path) for path in missing_files
Scott Leebf6a0942024-06-26 22:59:393845 # if a newly added dep is from a submodule, it becomes trickier
3846 # to get suggested owners, especially it is from a different host.
3847 #
3848 # skip the review enforcement for cross-repo deps.
3849 if not is_from_submodules(path, submodule_paths)
Sam Maiera6e76d72022-02-11 21:43:503850 ]
3851
3852 if unapproved_dependencies:
3853 output_list = [
3854 output(
3855 'You need LGTM from owners of depends-on paths in DEPS that were '
3856 'modified in this CL:\n %s' %
3857 '\n '.join(sorted(unapproved_dependencies)))
3858 ]
3859 suggested_owners = input_api.owners_client.SuggestOwners(
3860 missing_files, exclude=[owner_email])
3861 output_list.append(
3862 output('Suggested missing target path OWNERS:\n %s' %
3863 '\n '.join(suggested_owners or [])))
3864 return output_list
3865
3866 return []
[email protected]e871964c2013-05-13 14:14:553867
3868
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493869# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:363870def CheckSpamLogging(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503871 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3872 files_to_skip = (
3873 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3874 input_api.DEFAULT_FILES_TO_SKIP + (
Jaewon Jung2f323bb2022-12-07 23:55:013875 r"^base/fuchsia/scoped_fx_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313876 r"^base/logging\.h$",
3877 r"^base/logging\.cc$",
3878 r"^base/task/thread_pool/task_tracker\.cc$",
3879 r"^chrome/app/chrome_main_delegate\.cc$",
Yao Li359937b2023-02-15 23:43:033880 r"^chrome/browser/ash/arc/enterprise/cert_store/arc_cert_installer\.cc$",
3881 r"^chrome/browser/ash/policy/remote_commands/user_command_arc_job\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313882 r"^chrome/browser/chrome_browser_main\.cc$",
3883 r"^chrome/browser/ui/startup/startup_browser_creator\.cc$",
3884 r"^chrome/browser/browser_switcher/bho/.*",
3885 r"^chrome/browser/diagnostics/diagnostics_writer\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313886 r"^chrome/chrome_elf/dll_hash/dll_hash_main\.cc$",
3887 r"^chrome/installer/setup/.*",
Daniel Ruberyad36eea2024-08-01 01:38:323888 # crdmg runs as a separate binary which intentionally does
3889 # not depend on base logging.
3890 r"^chrome/utility/safe_browsing/mac/crdmg\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313891 r"^chromecast/",
Vigen Issahhanjane2d93822023-06-30 15:57:203892 r"^components/cast",
Bruce Dawson40fece62022-09-16 19:58:313893 r"^components/media_control/renderer/media_playback_options\.cc$",
Salma Elmahallawy52976452023-01-27 17:04:493894 r"^components/policy/core/common/policy_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313895 r"^components/viz/service/display/"
Sam Maiera6e76d72022-02-11 21:43:503896 r"overlay_strategy_underlay_cast\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313897 r"^components/zucchini/.*",
Sam Maiera6e76d72022-02-11 21:43:503898 # TODO(peter): Remove exception. https://crbug.com/534537
Bruce Dawson40fece62022-09-16 19:58:313899 r"^content/browser/notifications/"
Sam Maiera6e76d72022-02-11 21:43:503900 r"notification_event_dispatcher_impl\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313901 r"^content/common/gpu/client/gl_helper_benchmark\.cc$",
3902 r"^courgette/courgette_minimal_tool\.cc$",
3903 r"^courgette/courgette_tool\.cc$",
3904 r"^extensions/renderer/logging_native_handler\.cc$",
3905 r"^fuchsia_web/common/init_logging\.cc$",
3906 r"^fuchsia_web/runners/common/web_component\.cc$",
Caroline Liua7050132023-02-13 22:23:153907 r"^fuchsia_web/shell/.*\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313908 r"^headless/app/headless_shell\.cc$",
3909 r"^ipc/ipc_logging\.cc$",
3910 r"^native_client_sdk/",
3911 r"^remoting/base/logging\.h$",
3912 r"^remoting/host/.*",
3913 r"^sandbox/linux/.*",
Austin Sullivana6054e02024-05-20 16:31:293914 r"^services/webnn/tflite/graph_impl_tflite\.cc$",
3915 r"^services/webnn/coreml/graph_impl_coreml\.mm$",
Bruce Dawson40fece62022-09-16 19:58:313916 r"^storage/browser/file_system/dump_file_system\.cc$",
Steinar H. Gundersone5689e42024-08-07 18:17:193917 r"^testing/perf/",
Bruce Dawson40fece62022-09-16 19:58:313918 r"^tools/",
3919 r"^ui/base/resource/data_pack\.cc$",
3920 r"^ui/aura/bench/bench_main\.cc$",
3921 r"^ui/ozone/platform/cast/",
3922 r"^ui/base/x/xwmstartupcheck/"
Sam Maiera6e76d72022-02-11 21:43:503923 r"xwmstartupcheck\.cc$"))
3924 source_file_filter = lambda x: input_api.FilterSourceFile(
3925 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:403926
Sam Maiera6e76d72022-02-11 21:43:503927 log_info = set([])
3928 printf = set([])
[email protected]85218562013-11-22 07:41:403929
Sam Maiera6e76d72022-02-11 21:43:503930 for f in input_api.AffectedSourceFiles(source_file_filter):
3931 for _, line in f.ChangedContents():
3932 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
3933 log_info.add(f.LocalPath())
3934 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
3935 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:373936
Sam Maiera6e76d72022-02-11 21:43:503937 if input_api.re.search(r"\bprintf\(", line):
3938 printf.add(f.LocalPath())
3939 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
3940 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:403941
Sam Maiera6e76d72022-02-11 21:43:503942 if log_info:
3943 return [
3944 output_api.PresubmitError(
3945 'These files spam the console log with LOG(INFO):',
3946 items=log_info)
3947 ]
3948 if printf:
3949 return [
3950 output_api.PresubmitError(
3951 'These files spam the console log with printf/fprintf:',
3952 items=printf)
3953 ]
3954 return []
[email protected]85218562013-11-22 07:41:403955
3956
Saagar Sanghavifceeaae2020-08-12 16:40:363957def CheckForAnonymousVariables(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503958 """These types are all expected to hold locks while in scope and
3959 so should never be anonymous (which causes them to be immediately
3960 destroyed)."""
3961 they_who_must_be_named = [
3962 'base::AutoLock',
3963 'base::AutoReset',
3964 'base::AutoUnlock',
3965 'SkAutoAlphaRestore',
3966 'SkAutoBitmapShaderInstall',
3967 'SkAutoBlitterChoose',
3968 'SkAutoBounderCommit',
3969 'SkAutoCallProc',
3970 'SkAutoCanvasRestore',
3971 'SkAutoCommentBlock',
3972 'SkAutoDescriptor',
3973 'SkAutoDisableDirectionCheck',
3974 'SkAutoDisableOvalCheck',
3975 'SkAutoFree',
3976 'SkAutoGlyphCache',
3977 'SkAutoHDC',
3978 'SkAutoLockColors',
3979 'SkAutoLockPixels',
3980 'SkAutoMalloc',
3981 'SkAutoMaskFreeImage',
3982 'SkAutoMutexAcquire',
3983 'SkAutoPathBoundsUpdate',
3984 'SkAutoPDFRelease',
3985 'SkAutoRasterClipValidate',
3986 'SkAutoRef',
3987 'SkAutoTime',
3988 'SkAutoTrace',
3989 'SkAutoUnref',
3990 ]
3991 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
3992 # bad: base::AutoLock(lock.get());
3993 # not bad: base::AutoLock lock(lock.get());
3994 bad_pattern = input_api.re.compile(anonymous)
3995 # good: new base::AutoLock(lock.get())
3996 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
3997 errors = []
[email protected]49aa76a2013-12-04 06:59:163998
Sam Maiera6e76d72022-02-11 21:43:503999 for f in input_api.AffectedFiles():
4000 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
4001 continue
4002 for linenum, line in f.ChangedContents():
4003 if bad_pattern.search(line) and not good_pattern.search(line):
4004 errors.append('%s:%d' % (f.LocalPath(), linenum))
[email protected]49aa76a2013-12-04 06:59:164005
Sam Maiera6e76d72022-02-11 21:43:504006 if errors:
4007 return [
4008 output_api.PresubmitError(
4009 'These lines create anonymous variables that need to be named:',
4010 items=errors)
4011 ]
4012 return []
[email protected]49aa76a2013-12-04 06:59:164013
4014
Saagar Sanghavifceeaae2020-08-12 16:40:364015def CheckUniquePtrOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504016 # Returns whether |template_str| is of the form <T, U...> for some types T
Glen Robertson9142ffd72024-05-16 01:37:474017 # and U, or is invalid due to mismatched angle bracket pairs. Assumes that
4018 # |template_str| is already in the form <...>.
4019 def HasMoreThanOneArgOrInvalid(template_str):
Sam Maiera6e76d72022-02-11 21:43:504020 # Level of <...> nesting.
4021 nesting = 0
4022 for c in template_str:
4023 if c == '<':
4024 nesting += 1
4025 elif c == '>':
4026 nesting -= 1
4027 elif c == ',' and nesting == 1:
4028 return True
Glen Robertson9142ffd72024-05-16 01:37:474029 if nesting != 0:
Daniel Cheng566634ff2024-06-29 14:56:534030 # Invalid.
4031 return True
Sam Maiera6e76d72022-02-11 21:43:504032 return False
Vaclav Brozekb7fadb692018-08-30 06:39:534033
Sam Maiera6e76d72022-02-11 21:43:504034 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
4035 sources = lambda affected_file: input_api.FilterSourceFile(
4036 affected_file,
4037 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4038 DEFAULT_FILES_TO_SKIP),
4039 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:554040
Sam Maiera6e76d72022-02-11 21:43:504041 # Pattern to capture a single "<...>" block of template arguments. It can
4042 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
4043 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
4044 # latter would likely require counting that < and > match, which is not
4045 # expressible in regular languages. Should the need arise, one can introduce
4046 # limited counting (matching up to a total number of nesting depth), which
4047 # should cover all practical cases for already a low nesting limit.
4048 template_arg_pattern = (
4049 r'<[^>]*' # Opening block of <.
4050 r'>([^<]*>)?') # Closing block of >.
4051 # Prefix expressing that whatever follows is not already inside a <...>
4052 # block.
4053 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
4054 null_construct_pattern = input_api.re.compile(
4055 not_inside_template_arg_pattern + r'\bstd::unique_ptr' +
4056 template_arg_pattern + r'\(\)')
Vaclav Brozeka54c528b2018-04-06 19:23:554057
Sam Maiera6e76d72022-02-11 21:43:504058 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
4059 template_arg_no_array_pattern = (
4060 r'<[^>]*[^]]' # Opening block of <.
4061 r'>([^(<]*[^]]>)?') # Closing block of >.
4062 # Prefix saying that what follows is the start of an expression.
4063 start_of_expr_pattern = r'(=|\breturn|^)\s*'
4064 # Suffix saying that what follows are call parentheses with a non-empty list
4065 # of arguments.
4066 nonempty_arg_list_pattern = r'\(([^)]|$)'
4067 # Put the template argument into a capture group for deeper examination later.
4068 return_construct_pattern = input_api.re.compile(
4069 start_of_expr_pattern + r'std::unique_ptr' + '(?P<template_arg>' +
4070 template_arg_no_array_pattern + ')' + nonempty_arg_list_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:554071
Sam Maiera6e76d72022-02-11 21:43:504072 problems_constructor = []
4073 problems_nullptr = []
4074 for f in input_api.AffectedSourceFiles(sources):
4075 for line_number, line in f.ChangedContents():
4076 # Disallow:
4077 # return std::unique_ptr<T>(foo);
4078 # bar = std::unique_ptr<T>(foo);
4079 # But allow:
4080 # return std::unique_ptr<T[]>(foo);
4081 # bar = std::unique_ptr<T[]>(foo);
4082 # And also allow cases when the second template argument is present. Those
4083 # cases cannot be handled by std::make_unique:
4084 # return std::unique_ptr<T, U>(foo);
4085 # bar = std::unique_ptr<T, U>(foo);
4086 local_path = f.LocalPath()
4087 return_construct_result = return_construct_pattern.search(line)
Glen Robertson9142ffd72024-05-16 01:37:474088 if return_construct_result and not HasMoreThanOneArgOrInvalid(
Sam Maiera6e76d72022-02-11 21:43:504089 return_construct_result.group('template_arg')):
4090 problems_constructor.append(
4091 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4092 # Disallow:
4093 # std::unique_ptr<T>()
4094 if null_construct_pattern.search(line):
4095 problems_nullptr.append(
4096 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Vaclav Brozek851d9602018-04-04 16:13:054097
Sam Maiera6e76d72022-02-11 21:43:504098 errors = []
4099 if problems_nullptr:
4100 errors.append(
4101 output_api.PresubmitPromptWarning(
4102 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
4103 problems_nullptr))
4104 if problems_constructor:
4105 errors.append(
4106 output_api.PresubmitError(
4107 'The following files use explicit std::unique_ptr constructor. '
4108 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
4109 'std::make_unique is not an option.', problems_constructor))
4110 return errors
Peter Kasting4844e46e2018-02-23 07:27:104111
4112
Saagar Sanghavifceeaae2020-08-12 16:40:364113def CheckUserActionUpdate(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504114 """Checks if any new user action has been added."""
4115 if any('actions.xml' == input_api.os_path.basename(f)
4116 for f in input_api.LocalPaths()):
4117 # If actions.xml is already included in the changelist, the PRESUBMIT
4118 # for actions.xml will do a more complete presubmit check.
4119 return []
4120
4121 file_inclusion_pattern = [r'.*\.(cc|mm)$']
4122 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
4123 input_api.DEFAULT_FILES_TO_SKIP)
4124 file_filter = lambda f: input_api.FilterSourceFile(
4125 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
4126
4127 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
4128 current_actions = None
4129 for f in input_api.AffectedFiles(file_filter=file_filter):
4130 for line_num, line in f.ChangedContents():
4131 match = input_api.re.search(action_re, line)
4132 if match:
4133 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
4134 # loaded only once.
4135 if not current_actions:
Bruce Dawson6cb2d4d2023-03-01 21:35:094136 with open('tools/metrics/actions/actions.xml',
4137 encoding='utf-8') as actions_f:
Sam Maiera6e76d72022-02-11 21:43:504138 current_actions = actions_f.read()
4139 # Search for the matched user action name in |current_actions|.
4140 for action_name in match.groups():
4141 action = 'name="{0}"'.format(action_name)
4142 if action not in current_actions:
4143 return [
4144 output_api.PresubmitPromptWarning(
4145 'File %s line %d: %s is missing in '
4146 'tools/metrics/actions/actions.xml. Please run '
4147 'tools/metrics/actions/extract_actions.py to update.'
4148 % (f.LocalPath(), line_num, action_name))
4149 ]
[email protected]999261d2014-03-03 20:08:084150 return []
4151
[email protected]999261d2014-03-03 20:08:084152
Daniel Cheng13ca61a882017-08-25 15:11:254153def _ImportJSONCommentEater(input_api):
Sam Maiera6e76d72022-02-11 21:43:504154 import sys
4155 sys.path = sys.path + [
4156 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4157 'json_comment_eater')
4158 ]
4159 import json_comment_eater
4160 return json_comment_eater
Daniel Cheng13ca61a882017-08-25 15:11:254161
4162
[email protected]99171a92014-06-03 08:44:474163def _GetJSONParseError(input_api, filename, eat_comments=True):
dchenge07de812016-06-20 19:27:174164 try:
Sam Maiera6e76d72022-02-11 21:43:504165 contents = input_api.ReadFile(filename)
4166 if eat_comments:
4167 json_comment_eater = _ImportJSONCommentEater(input_api)
4168 contents = json_comment_eater.Nom(contents)
dchenge07de812016-06-20 19:27:174169
Sam Maiera6e76d72022-02-11 21:43:504170 input_api.json.loads(contents)
4171 except ValueError as e:
4172 return e
Andrew Grieve4deedb12022-02-03 21:34:504173 return None
4174
4175
Sam Maiera6e76d72022-02-11 21:43:504176def _GetIDLParseError(input_api, filename):
4177 try:
4178 contents = input_api.ReadFile(filename)
Devlin Croninf7582a12022-04-21 21:14:284179 for i, char in enumerate(contents):
Daniel Chenga37c03db2022-05-12 17:20:344180 if not char.isascii():
4181 return (
4182 'Non-ascii character "%s" (ord %d) found at offset %d.' %
4183 (char, ord(char), i))
Sam Maiera6e76d72022-02-11 21:43:504184 idl_schema = input_api.os_path.join(input_api.PresubmitLocalPath(),
4185 'tools', 'json_schema_compiler',
4186 'idl_schema.py')
4187 process = input_api.subprocess.Popen(
Bruce Dawson679fb082022-04-14 00:47:284188 [input_api.python3_executable, idl_schema],
Sam Maiera6e76d72022-02-11 21:43:504189 stdin=input_api.subprocess.PIPE,
4190 stdout=input_api.subprocess.PIPE,
4191 stderr=input_api.subprocess.PIPE,
4192 universal_newlines=True)
4193 (_, error) = process.communicate(input=contents)
4194 return error or None
4195 except ValueError as e:
4196 return e
agrievef32bcc72016-04-04 14:57:404197
agrievef32bcc72016-04-04 14:57:404198
Sam Maiera6e76d72022-02-11 21:43:504199def CheckParseErrors(input_api, output_api):
4200 """Check that IDL and JSON files do not contain syntax errors."""
4201 actions = {
4202 '.idl': _GetIDLParseError,
4203 '.json': _GetJSONParseError,
4204 }
4205 # Most JSON files are preprocessed and support comments, but these do not.
4206 json_no_comments_patterns = [
Bruce Dawson40fece62022-09-16 19:58:314207 r'^testing/',
Sam Maiera6e76d72022-02-11 21:43:504208 ]
4209 # Only run IDL checker on files in these directories.
4210 idl_included_patterns = [
Bruce Dawson40fece62022-09-16 19:58:314211 r'^chrome/common/extensions/api/',
4212 r'^extensions/common/api/',
Sam Maiera6e76d72022-02-11 21:43:504213 ]
agrievef32bcc72016-04-04 14:57:404214
Sam Maiera6e76d72022-02-11 21:43:504215 def get_action(affected_file):
4216 filename = affected_file.LocalPath()
4217 return actions.get(input_api.os_path.splitext(filename)[1])
agrievef32bcc72016-04-04 14:57:404218
Sam Maiera6e76d72022-02-11 21:43:504219 def FilterFile(affected_file):
4220 action = get_action(affected_file)
4221 if not action:
4222 return False
Anton Bershanskyi4253349482025-02-11 21:01:274223 path = affected_file.UnixLocalPath()
agrievef32bcc72016-04-04 14:57:404224
Sam Maiera6e76d72022-02-11 21:43:504225 if _MatchesFile(input_api,
4226 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS, path):
4227 return False
4228
4229 if (action == _GetIDLParseError
4230 and not _MatchesFile(input_api, idl_included_patterns, path)):
4231 return False
4232 return True
4233
4234 results = []
4235 for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
4236 include_deletes=False):
4237 action = get_action(affected_file)
4238 kwargs = {}
4239 if (action == _GetJSONParseError
4240 and _MatchesFile(input_api, json_no_comments_patterns,
Anton Bershanskyi4253349482025-02-11 21:01:274241 affected_file.UnixLocalPath())):
Sam Maiera6e76d72022-02-11 21:43:504242 kwargs['eat_comments'] = False
4243 parse_error = action(input_api, affected_file.AbsoluteLocalPath(),
4244 **kwargs)
4245 if parse_error:
4246 results.append(
4247 output_api.PresubmitError(
4248 '%s could not be parsed: %s' %
4249 (affected_file.LocalPath(), parse_error)))
4250 return results
4251
4252
4253def CheckJavaStyle(input_api, output_api):
4254 """Runs checkstyle on changed java files and returns errors if any exist."""
4255
4256 # Return early if no java files were modified.
4257 if not any(
4258 _IsJavaFile(input_api, f.LocalPath())
4259 for f in input_api.AffectedFiles()):
4260 return []
4261
4262 import sys
4263 original_sys_path = sys.path
4264 try:
4265 sys.path = sys.path + [
4266 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4267 'android', 'checkstyle')
4268 ]
4269 import checkstyle
4270 finally:
4271 # Restore sys.path to what it was before.
4272 sys.path = original_sys_path
4273
Andrew Grieve4f88e3ca2022-11-22 19:09:204274 return checkstyle.run_presubmit(
Sam Maiera6e76d72022-02-11 21:43:504275 input_api,
4276 output_api,
Sam Maiera6e76d72022-02-11 21:43:504277 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
4278
4279
4280def CheckPythonDevilInit(input_api, output_api):
4281 """Checks to make sure devil is initialized correctly in python scripts."""
4282 script_common_initialize_pattern = input_api.re.compile(
4283 r'script_common\.InitializeEnvironment\(')
4284 devil_env_config_initialize = input_api.re.compile(
4285 r'devil_env\.config\.Initialize\(')
4286
4287 errors = []
4288
4289 sources = lambda affected_file: input_api.FilterSourceFile(
4290 affected_file,
4291 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314292 r'^build/android/devil_chromium\.py',
Sven Zheng8e079562024-05-10 20:11:064293 r'^tools/bisect-builds\.py',
Bruce Dawson40fece62022-09-16 19:58:314294 r'^third_party/.*',
Sam Maiera6e76d72022-02-11 21:43:504295 )),
4296 files_to_check=[r'.*\.py$'])
4297
4298 for f in input_api.AffectedSourceFiles(sources):
4299 for line_num, line in f.ChangedContents():
4300 if (script_common_initialize_pattern.search(line)
4301 or devil_env_config_initialize.search(line)):
4302 errors.append("%s:%d" % (f.LocalPath(), line_num))
4303
4304 results = []
4305
4306 if errors:
4307 results.append(
4308 output_api.PresubmitError(
4309 'Devil initialization should always be done using '
4310 'devil_chromium.Initialize() in the chromium project, to use better '
4311 'defaults for dependencies (ex. up-to-date version of adb).',
4312 errors))
4313
4314 return results
4315
4316
4317def _MatchesFile(input_api, patterns, path):
4318 for pattern in patterns:
4319 if input_api.re.search(pattern, path):
4320 return True
4321 return False
4322
4323
Daniel Chenga37c03db2022-05-12 17:20:344324def _ChangeHasSecurityReviewer(input_api, owners_file):
4325 """Returns True iff the CL has a reviewer from SECURITY_OWNERS.
Sam Maiera6e76d72022-02-11 21:43:504326
Daniel Chenga37c03db2022-05-12 17:20:344327 Args:
4328 input_api: The presubmit input API.
4329 owners_file: OWNERS file with required reviewers. Typically, this is
4330 something like ipc/SECURITY_OWNERS.
4331
4332 Note: if the presubmit is running for commit rather than for upload, this
4333 only returns True if a security reviewer has also approved the CL.
Sam Maiera6e76d72022-02-11 21:43:504334 """
Daniel Chengd88244472022-05-16 09:08:474335 # Owners-Override should bypass all additional OWNERS enforcement checks.
4336 # A CR+1 vote will still be required to land this change.
4337 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
4338 input_api.change.issue)):
4339 return True
4340
Daniel Chenga37c03db2022-05-12 17:20:344341 owner_email, reviewers = (
4342 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
Daniel Cheng3008dc12022-05-13 04:02:114343 input_api,
4344 None,
4345 approval_needed=input_api.is_committing and not input_api.dry_run))
Sam Maiera6e76d72022-02-11 21:43:504346
Daniel Chenga37c03db2022-05-12 17:20:344347 security_owners = input_api.owners_client.ListOwners(owners_file)
4348 return any(owner in reviewers for owner in security_owners)
Sam Maiera6e76d72022-02-11 21:43:504349
Daniel Chenga37c03db2022-05-12 17:20:344350
4351@dataclass
Daniel Cheng171dad8d2022-05-21 00:40:254352class _SecurityProblemWithItems:
4353 problem: str
4354 items: Sequence[str]
4355
4356
4357@dataclass
Daniel Chenga37c03db2022-05-12 17:20:344358class _MissingSecurityOwnersResult:
Daniel Cheng171dad8d2022-05-21 00:40:254359 owners_file_problems: Sequence[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:344360 has_security_sensitive_files: bool
Daniel Cheng171dad8d2022-05-21 00:40:254361 missing_reviewer_problem: Optional[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:344362
4363
4364def _FindMissingSecurityOwners(input_api,
4365 output_api,
4366 file_patterns: Sequence[str],
4367 excluded_patterns: Sequence[str],
4368 required_owners_file: str,
4369 custom_rule_function: Optional[Callable] = None
4370 ) -> _MissingSecurityOwnersResult:
4371 """Find OWNERS files missing per-file rules for security-sensitive files.
4372
4373 Args:
4374 input_api: the PRESUBMIT input API object.
4375 output_api: the PRESUBMIT output API object.
4376 file_patterns: basename patterns that require a corresponding per-file
4377 security restriction.
4378 excluded_patterns: path patterns that should be exempted from
4379 requiring a security restriction.
4380 required_owners_file: path to the required OWNERS file, e.g.
4381 ipc/SECURITY_OWNERS
4382 cc_alias: If not None, email that will be CCed automatically if the
4383 change contains security-sensitive files, as determined by
4384 `file_patterns` and `excluded_patterns`.
4385 custom_rule_function: If not None, will be called with `input_api` and
4386 the current file under consideration. Returning True will add an
4387 exact match per-file rule check for the current file.
4388 """
4389
4390 # `to_check` is a mapping of an OWNERS file path to Patterns.
4391 #
4392 # Patterns is a dictionary mapping glob patterns (suitable for use in
4393 # per-file rules) to a PatternEntry.
4394 #
Sam Maiera6e76d72022-02-11 21:43:504395 # PatternEntry is a dictionary with two keys:
4396 # - 'files': the files that are matched by this pattern
4397 # - 'rules': the per-file rules needed for this pattern
Daniel Chenga37c03db2022-05-12 17:20:344398 #
Sam Maiera6e76d72022-02-11 21:43:504399 # For example, if we expect OWNERS file to contain rules for *.mojom and
4400 # *_struct_traits*.*, Patterns might look like this:
4401 # {
4402 # '*.mojom': {
4403 # 'files': ...,
4404 # 'rules': [
4405 # 'per-file *.mojom=set noparent',
4406 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
4407 # ],
4408 # },
4409 # '*_struct_traits*.*': {
4410 # 'files': ...,
4411 # 'rules': [
4412 # 'per-file *_struct_traits*.*=set noparent',
4413 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
4414 # ],
4415 # },
4416 # }
4417 to_check = {}
Daniel Chenga37c03db2022-05-12 17:20:344418 files_to_review = []
Sam Maiera6e76d72022-02-11 21:43:504419
Daniel Chenga37c03db2022-05-12 17:20:344420 def AddPatternToCheck(file, pattern):
Sam Maiera6e76d72022-02-11 21:43:504421 owners_file = input_api.os_path.join(
Daniel Chengd88244472022-05-16 09:08:474422 input_api.os_path.dirname(file.LocalPath()), 'OWNERS')
Sam Maiera6e76d72022-02-11 21:43:504423 if owners_file not in to_check:
4424 to_check[owners_file] = {}
4425 if pattern not in to_check[owners_file]:
4426 to_check[owners_file][pattern] = {
4427 'files': [],
4428 'rules': [
Daniel Chenga37c03db2022-05-12 17:20:344429 f'per-file {pattern}=set noparent',
4430 f'per-file {pattern}=file://{required_owners_file}',
Sam Maiera6e76d72022-02-11 21:43:504431 ]
4432 }
Daniel Chenged57a162022-05-25 02:56:344433 to_check[owners_file][pattern]['files'].append(file.LocalPath())
Daniel Chenga37c03db2022-05-12 17:20:344434 files_to_review.append(file.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:504435
Daniel Chenga37c03db2022-05-12 17:20:344436 # Only enforce security OWNERS rules for a directory if that directory has a
4437 # file that matches `file_patterns`. For example, if a directory only
4438 # contains *.mojom files and no *_messages*.h files, the check should only
4439 # ensure that rules for *.mojom files are present.
4440 for file in input_api.AffectedFiles(include_deletes=False):
4441 file_basename = input_api.os_path.basename(file.LocalPath())
4442 if custom_rule_function is not None and custom_rule_function(
4443 input_api, file):
4444 AddPatternToCheck(file, file_basename)
4445 continue
Sam Maiera6e76d72022-02-11 21:43:504446
Daniel Chenga37c03db2022-05-12 17:20:344447 if any(
4448 input_api.fnmatch.fnmatch(file.LocalPath(), pattern)
4449 for pattern in excluded_patterns):
Sam Maiera6e76d72022-02-11 21:43:504450 continue
4451
4452 for pattern in file_patterns:
Daniel Chenga37c03db2022-05-12 17:20:344453 # Unlike `excluded_patterns`, `file_patterns` is checked only against the
4454 # file's basename.
4455 if input_api.fnmatch.fnmatch(file_basename, pattern):
4456 AddPatternToCheck(file, pattern)
Sam Maiera6e76d72022-02-11 21:43:504457 break
4458
Daniel Chenga37c03db2022-05-12 17:20:344459 has_security_sensitive_files = bool(to_check)
Daniel Cheng171dad8d2022-05-21 00:40:254460
4461 # Check if any newly added lines in OWNERS files intersect with required
4462 # per-file OWNERS lines. If so, ensure that a security reviewer is included.
4463 # This is a hack, but is needed because the OWNERS check (by design) ignores
4464 # new OWNERS entries; otherwise, a non-owner could add someone as a new
4465 # OWNER and have that newly-added OWNER self-approve their own addition.
4466 newly_covered_files = []
4467 for file in input_api.AffectedFiles(include_deletes=False):
4468 if not file.LocalPath() in to_check:
4469 continue
4470 for _, line in file.ChangedContents():
4471 for _, entry in to_check[file.LocalPath()].items():
4472 if line in entry['rules']:
4473 newly_covered_files.extend(entry['files'])
4474
4475 missing_reviewer_problems = None
4476 if newly_covered_files and not _ChangeHasSecurityReviewer(
Daniel Chenga37c03db2022-05-12 17:20:344477 input_api, required_owners_file):
Daniel Cheng171dad8d2022-05-21 00:40:254478 missing_reviewer_problems = _SecurityProblemWithItems(
4479 f'Review from an owner in {required_owners_file} is required for '
4480 'the following newly-added files:',
4481 [f'{file}' for file in sorted(set(newly_covered_files))])
Sam Maiera6e76d72022-02-11 21:43:504482
4483 # Go through the OWNERS files to check, filtering out rules that are already
4484 # present in that OWNERS file.
4485 for owners_file, patterns in to_check.items():
4486 try:
Daniel Cheng171dad8d2022-05-21 00:40:254487 lines = set(
4488 input_api.ReadFile(
4489 input_api.os_path.join(input_api.change.RepositoryRoot(),
4490 owners_file)).splitlines())
4491 for entry in patterns.values():
4492 entry['rules'] = [
4493 rule for rule in entry['rules'] if rule not in lines
4494 ]
Sam Maiera6e76d72022-02-11 21:43:504495 except IOError:
4496 # No OWNERS file, so all the rules are definitely missing.
4497 continue
4498
4499 # All the remaining lines weren't found in OWNERS files, so emit an error.
Daniel Cheng171dad8d2022-05-21 00:40:254500 owners_file_problems = []
Daniel Chenga37c03db2022-05-12 17:20:344501
Sam Maiera6e76d72022-02-11 21:43:504502 for owners_file, patterns in to_check.items():
4503 missing_lines = []
4504 files = []
4505 for _, entry in patterns.items():
Daniel Chenged57a162022-05-25 02:56:344506 files.extend(entry['files'])
Sam Maiera6e76d72022-02-11 21:43:504507 missing_lines.extend(entry['rules'])
Sam Maiera6e76d72022-02-11 21:43:504508 if missing_lines:
Daniel Cheng171dad8d2022-05-21 00:40:254509 joined_missing_lines = '\n'.join(line for line in missing_lines)
4510 owners_file_problems.append(
4511 _SecurityProblemWithItems(
4512 'Found missing OWNERS lines for security-sensitive files. '
4513 f'Please add the following lines to {owners_file}:\n'
4514 f'{joined_missing_lines}\n\nTo ensure security review for:',
4515 files))
Daniel Chenga37c03db2022-05-12 17:20:344516
Daniel Cheng171dad8d2022-05-21 00:40:254517 return _MissingSecurityOwnersResult(owners_file_problems,
Daniel Chenga37c03db2022-05-12 17:20:344518 has_security_sensitive_files,
Daniel Cheng171dad8d2022-05-21 00:40:254519 missing_reviewer_problems)
Daniel Chenga37c03db2022-05-12 17:20:344520
4521
4522def _CheckChangeForIpcSecurityOwners(input_api, output_api):
4523 # Whether or not a file affects IPC is (mostly) determined by a simple list
4524 # of filename patterns.
4525 file_patterns = [
4526 # Legacy IPC:
4527 '*_messages.cc',
4528 '*_messages*.h',
4529 '*_param_traits*.*',
4530 # Mojo IPC:
4531 '*.mojom',
4532 '*_mojom_traits*.*',
4533 '*_type_converter*.*',
4534 # Android native IPC:
4535 '*.aidl',
4536 ]
4537
Daniel Chenga37c03db2022-05-12 17:20:344538 excluded_patterns = [
Daniel Cheng518943f2022-05-12 22:15:464539 # These third_party directories do not contain IPCs, but contain files
4540 # matching the above patterns, which trigger false positives.
Daniel Chenga37c03db2022-05-12 17:20:344541 'third_party/crashpad/*',
4542 'third_party/blink/renderer/platform/bindings/*',
Evan Stade23a77da2025-02-06 21:15:314543 'third_party/protobuf/*',
Daniel Chenga37c03db2022-05-12 17:20:344544 'third_party/win_build_output/*',
Daniel Chengd88244472022-05-16 09:08:474545 # Enum-only mojoms used for web metrics, so no security review needed.
4546 'third_party/blink/public/mojom/use_counter/metrics/*',
Daniel Chenga37c03db2022-05-12 17:20:344547 # These files are just used to communicate between class loaders running
4548 # in the same process.
4549 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
4550 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
4551 ]
4552
4553 def IsMojoServiceManifestFile(input_api, file):
Dirk Prankee4df27972025-02-26 18:39:354554 manifest_pattern = input_api.re.compile(r'manifests?\.(cc|h)$')
4555 test_manifest_pattern = input_api.re.compile(r'test_manifests?\.(cc|h)')
Daniel Chenga37c03db2022-05-12 17:20:344556 if not manifest_pattern.search(file.LocalPath()):
4557 return False
4558
4559 if test_manifest_pattern.search(file.LocalPath()):
4560 return False
4561
4562 # All actual service manifest files should contain at least one
4563 # qualified reference to service_manager::Manifest.
4564 return any('service_manager::Manifest' in line
4565 for line in file.NewContents())
4566
4567 return _FindMissingSecurityOwners(
4568 input_api,
4569 output_api,
4570 file_patterns,
4571 excluded_patterns,
4572 'ipc/SECURITY_OWNERS',
4573 custom_rule_function=IsMojoServiceManifestFile)
4574
4575
4576def _CheckChangeForFuchsiaSecurityOwners(input_api, output_api):
4577 file_patterns = [
4578 # Component specifications.
4579 '*.cml', # Component Framework v2.
4580 '*.cmx', # Component Framework v1.
4581
4582 # Fuchsia IDL protocol specifications.
4583 '*.fidl',
4584 ]
4585
4586 # Don't check for owners files for changes in these directories.
4587 excluded_patterns = [
4588 'third_party/crashpad/*',
4589 ]
4590
4591 return _FindMissingSecurityOwners(input_api, output_api, file_patterns,
4592 excluded_patterns,
4593 'build/fuchsia/SECURITY_OWNERS')
4594
4595
4596def CheckSecurityOwners(input_api, output_api):
4597 """Checks that various security-sensitive files have an IPC OWNERS rule."""
4598 ipc_results = _CheckChangeForIpcSecurityOwners(input_api, output_api)
4599 fuchsia_results = _CheckChangeForFuchsiaSecurityOwners(
4600 input_api, output_api)
4601
4602 if ipc_results.has_security_sensitive_files:
4603 output_api.AppendCC('[email protected]')
Sam Maiera6e76d72022-02-11 21:43:504604
4605 results = []
Daniel Chenga37c03db2022-05-12 17:20:344606
Daniel Cheng171dad8d2022-05-21 00:40:254607 missing_reviewer_problems = []
4608 if ipc_results.missing_reviewer_problem:
4609 missing_reviewer_problems.append(ipc_results.missing_reviewer_problem)
4610 if fuchsia_results.missing_reviewer_problem:
4611 missing_reviewer_problems.append(
4612 fuchsia_results.missing_reviewer_problem)
Daniel Chenga37c03db2022-05-12 17:20:344613
Daniel Cheng171dad8d2022-05-21 00:40:254614 # Missing reviewers are an error unless there's no issue number
4615 # associated with this branch; in that case, the presubmit is being run
4616 # with --all or --files.
4617 #
4618 # Note that upload should never be an error; otherwise, it would be
4619 # impossible to upload changes at all.
4620 if input_api.is_committing and input_api.change.issue:
4621 make_presubmit_message = output_api.PresubmitError
4622 else:
4623 make_presubmit_message = output_api.PresubmitNotifyResult
4624 for problem in missing_reviewer_problems:
Sam Maiera6e76d72022-02-11 21:43:504625 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:254626 make_presubmit_message(problem.problem, items=problem.items))
Daniel Chenga37c03db2022-05-12 17:20:344627
Daniel Cheng171dad8d2022-05-21 00:40:254628 owners_file_problems = []
4629 owners_file_problems.extend(ipc_results.owners_file_problems)
4630 owners_file_problems.extend(fuchsia_results.owners_file_problems)
Daniel Chenga37c03db2022-05-12 17:20:344631
Daniel Cheng171dad8d2022-05-21 00:40:254632 for problem in owners_file_problems:
Daniel Cheng3008dc12022-05-13 04:02:114633 # Missing per-file rules are always an error. While swarming and caching
4634 # means that uploading a patchset with updated OWNERS files and sending
4635 # it to the CQ again should not have a large incremental cost, it is
4636 # still frustrating to discover the error only after the change has
4637 # already been uploaded.
Daniel Chenga37c03db2022-05-12 17:20:344638 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:254639 output_api.PresubmitError(problem.problem, items=problem.items))
Sam Maiera6e76d72022-02-11 21:43:504640
4641 return results
4642
4643
4644def _GetFilesUsingSecurityCriticalFunctions(input_api):
4645 """Checks affected files for changes to security-critical calls. This
4646 function checks the full change diff, to catch both additions/changes
4647 and removals.
4648
4649 Returns a dict keyed by file name, and the value is a set of detected
4650 functions.
4651 """
4652 # Map of function pretty name (displayed in an error) to the pattern to
4653 # match it with.
4654 _PATTERNS_TO_CHECK = {
4655 'content::GetServiceSandboxType<>()': 'GetServiceSandboxType\\<'
4656 }
4657 _PATTERNS_TO_CHECK = {
4658 k: input_api.re.compile(v)
4659 for k, v in _PATTERNS_TO_CHECK.items()
4660 }
4661
Sam Maiera6e76d72022-02-11 21:43:504662 # We don't want to trigger on strings within this file.
4663 def presubmit_file_filter(f):
Daniel Chenga37c03db2022-05-12 17:20:344664 return 'PRESUBMIT.py' != input_api.os_path.split(f.LocalPath())[1]
Sam Maiera6e76d72022-02-11 21:43:504665
4666 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
4667 files_to_functions = {}
4668 for f in input_api.AffectedFiles(file_filter=presubmit_file_filter):
4669 diff = f.GenerateScmDiff()
4670 for line in diff.split('\n'):
4671 # Not using just RightHandSideLines() because removing a
4672 # call to a security-critical function can be just as important
4673 # as adding or changing the arguments.
4674 if line.startswith('-') or (line.startswith('+')
4675 and not line.startswith('++')):
4676 for name, pattern in _PATTERNS_TO_CHECK.items():
4677 if pattern.search(line):
4678 path = f.LocalPath()
4679 if not path in files_to_functions:
4680 files_to_functions[path] = set()
4681 files_to_functions[path].add(name)
4682 return files_to_functions
4683
4684
4685def CheckSecurityChanges(input_api, output_api):
4686 """Checks that changes involving security-critical functions are reviewed
4687 by the security team.
4688 """
4689 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
4690 if not len(files_to_functions):
4691 return []
4692
Sam Maiera6e76d72022-02-11 21:43:504693 owners_file = 'ipc/SECURITY_OWNERS'
Daniel Chenga37c03db2022-05-12 17:20:344694 if _ChangeHasSecurityReviewer(input_api, owners_file):
Sam Maiera6e76d72022-02-11 21:43:504695 return []
4696
Daniel Chenga37c03db2022-05-12 17:20:344697 msg = 'The following files change calls to security-sensitive functions\n' \
Sam Maiera6e76d72022-02-11 21:43:504698 'that need to be reviewed by {}.\n'.format(owners_file)
4699 for path, names in files_to_functions.items():
4700 msg += ' {}\n'.format(path)
4701 for name in names:
4702 msg += ' {}\n'.format(name)
4703 msg += '\n'
4704
4705 if input_api.is_committing:
4706 output = output_api.PresubmitError
Mohamed Heikale217fc852020-07-06 19:44:034707 else:
Sam Maiera6e76d72022-02-11 21:43:504708 output = output_api.PresubmitNotifyResult
4709 return [output(msg)]
4710
4711
4712def CheckSetNoParent(input_api, output_api):
4713 """Checks that set noparent is only used together with an OWNERS file in
4714 //build/OWNERS.setnoparent (see also
4715 //docs/code_reviews.md#owners-files-details)
4716 """
4717 # Return early if no OWNERS files were modified.
4718 if not any(f.LocalPath().endswith('OWNERS')
4719 for f in input_api.AffectedFiles(include_deletes=False)):
4720 return []
4721
4722 errors = []
4723
4724 allowed_owners_files_file = 'build/OWNERS.setnoparent'
4725 allowed_owners_files = set()
Bruce Dawson58a45d22023-02-27 11:24:164726 with open(allowed_owners_files_file, 'r', encoding='utf-8') as f:
Sam Maiera6e76d72022-02-11 21:43:504727 for line in f:
4728 line = line.strip()
4729 if not line or line.startswith('#'):
4730 continue
4731 allowed_owners_files.add(line)
4732
4733 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
4734
4735 for f in input_api.AffectedFiles(include_deletes=False):
4736 if not f.LocalPath().endswith('OWNERS'):
4737 continue
4738
4739 found_owners_files = set()
4740 found_set_noparent_lines = dict()
4741
4742 # Parse the OWNERS file.
4743 for lineno, line in enumerate(f.NewContents(), 1):
4744 line = line.strip()
4745 if line.startswith('set noparent'):
4746 found_set_noparent_lines[''] = lineno
4747 if line.startswith('file://'):
4748 if line in allowed_owners_files:
4749 found_owners_files.add('')
4750 if line.startswith('per-file'):
4751 match = per_file_pattern.match(line)
4752 if match:
4753 glob = match.group(1).strip()
4754 directive = match.group(2).strip()
4755 if directive == 'set noparent':
4756 found_set_noparent_lines[glob] = lineno
4757 if directive.startswith('file://'):
4758 if directive in allowed_owners_files:
4759 found_owners_files.add(glob)
4760
4761 # Check that every set noparent line has a corresponding file:// line
4762 # listed in build/OWNERS.setnoparent. An exception is made for top level
4763 # directories since src/OWNERS shouldn't review them.
Anton Bershanskyi4253349482025-02-11 21:01:274764 linux_path = f.UnixLocalPath()
Bruce Dawson6bb0d672022-04-06 15:13:494765 if (linux_path.count('/') != 1
4766 and (not linux_path in _EXCLUDED_SET_NO_PARENT_PATHS)):
Sam Maiera6e76d72022-02-11 21:43:504767 for set_noparent_line in found_set_noparent_lines:
4768 if set_noparent_line in found_owners_files:
4769 continue
4770 errors.append(' %s:%d' %
Bruce Dawson6bb0d672022-04-06 15:13:494771 (linux_path,
Sam Maiera6e76d72022-02-11 21:43:504772 found_set_noparent_lines[set_noparent_line]))
4773
4774 results = []
4775 if errors:
4776 if input_api.is_committing:
4777 output = output_api.PresubmitError
4778 else:
4779 output = output_api.PresubmitPromptWarning
4780 results.append(
4781 output(
4782 'Found the following "set noparent" restrictions in OWNERS files that '
4783 'do not include owners from build/OWNERS.setnoparent:',
4784 long_text='\n\n'.join(errors)))
4785 return results
4786
4787
4788def CheckUselessForwardDeclarations(input_api, output_api):
4789 """Checks that added or removed lines in non third party affected
4790 header files do not lead to new useless class or struct forward
4791 declaration.
4792 """
4793 results = []
4794 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
4795 input_api.re.MULTILINE)
4796 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
4797 input_api.re.MULTILINE)
4798 for f in input_api.AffectedFiles(include_deletes=False):
Anton Bershanskyi4253349482025-02-11 21:01:274799 local_path = f.UnixLocalPath()
4800 if (local_path.startswith('third_party')
4801 and not local_path.startswith('third_party/blink')):
Sam Maiera6e76d72022-02-11 21:43:504802 continue
4803
Anton Bershanskyi4253349482025-02-11 21:01:274804 if not local_path.endswith('.h'):
Sam Maiera6e76d72022-02-11 21:43:504805 continue
4806
4807 contents = input_api.ReadFile(f)
4808 fwd_decls = input_api.re.findall(class_pattern, contents)
4809 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
4810
4811 useless_fwd_decls = []
4812 for decl in fwd_decls:
4813 count = sum(1 for _ in input_api.re.finditer(
4814 r'\b%s\b' % input_api.re.escape(decl), contents))
4815 if count == 1:
4816 useless_fwd_decls.append(decl)
4817
4818 if not useless_fwd_decls:
4819 continue
4820
4821 for line in f.GenerateScmDiff().splitlines():
4822 if (line.startswith('-') and not line.startswith('--')
4823 or line.startswith('+') and not line.startswith('++')):
4824 for decl in useless_fwd_decls:
4825 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
4826 results.append(
4827 output_api.PresubmitPromptWarning(
4828 '%s: %s forward declaration is no longer needed'
4829 % (f.LocalPath(), decl)))
4830 useless_fwd_decls.remove(decl)
4831
4832 return results
4833
4834
4835def _CheckAndroidDebuggableBuild(input_api, output_api):
4836 """Checks that code uses BuildInfo.isDebugAndroid() instead of
4837 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
4838 this is a debuggable build of Android.
4839 """
4840 build_type_check_pattern = input_api.re.compile(
4841 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
4842
4843 errors = []
4844
4845 sources = lambda affected_file: input_api.FilterSourceFile(
4846 affected_file,
4847 files_to_skip=(
4848 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4849 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314850 r"^android_webview/support_library/boundary_interfaces/",
4851 r"^chrome/android/webapk/.*",
4852 r'^third_party/.*',
4853 r"tools/android/customtabs_benchmark/.*",
4854 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504855 )),
4856 files_to_check=[r'.*\.java$'])
4857
4858 for f in input_api.AffectedSourceFiles(sources):
4859 for line_num, line in f.ChangedContents():
4860 if build_type_check_pattern.search(line):
4861 errors.append("%s:%d" % (f.LocalPath(), line_num))
4862
4863 results = []
4864
4865 if errors:
4866 results.append(
4867 output_api.PresubmitPromptWarning(
4868 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
4869 ' Please use BuildInfo.isDebugAndroid() instead.', errors))
4870
4871 return results
4872
4873# TODO: add unit tests
4874def _CheckAndroidToastUsage(input_api, output_api):
4875 """Checks that code uses org.chromium.ui.widget.Toast instead of
4876 android.widget.Toast (Chromium Toast doesn't force hardware
4877 acceleration on low-end devices, saving memory).
4878 """
4879 toast_import_pattern = input_api.re.compile(
4880 r'^import android\.widget\.Toast;$')
4881
4882 errors = []
4883
4884 sources = lambda affected_file: input_api.FilterSourceFile(
4885 affected_file,
4886 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
Bruce Dawson40fece62022-09-16 19:58:314887 DEFAULT_FILES_TO_SKIP + (r'^chromecast/.*',
4888 r'^remoting/.*')),
Sam Maiera6e76d72022-02-11 21:43:504889 files_to_check=[r'.*\.java$'])
4890
4891 for f in input_api.AffectedSourceFiles(sources):
4892 for line_num, line in f.ChangedContents():
4893 if toast_import_pattern.search(line):
4894 errors.append("%s:%d" % (f.LocalPath(), line_num))
4895
4896 results = []
4897
4898 if errors:
4899 results.append(
4900 output_api.PresubmitError(
4901 'android.widget.Toast usage is detected. Android toasts use hardware'
4902 ' acceleration, and can be\ncostly on low-end devices. Please use'
4903 ' org.chromium.ui.widget.Toast instead.\n'
4904 'Contact [email protected] if you have any questions.',
4905 errors))
4906
4907 return results
4908
4909
4910def _CheckAndroidCrLogUsage(input_api, output_api):
4911 """Checks that new logs using org.chromium.base.Log:
4912 - Are using 'TAG' as variable name for the tags (warn)
4913 - Are using a tag that is shorter than 20 characters (error)
4914 """
4915
4916 # Do not check format of logs in the given files
4917 cr_log_check_excluded_paths = [
4918 # //chrome/android/webapk cannot depend on //base
Bruce Dawson40fece62022-09-16 19:58:314919 r"^chrome/android/webapk/.*",
Sam Maiera6e76d72022-02-11 21:43:504920 # WebView license viewer code cannot depend on //base; used in stub APK.
Bruce Dawson40fece62022-09-16 19:58:314921 r"^android_webview/glue/java/src/com/android/"
4922 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504923 # The customtabs_benchmark is a small app that does not depend on Chromium
4924 # java pieces.
Bruce Dawson40fece62022-09-16 19:58:314925 r"tools/android/customtabs_benchmark/.*",
Sam Maiera6e76d72022-02-11 21:43:504926 ]
4927
4928 cr_log_import_pattern = input_api.re.compile(
4929 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
4930 class_in_base_pattern = input_api.re.compile(
4931 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
4932 has_some_log_import_pattern = input_api.re.compile(r'^import .*\.Log;$',
4933 input_api.re.MULTILINE)
4934 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
4935 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
4936 log_decl_pattern = input_api.re.compile(
4937 r'static final String TAG = "(?P<name>(.*))"')
4938 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
4939
4940 REF_MSG = ('See docs/android_logging.md for more info.')
4941 sources = lambda x: input_api.FilterSourceFile(
4942 x,
4943 files_to_check=[r'.*\.java$'],
4944 files_to_skip=cr_log_check_excluded_paths)
4945
4946 tag_decl_errors = []
Andrew Grieved3a35d82024-01-02 21:24:384947 tag_length_errors = []
Sam Maiera6e76d72022-02-11 21:43:504948 tag_errors = []
4949 tag_with_dot_errors = []
4950 util_log_errors = []
4951
4952 for f in input_api.AffectedSourceFiles(sources):
4953 file_content = input_api.ReadFile(f)
4954 has_modified_logs = False
4955 # Per line checks
4956 if (cr_log_import_pattern.search(file_content)
4957 or (class_in_base_pattern.search(file_content)
4958 and not has_some_log_import_pattern.search(file_content))):
4959 # Checks to run for files using cr log
4960 for line_num, line in f.ChangedContents():
4961 if rough_log_decl_pattern.search(line):
4962 has_modified_logs = True
4963
4964 # Check if the new line is doing some logging
4965 match = log_call_pattern.search(line)
4966 if match:
4967 has_modified_logs = True
4968
4969 # Make sure it uses "TAG"
4970 if not match.group('tag') == 'TAG':
4971 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
4972 else:
4973 # Report non cr Log function calls in changed lines
4974 for line_num, line in f.ChangedContents():
4975 if log_call_pattern.search(line):
4976 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
4977
4978 # Per file checks
4979 if has_modified_logs:
4980 # Make sure the tag is using the "cr" prefix and is not too long
4981 match = log_decl_pattern.search(file_content)
4982 tag_name = match.group('name') if match else None
4983 if not tag_name:
4984 tag_decl_errors.append(f.LocalPath())
Andrew Grieved3a35d82024-01-02 21:24:384985 elif len(tag_name) > 20:
4986 tag_length_errors.append(f.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:504987 elif '.' in tag_name:
4988 tag_with_dot_errors.append(f.LocalPath())
4989
4990 results = []
4991 if tag_decl_errors:
4992 results.append(
4993 output_api.PresubmitPromptWarning(
4994 'Please define your tags using the suggested format: .\n'
4995 '"private static final String TAG = "<package tag>".\n'
4996 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
4997 tag_decl_errors))
4998
Andrew Grieved3a35d82024-01-02 21:24:384999 if tag_length_errors:
5000 results.append(
5001 output_api.PresubmitError(
5002 'The tag length is restricted by the system to be at most '
5003 '20 characters.\n' + REF_MSG, tag_length_errors))
5004
Sam Maiera6e76d72022-02-11 21:43:505005 if tag_errors:
5006 results.append(
5007 output_api.PresubmitPromptWarning(
5008 'Please use a variable named "TAG" for your log tags.\n' +
5009 REF_MSG, tag_errors))
5010
5011 if util_log_errors:
5012 results.append(
5013 output_api.PresubmitPromptWarning(
5014 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
5015 util_log_errors))
5016
5017 if tag_with_dot_errors:
5018 results.append(
5019 output_api.PresubmitPromptWarning(
5020 'Dot in log tags cause them to be elided in crash reports.\n' +
5021 REF_MSG, tag_with_dot_errors))
5022
5023 return results
5024
5025
Sam Maiera6e76d72022-02-11 21:43:505026def _CheckAndroidTestAnnotationUsage(input_api, output_api):
5027 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
5028 deprecated_annotation_import_pattern = input_api.re.compile(
5029 r'^import android\.test\.suitebuilder\.annotation\..*;',
5030 input_api.re.MULTILINE)
5031 sources = lambda x: input_api.FilterSourceFile(
5032 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
5033 errors = []
5034 for f in input_api.AffectedFiles(file_filter=sources):
5035 for line_num, line in f.ChangedContents():
5036 if deprecated_annotation_import_pattern.search(line):
5037 errors.append("%s:%d" % (f.LocalPath(), line_num))
5038
5039 results = []
5040 if errors:
5041 results.append(
5042 output_api.PresubmitError(
5043 'Annotations in android.test.suitebuilder.annotation have been'
Mohamed Heikal3d7a94c2023-03-28 16:55:245044 ' deprecated since API level 24. Please use androidx.test.filters'
5045 ' from //third_party/androidx:androidx_test_runner_java instead.'
Sam Maiera6e76d72022-02-11 21:43:505046 ' Contact [email protected] if you have any questions.',
5047 errors))
5048 return results
5049
5050
5051def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
5052 """Checks if MDPI assets are placed in a correct directory."""
Anton Bershanskyi4253349482025-02-11 21:01:275053 file_filter = lambda f: (f.UnixLocalPath().endswith(
5054 '.png') and ('/res/drawable/' in f.
5055 UnixLocalPath() or '/res/drawable-ldrtl/' in f.UnixLocalPath()))
Sam Maiera6e76d72022-02-11 21:43:505056 errors = []
5057 for f in input_api.AffectedFiles(include_deletes=False,
5058 file_filter=file_filter):
5059 errors.append(' %s' % f.LocalPath())
5060
5061 results = []
5062 if errors:
5063 results.append(
5064 output_api.PresubmitError(
5065 'MDPI assets should be placed in /res/drawable-mdpi/ or '
5066 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
5067 '/res/drawable-ldrtl/.\n'
5068 'Contact [email protected] if you have questions.', errors))
5069 return results
5070
5071
5072def _CheckAndroidWebkitImports(input_api, output_api):
5073 """Checks that code uses org.chromium.base.Callback instead of
5074 android.webview.ValueCallback except in the WebView glue layer
5075 and WebLayer.
5076 """
5077 valuecallback_import_pattern = input_api.re.compile(
5078 r'^import android\.webkit\.ValueCallback;$')
5079
5080 errors = []
5081
5082 sources = lambda affected_file: input_api.FilterSourceFile(
5083 affected_file,
5084 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
5085 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:315086 r'^android_webview/glue/.*',
elabadysayedcbbaea72024-08-01 16:10:425087 r'^android_webview/support_library/.*',
Bruce Dawson40fece62022-09-16 19:58:315088 r'^weblayer/.*',
Sam Maiera6e76d72022-02-11 21:43:505089 )),
5090 files_to_check=[r'.*\.java$'])
5091
5092 for f in input_api.AffectedSourceFiles(sources):
5093 for line_num, line in f.ChangedContents():
5094 if valuecallback_import_pattern.search(line):
5095 errors.append("%s:%d" % (f.LocalPath(), line_num))
5096
5097 results = []
5098
5099 if errors:
5100 results.append(
5101 output_api.PresubmitError(
5102 'android.webkit.ValueCallback usage is detected outside of the glue'
5103 ' layer. To stay compatible with the support library, android.webkit.*'
5104 ' classes should only be used inside the glue layer and'
5105 ' org.chromium.base.Callback should be used instead.', errors))
5106
5107 return results
5108
5109
5110def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
5111 """Checks Android XML styles """
5112
5113 # Return early if no relevant files were modified.
5114 if not any(
5115 _IsXmlOrGrdFile(input_api, f.LocalPath())
5116 for f in input_api.AffectedFiles(include_deletes=False)):
5117 return []
5118
5119 import sys
5120 original_sys_path = sys.path
5121 try:
5122 sys.path = sys.path + [
5123 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5124 'android', 'checkxmlstyle')
5125 ]
5126 import checkxmlstyle
5127 finally:
5128 # Restore sys.path to what it was before.
5129 sys.path = original_sys_path
5130
5131 if is_check_on_upload:
5132 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
5133 else:
5134 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
5135
5136
5137def _CheckAndroidInfoBarDeprecation(input_api, output_api):
5138 """Checks Android Infobar Deprecation """
5139
5140 import sys
5141 original_sys_path = sys.path
5142 try:
5143 sys.path = sys.path + [
5144 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5145 'android', 'infobar_deprecation')
5146 ]
5147 import infobar_deprecation
5148 finally:
5149 # Restore sys.path to what it was before.
5150 sys.path = original_sys_path
5151
5152 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
5153
5154
5155class _PydepsCheckerResult:
5156 def __init__(self, cmd, pydeps_path, process, old_contents):
5157 self._cmd = cmd
5158 self._pydeps_path = pydeps_path
5159 self._process = process
5160 self._old_contents = old_contents
5161
5162 def GetError(self):
5163 """Returns an error message, or None."""
5164 import difflib
Andrew Grieved27620b62023-07-13 16:35:075165 new_contents = self._process.stdout.read().splitlines()[2:]
Sam Maiera6e76d72022-02-11 21:43:505166 if self._process.wait() != 0:
5167 # STDERR should already be printed.
5168 return 'Command failed: ' + self._cmd
Sam Maiera6e76d72022-02-11 21:43:505169 if self._old_contents != new_contents:
5170 diff = '\n'.join(
5171 difflib.context_diff(self._old_contents, new_contents))
5172 return ('File is stale: {}\n'
5173 'Diff (apply to fix):\n'
5174 '{}\n'
5175 'To regenerate, run:\n\n'
5176 ' {}').format(self._pydeps_path, diff, self._cmd)
5177 return None
5178
5179
5180class PydepsChecker:
5181 def __init__(self, input_api, pydeps_files):
5182 self._file_cache = {}
5183 self._input_api = input_api
5184 self._pydeps_files = pydeps_files
5185
5186 def _LoadFile(self, path):
5187 """Returns the list of paths within a .pydeps file relative to //."""
5188 if path not in self._file_cache:
5189 with open(path, encoding='utf-8') as f:
5190 self._file_cache[path] = f.read()
5191 return self._file_cache[path]
5192
5193 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
Gao Shenga79ebd42022-08-08 17:25:595194 """Returns an iterable of paths within the .pydep, relativized to //."""
Sam Maiera6e76d72022-02-11 21:43:505195 pydeps_data = self._LoadFile(pydeps_path)
5196 uses_gn_paths = '--gn-paths' in pydeps_data
5197 entries = (l for l in pydeps_data.splitlines()
5198 if not l.startswith('#'))
5199 if uses_gn_paths:
5200 # Paths look like: //foo/bar/baz
5201 return (e[2:] for e in entries)
5202 else:
5203 # Paths look like: path/relative/to/file.pydeps
5204 os_path = self._input_api.os_path
5205 pydeps_dir = os_path.dirname(pydeps_path)
5206 return (os_path.normpath(os_path.join(pydeps_dir, e))
5207 for e in entries)
5208
5209 def _CreateFilesToPydepsMap(self):
5210 """Returns a map of local_path -> list_of_pydeps."""
5211 ret = {}
5212 for pydep_local_path in self._pydeps_files:
5213 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
5214 ret.setdefault(path, []).append(pydep_local_path)
5215 return ret
5216
5217 def ComputeAffectedPydeps(self):
5218 """Returns an iterable of .pydeps files that might need regenerating."""
5219 affected_pydeps = set()
5220 file_to_pydeps_map = None
5221 for f in self._input_api.AffectedFiles(include_deletes=True):
5222 local_path = f.LocalPath()
5223 # Changes to DEPS can lead to .pydeps changes if any .py files are in
5224 # subrepositories. We can't figure out which files change, so re-check
5225 # all files.
5226 # Changes to print_python_deps.py affect all .pydeps.
5227 if local_path in ('DEPS', 'PRESUBMIT.py'
5228 ) or local_path.endswith('print_python_deps.py'):
5229 return self._pydeps_files
5230 elif local_path.endswith('.pydeps'):
5231 if local_path in self._pydeps_files:
5232 affected_pydeps.add(local_path)
5233 elif local_path.endswith('.py'):
5234 if file_to_pydeps_map is None:
5235 file_to_pydeps_map = self._CreateFilesToPydepsMap()
5236 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
5237 return affected_pydeps
5238
5239 def DetermineIfStaleAsync(self, pydeps_path):
5240 """Runs print_python_deps.py to see if the files is stale."""
5241 import os
5242
5243 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
5244 if old_pydeps_data:
5245 cmd = old_pydeps_data[1][1:].strip()
5246 if '--output' not in cmd:
5247 cmd += ' --output ' + pydeps_path
5248 old_contents = old_pydeps_data[2:]
5249 else:
5250 # A default cmd that should work in most cases (as long as pydeps filename
5251 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
5252 # file is empty/new.
5253 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
5254 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
5255 old_contents = []
5256 env = dict(os.environ)
5257 env['PYTHONDONTWRITEBYTECODE'] = '1'
5258 process = self._input_api.subprocess.Popen(
5259 cmd + ' --output ""',
5260 shell=True,
5261 env=env,
5262 stdout=self._input_api.subprocess.PIPE,
5263 encoding='utf-8')
5264 return _PydepsCheckerResult(cmd, pydeps_path, process, old_contents)
agrievef32bcc72016-04-04 14:57:405265
5266
Tibor Goldschwendt360793f72019-06-25 18:23:495267def _ParseGclientArgs():
Sam Maiera6e76d72022-02-11 21:43:505268 args = {}
5269 with open('build/config/gclient_args.gni', 'r') as f:
5270 for line in f:
5271 line = line.strip()
5272 if not line or line.startswith('#'):
5273 continue
5274 attribute, value = line.split('=')
5275 args[attribute.strip()] = value.strip()
5276 return args
Tibor Goldschwendt360793f72019-06-25 18:23:495277
5278
Saagar Sanghavifceeaae2020-08-12 16:40:365279def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
Sam Maiera6e76d72022-02-11 21:43:505280 """Checks if a .pydeps file needs to be regenerated."""
5281 # This check is for Python dependency lists (.pydeps files), and involves
5282 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
5283 # doesn't work on Windows and Mac, so skip it on other platforms.
5284 if not input_api.platform.startswith('linux'):
5285 return []
Erik Staabc734cd7a2021-11-23 03:11:525286
Sam Maiera6e76d72022-02-11 21:43:505287 results = []
5288 # First, check for new / deleted .pydeps.
5289 for f in input_api.AffectedFiles(include_deletes=True):
5290 # Check whether we are running the presubmit check for a file in src.
Sam Maiera6e76d72022-02-11 21:43:505291 if f.LocalPath().endswith('.pydeps'):
Andrew Grieve713b89b2024-10-15 20:20:085292 # f.LocalPath is relative to repo (src, or internal repo).
5293 # os_path.exists is relative to src repo.
5294 # Therefore if os_path.exists is true, it means f.LocalPath is relative
5295 # to src and we can conclude that the pydeps is in src.
5296 exists = input_api.os_path.exists(f.LocalPath())
5297 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
5298 results.append(
5299 output_api.PresubmitError(
5300 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
5301 'remove %s' % f.LocalPath()))
5302 elif (f.Action() != 'D' and exists
5303 and f.LocalPath() not in _ALL_PYDEPS_FILES):
5304 results.append(
5305 output_api.PresubmitError(
5306 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
5307 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:405308
Sam Maiera6e76d72022-02-11 21:43:505309 if results:
5310 return results
5311
Gavin Mak23884402024-07-25 20:39:265312 try:
5313 parsed_args = _ParseGclientArgs()
5314 except FileNotFoundError:
5315 message = (
5316 'build/config/gclient_args.gni not found. Please make sure your '
5317 'workspace has been initialized with gclient sync.'
5318 )
5319 import sys
5320 original_sys_path = sys.path
5321 try:
5322 sys.path = sys.path + [
5323 input_api.os_path.join(input_api.PresubmitLocalPath(),
5324 'third_party', 'depot_tools')
5325 ]
5326 import gclient_utils
5327 if gclient_utils.IsEnvCog():
5328 # Users will always hit this when they run presubmits before cog
5329 # workspace initialization finishes. The check shouldn't fail in
5330 # this case. This is an unavoidable workaround that's needed for
5331 # good presubmit UX for cog.
5332 results.append(output_api.PresubmitPromptWarning(message))
5333 else:
5334 results.append(output_api.PresubmitError(message))
5335 return results
5336 finally:
5337 # Restore sys.path to what it was before.
5338 sys.path = original_sys_path
5339
5340 is_android = parsed_args.get('checkout_android', 'false') == 'true'
Sam Maiera6e76d72022-02-11 21:43:505341 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
5342 affected_pydeps = set(checker.ComputeAffectedPydeps())
5343 affected_android_pydeps = affected_pydeps.intersection(
5344 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
5345 if affected_android_pydeps and not is_android:
5346 results.append(
5347 output_api.PresubmitPromptOrNotify(
5348 'You have changed python files that may affect pydeps for android\n'
Gao Shenga79ebd42022-08-08 17:25:595349 'specific scripts. However, the relevant presubmit check cannot be\n'
Sam Maiera6e76d72022-02-11 21:43:505350 'run because you are not using an Android checkout. To validate that\n'
5351 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
5352 'use the android-internal-presubmit optional trybot.\n'
5353 'Possibly stale pydeps files:\n{}'.format(
5354 '\n'.join(affected_android_pydeps))))
5355
5356 all_pydeps = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
5357 pydeps_to_check = affected_pydeps.intersection(all_pydeps)
5358 # Process these concurrently, as each one takes 1-2 seconds.
5359 pydep_results = [checker.DetermineIfStaleAsync(p) for p in pydeps_to_check]
5360 for result in pydep_results:
5361 error_msg = result.GetError()
5362 if error_msg:
5363 results.append(output_api.PresubmitError(error_msg))
5364
agrievef32bcc72016-04-04 14:57:405365 return results
5366
agrievef32bcc72016-04-04 14:57:405367
Saagar Sanghavifceeaae2020-08-12 16:40:365368def CheckSingletonInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505369 """Checks to make sure no header files have |Singleton<|."""
5370
5371 def FileFilter(affected_file):
5372 # It's ok for base/memory/singleton.h to have |Singleton<|.
5373 files_to_skip = (_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
Bruce Dawson40fece62022-09-16 19:58:315374 (r"^base/memory/singleton\.h$",
5375 r"^net/quic/platform/impl/quic_singleton_impl\.h$"))
Sam Maiera6e76d72022-02-11 21:43:505376 return input_api.FilterSourceFile(affected_file,
5377 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:435378
Sam Maiera6e76d72022-02-11 21:43:505379 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
5380 files = []
5381 for f in input_api.AffectedSourceFiles(FileFilter):
5382 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx')
5383 or f.LocalPath().endswith('.hpp')
5384 or f.LocalPath().endswith('.inl')):
5385 contents = input_api.ReadFile(f)
5386 for line in contents.splitlines(False):
5387 if (not line.lstrip().startswith('//')
5388 and # Strip C++ comment.
5389 pattern.search(line)):
5390 files.append(f)
5391 break
glidere61efad2015-02-18 17:39:435392
Sam Maiera6e76d72022-02-11 21:43:505393 if files:
5394 return [
5395 output_api.PresubmitError(
5396 'Found base::Singleton<T> in the following header files.\n' +
5397 'Please move them to an appropriate source file so that the ' +
5398 'template gets instantiated in a single compilation unit.',
5399 files)
5400 ]
5401 return []
glidere61efad2015-02-18 17:39:435402
5403
[email protected]fd20b902014-05-09 02:14:535404_DEPRECATED_CSS = [
5405 # Values
5406 ( "-webkit-box", "flex" ),
5407 ( "-webkit-inline-box", "inline-flex" ),
5408 ( "-webkit-flex", "flex" ),
5409 ( "-webkit-inline-flex", "inline-flex" ),
5410 ( "-webkit-min-content", "min-content" ),
5411 ( "-webkit-max-content", "max-content" ),
5412
5413 # Properties
5414 ( "-webkit-background-clip", "background-clip" ),
5415 ( "-webkit-background-origin", "background-origin" ),
5416 ( "-webkit-background-size", "background-size" ),
5417 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:445418 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:535419
5420 # Functions
5421 ( "-webkit-gradient", "gradient" ),
5422 ( "-webkit-repeating-gradient", "repeating-gradient" ),
5423 ( "-webkit-linear-gradient", "linear-gradient" ),
5424 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
5425 ( "-webkit-radial-gradient", "radial-gradient" ),
5426 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
5427]
5428
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:205429
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:495430# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:365431def CheckNoDeprecatedCss(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505432 """ Make sure that we don't use deprecated CSS
5433 properties, functions or values. Our external
5434 documentation and iOS CSS for dom distiller
5435 (reader mode) are ignored by the hooks as it
5436 needs to be consumed by WebKit. """
5437 results = []
5438 file_inclusion_pattern = [r".+\.css$"]
5439 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
5440 input_api.DEFAULT_FILES_TO_SKIP +
dpapad7fcdfc42024-12-06 01:21:385441 (# Legacy CSS file using deprecated CSS.
5442 r"^chrome/browser/resources/chromeos/arc_support/cr_overlay.css$",
5443 r"^chrome/common/extensions/docs", r"^chrome/docs",
Teresa Mao1d910882024-04-26 21:06:255444 r"^native_client_sdk",
5445 # The NTP team prefers reserving -webkit-line-clamp for
5446 # ellipsis effect which can only be used with -webkit-box.
5447 r"ui/webui/resources/cr_components/most_visited/.*\.css$"))
Sam Maiera6e76d72022-02-11 21:43:505448 file_filter = lambda f: input_api.FilterSourceFile(
5449 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
5450 for fpath in input_api.AffectedFiles(file_filter=file_filter):
5451 for line_num, line in fpath.ChangedContents():
5452 for (deprecated_value, value) in _DEPRECATED_CSS:
5453 if deprecated_value in line:
5454 results.append(
5455 output_api.PresubmitError(
5456 "%s:%d: Use of deprecated CSS %s, use %s instead" %
5457 (fpath.LocalPath(), line_num, deprecated_value,
5458 value)))
5459 return results
[email protected]fd20b902014-05-09 02:14:535460
mohan.reddyf21db962014-10-16 12:26:475461
Saagar Sanghavifceeaae2020-08-12 16:40:365462def CheckForRelativeIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505463 bad_files = {}
5464 for f in input_api.AffectedFiles(include_deletes=False):
Anton Bershanskyi4253349482025-02-11 21:01:275465 if (f.UnixLocalPath().startswith('third_party')
5466 and not f.LocalPath().startswith('third_party/blink')):
Sam Maiera6e76d72022-02-11 21:43:505467 continue
rlanday6802cf632017-05-30 17:48:365468
Sam Maiera6e76d72022-02-11 21:43:505469 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
5470 continue
rlanday6802cf632017-05-30 17:48:365471
Sam Maiera6e76d72022-02-11 21:43:505472 relative_includes = [
5473 line for _, line in f.ChangedContents()
5474 if "#include" in line and "../" in line
5475 ]
5476 if not relative_includes:
5477 continue
5478 bad_files[f.LocalPath()] = relative_includes
rlanday6802cf632017-05-30 17:48:365479
Sam Maiera6e76d72022-02-11 21:43:505480 if not bad_files:
5481 return []
rlanday6802cf632017-05-30 17:48:365482
Sam Maiera6e76d72022-02-11 21:43:505483 error_descriptions = []
5484 for file_path, bad_lines in bad_files.items():
5485 error_description = file_path
5486 for line in bad_lines:
5487 error_description += '\n ' + line
5488 error_descriptions.append(error_description)
rlanday6802cf632017-05-30 17:48:365489
Sam Maiera6e76d72022-02-11 21:43:505490 results = []
5491 results.append(
5492 output_api.PresubmitError(
5493 'You added one or more relative #include paths (including "../").\n'
5494 'These shouldn\'t be used because they can be used to include headers\n'
5495 'from code that\'s not correctly specified as a dependency in the\n'
5496 'relevant BUILD.gn file(s).', error_descriptions))
rlanday6802cf632017-05-30 17:48:365497
Sam Maiera6e76d72022-02-11 21:43:505498 return results
rlanday6802cf632017-05-30 17:48:365499
Takeshi Yoshinoe387aa32017-08-02 13:16:135500
Saagar Sanghavifceeaae2020-08-12 16:40:365501def CheckForCcIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505502 """Check that nobody tries to include a cc file. It's a relatively
5503 common error which results in duplicate symbols in object
5504 files. This may not always break the build until someone later gets
5505 very confusing linking errors."""
5506 results = []
5507 for f in input_api.AffectedFiles(include_deletes=False):
5508 # We let third_party code do whatever it wants
Anton Bershanskyi4253349482025-02-11 21:01:275509 if (f.UnixLocalPath().startswith('third_party')
5510 and not f.LocalPath().startswith('third_party/blink')):
Sam Maiera6e76d72022-02-11 21:43:505511 continue
Daniel Bratell65b033262019-04-23 08:17:065512
Sam Maiera6e76d72022-02-11 21:43:505513 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
5514 continue
Daniel Bratell65b033262019-04-23 08:17:065515
Sam Maiera6e76d72022-02-11 21:43:505516 for _, line in f.ChangedContents():
5517 if line.startswith('#include "'):
5518 included_file = line.split('"')[1]
5519 if _IsCPlusPlusFile(input_api, included_file):
5520 # The most common naming for external files with C++ code,
5521 # apart from standard headers, is to call them foo.inc, but
5522 # Chromium sometimes uses foo-inc.cc so allow that as well.
5523 if not included_file.endswith(('.h', '-inc.cc')):
5524 results.append(
5525 output_api.PresubmitError(
5526 'Only header files or .inc files should be included in other\n'
5527 'C++ files. Compiling the contents of a cc file more than once\n'
5528 'will cause duplicate information in the build which may later\n'
5529 'result in strange link_errors.\n' +
5530 f.LocalPath() + ':\n ' + line))
Daniel Bratell65b033262019-04-23 08:17:065531
Sam Maiera6e76d72022-02-11 21:43:505532 return results
Daniel Bratell65b033262019-04-23 08:17:065533
5534
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205535def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
Sam Maiera6e76d72022-02-11 21:43:505536 if not isinstance(key, ast.Str):
5537 return 'Key at line %d must be a string literal' % key.lineno
5538 if not isinstance(value, ast.Dict):
5539 return 'Value at line %d must be a dict' % value.lineno
5540 if len(value.keys) != 1:
5541 return 'Dict at line %d must have single entry' % value.lineno
5542 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
5543 return (
5544 'Entry at line %d must have a string literal \'filepath\' as key' %
5545 value.lineno)
5546 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:135547
Takeshi Yoshinoe387aa32017-08-02 13:16:135548
Sergey Ulanov4af16052018-11-08 02:41:465549def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Sam Maiera6e76d72022-02-11 21:43:505550 if not isinstance(key, ast.Str):
5551 return 'Key at line %d must be a string literal' % key.lineno
5552 if not isinstance(value, ast.List):
5553 return 'Value at line %d must be a list' % value.lineno
5554 for element in value.elts:
5555 if not isinstance(element, ast.Str):
5556 return 'Watchlist elements on line %d is not a string' % key.lineno
5557 if not email_regex.match(element.s):
5558 return ('Watchlist element on line %d doesn\'t look like a valid '
5559 + 'email: %s') % (key.lineno, element.s)
5560 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:135561
Takeshi Yoshinoe387aa32017-08-02 13:16:135562
Sergey Ulanov4af16052018-11-08 02:41:465563def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Sam Maiera6e76d72022-02-11 21:43:505564 mismatch_template = (
5565 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
5566 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:135567
Sam Maiera6e76d72022-02-11 21:43:505568 email_regex = input_api.re.compile(
5569 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
Sergey Ulanov4af16052018-11-08 02:41:465570
Sam Maiera6e76d72022-02-11 21:43:505571 ast = input_api.ast
5572 i = 0
5573 last_key = ''
5574 while True:
5575 if i >= len(wd_dict.keys):
5576 if i >= len(w_dict.keys):
5577 return None
5578 return mismatch_template % ('missing',
5579 'line %d' % w_dict.keys[i].lineno)
5580 elif i >= len(w_dict.keys):
5581 return (mismatch_template %
5582 ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:135583
Sam Maiera6e76d72022-02-11 21:43:505584 wd_key = wd_dict.keys[i]
5585 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:135586
Sam Maiera6e76d72022-02-11 21:43:505587 result = _CheckWatchlistDefinitionsEntrySyntax(wd_key,
5588 wd_dict.values[i], ast)
5589 if result is not None:
5590 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:135591
Sam Maiera6e76d72022-02-11 21:43:505592 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast,
5593 email_regex)
5594 if result is not None:
5595 return 'Bad entry in WATCHLISTS dict: %s' % result
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205596
Sam Maiera6e76d72022-02-11 21:43:505597 if wd_key.s != w_key.s:
5598 return mismatch_template % ('%s at line %d' %
5599 (wd_key.s, wd_key.lineno),
5600 '%s at line %d' %
5601 (w_key.s, w_key.lineno))
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205602
Sam Maiera6e76d72022-02-11 21:43:505603 if wd_key.s < last_key:
5604 return (
5605 'WATCHLISTS dict is not sorted lexicographically at line %d and %d'
5606 % (wd_key.lineno, w_key.lineno))
5607 last_key = wd_key.s
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205608
Sam Maiera6e76d72022-02-11 21:43:505609 i = i + 1
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205610
5611
Sergey Ulanov4af16052018-11-08 02:41:465612def _CheckWATCHLISTSSyntax(expression, input_api):
Sam Maiera6e76d72022-02-11 21:43:505613 ast = input_api.ast
5614 if not isinstance(expression, ast.Expression):
5615 return 'WATCHLISTS file must contain a valid expression'
5616 dictionary = expression.body
5617 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
5618 return 'WATCHLISTS file must have single dict with exactly two entries'
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205619
Sam Maiera6e76d72022-02-11 21:43:505620 first_key = dictionary.keys[0]
5621 first_value = dictionary.values[0]
5622 second_key = dictionary.keys[1]
5623 second_value = dictionary.values[1]
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205624
Sam Maiera6e76d72022-02-11 21:43:505625 if (not isinstance(first_key, ast.Str)
5626 or first_key.s != 'WATCHLIST_DEFINITIONS'
5627 or not isinstance(first_value, ast.Dict)):
5628 return ('The first entry of the dict in WATCHLISTS file must be '
5629 'WATCHLIST_DEFINITIONS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205630
Sam Maiera6e76d72022-02-11 21:43:505631 if (not isinstance(second_key, ast.Str) or second_key.s != 'WATCHLISTS'
5632 or not isinstance(second_value, ast.Dict)):
5633 return ('The second entry of the dict in WATCHLISTS file must be '
5634 'WATCHLISTS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205635
Sam Maiera6e76d72022-02-11 21:43:505636 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:135637
5638
Saagar Sanghavifceeaae2020-08-12 16:40:365639def CheckWATCHLISTS(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505640 for f in input_api.AffectedFiles(include_deletes=False):
5641 if f.LocalPath() == 'WATCHLISTS':
5642 contents = input_api.ReadFile(f, 'r')
Takeshi Yoshinoe387aa32017-08-02 13:16:135643
Sam Maiera6e76d72022-02-11 21:43:505644 try:
5645 # First, make sure that it can be evaluated.
5646 input_api.ast.literal_eval(contents)
5647 # Get an AST tree for it and scan the tree for detailed style checking.
5648 expression = input_api.ast.parse(contents,
5649 filename='WATCHLISTS',
5650 mode='eval')
5651 except ValueError as e:
5652 return [
5653 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5654 long_text=repr(e))
5655 ]
5656 except SyntaxError as e:
5657 return [
5658 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5659 long_text=repr(e))
5660 ]
5661 except TypeError as e:
5662 return [
5663 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5664 long_text=repr(e))
5665 ]
Takeshi Yoshinoe387aa32017-08-02 13:16:135666
Sam Maiera6e76d72022-02-11 21:43:505667 result = _CheckWATCHLISTSSyntax(expression, input_api)
5668 if result is not None:
5669 return [output_api.PresubmitError(result)]
5670 break
Takeshi Yoshinoe387aa32017-08-02 13:16:135671
Sam Maiera6e76d72022-02-11 21:43:505672 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:135673
Sean Kaucb7c9b32022-10-25 21:25:525674def CheckGnRebasePath(input_api, output_api):
Terrence Reilly313f44ff2025-01-22 15:10:145675 """Checks that target_gen_dir is not used with "//" in rebase_path().
Sean Kaucb7c9b32022-10-25 21:25:525676
5677 Developers should use root_build_dir instead of "//" when using target_gen_dir because
5678 Chromium is sometimes built outside of the source tree.
5679 """
5680
5681 def gn_files(f):
5682 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
5683
5684 rebase_path_regex = input_api.re.compile(r'rebase_path\(("\$target_gen_dir"|target_gen_dir), ("/"|"//")\)')
5685 problems = []
5686 for f in input_api.AffectedSourceFiles(gn_files):
5687 for line_num, line in f.ChangedContents():
5688 if rebase_path_regex.search(line):
5689 problems.append(
5690 'Absolute path in rebase_path() in %s:%d' %
5691 (f.LocalPath(), line_num))
5692
5693 if problems:
5694 return [
5695 output_api.PresubmitPromptWarning(
5696 'Using an absolute path in rebase_path()',
5697 items=sorted(problems),
5698 long_text=(
5699 'rebase_path() should use root_build_dir instead of "/" ',
5700 'since builds can be initiated from outside of the source ',
5701 'root.'))
5702 ]
5703 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:135704
Andrew Grieve1b290e4a22020-11-24 20:07:015705def CheckGnGlobForward(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505706 """Checks that forward_variables_from(invoker, "*") follows best practices.
Andrew Grieve1b290e4a22020-11-24 20:07:015707
Sam Maiera6e76d72022-02-11 21:43:505708 As documented at //build/docs/writing_gn_templates.md
5709 """
Andrew Grieve1b290e4a22020-11-24 20:07:015710
Sam Maiera6e76d72022-02-11 21:43:505711 def gn_files(f):
5712 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
Andrew Grieve1b290e4a22020-11-24 20:07:015713
Sam Maiera6e76d72022-02-11 21:43:505714 problems = []
5715 for f in input_api.AffectedSourceFiles(gn_files):
5716 for line_num, line in f.ChangedContents():
5717 if 'forward_variables_from(invoker, "*")' in line:
5718 problems.append(
5719 'Bare forward_variables_from(invoker, "*") in %s:%d' %
5720 (f.LocalPath(), line_num))
5721
5722 if problems:
5723 return [
5724 output_api.PresubmitPromptWarning(
5725 'forward_variables_from("*") without exclusions',
5726 items=sorted(problems),
5727 long_text=(
Gao Shenga79ebd42022-08-08 17:25:595728 'The variables "visibility" and "test_only" should be '
Sam Maiera6e76d72022-02-11 21:43:505729 'explicitly listed in forward_variables_from(). For more '
5730 'details, see:\n'
5731 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
5732 'build/docs/writing_gn_templates.md'
5733 '#Using-forward_variables_from'))
5734 ]
5735 return []
Andrew Grieve1b290e4a22020-11-24 20:07:015736
Saagar Sanghavifceeaae2020-08-12 16:40:365737def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505738 """Checks that newly added header files have corresponding GN changes.
5739 Note that this is only a heuristic. To be precise, run script:
5740 build/check_gn_headers.py.
5741 """
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195742
Sam Maiera6e76d72022-02-11 21:43:505743 def headers(f):
5744 return input_api.FilterSourceFile(
5745 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195746
Sam Maiera6e76d72022-02-11 21:43:505747 new_headers = []
5748 for f in input_api.AffectedSourceFiles(headers):
5749 if f.Action() != 'A':
5750 continue
5751 new_headers.append(f.LocalPath())
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195752
Sam Maiera6e76d72022-02-11 21:43:505753 def gn_files(f):
5754 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195755
Sam Maiera6e76d72022-02-11 21:43:505756 all_gn_changed_contents = ''
5757 for f in input_api.AffectedSourceFiles(gn_files):
5758 for _, line in f.ChangedContents():
5759 all_gn_changed_contents += line
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195760
Sam Maiera6e76d72022-02-11 21:43:505761 problems = []
5762 for header in new_headers:
5763 basename = input_api.os_path.basename(header)
5764 if basename not in all_gn_changed_contents:
5765 problems.append(header)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195766
Sam Maiera6e76d72022-02-11 21:43:505767 if problems:
5768 return [
5769 output_api.PresubmitPromptWarning(
5770 'Missing GN changes for new header files',
5771 items=sorted(problems),
5772 long_text=
5773 'Please double check whether newly added header files need '
5774 'corresponding changes in gn or gni files.\nThis checking is only a '
5775 'heuristic. Run build/check_gn_headers.py to be precise.\n'
5776 'Read https://crbug.com/661774 for more info.')
5777 ]
5778 return []
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195779
5780
Saagar Sanghavifceeaae2020-08-12 16:40:365781def CheckCorrectProductNameInMessages(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505782 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
Michael Giuffridad3bc8672018-10-25 22:48:025783
Sam Maiera6e76d72022-02-11 21:43:505784 This assumes we won't intentionally reference one product from the other
5785 product.
5786 """
5787 all_problems = []
5788 test_cases = [{
5789 "filename_postfix": "google_chrome_strings.grd",
5790 "correct_name": "Chrome",
5791 "incorrect_name": "Chromium",
5792 }, {
Thiago Perrotta099034f2023-06-05 18:10:205793 "filename_postfix": "google_chrome_strings.grd",
5794 "correct_name": "Chrome",
5795 "incorrect_name": "Chrome for Testing",
5796 }, {
Sam Maiera6e76d72022-02-11 21:43:505797 "filename_postfix": "chromium_strings.grd",
5798 "correct_name": "Chromium",
5799 "incorrect_name": "Chrome",
5800 }]
Michael Giuffridad3bc8672018-10-25 22:48:025801
Sam Maiera6e76d72022-02-11 21:43:505802 for test_case in test_cases:
5803 problems = []
5804 filename_filter = lambda x: x.LocalPath().endswith(test_case[
5805 "filename_postfix"])
Michael Giuffridad3bc8672018-10-25 22:48:025806
Sam Maiera6e76d72022-02-11 21:43:505807 # Check each new line. Can yield false positives in multiline comments, but
5808 # easier than trying to parse the XML because messages can have nested
5809 # children, and associating message elements with affected lines is hard.
5810 for f in input_api.AffectedSourceFiles(filename_filter):
5811 for line_num, line in f.ChangedContents():
5812 if "<message" in line or "<!--" in line or "-->" in line:
5813 continue
5814 if test_case["incorrect_name"] in line:
Thiago Perrotta099034f2023-06-05 18:10:205815 # Chrome for Testing is a special edge case: https://goo.gle/chrome-for-testing#bookmark=id.n1rat320av91
5816 if (test_case["correct_name"] == "Chromium" and line.count("Chrome") == line.count("Chrome for Testing")):
5817 continue
Sam Maiera6e76d72022-02-11 21:43:505818 problems.append("Incorrect product name in %s:%d" %
5819 (f.LocalPath(), line_num))
Michael Giuffridad3bc8672018-10-25 22:48:025820
Sam Maiera6e76d72022-02-11 21:43:505821 if problems:
5822 message = (
5823 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
5824 % (test_case["correct_name"], test_case["correct_name"],
5825 test_case["incorrect_name"]))
5826 all_problems.append(
5827 output_api.PresubmitPromptWarning(message, items=problems))
Michael Giuffridad3bc8672018-10-25 22:48:025828
Sam Maiera6e76d72022-02-11 21:43:505829 return all_problems
Michael Giuffridad3bc8672018-10-25 22:48:025830
5831
Saagar Sanghavifceeaae2020-08-12 16:40:365832def CheckForTooLargeFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505833 """Avoid large files, especially binary files, in the repository since
5834 git doesn't scale well for those. They will be in everyone's repo
5835 clones forever, forever making Chromium slower to clone and work
5836 with."""
Daniel Bratell93eb6c62019-04-29 20:13:365837
Sam Maiera6e76d72022-02-11 21:43:505838 # Uploading files to cloud storage is not trivial so we don't want
5839 # to set the limit too low, but the upper limit for "normal" large
5840 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
5841 # anything over 20 MB is exceptional.
Bruce Dawsonbb414db2022-12-27 20:21:255842 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024
Daniel Bratell93eb6c62019-04-29 20:13:365843
Sam Maiera6e76d72022-02-11 21:43:505844 too_large_files = []
5845 for f in input_api.AffectedFiles():
5846 # Check both added and modified files (but not deleted files).
5847 if f.Action() in ('A', 'M'):
5848 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Joe DeBlasio10a832f2023-04-21 20:20:185849 if size > TOO_LARGE_FILE_SIZE_LIMIT:
Sam Maiera6e76d72022-02-11 21:43:505850 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
Daniel Bratell93eb6c62019-04-29 20:13:365851
Sam Maiera6e76d72022-02-11 21:43:505852 if too_large_files:
5853 message = (
5854 'Do not commit large files to git since git scales badly for those.\n'
5855 +
5856 'Instead put the large files in cloud storage and use DEPS to\n' +
5857 'fetch them.\n' + '\n'.join(too_large_files))
5858 return [
5859 output_api.PresubmitError('Too large files found in commit',
5860 long_text=message + '\n')
5861 ]
5862 else:
5863 return []
Daniel Bratell93eb6c62019-04-29 20:13:365864
Max Morozb47503b2019-08-08 21:03:275865
Saagar Sanghavifceeaae2020-08-12 16:40:365866def CheckFuzzTargetsOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505867 """Checks specific for fuzz target sources."""
5868 EXPORTED_SYMBOLS = [
5869 'LLVMFuzzerInitialize',
5870 'LLVMFuzzerCustomMutator',
5871 'LLVMFuzzerCustomCrossOver',
5872 'LLVMFuzzerMutate',
5873 ]
Max Morozb47503b2019-08-08 21:03:275874
Sam Maiera6e76d72022-02-11 21:43:505875 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
Max Morozb47503b2019-08-08 21:03:275876
Sam Maiera6e76d72022-02-11 21:43:505877 def FilterFile(affected_file):
5878 """Ignore libFuzzer source code."""
5879 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
Bruce Dawson40fece62022-09-16 19:58:315880 files_to_skip = r"^third_party/libFuzzer"
Max Morozb47503b2019-08-08 21:03:275881
Sam Maiera6e76d72022-02-11 21:43:505882 return input_api.FilterSourceFile(affected_file,
5883 files_to_check=[files_to_check],
5884 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:275885
Sam Maiera6e76d72022-02-11 21:43:505886 files_with_missing_header = []
5887 for f in input_api.AffectedSourceFiles(FilterFile):
5888 contents = input_api.ReadFile(f, 'r')
5889 if REQUIRED_HEADER in contents:
5890 continue
Max Morozb47503b2019-08-08 21:03:275891
Sam Maiera6e76d72022-02-11 21:43:505892 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
5893 files_with_missing_header.append(f.LocalPath())
Max Morozb47503b2019-08-08 21:03:275894
Sam Maiera6e76d72022-02-11 21:43:505895 if not files_with_missing_header:
5896 return []
Max Morozb47503b2019-08-08 21:03:275897
Sam Maiera6e76d72022-02-11 21:43:505898 long_text = (
5899 'If you define any of the libFuzzer optional functions (%s), it is '
5900 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
5901 'work incorrectly on Mac (crbug.com/687076).\nNote that '
5902 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
5903 'to access command line arguments passed to the fuzzer. Instead, prefer '
5904 'static initialization and shared resources as documented in '
5905 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
5906 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n'
5907 % (', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER))
Max Morozb47503b2019-08-08 21:03:275908
Sam Maiera6e76d72022-02-11 21:43:505909 return [
5910 output_api.PresubmitPromptWarning(message="Missing '%s' in:" %
5911 REQUIRED_HEADER,
5912 items=files_with_missing_header,
5913 long_text=long_text)
5914 ]
Max Morozb47503b2019-08-08 21:03:275915
5916
Mohamed Heikald048240a2019-11-12 16:57:375917def _CheckNewImagesWarning(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505918 """
5919 Warns authors who add images into the repo to make sure their images are
5920 optimized before committing.
5921 """
5922 images_added = False
5923 image_paths = []
5924 errors = []
5925 filter_lambda = lambda x: input_api.FilterSourceFile(
5926 x,
5927 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
5928 DEFAULT_FILES_TO_SKIP),
5929 files_to_check=[r'.*\/(drawable|mipmap)'])
5930 for f in input_api.AffectedFiles(include_deletes=False,
5931 file_filter=filter_lambda):
5932 local_path = f.LocalPath().lower()
5933 if any(
5934 local_path.endswith(extension)
5935 for extension in _IMAGE_EXTENSIONS):
5936 images_added = True
5937 image_paths.append(f)
5938 if images_added:
5939 errors.append(
5940 output_api.PresubmitPromptWarning(
5941 'It looks like you are trying to commit some images. If these are '
5942 'non-test-only images, please make sure to read and apply the tips in '
5943 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
5944 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
5945 'FYI only and will not block your CL on the CQ.', image_paths))
5946 return errors
Mohamed Heikald048240a2019-11-12 16:57:375947
5948
Saagar Sanghavifceeaae2020-08-12 16:40:365949def ChecksAndroidSpecificOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505950 """Groups upload checks that target android code."""
5951 results = []
5952 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
5953 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
5954 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
5955 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505956 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
5957 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
5958 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
5959 results.extend(_CheckNewImagesWarning(input_api, output_api))
5960 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
5961 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
5962 return results
5963
Becky Zhou7c69b50992018-12-10 19:37:575964
Saagar Sanghavifceeaae2020-08-12 16:40:365965def ChecksAndroidSpecificOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505966 """Groups commit checks that target android code."""
5967 results = []
5968 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
5969 return results
dgnaa68d5e2015-06-10 10:08:225970
Chris Hall59f8d0c72020-05-01 07:31:195971# TODO(chrishall): could we additionally match on any path owned by
5972# ui/accessibility/OWNERS ?
5973_ACCESSIBILITY_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:315974 r"^chrome/browser.*/accessibility/",
5975 r"^chrome/browser/extensions/api/automation.*/",
5976 r"^chrome/renderer/extensions/accessibility_.*",
5977 r"^chrome/tests/data/accessibility/",
5978 r"^content/browser/accessibility/",
5979 r"^content/renderer/accessibility/",
5980 r"^content/tests/data/accessibility/",
5981 r"^extensions/renderer/api/automation/",
Katie Dektar58ef07b2022-09-27 13:19:175982 r"^services/accessibility/",
Abigail Klein7a63c572024-02-28 20:45:095983 r"^services/screen_ai/",
Bruce Dawson40fece62022-09-16 19:58:315984 r"^ui/accessibility/",
5985 r"^ui/views/accessibility/",
Chris Hall59f8d0c72020-05-01 07:31:195986)
5987
Saagar Sanghavifceeaae2020-08-12 16:40:365988def CheckAccessibilityRelnotesField(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505989 """Checks that commits to accessibility code contain an AX-Relnotes field in
5990 their commit message."""
Chris Hall59f8d0c72020-05-01 07:31:195991
Sam Maiera6e76d72022-02-11 21:43:505992 def FileFilter(affected_file):
5993 paths = _ACCESSIBILITY_PATHS
5994 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:195995
Sam Maiera6e76d72022-02-11 21:43:505996 # Only consider changes affecting accessibility paths.
5997 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
5998 return []
Akihiro Ota08108e542020-05-20 15:30:535999
Sam Maiera6e76d72022-02-11 21:43:506000 # AX-Relnotes can appear in either the description or the footer.
6001 # When searching the description, require 'AX-Relnotes:' to appear at the
6002 # beginning of a line.
6003 ax_regex = input_api.re.compile('ax-relnotes[:=]')
6004 description_has_relnotes = any(
6005 ax_regex.match(line)
6006 for line in input_api.change.DescriptionText().lower().splitlines())
Chris Hall59f8d0c72020-05-01 07:31:196007
Sam Maiera6e76d72022-02-11 21:43:506008 footer_relnotes = input_api.change.GitFootersFromDescription().get(
6009 'AX-Relnotes', [])
6010 if description_has_relnotes or footer_relnotes:
6011 return []
Chris Hall59f8d0c72020-05-01 07:31:196012
Sam Maiera6e76d72022-02-11 21:43:506013 # TODO(chrishall): link to Relnotes documentation in message.
6014 message = (
6015 "Missing 'AX-Relnotes:' field required for accessibility changes"
6016 "\n please add 'AX-Relnotes: [release notes].' to describe any "
6017 "user-facing changes"
6018 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
6019 "user-facing effects"
6020 "\n if this is confusing or annoying then please contact members "
6021 "of ui/accessibility/OWNERS.")
6022
6023 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:226024
Mark Schillaci44c90b42024-11-22 20:44:386025
6026_ACCESSIBILITY_ARIA_METHOD_CANDIDATES_PATTERNS = r'(\-\>|\.)(get|has|FastGet|FastHas)Attribute\('
6027
6028_ACCESSIBILITY_ARIA_BAD_PARAMS_PATTERNS = (
6029 r"\(html_names::kAria(.*)Attr\)",
6030 r"\(html_names::kRoleAttr\)"
6031)
6032
6033_ACCESSIBILITY_ARIA_FILE_CANDIDATES_PATTERNS = (
6034 r".*/accessibility/.*.(cc|h)",
6035 r".*/ax_.*.(cc|h)"
6036)
6037
6038def CheckAccessibilityAriaElementAttributeGetters(input_api, output_api):
6039 """Checks that the blink accessibility code follows the defined patterns
6040 for checking aria attributes, so that ElementInternals is not bypassed."""
6041
6042 # Limit to accessibility-related files.
6043 def FileFilter(affected_file):
6044 paths = _ACCESSIBILITY_ARIA_FILE_CANDIDATES_PATTERNS
6045 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
6046
6047 aria_method_regex = input_api.re.compile(_ACCESSIBILITY_ARIA_METHOD_CANDIDATES_PATTERNS)
6048 aria_bad_params_regex = input_api.re.compile(
6049 "|".join(_ACCESSIBILITY_ARIA_BAD_PARAMS_PATTERNS)
6050 )
6051 problems = []
6052
6053 for f in input_api.AffectedSourceFiles(FileFilter):
6054 for line_num, line in f.ChangedContents():
6055 if aria_method_regex.search(line) and aria_bad_params_regex.search(line):
6056 problems.append(f"{f.LocalPath()}:{line_num}\n {line.strip()}")
6057
6058 if problems:
6059 return [
6060 output_api.PresubmitPromptWarning(
6061 "Accessibility code should not use element methods to get or check"
6062 "\nthe presence of aria attributes"
6063 "\nPlease use ARIA-specific attribute access, e.g. HasAriaAttribute(),"
6064 "\nAriaTokenAttribute(), AriaBoolAttribute(), AriaBooleanAttribute(),"
6065 "\nAriaFloatAttribute().",
6066 problems,
6067 )
6068 ]
6069 return []
6070
seanmccullough4a9356252021-04-08 19:54:096071# string pattern, sequence of strings to show when pattern matches,
6072# error flag. True if match is a presubmit error, otherwise it's a warning.
6073_NON_INCLUSIVE_TERMS = (
6074 (
6075 # Note that \b pattern in python re is pretty particular. In this
6076 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
6077 # ...' will not. This may require some tweaking to catch these cases
6078 # without triggering a lot of false positives. Leaving it naive and
6079 # less matchy for now.
Josip Sokcevic9d2806a02023-12-13 03:04:026080 r'/(?i)\b((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:096081 (
6082 'Please don\'t use blacklist, whitelist, ' # nocheck
6083 'or slave in your', # nocheck
6084 'code and make every effort to use other terms. Using "// nocheck"',
6085 '"# nocheck" or "<!-- nocheck -->"',
6086 'at the end of the offending line will bypass this PRESUBMIT error',
6087 'but avoid using this whenever possible. Reach out to',
6088 '[email protected] if you have questions'),
6089 True),)
6090
Saagar Sanghavifceeaae2020-08-12 16:40:366091def ChecksCommon(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506092 """Checks common to both upload and commit."""
6093 results = []
Eric Boren6fd2b932018-01-25 15:05:086094 results.extend(
Sam Maiera6e76d72022-02-11 21:43:506095 input_api.canned_checks.PanProjectChecks(
6096 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:086097
Sam Maiera6e76d72022-02-11 21:43:506098 author = input_api.change.author_email
6099 if author and author not in _KNOWN_ROBOTS:
6100 results.extend(
6101 input_api.canned_checks.CheckAuthorizedAuthor(
6102 input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:246103
Sam Maiera6e76d72022-02-11 21:43:506104 results.extend(
6105 input_api.canned_checks.CheckChangeHasNoTabs(
6106 input_api,
6107 output_api,
6108 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
6109 results.extend(
6110 input_api.RunTests(
6111 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Edward Lesmesce51df52020-08-04 22:10:176112
Bruce Dawsonc8054482022-03-28 15:33:376113 dirmd = 'dirmd.bat' if input_api.is_windows else 'dirmd'
Sam Maiera6e76d72022-02-11 21:43:506114 dirmd_bin = input_api.os_path.join(input_api.PresubmitLocalPath(),
Bruce Dawsonc8054482022-03-28 15:33:376115 'third_party', 'depot_tools', dirmd)
Sam Maiera6e76d72022-02-11 21:43:506116 results.extend(
6117 input_api.RunTests(
6118 input_api.canned_checks.CheckDirMetadataFormat(
6119 input_api, output_api, dirmd_bin)))
6120 results.extend(
6121 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
6122 input_api, output_api))
6123 results.extend(
6124 input_api.canned_checks.CheckNoNewMetadataInOwners(
6125 input_api, output_api))
6126 results.extend(
6127 input_api.canned_checks.CheckInclusiveLanguage(
6128 input_api,
6129 output_api,
6130 excluded_directories_relative_path=[
6131 'infra', 'inclusive_language_presubmit_exempt_dirs.txt'
6132 ],
6133 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Dirk Prankee3c9c62d2021-05-18 18:35:596134
Aleksey Khoroshilov2978c942022-06-13 16:14:126135 presubmit_py_filter = lambda f: input_api.FilterSourceFile(
Bruce Dawson696963f2022-09-13 01:15:476136 f, files_to_check=[r'.*PRESUBMIT\.py$'])
Aleksey Khoroshilov2978c942022-06-13 16:14:126137 for f in input_api.AffectedFiles(include_deletes=False,
6138 file_filter=presubmit_py_filter):
6139 full_path = input_api.os_path.dirname(f.AbsoluteLocalPath())
6140 test_file = input_api.os_path.join(full_path, 'PRESUBMIT_test.py')
6141 # The PRESUBMIT.py file (and the directory containing it) might have
6142 # been affected by being moved or removed, so only try to run the tests
6143 # if they still exist.
6144 if not input_api.os_path.exists(test_file):
6145 continue
Sam Maiera6e76d72022-02-11 21:43:506146
Aleksey Khoroshilov2978c942022-06-13 16:14:126147 results.extend(
6148 input_api.canned_checks.RunUnitTestsInDirectory(
6149 input_api,
6150 output_api,
6151 full_path,
Takuto Ikuta40def482023-06-02 02:23:496152 files_to_check=[r'^PRESUBMIT_test\.py$']))
Sam Maiera6e76d72022-02-11 21:43:506153 return results
[email protected]1f7b4172010-01-28 01:17:346154
[email protected]b337cb5b2011-01-23 21:24:056155
Saagar Sanghavifceeaae2020-08-12 16:40:366156def CheckPatchFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506157 problems = [
6158 f.LocalPath() for f in input_api.AffectedFiles()
6159 if f.LocalPath().endswith(('.orig', '.rej'))
6160 ]
6161 # Cargo.toml.orig files are part of third-party crates downloaded from
6162 # crates.io and should be included.
6163 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
6164 if problems:
6165 return [
6166 output_api.PresubmitError("Don't commit .rej and .orig files.",
6167 problems)
6168 ]
6169 else:
6170 return []
[email protected]b8079ae4a2012-12-05 19:56:496171
6172
Saagar Sanghavifceeaae2020-08-12 16:40:366173def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506174 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
6175 macro_re = input_api.re.compile(
6176 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
6177 include_re = input_api.re.compile(r'^#include\s+"build/build_config.h"',
6178 input_api.re.MULTILINE)
6179 extension_re = input_api.re.compile(r'\.[a-z]+$')
6180 errors = []
Bruce Dawsonf7679202022-08-09 20:24:006181 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:506182 for f in input_api.AffectedFiles(include_deletes=False):
Bruce Dawsonf7679202022-08-09 20:24:006183 # The build-config macros are allowed to be used in build_config.h
6184 # without including itself.
6185 if f.LocalPath() == config_h_file:
6186 continue
Sam Maiera6e76d72022-02-11 21:43:506187 if not f.LocalPath().endswith(
6188 ('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
6189 continue
Arthur Sonzognia3dec412024-04-29 12:05:376190
Sam Maiera6e76d72022-02-11 21:43:506191 found_line_number = None
6192 found_macro = None
6193 all_lines = input_api.ReadFile(f, 'r').splitlines()
6194 for line_num, line in enumerate(all_lines):
6195 match = macro_re.search(line)
6196 if match:
6197 found_line_number = line_num
6198 found_macro = match.group(2)
6199 break
6200 if not found_line_number:
6201 continue
Kent Tamura5a8755d2017-06-29 23:37:076202
Sam Maiera6e76d72022-02-11 21:43:506203 found_include_line = -1
6204 for line_num, line in enumerate(all_lines):
6205 if include_re.search(line):
6206 found_include_line = line_num
6207 break
6208 if found_include_line >= 0 and found_include_line < found_line_number:
6209 continue
Kent Tamura5a8755d2017-06-29 23:37:076210
Sam Maiera6e76d72022-02-11 21:43:506211 if not f.LocalPath().endswith('.h'):
6212 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
6213 try:
6214 content = input_api.ReadFile(primary_header_path, 'r')
6215 if include_re.search(content):
6216 continue
6217 except IOError:
6218 pass
6219 errors.append('%s:%d %s macro is used without first including build/'
6220 'build_config.h.' %
6221 (f.LocalPath(), found_line_number, found_macro))
6222 if errors:
6223 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
6224 return []
Kent Tamura5a8755d2017-06-29 23:37:076225
6226
Lei Zhang1c12a22f2021-05-12 11:28:456227def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506228 stl_include_re = input_api.re.compile(r'^#include\s+<('
6229 r'algorithm|'
6230 r'array|'
6231 r'limits|'
6232 r'list|'
6233 r'map|'
6234 r'memory|'
6235 r'queue|'
6236 r'set|'
6237 r'string|'
6238 r'unordered_map|'
6239 r'unordered_set|'
6240 r'utility|'
6241 r'vector)>')
6242 std_namespace_re = input_api.re.compile(r'std::')
6243 errors = []
6244 for f in input_api.AffectedFiles():
6245 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
6246 continue
Lei Zhang1c12a22f2021-05-12 11:28:456247
Sam Maiera6e76d72022-02-11 21:43:506248 uses_std_namespace = False
6249 has_stl_include = False
6250 for line in f.NewContents():
6251 if has_stl_include and uses_std_namespace:
6252 break
Lei Zhang1c12a22f2021-05-12 11:28:456253
Sam Maiera6e76d72022-02-11 21:43:506254 if not has_stl_include and stl_include_re.search(line):
6255 has_stl_include = True
6256 continue
Lei Zhang1c12a22f2021-05-12 11:28:456257
Bruce Dawson4a5579a2022-04-08 17:11:366258 if not uses_std_namespace and (std_namespace_re.search(line)
6259 or 'no-std-usage-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:506260 uses_std_namespace = True
6261 continue
Lei Zhang1c12a22f2021-05-12 11:28:456262
Sam Maiera6e76d72022-02-11 21:43:506263 if has_stl_include and not uses_std_namespace:
6264 errors.append(
6265 '%s: Includes STL header(s) but does not reference std::' %
6266 f.LocalPath())
6267 if errors:
6268 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
6269 return []
Lei Zhang1c12a22f2021-05-12 11:28:456270
6271
Xiaohan Wang42d96c22022-01-20 17:23:116272def _CheckForDeprecatedOSMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:506273 """Check for sensible looking, totally invalid OS macros."""
6274 preprocessor_statement = input_api.re.compile(r'^\s*#')
6275 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
6276 results = []
6277 for lnum, line in f.ChangedContents():
6278 if preprocessor_statement.search(line):
6279 for match in os_macro.finditer(line):
6280 results.append(
6281 ' %s:%d: %s' %
6282 (f.LocalPath(), lnum, 'defined(OS_' + match.group(1) +
6283 ') -> BUILDFLAG(IS_' + match.group(1) + ')'))
6284 return results
[email protected]b00342e7f2013-03-26 16:21:546285
6286
Xiaohan Wang42d96c22022-01-20 17:23:116287def CheckForDeprecatedOSMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506288 """Check all affected files for invalid OS macros."""
6289 bad_macros = []
Bruce Dawsonf7679202022-08-09 20:24:006290 # The OS_ macros are allowed to be used in build/build_config.h.
6291 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:506292 for f in input_api.AffectedSourceFiles(None):
Bruce Dawsonf7679202022-08-09 20:24:006293 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')) \
6294 and f.LocalPath() != config_h_file:
Sam Maiera6e76d72022-02-11 21:43:506295 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
[email protected]b00342e7f2013-03-26 16:21:546296
Sam Maiera6e76d72022-02-11 21:43:506297 if not bad_macros:
6298 return []
[email protected]b00342e7f2013-03-26 16:21:546299
Sam Maiera6e76d72022-02-11 21:43:506300 return [
6301 output_api.PresubmitError(
6302 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
6303 'defined in build_config.h):', bad_macros)
6304 ]
[email protected]b00342e7f2013-03-26 16:21:546305
lliabraa35bab3932014-10-01 12:16:446306
6307def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:506308 """Check all affected files for invalid "if defined" macros."""
6309 ALWAYS_DEFINED_MACROS = (
6310 "TARGET_CPU_PPC",
6311 "TARGET_CPU_PPC64",
6312 "TARGET_CPU_68K",
6313 "TARGET_CPU_X86",
6314 "TARGET_CPU_ARM",
6315 "TARGET_CPU_MIPS",
6316 "TARGET_CPU_SPARC",
6317 "TARGET_CPU_ALPHA",
6318 "TARGET_IPHONE_SIMULATOR",
6319 "TARGET_OS_EMBEDDED",
6320 "TARGET_OS_IPHONE",
6321 "TARGET_OS_MAC",
6322 "TARGET_OS_UNIX",
6323 "TARGET_OS_WIN32",
6324 )
6325 ifdef_macro = input_api.re.compile(
6326 r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
6327 results = []
6328 for lnum, line in f.ChangedContents():
6329 for match in ifdef_macro.finditer(line):
6330 if match.group(1) in ALWAYS_DEFINED_MACROS:
6331 always_defined = ' %s is always defined. ' % match.group(1)
6332 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
6333 results.append(
6334 ' %s:%d %s\n\t%s' %
6335 (f.LocalPath(), lnum, always_defined, did_you_mean))
6336 return results
lliabraa35bab3932014-10-01 12:16:446337
6338
Saagar Sanghavifceeaae2020-08-12 16:40:366339def CheckForInvalidIfDefinedMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506340 """Check all affected files for invalid "if defined" macros."""
Arthur Sonzogni4fd14fd2024-06-02 18:42:526341 SKIPPED_PATHS = [
6342 'base/allocator/partition_allocator/src/partition_alloc/build_config.h',
6343 'build/build_config.h',
6344 'third_party/abseil-cpp/',
6345 'third_party/sqlite/',
6346 ]
6347 def affected_files_filter(f):
6348 # Normalize the local path to Linux-style path separators so that the
6349 # path comparisons work on Windows as well.
Anton Bershanskyi4253349482025-02-11 21:01:276350 path = f.UnixLocalPath()
Arthur Sonzogni4fd14fd2024-06-02 18:42:526351
6352 for skipped_path in SKIPPED_PATHS:
6353 if path.startswith(skipped_path):
6354 return False
6355
6356 return path.endswith(('.h', '.c', '.cc', '.m', '.mm'))
6357
Sam Maiera6e76d72022-02-11 21:43:506358 bad_macros = []
Arthur Sonzogni4fd14fd2024-06-02 18:42:526359 for f in input_api.AffectedSourceFiles(affected_files_filter):
6360 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
lliabraa35bab3932014-10-01 12:16:446361
Sam Maiera6e76d72022-02-11 21:43:506362 if not bad_macros:
6363 return []
lliabraa35bab3932014-10-01 12:16:446364
Sam Maiera6e76d72022-02-11 21:43:506365 return [
6366 output_api.PresubmitError(
6367 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
6368 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
6369 bad_macros)
6370 ]
lliabraa35bab3932014-10-01 12:16:446371
Saagar Sanghavifceeaae2020-08-12 16:40:366372def CheckForIPCRules(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506373 """Check for same IPC rules described in
6374 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
6375 """
6376 base_pattern = r'IPC_ENUM_TRAITS\('
6377 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
6378 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
mlamouria82272622014-09-16 18:45:046379
Sam Maiera6e76d72022-02-11 21:43:506380 problems = []
6381 for f in input_api.AffectedSourceFiles(None):
6382 local_path = f.LocalPath()
6383 if not local_path.endswith('.h'):
6384 continue
6385 for line_number, line in f.ChangedContents():
6386 if inclusion_pattern.search(
6387 line) and not comment_pattern.search(line):
6388 problems.append('%s:%d\n %s' %
6389 (local_path, line_number, line.strip()))
mlamouria82272622014-09-16 18:45:046390
Sam Maiera6e76d72022-02-11 21:43:506391 if problems:
6392 return [
6393 output_api.PresubmitPromptWarning(_IPC_ENUM_TRAITS_DEPRECATED,
6394 problems)
6395 ]
6396 else:
6397 return []
mlamouria82272622014-09-16 18:45:046398
[email protected]b00342e7f2013-03-26 16:21:546399
Saagar Sanghavifceeaae2020-08-12 16:40:366400def CheckForLongPathnames(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506401 """Check to make sure no files being submitted have long paths.
6402 This causes issues on Windows.
6403 """
6404 problems = []
6405 for f in input_api.AffectedTestableFiles():
6406 local_path = f.LocalPath()
6407 # Windows has a path limit of 260 characters. Limit path length to 200 so
6408 # that we have some extra for the prefix on dev machines and the bots.
Weizhong Xia8b461f12024-06-21 21:46:336409 if (local_path.startswith('third_party/blink/web_tests/platform/') and
6410 not local_path.startswith('third_party/blink/web_tests/platform/win')):
6411 # Do not check length of the path for files not used by Windows
6412 continue
Sam Maiera6e76d72022-02-11 21:43:506413 if len(local_path) > 200:
6414 problems.append(local_path)
Stephen Martinis97a394142018-06-07 23:06:056415
Sam Maiera6e76d72022-02-11 21:43:506416 if problems:
6417 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
6418 else:
6419 return []
Stephen Martinis97a394142018-06-07 23:06:056420
6421
Saagar Sanghavifceeaae2020-08-12 16:40:366422def CheckForIncludeGuards(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506423 """Check that header files have proper guards against multiple inclusion.
6424 If a file should not have such guards (and it probably should) then it
Bruce Dawson4a5579a2022-04-08 17:11:366425 should include the string "no-include-guard-because-multiply-included" or
6426 "no-include-guard-because-pch-file".
Sam Maiera6e76d72022-02-11 21:43:506427 """
Daniel Bratell8ba52722018-03-02 16:06:146428
Sam Maiera6e76d72022-02-11 21:43:506429 def is_chromium_header_file(f):
6430 # We only check header files under the control of the Chromium
mikt84d6c712024-03-27 13:29:036431 # project. This excludes:
6432 # - third_party/*, except blink.
6433 # - base/allocator/partition_allocator/: PartitionAlloc is a standalone
6434 # library used outside of Chrome. Includes are referenced from its
6435 # own base directory. It has its own `CheckForIncludeGuards`
6436 # PRESUBMIT.py check.
6437 # - *_message_generator.h: They use include guards in a special,
6438 # non-typical way.
Sam Maiera6e76d72022-02-11 21:43:506439 file_with_path = input_api.os_path.normpath(f.LocalPath())
6440 return (file_with_path.endswith('.h')
6441 and not file_with_path.endswith('_message_generator.h')
Bruce Dawson4c4c2922022-05-02 18:07:336442 and not file_with_path.endswith('com_imported_mstscax.h')
Peter Kasting66c1f752024-12-02 15:28:376443 and not file_with_path.startswith(
6444 input_api.os_path.join('base', 'allocator',
6445 'partition_allocator'))
Sam Maiera6e76d72022-02-11 21:43:506446 and (not file_with_path.startswith('third_party')
6447 or file_with_path.startswith(
6448 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:146449
Sam Maiera6e76d72022-02-11 21:43:506450 def replace_special_with_underscore(string):
6451 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:146452
Sam Maiera6e76d72022-02-11 21:43:506453 errors = []
Daniel Bratell8ba52722018-03-02 16:06:146454
Sam Maiera6e76d72022-02-11 21:43:506455 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
6456 guard_name = None
6457 guard_line_number = None
6458 seen_guard_end = False
Lei Zhangd84f9512024-05-28 19:43:306459 bypass_checks_at_end_of_file = False
Daniel Bratell8ba52722018-03-02 16:06:146460
Sam Maiera6e76d72022-02-11 21:43:506461 file_with_path = input_api.os_path.normpath(f.LocalPath())
6462 base_file_name = input_api.os_path.splitext(
6463 input_api.os_path.basename(file_with_path))[0]
6464 upper_base_file_name = base_file_name.upper()
Daniel Bratell8ba52722018-03-02 16:06:146465
Sam Maiera6e76d72022-02-11 21:43:506466 expected_guard = replace_special_with_underscore(
6467 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:146468
Sam Maiera6e76d72022-02-11 21:43:506469 # For "path/elem/file_name.h" we should really only accept
6470 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
6471 # are too many (1000+) files with slight deviations from the
6472 # coding style. The most important part is that the include guard
6473 # is there, and that it's unique, not the name so this check is
6474 # forgiving for existing files.
6475 #
6476 # As code becomes more uniform, this could be made stricter.
Daniel Bratell8ba52722018-03-02 16:06:146477
Sam Maiera6e76d72022-02-11 21:43:506478 guard_name_pattern_list = [
6479 # Anything with the right suffix (maybe with an extra _).
6480 r'\w+_H__?',
Daniel Bratell8ba52722018-03-02 16:06:146481
Sam Maiera6e76d72022-02-11 21:43:506482 # To cover include guards with old Blink style.
6483 r'\w+_h',
Daniel Bratell8ba52722018-03-02 16:06:146484
Sam Maiera6e76d72022-02-11 21:43:506485 # Anything including the uppercase name of the file.
6486 r'\w*' + input_api.re.escape(
6487 replace_special_with_underscore(upper_base_file_name)) +
6488 r'\w*',
6489 ]
6490 guard_name_pattern = '|'.join(guard_name_pattern_list)
6491 guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
6492 guard_name_pattern + ')')
Daniel Bratell8ba52722018-03-02 16:06:146493
Sam Maiera6e76d72022-02-11 21:43:506494 for line_number, line in enumerate(f.NewContents()):
Bruce Dawson4a5579a2022-04-08 17:11:366495 if ('no-include-guard-because-multiply-included' in line
6496 or 'no-include-guard-because-pch-file' in line):
Lei Zhangd84f9512024-05-28 19:43:306497 bypass_checks_at_end_of_file = True
Sam Maiera6e76d72022-02-11 21:43:506498 break
Daniel Bratell8ba52722018-03-02 16:06:146499
Sam Maiera6e76d72022-02-11 21:43:506500 if guard_name is None:
6501 match = guard_pattern.match(line)
6502 if match:
6503 guard_name = match.group(1)
6504 guard_line_number = line_number
Daniel Bratell8ba52722018-03-02 16:06:146505
Sam Maiera6e76d72022-02-11 21:43:506506 # We allow existing files to use include guards whose names
6507 # don't match the chromium style guide, but new files should
6508 # get it right.
Bruce Dawson6cc154e2022-04-12 20:39:496509 if guard_name != expected_guard:
Bruce Dawson95eb7562022-09-14 15:27:166510 if f.Action() == 'A': # If file was just 'A'dded
Sam Maiera6e76d72022-02-11 21:43:506511 errors.append(
6512 output_api.PresubmitPromptWarning(
6513 'Header using the wrong include guard name %s'
6514 % guard_name, [
6515 '%s:%d' %
6516 (f.LocalPath(), line_number + 1)
6517 ], 'Expected: %r\nFound: %r' %
6518 (expected_guard, guard_name)))
6519 else:
6520 # The line after #ifndef should have a #define of the same name.
6521 if line_number == guard_line_number + 1:
6522 expected_line = '#define %s' % guard_name
6523 if line != expected_line:
6524 errors.append(
6525 output_api.PresubmitPromptWarning(
6526 'Missing "%s" for include guard' %
6527 expected_line,
6528 ['%s:%d' % (f.LocalPath(), line_number + 1)],
6529 'Expected: %r\nGot: %r' %
6530 (expected_line, line)))
Daniel Bratell8ba52722018-03-02 16:06:146531
Sam Maiera6e76d72022-02-11 21:43:506532 if not seen_guard_end and line == '#endif // %s' % guard_name:
6533 seen_guard_end = True
6534 elif seen_guard_end:
6535 if line.strip() != '':
6536 errors.append(
6537 output_api.PresubmitPromptWarning(
6538 'Include guard %s not covering the whole file'
6539 % (guard_name), [f.LocalPath()]))
6540 break # Nothing else to check and enough to warn once.
Daniel Bratell8ba52722018-03-02 16:06:146541
Lei Zhangd84f9512024-05-28 19:43:306542 if bypass_checks_at_end_of_file:
6543 continue
6544
Sam Maiera6e76d72022-02-11 21:43:506545 if guard_name is None:
6546 errors.append(
6547 output_api.PresubmitPromptWarning(
Bruce Dawson32114b62022-04-11 16:45:496548 'Missing include guard in %s\n'
Sam Maiera6e76d72022-02-11 21:43:506549 'Recommended name: %s\n'
6550 'This check can be disabled by having the string\n'
Bruce Dawson4a5579a2022-04-08 17:11:366551 '"no-include-guard-because-multiply-included" or\n'
6552 '"no-include-guard-because-pch-file" in the header.'
Sam Maiera6e76d72022-02-11 21:43:506553 % (f.LocalPath(), expected_guard)))
Lei Zhangd84f9512024-05-28 19:43:306554 elif not seen_guard_end:
6555 errors.append(
6556 output_api.PresubmitPromptWarning(
6557 'Incorrect or missing include guard #endif in %s\n'
6558 'Recommended #endif comment: // %s'
6559 % (f.LocalPath(), expected_guard)))
Sam Maiera6e76d72022-02-11 21:43:506560
6561 return errors
Daniel Bratell8ba52722018-03-02 16:06:146562
6563
Saagar Sanghavifceeaae2020-08-12 16:40:366564def CheckForWindowsLineEndings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506565 """Check source code and known ascii text files for Windows style line
6566 endings.
6567 """
Bruce Dawson5efbdc652022-04-11 19:29:516568 known_text_files = r'.*\.(txt|html|htm|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:236569
dpapadfd421fb2025-02-13 00:47:326570 _WEBUI_FILES_EXTENSIONS = r'\.(css|html|js|ts|svg)$'
6571
Sam Maiera6e76d72022-02-11 21:43:506572 file_inclusion_pattern = (known_text_files,
6573 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
dpapadfd421fb2025-02-13 00:47:326574 r'.+%s' % _HEADER_EXTENSIONS,
6575 r'.+%s' % _WEBUI_FILES_EXTENSIONS)
6576
6577 # Exclude folder that contains .ts files that are actually binary video
6578 # format and not TypeScript.
6579 file_exclusion_pattern = (r'media/test/data/')
mostynbb639aca52015-01-07 20:31:236580
Sam Maiera6e76d72022-02-11 21:43:506581 problems = []
6582 source_file_filter = lambda f: input_api.FilterSourceFile(
dpapadfd421fb2025-02-13 00:47:326583 f, files_to_check=file_inclusion_pattern,
6584 files_to_skip=file_exclusion_pattern)
Sam Maiera6e76d72022-02-11 21:43:506585 for f in input_api.AffectedSourceFiles(source_file_filter):
Bruce Dawson5efbdc652022-04-11 19:29:516586 # Ignore test files that contain crlf intentionally.
6587 if f.LocalPath().endswith('crlf.txt'):
Daniel Chenga37c03db2022-05-12 17:20:346588 continue
Sam Maiera6e76d72022-02-11 21:43:506589 include_file = False
6590 for line in input_api.ReadFile(f, 'r').splitlines(True):
6591 if line.endswith('\r\n'):
6592 include_file = True
6593 if include_file:
6594 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:236595
Sam Maiera6e76d72022-02-11 21:43:506596 if problems:
6597 return [
6598 output_api.PresubmitPromptWarning(
6599 'Are you sure that you want '
6600 'these files to contain Windows style line endings?\n' +
6601 '\n'.join(problems))
6602 ]
mostynbb639aca52015-01-07 20:31:236603
Sam Maiera6e76d72022-02-11 21:43:506604 return []
6605
mostynbb639aca52015-01-07 20:31:236606
Evan Stade6cfc964c12021-05-18 20:21:166607def CheckIconFilesForLicenseHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506608 """Check that .icon files (which are fragments of C++) have license headers.
6609 """
Evan Stade6cfc964c12021-05-18 20:21:166610
Sam Maiera6e76d72022-02-11 21:43:506611 icon_files = (r'.*\.icon$', )
Evan Stade6cfc964c12021-05-18 20:21:166612
Sam Maiera6e76d72022-02-11 21:43:506613 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
6614 return input_api.canned_checks.CheckLicense(input_api,
6615 output_api,
6616 source_file_filter=icons)
6617
Evan Stade6cfc964c12021-05-18 20:21:166618
Jose Magana2b456f22021-03-09 23:26:406619def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506620 """Check source code for use of Chrome App technologies being
6621 deprecated.
6622 """
Jose Magana2b456f22021-03-09 23:26:406623
Sam Maiera6e76d72022-02-11 21:43:506624 def _CheckForDeprecatedTech(input_api,
6625 output_api,
6626 detection_list,
6627 files_to_check=None,
6628 files_to_skip=None):
Jose Magana2b456f22021-03-09 23:26:406629
Sam Maiera6e76d72022-02-11 21:43:506630 if (files_to_check or files_to_skip):
6631 source_file_filter = lambda f: input_api.FilterSourceFile(
6632 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
6633 else:
6634 source_file_filter = None
6635
6636 problems = []
6637
6638 for f in input_api.AffectedSourceFiles(source_file_filter):
6639 if f.Action() == 'D':
6640 continue
6641 for _, line in f.ChangedContents():
6642 if any(detect in line for detect in detection_list):
6643 problems.append(f.LocalPath())
6644
6645 return problems
6646
6647 # to avoid this presubmit script triggering warnings
6648 files_to_skip = ['PRESUBMIT.py', 'PRESUBMIT_test.py']
Jose Magana2b456f22021-03-09 23:26:406649
6650 problems = []
6651
Sam Maiera6e76d72022-02-11 21:43:506652 # NMF: any files with extensions .nmf or NMF
6653 _NMF_FILES = r'\.(nmf|NMF)$'
6654 problems += _CheckForDeprecatedTech(
6655 input_api,
6656 output_api,
6657 detection_list=[''], # any change to the file will trigger warning
6658 files_to_check=[r'.+%s' % _NMF_FILES])
Jose Magana2b456f22021-03-09 23:26:406659
Sam Maiera6e76d72022-02-11 21:43:506660 # MANIFEST: any manifest.json that in its diff includes "app":
6661 _MANIFEST_FILES = r'(manifest\.json)$'
6662 problems += _CheckForDeprecatedTech(
6663 input_api,
6664 output_api,
6665 detection_list=['"app":'],
6666 files_to_check=[r'.*%s' % _MANIFEST_FILES])
Jose Magana2b456f22021-03-09 23:26:406667
Sam Maiera6e76d72022-02-11 21:43:506668 # NaCl / PNaCl: any file that in its diff contains the strings in the list
6669 problems += _CheckForDeprecatedTech(
6670 input_api,
6671 output_api,
6672 detection_list=['config=nacl', 'enable-nacl', 'cpu=pnacl', 'nacl_io'],
Bruce Dawson40fece62022-09-16 19:58:316673 files_to_skip=files_to_skip + [r"^native_client_sdk/"])
Jose Magana2b456f22021-03-09 23:26:406674
Gao Shenga79ebd42022-08-08 17:25:596675 # PPAPI: any C/C++ file that in its diff includes a ppapi library
Sam Maiera6e76d72022-02-11 21:43:506676 problems += _CheckForDeprecatedTech(
6677 input_api,
6678 output_api,
6679 detection_list=['#include "ppapi', '#include <ppapi'],
6680 files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,
6681 r'.+%s' % _IMPLEMENTATION_EXTENSIONS),
Bruce Dawson40fece62022-09-16 19:58:316682 files_to_skip=[r"^ppapi/"])
Jose Magana2b456f22021-03-09 23:26:406683
Sam Maiera6e76d72022-02-11 21:43:506684 if problems:
6685 return [
6686 output_api.PresubmitPromptWarning(
6687 'You are adding/modifying code'
6688 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
6689 ' PNaCl, PPAPI). See this blog post for more details:\n'
6690 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
6691 'and this documentation for options to replace these technologies:\n'
6692 'https://developer.chrome.com/docs/apps/migration/\n' +
6693 '\n'.join(problems))
6694 ]
Jose Magana2b456f22021-03-09 23:26:406695
Sam Maiera6e76d72022-02-11 21:43:506696 return []
Jose Magana2b456f22021-03-09 23:26:406697
mostynbb639aca52015-01-07 20:31:236698
Saagar Sanghavifceeaae2020-08-12 16:40:366699def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
Sam Maiera6e76d72022-02-11 21:43:506700 """Checks that all source files use SYSLOG properly."""
6701 syslog_files = []
6702 for f in input_api.AffectedSourceFiles(src_file_filter):
6703 for line_number, line in f.ChangedContents():
6704 if 'SYSLOG' in line:
6705 syslog_files.append(f.LocalPath() + ':' + str(line_number))
pastarmovj032ba5bc2017-01-12 10:41:566706
Sam Maiera6e76d72022-02-11 21:43:506707 if syslog_files:
6708 return [
6709 output_api.PresubmitPromptWarning(
6710 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
6711 ' calls.\nFiles to check:\n',
6712 items=syslog_files)
6713 ]
6714 return []
pastarmovj89f7ee12016-09-20 14:58:136715
6716
[email protected]1f7b4172010-01-28 01:17:346717def CheckChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506718 if input_api.version < [2, 0, 0]:
6719 return [
6720 output_api.PresubmitError(
6721 "Your depot_tools is out of date. "
6722 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
6723 "but your version is %d.%d.%d" % tuple(input_api.version))
6724 ]
6725 results = []
6726 results.extend(
6727 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
6728 return results
[email protected]ca8d1982009-02-19 16:33:126729
6730
6731def CheckChangeOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506732 if input_api.version < [2, 0, 0]:
6733 return [
6734 output_api.PresubmitError(
6735 "Your depot_tools is out of date. "
6736 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
6737 "but your version is %d.%d.%d" % tuple(input_api.version))
6738 ]
Saagar Sanghavifceeaae2020-08-12 16:40:366739
Sam Maiera6e76d72022-02-11 21:43:506740 results = []
6741 # Make sure the tree is 'open'.
6742 results.extend(
6743 input_api.canned_checks.CheckTreeIsOpen(
6744 input_api,
6745 output_api,
6746 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:276747
Sam Maiera6e76d72022-02-11 21:43:506748 results.extend(
6749 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
6750 results.extend(
6751 input_api.canned_checks.CheckChangeHasBugField(input_api, output_api))
6752 results.extend(
6753 input_api.canned_checks.CheckChangeHasNoUnwantedTags(
6754 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:506755 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146756
6757
Saagar Sanghavifceeaae2020-08-12 16:40:366758def CheckStrings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506759 """Check string ICU syntax validity and if translation screenshots exist."""
6760 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
6761 # footer is set to true.
6762 git_footers = input_api.change.GitFootersFromDescription()
6763 skip_screenshot_check_footer = [
6764 footer.lower() for footer in git_footers.get(
6765 u'Skip-Translation-Screenshots-Check', [])
6766 ]
6767 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:026768
Sam Maiera6e76d72022-02-11 21:43:506769 import os
6770 import re
6771 import sys
6772 from io import StringIO
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146773
Sam Maiera6e76d72022-02-11 21:43:506774 new_or_added_paths = set(f.LocalPath() for f in input_api.AffectedFiles()
6775 if (f.Action() == 'A' or f.Action() == 'M'))
6776 removed_paths = set(f.LocalPath()
6777 for f in input_api.AffectedFiles(include_deletes=True)
6778 if f.Action() == 'D')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146779
Sam Maiera6e76d72022-02-11 21:43:506780 affected_grds = [
6781 f for f in input_api.AffectedFiles()
6782 if f.LocalPath().endswith(('.grd', '.grdp'))
6783 ]
6784 affected_grds = [
6785 f for f in affected_grds if not 'testdata' in f.LocalPath()
6786 ]
6787 if not affected_grds:
6788 return []
meacer8c0d3832019-12-26 21:46:166789
Sam Maiera6e76d72022-02-11 21:43:506790 affected_png_paths = [
Andrew Grieve713b89b2024-10-15 20:20:086791 f.LocalPath() for f in input_api.AffectedFiles()
6792 if f.LocalPath().endswith('.png')
Sam Maiera6e76d72022-02-11 21:43:506793 ]
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146794
Sam Maiera6e76d72022-02-11 21:43:506795 # Check for screenshots. Developers can upload screenshots using
6796 # tools/translation/upload_screenshots.py which finds and uploads
6797 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
6798 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
6799 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
6800 #
6801 # The logic here is as follows:
6802 #
6803 # - If the CL has a .png file under the screenshots directory for a grd
6804 # file, warn the developer. Actual images should never be checked into the
6805 # Chrome repo.
6806 #
6807 # - If the CL contains modified or new messages in grd files and doesn't
6808 # contain the corresponding .sha1 files, warn the developer to add images
6809 # and upload them via tools/translation/upload_screenshots.py.
6810 #
6811 # - If the CL contains modified or new messages in grd files and the
6812 # corresponding .sha1 files, everything looks good.
6813 #
6814 # - If the CL contains removed messages in grd files but the corresponding
6815 # .sha1 files aren't removed, warn the developer to remove them.
6816 unnecessary_screenshots = []
Jens Mueller054652c2023-05-10 15:12:306817 invalid_sha1 = []
Sam Maiera6e76d72022-02-11 21:43:506818 missing_sha1 = []
Bruce Dawson55776c42022-12-09 17:23:476819 missing_sha1_modified = []
Sam Maiera6e76d72022-02-11 21:43:506820 unnecessary_sha1_files = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146821
Sam Maiera6e76d72022-02-11 21:43:506822 # This checks verifies that the ICU syntax of messages this CL touched is
6823 # valid, and reports any found syntax errors.
6824 # Without this presubmit check, ICU syntax errors in Chromium strings can land
6825 # without developers being aware of them. Later on, such ICU syntax errors
6826 # break message extraction for translation, hence would block Chromium
6827 # translations until they are fixed.
6828 icu_syntax_errors = []
Jens Mueller054652c2023-05-10 15:12:306829 sha1_pattern = input_api.re.compile(r'^[a-fA-F0-9]{40}$',
6830 input_api.re.MULTILINE)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146831
Sam Maiera6e76d72022-02-11 21:43:506832 def _CheckScreenshotAdded(screenshots_dir, message_id):
6833 sha1_path = input_api.os_path.join(screenshots_dir,
6834 message_id + '.png.sha1')
6835 if sha1_path not in new_or_added_paths:
6836 missing_sha1.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306837 elif not _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256838 invalid_sha1.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146839
Bruce Dawson55776c42022-12-09 17:23:476840 def _CheckScreenshotModified(screenshots_dir, message_id):
6841 sha1_path = input_api.os_path.join(screenshots_dir,
6842 message_id + '.png.sha1')
6843 if sha1_path not in new_or_added_paths:
6844 missing_sha1_modified.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306845 elif not _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256846 invalid_sha1.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306847
6848 def _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256849 return sha1_pattern.search(
6850 next("\n".join(f.NewContents()) for f in input_api.AffectedFiles()
6851 if f.LocalPath() == sha1_path))
Bruce Dawson55776c42022-12-09 17:23:476852
Sam Maiera6e76d72022-02-11 21:43:506853 def _CheckScreenshotRemoved(screenshots_dir, message_id):
6854 sha1_path = input_api.os_path.join(screenshots_dir,
6855 message_id + '.png.sha1')
6856 if input_api.os_path.exists(
6857 sha1_path) and sha1_path not in removed_paths:
6858 unnecessary_sha1_files.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146859
Sam Maiera6e76d72022-02-11 21:43:506860 def _ValidateIcuSyntax(text, level, signatures):
6861 """Validates ICU syntax of a text string.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146862
Sam Maiera6e76d72022-02-11 21:43:506863 Check if text looks similar to ICU and checks for ICU syntax correctness
6864 in this case. Reports various issues with ICU syntax and values of
6865 variants. Supports checking of nested messages. Accumulate information of
6866 each ICU messages found in the text for further checking.
Rainhard Findlingfc31844c52020-05-15 09:58:266867
Sam Maiera6e76d72022-02-11 21:43:506868 Args:
6869 text: a string to check.
6870 level: a number of current nesting level.
6871 signatures: an accumulator, a list of tuple of (level, variable,
6872 kind, variants).
Rainhard Findlingfc31844c52020-05-15 09:58:266873
Sam Maiera6e76d72022-02-11 21:43:506874 Returns:
6875 None if a string is not ICU or no issue detected.
6876 A tuple of (message, start index, end index) if an issue detected.
6877 """
6878 valid_types = {
6879 'plural': (frozenset(
Rainhard Findling3cde3ef02024-02-05 18:40:326880 ['=0', '=1', '=2', '=3', 'zero', 'one', 'two', 'few', 'many',
Sam Maiera6e76d72022-02-11 21:43:506881 'other']), frozenset(['=1', 'other'])),
6882 'selectordinal': (frozenset(
Rainhard Findling3cde3ef02024-02-05 18:40:326883 ['=0', '=1', '=2', '=3', 'zero', 'one', 'two', 'few', 'many',
Sam Maiera6e76d72022-02-11 21:43:506884 'other']), frozenset(['one', 'other'])),
6885 'select': (frozenset(), frozenset(['other'])),
6886 }
Rainhard Findlingfc31844c52020-05-15 09:58:266887
Sam Maiera6e76d72022-02-11 21:43:506888 # Check if the message looks like an attempt to use ICU
6889 # plural. If yes - check if its syntax strictly matches ICU format.
6890 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b',
6891 text)
6892 if not like:
6893 signatures.append((level, None, None, None))
6894 return
Rainhard Findlingfc31844c52020-05-15 09:58:266895
Sam Maiera6e76d72022-02-11 21:43:506896 # Check for valid prefix and suffix
6897 m = re.match(
6898 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
6899 r'(plural|selectordinal|select),\s*'
6900 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
6901 if not m:
6902 return (('This message looks like an ICU plural, '
6903 'but does not follow ICU syntax.'), like.start(),
6904 like.end())
6905 starting, variable, kind, variant_pairs = m.groups()
6906 variants, depth, last_pos = _ParseIcuVariants(variant_pairs,
6907 m.start(4))
6908 if depth:
6909 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
6910 len(text))
6911 first = text[0]
6912 ending = text[last_pos:]
6913 if not starting:
6914 return ('Invalid ICU format. No initial opening bracket',
6915 last_pos - 1, last_pos)
6916 if not ending or '}' not in ending:
6917 return ('Invalid ICU format. No final closing bracket',
6918 last_pos - 1, last_pos)
6919 elif first != '{':
6920 return ((
6921 'Invalid ICU format. Extra characters at the start of a complex '
6922 'message (go/icu-message-migration): "%s"') % starting, 0,
6923 len(starting))
6924 elif ending != '}':
6925 return ((
6926 'Invalid ICU format. Extra characters at the end of a complex '
6927 'message (go/icu-message-migration): "%s"') % ending,
6928 last_pos - 1, len(text) - 1)
6929 if kind not in valid_types:
6930 return (('Unknown ICU message type %s. '
6931 'Valid types are: plural, select, selectordinal') % kind,
6932 0, 0)
6933 known, required = valid_types[kind]
6934 defined_variants = set()
6935 for variant, variant_range, value, value_range in variants:
6936 start, end = variant_range
6937 if variant in defined_variants:
6938 return ('Variant "%s" is defined more than once' % variant,
6939 start, end)
6940 elif known and variant not in known:
6941 return ('Variant "%s" is not valid for %s message' %
6942 (variant, kind), start, end)
6943 defined_variants.add(variant)
6944 # Check for nested structure
6945 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
6946 if res:
6947 return (res[0], res[1] + value_range[0] + 1,
6948 res[2] + value_range[0] + 1)
6949 missing = required - defined_variants
6950 if missing:
6951 return ('Required variants missing: %s' % ', '.join(missing), 0,
6952 len(text))
6953 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:266954
Sam Maiera6e76d72022-02-11 21:43:506955 def _ParseIcuVariants(text, offset=0):
6956 """Parse variants part of ICU complex message.
Rainhard Findlingfc31844c52020-05-15 09:58:266957
Sam Maiera6e76d72022-02-11 21:43:506958 Builds a tuple of variant names and values, as well as
6959 their offsets in the input string.
Rainhard Findlingfc31844c52020-05-15 09:58:266960
Sam Maiera6e76d72022-02-11 21:43:506961 Args:
6962 text: a string to parse
6963 offset: additional offset to add to positions in the text to get correct
6964 position in the complete ICU string.
Rainhard Findlingfc31844c52020-05-15 09:58:266965
Sam Maiera6e76d72022-02-11 21:43:506966 Returns:
6967 List of tuples, each tuple consist of four fields: variant name,
6968 variant name span (tuple of two integers), variant value, value
6969 span (tuple of two integers).
6970 """
6971 depth, start, end = 0, -1, -1
6972 variants = []
6973 key = None
6974 for idx, char in enumerate(text):
6975 if char == '{':
6976 if not depth:
6977 start = idx
6978 chunk = text[end + 1:start]
6979 key = chunk.strip()
6980 pos = offset + end + 1 + chunk.find(key)
6981 span = (pos, pos + len(key))
6982 depth += 1
6983 elif char == '}':
6984 if not depth:
6985 return variants, depth, offset + idx
6986 depth -= 1
6987 if not depth:
6988 end = idx
6989 variants.append((key, span, text[start:end + 1],
6990 (offset + start, offset + end + 1)))
6991 return variants, depth, offset + end + 1
Rainhard Findlingfc31844c52020-05-15 09:58:266992
Terrence Reilly313f44ff2025-01-22 15:10:146993 old_sys_path = sys.path
Sam Maiera6e76d72022-02-11 21:43:506994 try:
Sam Maiera6e76d72022-02-11 21:43:506995 sys.path = sys.path + [
6996 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
6997 'translation')
6998 ]
6999 from helper import grd_helper
7000 finally:
7001 sys.path = old_sys_path
Rainhard Findlingfc31844c52020-05-15 09:58:267002
Sam Maiera6e76d72022-02-11 21:43:507003 for f in affected_grds:
7004 file_path = f.LocalPath()
7005 old_id_to_msg_map = {}
7006 new_id_to_msg_map = {}
7007 # Note that this code doesn't check if the file has been deleted. This is
7008 # OK because it only uses the old and new file contents and doesn't load
7009 # the file via its path.
7010 # It's also possible that a file's content refers to a renamed or deleted
7011 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
7012 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
7013 # .grdp files.
7014 if file_path.endswith('.grdp'):
7015 if f.OldContents():
7016 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
7017 '\n'.join(f.OldContents()))
7018 if f.NewContents():
7019 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
7020 '\n'.join(f.NewContents()))
7021 else:
7022 file_dir = input_api.os_path.dirname(file_path) or '.'
7023 if f.OldContents():
7024 old_id_to_msg_map = grd_helper.GetGrdMessages(
7025 StringIO('\n'.join(f.OldContents())), file_dir)
7026 if f.NewContents():
7027 new_id_to_msg_map = grd_helper.GetGrdMessages(
7028 StringIO('\n'.join(f.NewContents())), file_dir)
Rainhard Findlingfc31844c52020-05-15 09:58:267029
Sam Maiera6e76d72022-02-11 21:43:507030 grd_name, ext = input_api.os_path.splitext(
7031 input_api.os_path.basename(file_path))
7032 screenshots_dir = input_api.os_path.join(
7033 input_api.os_path.dirname(file_path),
7034 grd_name + ext.replace('.', '_'))
Rainhard Findlingfc31844c52020-05-15 09:58:267035
Sam Maiera6e76d72022-02-11 21:43:507036 # Compute added, removed and modified message IDs.
7037 old_ids = set(old_id_to_msg_map)
7038 new_ids = set(new_id_to_msg_map)
7039 added_ids = new_ids - old_ids
7040 removed_ids = old_ids - new_ids
7041 modified_ids = set([])
7042 for key in old_ids.intersection(new_ids):
7043 if (old_id_to_msg_map[key].ContentsAsXml('', True) !=
7044 new_id_to_msg_map[key].ContentsAsXml('', True)):
7045 # The message content itself changed. Require an updated screenshot.
7046 modified_ids.add(key)
7047 elif old_id_to_msg_map[key].attrs['meaning'] != \
7048 new_id_to_msg_map[key].attrs['meaning']:
Jens Mueller054652c2023-05-10 15:12:307049 # The message meaning changed. We later check for a screenshot.
7050 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147051
Sam Maiera6e76d72022-02-11 21:43:507052 if run_screenshot_check:
7053 # Check the screenshot directory for .png files. Warn if there is any.
7054 for png_path in affected_png_paths:
7055 if png_path.startswith(screenshots_dir):
7056 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147057
Sam Maiera6e76d72022-02-11 21:43:507058 for added_id in added_ids:
7059 _CheckScreenshotAdded(screenshots_dir, added_id)
Rainhard Findlingd8d04372020-08-13 13:30:097060
Sam Maiera6e76d72022-02-11 21:43:507061 for modified_id in modified_ids:
Bruce Dawson55776c42022-12-09 17:23:477062 _CheckScreenshotModified(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147063
Sam Maiera6e76d72022-02-11 21:43:507064 for removed_id in removed_ids:
7065 _CheckScreenshotRemoved(screenshots_dir, removed_id)
7066
7067 # Check new and changed strings for ICU syntax errors.
7068 for key in added_ids.union(modified_ids):
7069 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
7070 err = _ValidateIcuSyntax(msg, 0, [])
7071 if err is not None:
7072 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
7073
7074 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:267075 if run_screenshot_check:
Sam Maiera6e76d72022-02-11 21:43:507076 if unnecessary_screenshots:
7077 results.append(
7078 output_api.PresubmitError(
7079 'Do not include actual screenshots in the changelist. Run '
7080 'tools/translate/upload_screenshots.py to upload them instead:',
7081 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147082
Sam Maiera6e76d72022-02-11 21:43:507083 if missing_sha1:
7084 results.append(
7085 output_api.PresubmitError(
Bruce Dawson55776c42022-12-09 17:23:477086 'You are adding UI strings.\n'
Sam Maiera6e76d72022-02-11 21:43:507087 'To ensure the best translations, take screenshots of the relevant UI '
7088 '(https://g.co/chrome/translation) and add these files to your '
7089 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147090
Jens Mueller054652c2023-05-10 15:12:307091 if invalid_sha1:
7092 results.append(
7093 output_api.PresubmitError(
7094 'The following files do not seem to contain valid sha1 hashes. '
7095 'Make sure they contain hashes created by '
7096 'tools/translate/upload_screenshots.py:', sorted(invalid_sha1)))
7097
Bruce Dawson55776c42022-12-09 17:23:477098 if missing_sha1_modified:
7099 results.append(
7100 output_api.PresubmitError(
7101 'You are modifying UI strings or their meanings.\n'
7102 'To ensure the best translations, take screenshots of the relevant UI '
7103 '(https://g.co/chrome/translation) and add these files to your '
7104 'changelist:', sorted(missing_sha1_modified)))
7105
Sam Maiera6e76d72022-02-11 21:43:507106 if unnecessary_sha1_files:
7107 results.append(
7108 output_api.PresubmitError(
7109 'You removed strings associated with these files. Remove:',
7110 sorted(unnecessary_sha1_files)))
7111 else:
7112 results.append(
7113 output_api.PresubmitPromptOrNotify('Skipping translation '
7114 'screenshots check.'))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147115
Sam Maiera6e76d72022-02-11 21:43:507116 if icu_syntax_errors:
7117 results.append(
7118 output_api.PresubmitPromptWarning(
7119 'ICU syntax errors were found in the following strings (problems or '
7120 'feedback? Contact [email protected]):',
7121 items=icu_syntax_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:267122
Sam Maiera6e76d72022-02-11 21:43:507123 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:127124
7125
Saagar Sanghavifceeaae2020-08-12 16:40:367126def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:127127 repo_root=None,
7128 translation_expectations_path=None,
7129 grd_files=None):
Sam Maiera6e76d72022-02-11 21:43:507130 import sys
7131 affected_grds = [
7132 f for f in input_api.AffectedFiles()
7133 if (f.LocalPath().endswith('.grd') or f.LocalPath().endswith('.grdp'))
7134 ]
7135 if not affected_grds:
7136 return []
7137
Terrence Reilly313f44ff2025-01-22 15:10:147138 old_sys_path = sys.path
Sam Maiera6e76d72022-02-11 21:43:507139 try:
Sam Maiera6e76d72022-02-11 21:43:507140 sys.path = sys.path + [
7141 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
7142 'translation')
7143 ]
Terrence Reilly313f44ff2025-01-22 15:10:147144 sys.path = sys.path + [
7145 input_api.os_path.join(input_api.PresubmitLocalPath(),
7146 'third_party', 'depot_tools')
7147 ]
Sam Maiera6e76d72022-02-11 21:43:507148 from helper import git_helper
7149 from helper import translation_helper
Terrence Reilly313f44ff2025-01-22 15:10:147150 import gclient_utils
Sam Maiera6e76d72022-02-11 21:43:507151 finally:
7152 sys.path = old_sys_path
7153
7154 # Check that translation expectations can be parsed and we can get a list of
7155 # translatable grd files. |repo_root| and |translation_expectations_path| are
7156 # only passed by tests.
7157 if not repo_root:
7158 repo_root = input_api.PresubmitLocalPath()
7159 if not translation_expectations_path:
7160 translation_expectations_path = input_api.os_path.join(
7161 repo_root, 'tools', 'gritsettings', 'translation_expectations.pyl')
Terrence Reilly313f44ff2025-01-22 15:10:147162 is_cog = gclient_utils.IsEnvCog()
7163 # Git is not available in cog workspaces.
7164 if not grd_files and not is_cog:
Sam Maiera6e76d72022-02-11 21:43:507165 grd_files = git_helper.list_grds_in_repository(repo_root)
Terrence Reilly313f44ff2025-01-22 15:10:147166 if not grd_files:
7167 grd_files = []
Sam Maiera6e76d72022-02-11 21:43:507168
7169 # Ignore bogus grd files used only for testing
Gao Shenga79ebd42022-08-08 17:25:597170 # ui/webui/resources/tools/generate_grd.py.
Sam Maiera6e76d72022-02-11 21:43:507171 ignore_path = input_api.os_path.join('ui', 'webui', 'resources', 'tools',
7172 'tests')
7173 grd_files = [p for p in grd_files if ignore_path not in p]
7174
7175 try:
7176 translation_helper.get_translatable_grds(
Terrence Reilly313f44ff2025-01-22 15:10:147177 repo_root, grd_files, translation_expectations_path, is_cog)
Sam Maiera6e76d72022-02-11 21:43:507178 except Exception as e:
7179 return [
7180 output_api.PresubmitNotifyResult(
7181 'Failed to get a list of translatable grd files. This happens when:\n'
7182 ' - One of the modified grd or grdp files cannot be parsed or\n'
7183 ' - %s is not updated.\n'
7184 'Stack:\n%s' % (translation_expectations_path, str(e)))
7185 ]
Mustafa Emre Acer51f2f742020-03-09 19:41:127186 return []
7187
Ken Rockotc31f4832020-05-29 18:58:517188
Saagar Sanghavifceeaae2020-08-12 16:40:367189def CheckStableMojomChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507190 """Changes to [Stable] mojom types must preserve backward-compatibility."""
7191 changed_mojoms = input_api.AffectedFiles(
7192 include_deletes=True,
7193 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:527194
Bruce Dawson344ab262022-06-04 11:35:107195 if not changed_mojoms or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:507196 return []
7197
7198 delta = []
7199 for mojom in changed_mojoms:
Sam Maiera6e76d72022-02-11 21:43:507200 delta.append({
7201 'filename': mojom.LocalPath(),
7202 'old': '\n'.join(mojom.OldContents()) or None,
7203 'new': '\n'.join(mojom.NewContents()) or None,
7204 })
7205
7206 process = input_api.subprocess.Popen([
Takuto Ikutadca10222022-04-13 02:51:217207 input_api.python3_executable,
Sam Maiera6e76d72022-02-11 21:43:507208 input_api.os_path.join(
7209 input_api.PresubmitLocalPath(), 'mojo', 'public', 'tools', 'mojom',
7210 'check_stable_mojom_compatibility.py'), '--src-root',
7211 input_api.PresubmitLocalPath()
7212 ],
7213 stdin=input_api.subprocess.PIPE,
7214 stdout=input_api.subprocess.PIPE,
7215 stderr=input_api.subprocess.PIPE,
7216 universal_newlines=True)
7217 (x, error) = process.communicate(input=input_api.json.dumps(delta))
7218 if process.returncode:
7219 return [
7220 output_api.PresubmitError(
7221 'One or more [Stable] mojom definitions appears to have been changed '
Alex Goughc99921652024-02-15 22:59:127222 'in a way that is not backward-compatible. See '
7223 'https://chromium.googlesource.com/chromium/src/+/HEAD/mojo/public/tools/bindings/README.md#versioning'
7224 ' for details.',
Sam Maiera6e76d72022-02-11 21:43:507225 long_text=error)
7226 ]
Erik Staabc734cd7a2021-11-23 03:11:527227 return []
7228
Dominic Battre645d42342020-12-04 16:14:107229def CheckDeprecationOfPreferences(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507230 """Removing a preference should come with a deprecation."""
Dominic Battre645d42342020-12-04 16:14:107231
Sam Maiera6e76d72022-02-11 21:43:507232 def FilterFile(affected_file):
7233 """Accept only .cc files and the like."""
7234 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
7235 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
7236 input_api.DEFAULT_FILES_TO_SKIP)
7237 return input_api.FilterSourceFile(
7238 affected_file,
7239 files_to_check=file_inclusion_pattern,
7240 files_to_skip=files_to_skip)
Dominic Battre645d42342020-12-04 16:14:107241
Sam Maiera6e76d72022-02-11 21:43:507242 def ModifiedLines(affected_file):
7243 """Returns a list of tuples (line number, line text) of added and removed
7244 lines.
Dominic Battre645d42342020-12-04 16:14:107245
Sam Maiera6e76d72022-02-11 21:43:507246 Deleted lines share the same line number as the previous line.
Dominic Battre645d42342020-12-04 16:14:107247
Sam Maiera6e76d72022-02-11 21:43:507248 This relies on the scm diff output describing each changed code section
7249 with a line of the form
Dominic Battre645d42342020-12-04 16:14:107250
Sam Maiera6e76d72022-02-11 21:43:507251 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
7252 """
7253 line_num = 0
7254 modified_lines = []
7255 for line in affected_file.GenerateScmDiff().splitlines():
7256 # Extract <new line num> of the patch fragment (see format above).
7257 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@',
7258 line)
7259 if m:
7260 line_num = int(m.groups(1)[0])
7261 continue
7262 if ((line.startswith('+') and not line.startswith('++'))
7263 or (line.startswith('-') and not line.startswith('--'))):
7264 modified_lines.append((line_num, line))
Dominic Battre645d42342020-12-04 16:14:107265
Sam Maiera6e76d72022-02-11 21:43:507266 if not line.startswith('-'):
7267 line_num += 1
7268 return modified_lines
Dominic Battre645d42342020-12-04 16:14:107269
Sam Maiera6e76d72022-02-11 21:43:507270 def FindLineWith(lines, needle):
7271 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
Dominic Battre645d42342020-12-04 16:14:107272
Sam Maiera6e76d72022-02-11 21:43:507273 If 0 or >1 lines contain `needle`, -1 is returned.
7274 """
7275 matching_line_numbers = [
7276 # + 1 for 1-based counting of line numbers.
7277 i + 1 for i, line in enumerate(lines) if needle in line
7278 ]
7279 return matching_line_numbers[0] if len(
7280 matching_line_numbers) == 1 else -1
Dominic Battre645d42342020-12-04 16:14:107281
Sam Maiera6e76d72022-02-11 21:43:507282 def ModifiedPrefMigration(affected_file):
7283 """Returns whether the MigrateObsolete.*Pref functions were modified."""
7284 # Determine first and last lines of MigrateObsolete.*Pref functions.
7285 new_contents = affected_file.NewContents()
7286 range_1 = (FindLineWith(new_contents,
7287 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
7288 FindLineWith(new_contents,
7289 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
7290 range_2 = (FindLineWith(new_contents,
7291 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
7292 FindLineWith(new_contents,
7293 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
7294 if (-1 in range_1 + range_2):
7295 raise Exception(
7296 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.'
7297 )
Dominic Battre645d42342020-12-04 16:14:107298
Sam Maiera6e76d72022-02-11 21:43:507299 # Check whether any of the modified lines are part of the
7300 # MigrateObsolete.*Pref functions.
7301 for line_nr, line in ModifiedLines(affected_file):
7302 if (range_1[0] <= line_nr <= range_1[1]
7303 or range_2[0] <= line_nr <= range_2[1]):
7304 return True
7305 return False
Dominic Battre645d42342020-12-04 16:14:107306
Sam Maiera6e76d72022-02-11 21:43:507307 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
7308 browser_prefs_file_pattern = input_api.re.compile(
7309 r'chrome/browser/prefs/browser_prefs.cc')
Dominic Battre645d42342020-12-04 16:14:107310
Sam Maiera6e76d72022-02-11 21:43:507311 changes = input_api.AffectedFiles(include_deletes=True,
7312 file_filter=FilterFile)
7313 potential_problems = []
7314 for f in changes:
7315 for line in f.GenerateScmDiff().splitlines():
7316 # Check deleted lines for pref registrations.
7317 if (line.startswith('-') and not line.startswith('--')
7318 and register_pref_pattern.search(line)):
7319 potential_problems.append('%s: %s' % (f.LocalPath(), line))
Dominic Battre645d42342020-12-04 16:14:107320
Sam Maiera6e76d72022-02-11 21:43:507321 if browser_prefs_file_pattern.search(f.LocalPath()):
7322 # If the developer modified the MigrateObsolete.*Prefs() functions, we
7323 # assume that they knew that they have to deprecate preferences and don't
7324 # warn.
7325 try:
7326 if ModifiedPrefMigration(f):
7327 return []
7328 except Exception as e:
7329 return [output_api.PresubmitError(str(e))]
Dominic Battre645d42342020-12-04 16:14:107330
Sam Maiera6e76d72022-02-11 21:43:507331 if potential_problems:
7332 return [
7333 output_api.PresubmitPromptWarning(
7334 'Discovered possible removal of preference registrations.\n\n'
7335 'Please make sure to properly deprecate preferences by clearing their\n'
7336 'value for a couple of milestones before finally removing the code.\n'
7337 'Otherwise data may stay in the preferences files forever. See\n'
7338 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
7339 'chrome/browser/prefs/README.md for examples.\n'
7340 'This may be a false positive warning (e.g. if you move preference\n'
7341 'registrations to a different place).\n', potential_problems)
7342 ]
7343 return []
7344
Matt Stark6ef08872021-07-29 01:21:467345
7346def CheckConsistentGrdChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507347 """Changes to GRD files must be consistent for tools to read them."""
7348 changed_grds = input_api.AffectedFiles(
7349 include_deletes=False,
7350 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
7351 errors = []
7352 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
7353 for matcher, msg in _INVALID_GRD_FILE_LINE]
7354 for grd in changed_grds:
7355 for i, line in enumerate(grd.NewContents()):
7356 for matcher, msg in invalid_file_regexes:
7357 if matcher.search(line):
7358 errors.append(
7359 output_api.PresubmitError(
7360 'Problem on {grd}:{i} - {msg}'.format(
7361 grd=grd.LocalPath(), i=i + 1, msg=msg)))
7362 return errors
7363
Kevin McNee967dd2d22021-11-15 16:09:297364
Henrique Ferreiro2a4b55942021-11-29 23:45:367365def CheckAssertAshOnlyCode(input_api, output_api):
7366 """Errors if a BUILD.gn file in an ash/ directory doesn't include
Georg Neis94f87f02024-10-22 08:20:137367 assert(is_chromeos).
7368 For a transition period, assert(is_chromeos_ash) is also accepted.
Henrique Ferreiro2a4b55942021-11-29 23:45:367369 """
7370
7371 def FileFilter(affected_file):
7372 """Includes directories known to be Ash only."""
7373 return input_api.FilterSourceFile(
7374 affected_file,
7375 files_to_check=(
7376 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
7377 r'.*/ash/.*BUILD\.gn'), # Any path component.
7378 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
7379
7380 errors = []
Georg Neis94f87f02024-10-22 08:20:137381 pattern = input_api.re.compile(r'assert\(is_chromeos(_ash)?\b')
Jameson Thies0ce669f2021-12-09 15:56:567382 for f in input_api.AffectedFiles(include_deletes=False,
7383 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:367384 if (not pattern.search(input_api.ReadFile(f))):
7385 errors.append(
7386 output_api.PresubmitError(
Georg Neis94f87f02024-10-22 08:20:137387 'Please add assert(is_chromeos) to %s. If that\'s not '
7388 'possible, please create an issue and add a comment such '
Alison Galed6b25fe2024-04-17 13:59:047389 'as:\n # TODO(crbug.com/XXX): add '
Georg Neis94f87f02024-10-22 08:20:137390 'assert(is_chromeos) when ...' % f.LocalPath()))
Henrique Ferreiro2a4b55942021-11-29 23:45:367391 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:277392
7393
Kalvin Lee84ad17a2023-09-25 11:14:417394def _IsMiraclePtrDisallowed(input_api, affected_file):
Anton Bershanskyi4253349482025-02-11 21:01:277395 path = affected_file.UnixLocalPath()
Sam Maiera6e76d72022-02-11 21:43:507396 if not _IsCPlusPlusFile(input_api, path):
7397 return False
7398
Bartek Nowierski49b1a452024-06-08 00:24:357399 # Renderer-only code is generally allowed to use MiraclePtr. These
7400 # directories, however, are specifically disallowed, for perf reasons.
Kalvin Lee84ad17a2023-09-25 11:14:417401 if ("third_party/blink/renderer/core/" in path
7402 or "third_party/blink/renderer/platform/heap/" in path
Bartek Nowierski49b1a452024-06-08 00:24:357403 or "third_party/blink/renderer/platform/wtf/" in path
7404 or "third_party/blink/renderer/platform/fonts/" in path):
7405 return True
7406
7407 # The below paths are an explicitly listed subset of Renderer-only code,
7408 # because the plan is to Oilpanize it.
7409 # TODO(crbug.com/330759291): Remove once Oilpanization is completed or
7410 # abandoned.
7411 if ("third_party/blink/renderer/core/paint/" in path
7412 or "third_party/blink/renderer/platform/graphics/compositing/" in path
7413 or "third_party/blink/renderer/platform/graphics/paint/" in path):
Sam Maiera6e76d72022-02-11 21:43:507414 return True
7415
Sam Maiera6e76d72022-02-11 21:43:507416 # We assume that everything else may be used outside of Renderer processes.
Lukasz Anforowicz7016d05e2021-11-30 03:56:277417 return False
7418
Alison Galed6b25fe2024-04-17 13:59:047419# TODO(crbug.com/40206238): Remove these checks, once they are replaced
Lukasz Anforowicz7016d05e2021-11-30 03:56:277420# by the Chromium Clang Plugin (which will be preferable because it will
7421# 1) report errors earlier - at compile-time and 2) cover more rules).
7422def CheckRawPtrUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507423 """Rough checks that raw_ptr<T> usage guidelines are followed."""
7424 errors = []
7425 # The regex below matches "raw_ptr<" following a word boundary, but not in a
7426 # C++ comment.
7427 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
Kalvin Lee84ad17a2023-09-25 11:14:417428 file_filter = lambda f: _IsMiraclePtrDisallowed(input_api, f)
Sam Maiera6e76d72022-02-11 21:43:507429 for f, line_num, line in input_api.RightHandSideLines(file_filter):
7430 if raw_ptr_matcher.search(line):
7431 errors.append(
7432 output_api.PresubmitError(
7433 'Problem on {path}:{line} - '\
Kalvin Lee84ad17a2023-09-25 11:14:417434 'raw_ptr<T> should not be used in this renderer code '\
Sam Maiera6e76d72022-02-11 21:43:507435 '(as documented in the "Pointers to unprotected memory" '\
7436 'section in //base/memory/raw_ptr.md)'.format(
7437 path=f.LocalPath(), line=line_num)))
7438 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:567439
mikt9337567c2023-09-08 18:38:177440def CheckAdvancedMemorySafetyChecksUsage(input_api, output_api):
7441 """Checks that ADVANCED_MEMORY_SAFETY_CHECKS() macro is neither added nor
7442 removed as it is managed by the memory safety team internally.
7443 Do not add / remove it manually."""
7444 paths = set([])
7445 # The regex below matches "ADVANCED_MEMORY_SAFETY_CHECKS(" following a word
7446 # boundary, but not in a C++ comment.
7447 macro_matcher = input_api.re.compile(
7448 r'^((?!//).)*\bADVANCED_MEMORY_SAFETY_CHECKS\(', input_api.re.MULTILINE)
7449 for f in input_api.AffectedFiles():
7450 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
7451 continue
7452 if macro_matcher.search(f.GenerateScmDiff()):
7453 paths.add(f.LocalPath())
7454 if not paths:
7455 return []
7456 return [output_api.PresubmitPromptWarning(
7457 'ADVANCED_MEMORY_SAFETY_CHECKS() macro is managed by ' \
7458 'the memory safety team (chrome-memory-safety@). ' \
7459 'Please contact us to add/delete the uses of the macro.',
7460 paths)]
Henrique Ferreirof9819f2e32021-11-30 13:31:567461
7462def CheckPythonShebang(input_api, output_api):
7463 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
7464 system-wide python.
7465 """
7466 errors = []
7467 sources = lambda affected_file: input_api.FilterSourceFile(
7468 affected_file,
7469 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
7470 r'third_party/blink/web_tests/external/') + input_api.
7471 DEFAULT_FILES_TO_SKIP),
7472 files_to_check=[r'.*\.py$'])
7473 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:277474 for line_num, line in f.ChangedContents():
7475 if line_num == 1 and line.startswith('#!/usr/bin/python'):
7476 errors.append(f.LocalPath())
7477 break
Henrique Ferreirof9819f2e32021-11-30 13:31:567478
7479 result = []
7480 for file in errors:
7481 result.append(
7482 output_api.PresubmitError(
7483 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
7484 file))
7485 return result
James Shen81cc0e22022-06-15 21:10:457486
7487
Andrew Grieve5a66ae72024-12-13 15:21:537488def CheckAndroidTestAnnotations(input_api, output_api):
James Shen81cc0e22022-06-15 21:10:457489 """Checks that tests have either @Batch or @DoNotBatch annotation. If this
7490 is not an instrumentation test, disregard."""
7491
7492 batch_annotation = input_api.re.compile(r'^\s*@Batch')
7493 do_not_batch_annotation = input_api.re.compile(r'^\s*@DoNotBatch')
Andrew Grieve5a66ae72024-12-13 15:21:537494 robolectric_test = input_api.re.compile(r'@RunWith\((.*?)RobolectricTestRunner')
James Shen81cc0e22022-06-15 21:10:457495 test_class_declaration = input_api.re.compile(r'^\s*public\sclass.*Test')
7496 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
Mark Schillaci8ef0d872023-07-18 22:07:597497 test_annotation_declaration = input_api.re.compile(r'^\s*public\s@interface\s.*{')
James Shen81cc0e22022-06-15 21:10:457498
ckitagawae8fd23b2022-06-17 15:29:387499 missing_annotation_errors = []
7500 extra_annotation_errors = []
Andrew Grieve5a66ae72024-12-13 15:21:537501 wrong_robolectric_test_runner_errors = []
James Shen81cc0e22022-06-15 21:10:457502
7503 def _FilterFile(affected_file):
7504 return input_api.FilterSourceFile(
7505 affected_file,
7506 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
7507 files_to_check=[r'.*Test\.java$'])
7508
7509 for f in input_api.AffectedSourceFiles(_FilterFile):
7510 batch_matched = None
7511 do_not_batch_matched = None
7512 is_instrumentation_test = True
Mark Schillaci8ef0d872023-07-18 22:07:597513 test_annotation_declaration_matched = None
Andrew Grieve5a66ae72024-12-13 15:21:537514 has_base_robolectric_rule = False
James Shen81cc0e22022-06-15 21:10:457515 for line in f.NewContents():
Andrew Grieve5a66ae72024-12-13 15:21:537516 if 'BaseRobolectricTestRule' in line:
7517 has_base_robolectric_rule = True
7518 continue
7519 if m := robolectric_test.search(line):
7520 is_instrumentation_test = False
7521 if m.group(1) == '' and not has_base_robolectric_rule:
7522 path = str(f.LocalPath())
7523 # These two spots cannot use it.
7524 if 'webapk' not in path and 'build' not in path:
7525 wrong_robolectric_test_runner_errors.append(path)
7526 break
7527 if uiautomator_test.search(line):
James Shen81cc0e22022-06-15 21:10:457528 is_instrumentation_test = False
7529 break
7530 if not batch_matched:
7531 batch_matched = batch_annotation.search(line)
7532 if not do_not_batch_matched:
7533 do_not_batch_matched = do_not_batch_annotation.search(line)
7534 test_class_declaration_matched = test_class_declaration.search(
7535 line)
Mark Schillaci8ef0d872023-07-18 22:07:597536 test_annotation_declaration_matched = test_annotation_declaration.search(line)
7537 if test_class_declaration_matched or test_annotation_declaration_matched:
James Shen81cc0e22022-06-15 21:10:457538 break
Mark Schillaci8ef0d872023-07-18 22:07:597539 if test_annotation_declaration_matched:
7540 continue
James Shen81cc0e22022-06-15 21:10:457541 if (is_instrumentation_test and
7542 not batch_matched and
7543 not do_not_batch_matched):
Sam Maier4cef9242022-10-03 14:21:247544 missing_annotation_errors.append(str(f.LocalPath()))
ckitagawae8fd23b2022-06-17 15:29:387545 if (not is_instrumentation_test and
7546 (batch_matched or
7547 do_not_batch_matched)):
Sam Maier4cef9242022-10-03 14:21:247548 extra_annotation_errors.append(str(f.LocalPath()))
James Shen81cc0e22022-06-15 21:10:457549
7550 results = []
7551
ckitagawae8fd23b2022-06-17 15:29:387552 if missing_annotation_errors:
James Shen81cc0e22022-06-15 21:10:457553 results.append(
7554 output_api.PresubmitPromptWarning(
7555 """
Andrew Grieve43a5cf82023-09-08 15:09:467556A change was made to an on-device test that has neither been annotated with
7557@Batch nor @DoNotBatch. If this is a new test, please add the annotation. If
7558this is an existing test, please consider adding it if you are sufficiently
7559familiar with the test (but do so as a separate change).
7560
Jens Mueller2085ff82023-02-27 11:54:497561See https://source.chromium.org/chromium/chromium/src/+/main:docs/testing/batching_instrumentation_tests.md
ckitagawae8fd23b2022-06-17 15:29:387562""", missing_annotation_errors))
7563 if extra_annotation_errors:
7564 results.append(
7565 output_api.PresubmitPromptWarning(
7566 """
7567Robolectric tests do not need a @Batch or @DoNotBatch annotations.
7568""", extra_annotation_errors))
Andrew Grieve5a66ae72024-12-13 15:21:537569 if wrong_robolectric_test_runner_errors:
7570 results.append(
7571 output_api.PresubmitPromptWarning(
7572 """
Wenyu Fu0005ab82025-01-03 18:13:267573Robolectric tests should use either @RunWith(BaseRobolectricTestRunner.class) (or
Andrew Grieve5a66ae72024-12-13 15:21:537574a subclass of it), or use "@Rule BaseRobolectricTestRule".
7575""", wrong_robolectric_test_runner_errors))
James Shen81cc0e22022-06-15 21:10:457576
7577 return results
Sam Maier4cef9242022-10-03 14:21:247578
7579
Mike Dougherty1b8be712022-10-20 00:15:137580def CheckNoJsInIos(input_api, output_api):
7581 """Checks to make sure that JavaScript files are not used on iOS."""
7582
7583 def _FilterFile(affected_file):
7584 return input_api.FilterSourceFile(
7585 affected_file,
7586 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP +
Daniel White44b8bd02023-08-22 16:20:367587 (r'^ios/third_party/*', r'^ios/tools/*', r'^third_party/*',
7588 r'^components/autofill/ios/form_util/resources/*'),
Mike Dougherty1b8be712022-10-20 00:15:137589 files_to_check=[r'^ios/.*\.js$', r'.*/ios/.*\.js$'])
7590
Mike Dougherty4d1050b2023-03-14 15:59:537591 deleted_files = []
7592
7593 # Collect filenames of all removed JS files.
Arthur Sonzognic66e9c82024-04-23 07:53:047594 for f in input_api.AffectedFiles(file_filter=_FilterFile):
Mike Dougherty4d1050b2023-03-14 15:59:537595 local_path = f.LocalPath()
7596
7597 if input_api.os_path.splitext(local_path)[1] == '.js' and f.Action() == 'D':
7598 deleted_files.append(input_api.os_path.basename(local_path))
7599
Mike Dougherty1b8be712022-10-20 00:15:137600 error_paths = []
Mike Dougherty4d1050b2023-03-14 15:59:537601 moved_paths = []
Mike Dougherty1b8be712022-10-20 00:15:137602 warning_paths = []
7603
7604 for f in input_api.AffectedSourceFiles(_FilterFile):
7605 local_path = f.LocalPath()
7606
7607 if input_api.os_path.splitext(local_path)[1] == '.js':
7608 if f.Action() == 'A':
Mike Dougherty4d1050b2023-03-14 15:59:537609 if input_api.os_path.basename(local_path) in deleted_files:
7610 # This script was probably moved rather than newly created.
7611 # Present a warning instead of an error for these cases.
7612 moved_paths.append(local_path)
7613 else:
7614 error_paths.append(local_path)
Mike Dougherty1b8be712022-10-20 00:15:137615 elif f.Action() != 'D':
7616 warning_paths.append(local_path)
7617
7618 results = []
7619
7620 if warning_paths:
7621 results.append(output_api.PresubmitPromptWarning(
7622 'TypeScript is now fully supported for iOS feature scripts. '
7623 'Consider converting JavaScript files to TypeScript. See '
7624 '//ios/web/public/js_messaging/README.md for more details.',
7625 warning_paths))
7626
Mike Dougherty4d1050b2023-03-14 15:59:537627 if moved_paths:
7628 results.append(output_api.PresubmitPromptWarning(
7629 'Do not use JavaScript on iOS for new files as TypeScript is '
7630 'fully supported. (If this is a moved file, you may leave the '
7631 'script unconverted.) See //ios/web/public/js_messaging/README.md '
7632 'for help using scripts on iOS.', moved_paths))
7633
Mike Dougherty1b8be712022-10-20 00:15:137634 if error_paths:
7635 results.append(output_api.PresubmitError(
7636 'Do not use JavaScript on iOS as TypeScript is fully supported. '
7637 'See //ios/web/public/js_messaging/README.md for help using '
7638 'scripts on iOS.', error_paths))
7639
7640 return results
Hans Wennborg23a81d52023-03-24 16:38:137641
7642def CheckLibcxxRevisionsMatch(input_api, output_api):
7643 """Check to make sure the libc++ version matches across deps files."""
Andrew Grieve21bb6792023-03-27 19:06:487644 # Disable check for changes to sub-repositories.
7645 if input_api.PresubmitLocalPath() != input_api.change.RepositoryRoot():
Sam Maierb926c58c2023-08-08 19:58:257646 return []
Hans Wennborg23a81d52023-03-24 16:38:137647
7648 DEPS_FILES = [ 'DEPS', 'buildtools/deps_revisions.gni' ]
7649
Anton Bershanskyi4253349482025-02-11 21:01:277650 file_filter = lambda f: f.UnixLocalPath() in DEPS_FILES
Hans Wennborg23a81d52023-03-24 16:38:137651 changed_deps_files = input_api.AffectedFiles(file_filter=file_filter)
7652 if not changed_deps_files:
7653 return []
7654
7655 def LibcxxRevision(file):
7656 file = input_api.os_path.join(input_api.PresubmitLocalPath(),
7657 *file.split('/'))
7658 return input_api.re.search(
7659 r'libcxx_revision.*[:=].*[\'"](\w+)[\'"]',
7660 input_api.ReadFile(file)).group(1)
7661
7662 if len(set([LibcxxRevision(f) for f in DEPS_FILES])) == 1:
7663 return []
7664
7665 return [output_api.PresubmitError(
7666 'libcxx_revision not equal across %s' % ', '.join(DEPS_FILES),
7667 changed_deps_files)]
Arthur Sonzogni7109bd32023-10-03 10:34:427668
7669
7670def CheckDanglingUntriaged(input_api, output_api):
7671 """Warn developers adding DanglingUntriaged raw_ptr."""
7672
7673 # Ignore during git presubmit --all.
7674 #
7675 # This would be too costly, because this would check every lines of every
7676 # C++ files. Check from _BANNED_CPP_FUNCTIONS are also reading the whole
7677 # source code, but only once to apply every checks. It seems the bots like
7678 # `win-presubmit` are particularly sensitive to reading the files. Adding
7679 # this check caused the bot to run 2x longer. See https://crbug.com/1486612.
7680 if input_api.no_diffs:
Arthur Sonzogni9eafd222023-11-10 08:50:397681 return []
Arthur Sonzogni7109bd32023-10-03 10:34:427682
7683 def FilterFile(file):
7684 return input_api.FilterSourceFile(
7685 file,
7686 files_to_check=[r".*\.(h|cc|cpp|cxx|m|mm)$"],
7687 files_to_skip=[r"^base/allocator.*"],
7688 )
7689
7690 count = 0
Arthur Sonzognic66e9c82024-04-23 07:53:047691 for f in input_api.AffectedFiles(file_filter=FilterFile):
Arthur Sonzogni9eafd222023-11-10 08:50:397692 count -= sum([l.count("DanglingUntriaged") for l in f.OldContents()])
7693 count += sum([l.count("DanglingUntriaged") for l in f.NewContents()])
Arthur Sonzogni7109bd32023-10-03 10:34:427694
7695 # Most likely, nothing changed:
7696 if count == 0:
7697 return []
7698
7699 # Congrats developers for improving it:
7700 if count < 0:
Arthur Sonzogni9eafd222023-11-10 08:50:397701 message = f"DanglingUntriaged pointers removed: {-count}\nThank you!"
Arthur Sonzogni7109bd32023-10-03 10:34:427702 return [output_api.PresubmitNotifyResult(message)]
7703
7704 # Check for 'DanglingUntriaged-notes' in the description:
7705 notes_regex = input_api.re.compile("DanglingUntriaged-notes[:=]")
7706 if any(
7707 notes_regex.match(line)
7708 for line in input_api.change.DescriptionText().splitlines()):
7709 return []
7710
7711 # Check for DanglingUntriaged-notes in the git footer:
7712 if input_api.change.GitFootersFromDescription().get(
7713 "DanglingUntriaged-notes", []):
7714 return []
7715
7716 message = (
Arthur Sonzogni9eafd222023-11-10 08:50:397717 "Unexpected new occurrences of `DanglingUntriaged` detected. Please\n" +
7718 "avoid adding new ones\n" +
7719 "\n" +
7720 "See documentation:\n" +
7721 "https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr.md\n" +
7722 "\n" +
7723 "See also the guide to fix dangling pointers:\n" +
7724 "https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr_guide.md\n" +
7725 "\n" +
7726 "To disable this warning, please add in the commit description:\n" +
Alex Gough26dcd852023-12-22 16:47:197727 "DanglingUntriaged-notes: <rationale for new untriaged dangling " +
Arthur Sonzogni9eafd222023-11-10 08:50:397728 "pointers>"
Arthur Sonzogni7109bd32023-10-03 10:34:427729 )
7730 return [output_api.PresubmitPromptWarning(message)]
Jan Keitel77be7522023-10-12 20:40:497731
7732def CheckInlineConstexprDefinitionsInHeaders(input_api, output_api):
7733 """Checks that non-static constexpr definitions in headers are inline."""
7734 # In a properly formatted file, constexpr definitions inside classes or
7735 # structs will have additional whitespace at the beginning of the line.
7736 # The pattern looks for variables initialized as constexpr kVar = ...; or
7737 # constexpr kVar{...};
7738 # The pattern does not match expressions that have braces in kVar to avoid
7739 # matching constexpr functions.
7740 pattern = input_api.re.compile(r'^constexpr (?!inline )[^\(\)]*[={]')
7741 attribute_pattern = input_api.re.compile(r'(\[\[[a-zA-Z_:]+\]\]|[A-Z]+[A-Z_]+) ')
7742 problems = []
7743 for f in input_api.AffectedFiles():
7744 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
7745 continue
7746
7747 for line_number, line in f.ChangedContents():
7748 line = attribute_pattern.sub('', line)
7749 if pattern.search(line):
7750 problems.append(
7751 f"{f.LocalPath()}: {line_number}\n {line}")
7752
7753 if problems:
7754 return [
7755 output_api.PresubmitPromptWarning(
7756 'Consider inlining constexpr variable definitions in headers '
7757 'outside of classes to avoid unnecessary copies of the '
7758 'constant. See https://abseil.io/tips/168 for more details.',
7759 problems)
7760 ]
7761 else:
7762 return []
Alison Galed6b25fe2024-04-17 13:59:047763
7764def CheckTodoBugReferences(input_api, output_api):
7765 """Checks that bugs in TODOs use updated issue tracker IDs."""
7766
Manish Goregaokardc9e3512025-02-03 15:30:587767 files_to_skip = ['PRESUBMIT_test.py', r"^third_party/rust/chromium_crates_io/vendor/.*"]
Alison Galed6b25fe2024-04-17 13:59:047768
7769 def _FilterFile(affected_file):
7770 return input_api.FilterSourceFile(
7771 affected_file,
7772 files_to_skip=files_to_skip)
7773
7774 # Monorail bug IDs are all less than or equal to 1524553 so check that all
7775 # bugs in TODOs are greater than that value.
Tom Sepez8e628582025-02-14 02:18:557776 pattern = input_api.re.compile(r'.*\bTODO\([^\)0-9]*([0-9]+)\).*')
Alison Galed6b25fe2024-04-17 13:59:047777 problems = []
7778 for f in input_api.AffectedSourceFiles(_FilterFile):
7779 for line_number, line in f.ChangedContents():
7780 match = pattern.match(line)
7781 if match and int(match.group(1)) <= 1524553:
7782 problems.append(
7783 f"{f.LocalPath()}: {line_number}\n {line}")
7784
7785 if problems:
7786 return [
7787 output_api.PresubmitPromptWarning(
Alison Galecb598de52024-04-26 17:03:257788 'TODOs should use the new Chromium Issue Tracker IDs which can '
7789 'be found by navigating to the bug. See '
7790 'https://crbug.com/336778624 for more details.',
Alison Galed6b25fe2024-04-17 13:59:047791 problems)
7792 ]
7793 else:
7794 return []