blob: 42fa7c4629d722b3b527737c337ae2e9484867d4 [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.', ),
Victor Hugo Vianna Silvad9139fbe2025-03-19 20:59:081072 True,
Victor Hugo Vianna Silva6e84e8d42025-03-19 00:32:001073 [
1074 _THIRD_PARTY_EXCEPT_BLINK
1075 ],
1076 ),
1077 BanRule(
1078 r'/absl::(apply|exchange|forward|in_place|index_sequence|'
1079 r'integer_sequence|make_from_tuple|make_index_sequence|'
1080 r'make_integer_sequence|move)',
1081 ('Abseil\'s util library is banned, use std.', ),
Victor Hugo Vianna Silvad9139fbe2025-03-19 20:59:081082 True,
Victor Hugo Vianna Silva6e84e8d42025-03-19 00:32:001083 [
1084 _THIRD_PARTY_EXCEPT_BLINK
1085 ],
1086 ),
1087 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531088 r'/#include <chrono>',
1089 ('<chrono> is banned. Use base/time instead.', ),
1090 True,
1091 [
1092 # Not an error in third_party folders:
1093 _THIRD_PARTY_EXCEPT_BLINK,
Daniel Cheng566634ff2024-06-29 14:56:531094 # This uses openscreen API depending on std::chrono.
1095 "components/openscreen_platform/task_runner.cc",
1096 ]),
1097 BanRule(
1098 r'/#include <exception>',
1099 ('Exceptions are banned and disabled in Chromium.', ),
1100 True,
1101 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1102 ),
1103 BanRule(
1104 r'/\bstd::function\b',
1105 ('std::function is banned. Use base::{Once,Repeating}Callback instead.',
1106 ),
1107 True,
1108 [
1109 # Has tests that template trait helpers don't unintentionally match
1110 # std::function.
1111 r'base/functional/callback_helpers_unittest\.cc',
1112 # Required to implement interfaces from the third-party perfetto
1113 # library.
1114 r'base/tracing/perfetto_task_runner\.cc',
1115 r'base/tracing/perfetto_task_runner\.h',
1116 # Needed for interop with the third-party nearby library type
1117 # location::nearby::connections::ResultCallback.
Dirk Prankee4df27972025-02-26 18:39:351118 r'chrome/services/sharing/nearby/nearby_connections_conversions\.cc'
Daniel Cheng566634ff2024-06-29 14:56:531119 # Needed for interop with the internal libassistant library.
Dirk Prankee4df27972025-02-26 18:39:351120 r'chromeos/ash/services/libassistant/callback_utils\.h',
Daniel Cheng566634ff2024-06-29 14:56:531121 # Needed for interop with Fuchsia fidl APIs.
Dirk Prankee4df27972025-02-26 18:39:351122 r'fuchsia_web/webengine/browser/context_impl_browsertest\.cc',
1123 r'fuchsia_web/webengine/browser/cookie_manager_impl_unittest\.cc',
1124 r'fuchsia_web/webengine/browser/media_player_impl_unittest\.cc',
Daniel Cheng566634ff2024-06-29 14:56:531125 # Required to interop with interfaces from the third-party ChromeML
1126 # library API.
Dirk Prankee4df27972025-02-26 18:39:351127 r'services/on_device_model/ml/chrome_ml_api\.h',
1128 r'services/on_device_model/ml/on_device_model_executor\.cc',
1129 r'services/on_device_model/ml/on_device_model_executor\.h',
Daniel Cheng566634ff2024-06-29 14:56:531130 # Required to interop with interfaces from the third-party perfetto
1131 # library.
Dirk Prankee4df27972025-02-26 18:39:351132 r'components/tracing/common/etw_consumer_win_unittest\.cc',
1133 r'services/tracing/public/cpp/perfetto/custom_event_recorder\.cc',
1134 r'services/tracing/public/cpp/perfetto/perfetto_traced_process\.cc',
1135 r'services/tracing/public/cpp/perfetto/perfetto_traced_process\.h',
1136 r'services/tracing/public/cpp/perfetto/perfetto_tracing_backend\.cc',
1137 r'services/tracing/public/cpp/perfetto/producer_client\.cc',
1138 r'services/tracing/public/cpp/perfetto/producer_client\.h',
1139 r'services/tracing/public/cpp/perfetto/producer_test_utils\.cc',
1140 r'services/tracing/public/cpp/perfetto/producer_test_utils\.h',
Daniel Cheng566634ff2024-06-29 14:56:531141 # Required for interop with the third-party webrtc library.
Dirk Prankee4df27972025-02-26 18:39:351142 r'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.cc',
1143 r'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.h',
Daniel Cheng566634ff2024-06-29 14:56:531144 # TODO(https://crbug.com/1364577): Various uses that should be
1145 # migrated to something else.
1146 # Should use base::OnceCallback or base::RepeatingCallback.
Dirk Prankee4df27972025-02-26 18:39:351147 r'base/allocator/dispatcher/initializer_unittest\.cc',
1148 r'chrome/browser/ash/accessibility/speech_monitor\.cc',
1149 r'chrome/browser/ash/accessibility/speech_monitor\.h',
1150 r'chrome/browser/ash/login/ash_hud_login_browsertest\.cc',
1151 r'chromecast/base/observer_unittest\.cc',
1152 r'chromecast/browser/cast_web_view\.h',
1153 r'chromecast/public/cast_media_shlib\.h',
1154 r'device/bluetooth/floss/exported_callback_manager\.h',
1155 r'device/bluetooth/floss/floss_dbus_client\.h',
1156 r'device/fido/cable/v2_handshake_unittest\.cc',
1157 r'device/fido/pin\.cc',
1158 r'services/tracing/perfetto/test_utils\.h',
Daniel Cheng566634ff2024-06-29 14:56:531159 # Should use base::FunctionRef.
Dirk Prankee4df27972025-02-26 18:39:351160 r'chrome/browser/media/webrtc/test_stats_dictionary\.cc',
1161 r'chrome/browser/media/webrtc/test_stats_dictionary\.h',
1162 r'chromeos/ash/services/libassistant/device_settings_controller\.cc',
1163 r'components/browser_ui/client_certificate/android/ssl_client_certificate_request\.cc',
1164 r'components/gwp_asan/client/sampling_malloc_shims_unittest\.cc',
1165 r'content/browser/font_unique_name_lookup/font_unique_name_lookup_unittest\.cc',
Daniel Cheng566634ff2024-06-29 14:56:531166 # Does not need std::function at all.
Dirk Prankee4df27972025-02-26 18:39:351167 r'components/omnibox/browser/autocomplete_result\.cc',
1168 r'device/fido/win/webauthn_api\.cc',
1169 r'media/audio/alsa/alsa_util\.cc',
1170 r'media/remoting/stream_provider\.h',
1171 r'sql/vfs_wrapper\.cc',
Daniel Cheng566634ff2024-06-29 14:56:531172 # TODO(https://crbug.com/1364585): Remove usage and exception list
1173 # entries.
Dirk Prankee4df27972025-02-26 18:39:351174 r'extensions/renderer/api/automation/automation_internal_custom_bindings\.cc',
1175 r'extensions/renderer/api/automation/automation_internal_custom_bindings\.h',
Daniel Cheng566634ff2024-06-29 14:56:531176 # TODO(https://crbug.com/1364579): Remove usage and exception list
1177 # entry.
Dirk Prankee4df27972025-02-26 18:39:351178 r'ui/views/controls/focus_ring\.h',
Lei Zhang1f9d9ec42024-06-20 18:42:271179
Daniel Cheng566634ff2024-06-29 14:56:531180 # Various pre-existing uses in //tools that is low-priority to fix.
Dirk Prankee4df27972025-02-26 18:39:351181 r'tools/binary_size/libsupersize/viewer/caspian/diff\.cc',
1182 r'tools/binary_size/libsupersize/viewer/caspian/model\.cc',
1183 r'tools/binary_size/libsupersize/viewer/caspian/model\.h',
1184 r'tools/binary_size/libsupersize/viewer/caspian/tree_builder\.h',
1185 r'tools/clang/base_bind_rewriters/BaseBindRewriters\.cpp',
Daniel Chenge5583e3c2022-09-22 00:19:411186
Daniel Cheng566634ff2024-06-29 14:56:531187 # Not an error in third_party folders.
1188 _THIRD_PARTY_EXCEPT_BLINK
1189 ],
Daniel Bratell609102be2019-03-27 20:53:211190 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151191 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531192 r'/#include <X11/',
1193 ('Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.', ),
1194 True,
1195 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Tom Andersona95e12042020-09-09 23:08:001196 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151197 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531198 r'/\bstd::ratio\b',
1199 ('std::ratio is banned by the Google Style Guide.', ),
1200 True,
1201 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:451202 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151203 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531204 r'/\bstd::aligned_alloc\b',
1205 (
1206 'std::aligned_alloc() is not yet allowed (crbug.com/1412818). Use ',
1207 'base::AlignedAlloc() instead.',
1208 ),
1209 True,
1210 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181211 ),
1212 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531213 r'/#include <(barrier|latch|semaphore|stop_token)>',
1214 ('The thread support library is banned. Use base/synchronization '
1215 'instead.', ),
1216 True,
1217 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181218 ),
1219 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531220 r'/\bstd::execution::(par|seq)\b',
1221 ('std::execution::(par|seq) is banned; they do not fit into '
1222 ' Chrome\'s threading model, and libc++ doesn\'t have full '
mikt19226ff22024-08-27 05:28:211223 'support.', ),
Daniel Cheng566634ff2024-06-29 14:56:531224 True,
1225 [_THIRD_PARTY_EXCEPT_BLINK],
Helmut Januschka7cc8a84f2024-02-07 22:50:411226 ),
1227 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531228 r'/\bstd::bit_cast\b',
1229 ('std::bit_cast is banned; use base::bit_cast instead for values and '
1230 'standard C++ casting when pointers are involved.', ),
1231 True,
1232 [
1233 # Don't warn in third_party folders.
1234 _THIRD_PARTY_EXCEPT_BLINK,
1235 # //base/numerics can't use base or absl.
1236 r'base/numerics/.*'
1237 ],
Avi Drissman70cb7f72023-12-12 17:44:371238 ),
1239 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531240 r'/\bstd::(c8rtomb|mbrtoc8)\b',
1241 ('std::c8rtomb() and std::mbrtoc8() are banned.', ),
1242 True,
1243 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181244 ),
1245 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531246 r'/\bchar8_t|std::u8string\b',
1247 (
1248 'char8_t and std::u8string are not yet allowed. Can you use [unsigned]',
1249 ' char and std::string instead?',
1250 ),
1251 True,
1252 [
1253 # The demangler does not use this type but needs to know about it.
Dirk Prankee4df27972025-02-26 18:39:351254 r'base/third_party/symbolize/demangle\.cc',
Daniel Cheng566634ff2024-06-29 14:56:531255 # Don't warn in third_party folders.
1256 _THIRD_PARTY_EXCEPT_BLINK
1257 ],
Peter Kastinge2c5ee82023-02-15 17:23:081258 ),
1259 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531260 r'/(\b(co_await|co_return|co_yield)\b|#include <coroutine>)',
1261 ('Coroutines are not yet allowed (https://crbug.com/1403840).', ),
1262 True,
1263 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081264 ),
1265 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531266 r'/^\s*(export\s|import\s+["<:\w]|module(;|\s+[:\w]))',
1267 ('Modules are disallowed for now due to lack of toolchain support.', ),
1268 True,
1269 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting69357dc2023-03-14 01:34:291270 ),
1271 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531272 r'/\[\[(\w*::)?no_unique_address\]\]',
1273 (
1274 '[[no_unique_address]] does not work as expected on Windows ',
1275 '(https://crbug.com/1414621). Use NO_UNIQUE_ADDRESS instead.',
1276 ),
1277 True,
1278 [
1279 # NO_UNIQUE_ADDRESS / PA_NO_UNIQUE_ADDRESS provide canonical access.
1280 r'^base/compiler_specific\.h',
1281 r'^base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/compiler_specific\.h',
1282 # Not an error in third_party folders.
1283 _THIRD_PARTY_EXCEPT_BLINK,
1284 ],
Peter Kasting8bc046d22023-11-14 00:38:031285 ),
1286 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531287 r'/#include <format>',
1288 ('<format> is not yet allowed. Use base::StringPrintf() instead.', ),
1289 True,
1290 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081291 ),
1292 BanRule(
Daniel Cheng89719222024-07-04 04:59:291293 pattern='std::views',
1294 explanation=(
1295 'Use of std::views is banned in Chrome. If you need this '
1296 'functionality, please contact [email protected].',
1297 ),
1298 treat_as_error=True,
1299 excluded_paths=[
1300 # Don't warn in third_party folders.
1301 _THIRD_PARTY_EXCEPT_BLINK
1302 ],
1303 ),
1304 BanRule(
1305 # Ban everything except specifically allowlisted constructs.
1306 pattern=r'/std::ranges::(?!' + '|'.join((
1307 # From https://en.cppreference.com/w/cpp/ranges:
1308 # Range access
1309 'begin',
1310 'end',
1311 'cbegin',
1312 'cend',
1313 'rbegin',
1314 'rend',
1315 'crbegin',
1316 'crend',
1317 'size',
1318 'ssize',
1319 'empty',
1320 'data',
1321 'cdata',
1322 # Range primitives
1323 'iterator_t',
1324 'const_iterator_t',
1325 'sentinel_t',
1326 'const_sentinel_t',
1327 'range_difference_t',
1328 'range_size_t',
1329 'range_value_t',
1330 'range_reference_t',
1331 'range_const_reference_t',
1332 'range_rvalue_reference_t',
1333 'range_common_reference_t',
1334 # Dangling iterator handling
1335 'dangling',
1336 'borrowed_iterator_t',
1337 # Banned: borrowed_subrange_t
1338 # Range concepts
1339 'range',
1340 'borrowed_range',
1341 'sized_range',
1342 'view',
1343 'input_range',
1344 'output_range',
1345 'forward_range',
1346 'bidirectional_range',
1347 'random_access_range',
1348 'contiguous_range',
1349 'common_range',
1350 'viewable_range',
1351 'constant_range',
1352 # Banned: Views
1353 # Banned: Range factories
1354 # Banned: Range adaptors
Peter Kastinga7f93752024-10-24 22:15:401355 # Incidentally listed on
1356 # https://en.cppreference.com/w/cpp/header/ranges:
1357 'enable_borrowed_range',
1358 'enable_view',
Daniel Cheng89719222024-07-04 04:59:291359 # From https://en.cppreference.com/w/cpp/algorithm/ranges:
1360 # Constrained algorithms: non-modifying sequence operations
1361 'all_of',
1362 'any_of',
1363 'none_of',
1364 'for_each',
1365 'for_each_n',
1366 'count',
1367 'count_if',
1368 'mismatch',
1369 'equal',
1370 'lexicographical_compare',
1371 'find',
1372 'find_if',
1373 'find_if_not',
1374 'find_end',
1375 'find_first_of',
1376 'adjacent_find',
1377 'search',
1378 'search_n',
1379 # Constrained algorithms: modifying sequence operations
1380 'copy',
1381 'copy_if',
1382 'copy_n',
1383 'copy_backward',
1384 'move',
1385 'move_backward',
1386 'fill',
1387 'fill_n',
1388 'transform',
1389 'generate',
1390 'generate_n',
1391 'remove',
1392 'remove_if',
1393 'remove_copy',
1394 'remove_copy_if',
1395 'replace',
1396 'replace_if',
1397 'replace_copy',
1398 'replace_copy_if',
1399 'swap_ranges',
1400 'reverse',
1401 'reverse_copy',
1402 'rotate',
1403 'rotate_copy',
1404 'shuffle',
1405 'sample',
1406 'unique',
1407 'unique_copy',
1408 # Constrained algorithms: partitioning operations
1409 'is_partitioned',
1410 'partition',
1411 'partition_copy',
1412 'stable_partition',
1413 'partition_point',
1414 # Constrained algorithms: sorting operations
1415 'is_sorted',
1416 'is_sorted_until',
1417 'sort',
1418 'partial_sort',
1419 'partial_sort_copy',
1420 'stable_sort',
1421 'nth_element',
1422 # Constrained algorithms: binary search operations (on sorted ranges)
1423 'lower_bound',
1424 'upper_bound',
1425 'binary_search',
1426 'equal_range',
1427 # Constrained algorithms: set operations (on sorted ranges)
1428 'merge',
1429 'inplace_merge',
1430 'includes',
1431 'set_difference',
1432 'set_intersection',
1433 'set_symmetric_difference',
1434 'set_union',
1435 # Constrained algorithms: heap operations
1436 'is_heap',
1437 'is_heap_until',
1438 'make_heap',
1439 'push_heap',
1440 'pop_heap',
1441 'sort_heap',
1442 # Constrained algorithms: minimum/maximum operations
1443 'max',
1444 'max_element',
1445 'min',
1446 'min_element',
1447 'minmax',
1448 'minmax_element',
1449 'clamp',
1450 # Constrained algorithms: permutation operations
1451 'is_permutation',
1452 'next_permutation',
1453 'prev_premutation',
1454 # Constrained uninitialized memory algorithms
1455 'uninitialized_copy',
1456 'uninitialized_copy_n',
1457 'uninitialized_fill',
1458 'uninitialized_fill_n',
1459 'uninitialized_move',
1460 'uninitialized_move_n',
1461 'uninitialized_default_construct',
1462 'uninitialized_default_construct_n',
1463 'uninitialized_value_construct',
1464 'uninitialized_value_construct_n',
1465 'destroy',
1466 'destroy_n',
1467 'destroy_at',
1468 'construct_at',
1469 # Return types
1470 'in_fun_result',
1471 'in_in_result',
1472 'in_out_result',
1473 'in_in_out_result',
1474 'in_out_out_result',
1475 'min_max_result',
1476 'in_found_result',
Peter Kastingf379c022025-01-13 14:01:001477 # From https://en.cppreference.com/w/cpp/header/functional
1478 'equal_to',
1479 'not_equal_to',
1480 'greater',
1481 'less',
1482 'greater_equal',
1483 'less_equal',
danakj91c715b2024-07-10 13:24:261484 # From https://en.cppreference.com/w/cpp/iterator
1485 'advance',
1486 'distance',
1487 'next',
1488 'prev',
Daniel Cheng89719222024-07-04 04:59:291489 )) + r')\w+',
1490 explanation=(
1491 'Use of range views and associated helpers is banned in Chrome. '
1492 'If you need this functionality, please contact [email protected].',
1493 ),
1494 treat_as_error=True,
1495 excluded_paths=[
1496 # Don't warn in third_party folders.
1497 _THIRD_PARTY_EXCEPT_BLINK
1498 ],
Peter Kastinge2c5ee82023-02-15 17:23:081499 ),
1500 BanRule(
Peter Kasting31879d82024-10-07 20:18:391501 r'/#include <regex>',
1502 ('<regex> is not allowed. Use third_party/re2 instead.',
1503 ),
1504 True,
1505 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1506 ),
1507 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531508 r'/#include <source_location>',
1509 ('<source_location> is not yet allowed. Use base/location.h instead.',
1510 ),
1511 True,
1512 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081513 ),
1514 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531515 r'/\bstd::to_address\b',
1516 (
1517 'std::to_address is banned because it is not guaranteed to be',
1518 'SFINAE-compatible. Use base::to_address from base/types/to_address.h',
1519 'instead.',
1520 ),
1521 True,
1522 [
1523 # Needed in base::to_address implementation.
1524 r'base/types/to_address.h',
1525 _THIRD_PARTY_EXCEPT_BLINK
1526 ], # Not an error in third_party folders.
Nick Diego Yamanee522ae82024-02-27 04:23:221527 ),
1528 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531529 r'/#include <syncstream>',
1530 ('<syncstream> is banned.', ),
1531 True,
1532 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181533 ),
1534 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531535 r'/\bRunMessageLoop\b',
1536 ('RunMessageLoop is deprecated, use RunLoop instead.', ),
1537 False,
1538 (),
Gabriel Charette147335ea2018-03-22 15:59:191539 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151540 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531541 'RunAllPendingInMessageLoop()',
1542 (
1543 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
1544 "if you're convinced you need this.",
1545 ),
1546 False,
1547 (),
Gabriel Charette147335ea2018-03-22 15:59:191548 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151549 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531550 'RunAllPendingInMessageLoop(BrowserThread',
1551 (
1552 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
1553 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
1554 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
1555 'async events instead of flushing threads.',
1556 ),
1557 False,
1558 (),
Gabriel Charette147335ea2018-03-22 15:59:191559 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151560 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531561 r'MessageLoopRunner',
1562 ('MessageLoopRunner is deprecated, use RunLoop instead.', ),
1563 False,
1564 (),
Gabriel Charette147335ea2018-03-22 15:59:191565 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151566 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531567 'GetDeferredQuitTaskForRunLoop',
1568 (
1569 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
1570 "gab@ if you found a use case where this is the only solution.",
1571 ),
1572 False,
1573 (),
Gabriel Charette147335ea2018-03-22 15:59:191574 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151575 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531576 'sqlite3_initialize(',
1577 (
1578 'Instead of calling sqlite3_initialize(), depend on //sql, ',
1579 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
1580 ),
1581 True,
1582 (
1583 r'^sql/initialization\.(cc|h)$',
1584 r'^third_party/sqlite/.*\.(c|cc|h)$',
1585 ),
Victor Costan3653df62018-02-08 21:38:161586 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151587 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531588 'CREATE VIEW',
1589 (
1590 'SQL views are disabled in Chromium feature code',
1591 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-views',
1592 ),
1593 True,
1594 (
1595 _THIRD_PARTY_EXCEPT_BLINK,
1596 # sql/ itself uses views when using memory-mapped IO.
1597 r'^sql/.*',
1598 # Various performance tools that do not build as part of Chrome.
1599 r'^infra/.*',
1600 r'^tools/perf.*',
1601 r'.*perfetto.*',
1602 ),
Austin Sullivand661ab52022-11-16 08:55:151603 ),
1604 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531605 'CREATE VIRTUAL TABLE',
1606 (
1607 'SQL virtual tables are disabled in Chromium feature code',
1608 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-virtual-tables',
1609 ),
1610 True,
1611 (
1612 _THIRD_PARTY_EXCEPT_BLINK,
1613 # sql/ itself uses virtual tables in the recovery module and tests.
1614 r'^sql/.*',
1615 # TODO(https://crbug.com/695592): Remove once WebSQL is deprecated.
1616 r'third_party/blink/web_tests/storage/websql/.*'
1617 # Various performance tools that do not build as part of Chrome.
1618 r'^tools/perf.*',
1619 r'.*perfetto.*',
1620 ),
Austin Sullivand661ab52022-11-16 08:55:151621 ),
1622 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531623 'std::random_shuffle',
1624 ('std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
1625 'base::RandomShuffle instead.'),
1626 True,
1627 (),
tzik5de2157f2018-05-08 03:42:471628 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151629 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531630 'ios/web/public/test/http_server',
1631 ('web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
1632 ),
1633 False,
1634 (),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:241635 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151636 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531637 'GetAddressOf',
1638 ('Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
1639 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
1640 'operator& is generally recommended. So always use operator& instead. ',
1641 'See http://crbug.com/914910 for more conversion guidance.'),
1642 True,
1643 (),
Robert Liao764c9492019-01-24 18:46:281644 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151645 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531646 'SHFileOperation',
1647 ('SHFileOperation was deprecated in Windows Vista, and there are less ',
1648 'complex functions to achieve the same goals. Use IFileOperation for ',
1649 'any esoteric actions instead.'),
1650 True,
1651 (),
Ben Lewisa9514602019-04-29 17:53:051652 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151653 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531654 'StringFromGUID2',
1655 ('StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
1656 'Use base::win::WStringFromGUID instead.'),
1657 True,
1658 (r'/base/win/win_util_unittest.cc', ),
Cliff Smolinsky81951642019-04-30 21:39:511659 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151660 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531661 'StringFromCLSID',
1662 ('StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
1663 'Use base::win::WStringFromGUID instead.'),
1664 True,
1665 (r'/base/win/win_util_unittest.cc', ),
Cliff Smolinsky81951642019-04-30 21:39:511666 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151667 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531668 'kCFAllocatorNull',
1669 (
1670 'The use of kCFAllocatorNull with the NoCopy creation of ',
1671 'CoreFoundation types is prohibited.',
1672 ),
1673 True,
1674 (),
Avi Drissman7382afa02019-04-29 23:27:131675 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151676 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531677 'mojo::ConvertTo',
1678 ('mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1679 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1680 'StringTraits if you would like to convert between custom types and',
1681 'the wire format of mojom types.'),
1682 False,
1683 (
1684 r'^fuchsia_web/webengine/browser/url_request_rewrite_rules_manager\.cc$',
1685 r'^fuchsia_web/webengine/url_request_rewrite_type_converters\.cc$',
1686 r'^third_party/blink/.*\.(cc|h)$',
1687 r'^content/renderer/.*\.(cc|h)$',
1688 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291689 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151690 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531691 'GetInterfaceProvider',
1692 ('InterfaceProvider is deprecated.',
1693 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1694 'or Platform::GetBrowserInterfaceBroker.'),
1695 False,
1696 (),
Oksana Zhuravlovac8222d22019-12-19 19:21:161697 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151698 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531699 'CComPtr',
1700 ('New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1701 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1702 'details.'),
1703 False,
1704 (),
Robert Liao1d78df52019-11-11 20:02:011705 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151706 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531707 r'/\b(IFACE|STD)METHOD_?\(',
1708 ('IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1709 'Instead, always use IFACEMETHODIMP in the declaration.'),
1710 False,
1711 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Xiaohan Wang72bd2ba2020-02-18 21:38:201712 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151713 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531714 'set_owned_by_client',
1715 ('set_owned_by_client is deprecated.',
1716 'views::View already owns the child views by default. This introduces ',
1717 'a competing ownership model which makes the code difficult to reason ',
1718 'about. See http://crbug.com/1044687 for more details.'),
1719 False,
1720 (),
Allen Bauer53b43fb12020-03-12 17:21:471721 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151722 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531723 'RemoveAllChildViewsWithoutDeleting',
1724 ('RemoveAllChildViewsWithoutDeleting is deprecated.',
1725 'This method is deemed dangerous as, unless raw pointers are re-added,',
1726 'calls to this method introduce memory leaks.'),
1727 False,
1728 (),
Peter Boström7ff41522021-07-29 03:43:271729 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151730 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531731 r'/\bTRACE_EVENT_ASYNC_',
1732 (
1733 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1734 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1735 ),
1736 False,
1737 (
1738 r'^base/trace_event/.*',
1739 r'^base/tracing/.*',
1740 ),
Eric Secklerbe6f48d2020-05-06 18:09:121741 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151742 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531743 'RoInitialize',
1744 ('Improper use of [base::win]::RoInitialize() has been implicated in a ',
1745 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
1746 'instead. See http://crbug.com/1197722 for more information.'),
1747 True,
1748 (
1749 r'^base/win/scoped_winrt_initializer\.cc$',
1750 r'^third_party/abseil-cpp/absl/.*',
1751 ),
Robert Liao22f66a52021-04-10 00:57:521752 ),
Patrick Monettec343bb982022-06-01 17:18:451753 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531754 r'base::Watchdog',
1755 (
1756 'base::Watchdog is deprecated because it creates its own thread.',
1757 'Instead, manually start a timer on a SequencedTaskRunner.',
1758 ),
1759 False,
1760 (),
Patrick Monettec343bb982022-06-01 17:18:451761 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091762 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531763 'base::Passed',
1764 ('Do not use base::Passed. It is a legacy helper for capturing ',
1765 'move-only types with base::BindRepeating, but invoking the ',
1766 'resulting RepeatingCallback moves the captured value out of ',
1767 'the callback storage, and subsequent invocations may pass the ',
1768 'value in a valid but undefined state. Prefer base::BindOnce().',
1769 'See http://crbug.com/1326449 for context.'),
1770 False,
1771 (
1772 # False positive, but it is also fine to let bind internals reference
1773 # base::Passed.
1774 r'^base[\\/]functional[\\/]bind\.h',
1775 r'^base[\\/]functional[\\/]bind_internal\.h',
1776 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091777 ),
Daniel Cheng2248b332022-07-27 06:16:591778 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531779 r'base::Feature k',
1780 ('Please use BASE_DECLARE_FEATURE() or BASE_FEATURE() instead of ',
1781 'directly declaring/defining features.'),
1782 True,
1783 [
1784 # Implements BASE_DECLARE_FEATURE().
1785 r'^base/feature_list\.h',
1786 ],
Daniel Chengba3bc2e2022-10-03 02:45:431787 ),
Robert Ogden92101dcb2022-10-19 23:49:361788 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531789 r'/\bchartorune\b',
1790 ('chartorune is not memory-safe, unless you can guarantee the input ',
1791 'string is always null-terminated. Otherwise, please use charntorune ',
1792 'from libphonenumber instead.'),
1793 True,
1794 [
1795 _THIRD_PARTY_EXCEPT_BLINK,
1796 # Exceptions to this rule should have a fuzzer.
1797 ],
Robert Ogden92101dcb2022-10-19 23:49:361798 ),
Arthur Sonzogni1da65fa2023-03-27 16:01:521799 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531800 r'/\b#include "base/atomicops\.h"\b',
1801 ('Do not use base::subtle atomics, but std::atomic, which are simpler '
1802 'to use, have better understood, clearer and richer semantics, and are '
1803 'harder to mis-use. See details in base/atomicops.h.', ),
1804 False,
1805 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Benoit Lize79cf0592023-01-27 10:01:571806 ),
Daniel Cheng566634ff2024-06-29 14:56:531807 BanRule(r'CrossThreadPersistent<', (
Arthur Sonzogni60348572e2023-04-07 10:22:521808 'Do not use blink::CrossThreadPersistent, but '
Daniel Cheng566634ff2024-06-29 14:56:531809 'blink::CrossThreadHandle. It is harder to mis-use.', 'More info: '
Arthur Sonzogni60348572e2023-04-07 10:22:521810 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1811 'Please contact platform-architecture-dev@ before adding new instances.'
Daniel Cheng566634ff2024-06-29 14:56:531812 ), False, []),
1813 BanRule(r'CrossThreadWeakPersistent<', (
Arthur Sonzogni60348572e2023-04-07 10:22:521814 'Do not use blink::CrossThreadWeakPersistent, but '
Daniel Cheng566634ff2024-06-29 14:56:531815 'blink::CrossThreadWeakHandle. It is harder to mis-use.', 'More info: '
Arthur Sonzogni60348572e2023-04-07 10:22:521816 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1817 'Please contact platform-architecture-dev@ before adding new instances.'
Daniel Cheng566634ff2024-06-29 14:56:531818 ), False, []),
1819 BanRule(r'objc/objc.h', (
Avi Drissman491617c2023-04-13 17:33:151820 'Do not include <objc/objc.h>. It defines away ARC lifetime '
1821 'annotations, and is thus dangerous.',
1822 'Please use the pimpl pattern; search for `ObjCStorage` for examples.',
1823 'For further reading on how to safely mix C++ and Obj-C, see',
1824 'https://chromium.googlesource.com/chromium/src/+/main/docs/mac/mixing_cpp_and_objc.md'
Daniel Cheng566634ff2024-06-29 14:56:531825 ), True, []),
1826 BanRule(
1827 r'/#include <filesystem>',
1828 ('libc++ <filesystem> is banned per the Google C++ styleguide.', ),
1829 True,
1830 # This fuzzing framework is a standalone open source project and
1831 # cannot rely on Chromium base.
1832 (r'third_party/centipede'),
Avi Drissman491617c2023-04-13 17:33:151833 ),
Grace Park8d59b54b2023-04-26 17:53:351834 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531835 r'TopDocument()',
1836 ('TopDocument() does not work correctly with out-of-process iframes. '
1837 'Please do not introduce new uses.', ),
1838 True,
1839 (
1840 # TODO(crbug.com/617677): Remove all remaining uses.
1841 r'^third_party/blink/renderer/core/dom/document\.cc',
1842 r'^third_party/blink/renderer/core/dom/document\.h',
1843 r'^third_party/blink/renderer/core/dom/element\.cc',
1844 r'^third_party/blink/renderer/core/exported/web_disallow_transition_scope_test\.cc',
1845 r'^third_party/blink/renderer/core/exported/web_document_test\.cc',
1846 r'^third_party/blink/renderer/core/html/html_anchor_element\.cc',
1847 r'^third_party/blink/renderer/core/html/html_dialog_element\.cc',
1848 r'^third_party/blink/renderer/core/html/html_element\.cc',
1849 r'^third_party/blink/renderer/core/html/html_frame_owner_element\.cc',
1850 r'^third_party/blink/renderer/core/html/media/video_wake_lock\.cc',
1851 r'^third_party/blink/renderer/core/loader/anchor_element_interaction_tracker\.cc',
1852 r'^third_party/blink/renderer/core/page/scrolling/root_scroller_controller\.cc',
1853 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.cc',
1854 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.h',
1855 r'^third_party/blink/renderer/core/script/classic_pending_script\.cc',
1856 r'^third_party/blink/renderer/core/script/script_loader\.cc',
1857 ),
Grace Park8d59b54b2023-04-26 17:53:351858 ),
Daniel Cheng72153e02023-05-18 21:18:141859 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531860 pattern=r'base::raw_ptr<',
1861 explanation=('Do not use base::raw_ptr, use raw_ptr.', ),
1862 treat_as_error=True,
1863 excluded_paths=(
1864 '^base/',
1865 '^tools/',
1866 ),
Daniel Cheng72153e02023-05-18 21:18:141867 ),
Arthur Sonzognif0eea302023-08-18 19:20:311868 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531869 pattern=r'base:raw_ref<',
1870 explanation=('Do not use base::raw_ref, use raw_ref.', ),
1871 treat_as_error=True,
1872 excluded_paths=(
1873 '^base/',
1874 '^tools/',
1875 ),
Arthur Sonzognif0eea302023-08-18 19:20:311876 ),
1877 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531878 pattern=r'/raw_ptr<[^;}]*\w{};',
1879 explanation=(
1880 'Do not use {} for raw_ptr initialization, use = nullptr instead.',
1881 ),
1882 treat_as_error=True,
1883 excluded_paths=(
1884 '^base/',
1885 '^tools/',
1886 ),
Arthur Sonzognif0eea302023-08-18 19:20:311887 ),
Anton Maliev66751812023-08-24 16:28:131888 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531889 pattern=r'/#include "base/allocator/.*/raw_'
1890 r'(ptr|ptr_cast|ptr_exclusion|ref).h"',
1891 explanation=(
1892 'Please include the corresponding facade headers:',
1893 '- #include "base/memory/raw_ptr.h"',
1894 '- #include "base/memory/raw_ptr_cast.h"',
1895 '- #include "base/memory/raw_ptr_exclusion.h"',
1896 '- #include "base/memory/raw_ref.h"',
1897 ),
1898 treat_as_error=True,
1899 excluded_paths=(
1900 '^base/',
1901 '^tools/',
1902 ),
Tom Sepez41eb158d2023-09-12 16:16:221903 ),
1904 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531905 pattern=r'ContentSettingsType::COOKIES',
1906 explanation=
1907 ('Do not use ContentSettingsType::COOKIES to check whether cookies are '
1908 'supported in the provided context. Instead rely on the '
1909 'content_settings::CookieSettings API. If you are using '
1910 'ContentSettingsType::COOKIES to check the user preference setting '
1911 'specifically, disregard this warning.', ),
1912 treat_as_error=False,
1913 excluded_paths=(
1914 '^chrome/browser/ui/content_settings/',
1915 '^components/content_settings/',
1916 '^services/network/cookie_settings.cc',
1917 '.*test.cc',
1918 ),
Arthur Sonzogni48c6aea22023-09-04 22:25:201919 ),
1920 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531921 pattern=r'ContentSettingsType::TRACKING_PROTECTION',
1922 explanation=
1923 ('Do not directly use ContentSettingsType::TRACKING_PROTECTION to check '
1924 'for tracking protection exceptions. Instead rely on the '
1925 'privacy_sandbox::TrackingProtectionSettings API.', ),
1926 treat_as_error=False,
1927 excluded_paths=(
1928 '^chrome/browser/ui/content_settings/',
1929 '^components/content_settings/',
1930 '^components/privacy_sandbox/tracking_protection_settings.cc',
1931 '.*test.cc',
1932 ),
Anton Maliev66751812023-08-24 16:28:131933 ),
Tom Andersoncd522072023-10-03 00:52:351934 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531935 pattern=r'/\bg_signal_connect',
1936 explanation=('Use ScopedGSignal instead of g_signal_connect*()', ),
1937 treat_as_error=True,
1938 excluded_paths=('^ui/base/glib/scoped_gsignal.h', ),
Michelle Abreo6b7437822024-04-26 17:29:041939 ),
1940 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531941 pattern=r'features::kIsolatedWebApps',
1942 explanation=(
1943 'Do not use `features::kIsolatedWebApps` directly to guard Isolated ',
1944 'Web App code. ',
Andrew Rayskiy7ae2b5d2025-02-28 16:59:381945 'Use `content::AreIsolatedWebAppsEnabled()` in the browser process '
1946 'or check the `kEnableIsolatedWebAppsInRenderer` command line flag '
1947 'in the renderer process.',
Daniel Cheng566634ff2024-06-29 14:56:531948 ),
1949 treat_as_error=True,
Andrew Rayskiy7ae2b5d2025-02-28 16:59:381950 excluded_paths=_TEST_CODE_EXCLUDED_PATHS + (
1951 '^chrome/browser/about_flags.cc',
1952 '^chrome/browser/component_updater/iwa_key_distribution_component_installer.cc',
1953 '^chrome/browser/web_applications/isolated_web_apps/chrome_content_browser_client_isolated_web_apps_part.cc',
1954 '^chrome/browser/ui/startup/bad_flags_prompt.cc',
1955 '^content/shell/browser/shell_content_browser_client.cc',
1956 )),
Daniel Cheng566634ff2024-06-29 14:56:531957 BanRule(
1958 pattern=r'features::kIsolatedWebAppDevMode',
1959 explanation=(
1960 'Do not use `features::kIsolatedWebAppDevMode` directly to guard code ',
1961 'related to Isolated Web App Developer Mode. ',
1962 'Use `web_app::IsIwaDevModeEnabled()` instead.',
1963 ),
1964 treat_as_error=True,
1965 excluded_paths=_TEST_CODE_EXCLUDED_PATHS + (
1966 '^chrome/browser/about_flags.cc',
1967 '^chrome/browser/web_applications/isolated_web_apps/isolated_web_app_features.cc',
1968 '^chrome/browser/ui/startup/bad_flags_prompt.cc',
1969 )),
1970 BanRule(
1971 pattern=r'features::kIsolatedWebAppUnmanagedInstall',
1972 explanation=(
1973 'Do not use `features::kIsolatedWebAppUnmanagedInstall` directly to ',
1974 'guard code related to unmanaged install flow for Isolated Web Apps. ',
1975 'Use `web_app::IsIwaUnmanagedInstallEnabled()` instead.',
1976 ),
1977 treat_as_error=True,
1978 excluded_paths=_TEST_CODE_EXCLUDED_PATHS + (
1979 '^chrome/browser/about_flags.cc',
1980 '^chrome/browser/web_applications/isolated_web_apps/isolated_web_app_features.cc',
1981 )),
1982 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531983 pattern='/(CUIAutomation|AccessibleObjectFromWindow)',
1984 explanation=
1985 ('Direct usage of UIAutomation or IAccessible2 in client code is '
1986 'discouraged in Chromium, as it is not an assistive technology and '
1987 'should not rely on accessibility APIs directly. These APIs can '
1988 'introduce significant performance overhead. However, if you believe '
1989 'your use case warrants an exception, please discuss it with an '
1990 'accessibility owner before proceeding. For more information on the '
1991 'performance implications, see https://docs.google.com/document/d/1jN4itpCe_bDXF0BhFaYwv4xVLsCWkL9eULdzjmLzkuk/edit#heading=h.pwth3nbwdub0.',
1992 ),
1993 treat_as_error=False,
Andrew Rayskiycdd45e732024-03-20 14:32:391994 ),
1995 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531996 pattern=r'/WIDGET_OWNS_NATIVE_WIDGET|'
1997 r'NATIVE_WIDGET_OWNS_WIDGET',
1998 explanation=
1999 ('WIDGET_OWNS_NATIVE_WIDGET and NATIVE_WIDGET_OWNS_WIDGET are in the '
2000 'process of being deprecated. Consider using the new '
2001 'CLIENT_OWNS_WIDGET ownership model. Eventually, this will be the only '
2002 'available ownership model available and the associated enumeration'
2003 'will be removed.', ),
2004 treat_as_error=False,
Andrew Rayskiycdd45e732024-03-20 14:32:392005 ),
2006 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:532007 pattern='ProfileManager::GetLastUsedProfile',
2008 explanation=
2009 ('Most code should already be scoped to a Profile. Pass in a Profile* '
2010 'or retreive from an existing entity with a reference to the Profile '
2011 '(e.g. WebContents).', ),
2012 treat_as_error=False,
Arthur Sonzogni5cbd3e32024-02-08 17:51:322013 ),
Helmut Januschkab3f71ab52024-03-12 02:48:052014 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:532015 pattern=(r'/FindBrowserWithUiElementContext|'
2016 r'FindBrowserWithTab|'
2017 r'FindBrowserWithGroup|'
2018 r'FindTabbedBrowser|'
2019 r'FindAnyBrowser|'
2020 r'FindBrowserWithProfile|'
Erik Chen5f02eb4c2024-08-23 06:30:442021 r'FindLastActive|'
Daniel Cheng566634ff2024-06-29 14:56:532022 r'FindBrowserWithActiveWindow'),
2023 explanation=
2024 ('Most code should already be scoped to a Browser. Pass in a Browser* '
2025 'or retreive from an existing entity with a reference to the Browser.',
2026 ),
2027 treat_as_error=False,
Helmut Januschkab3f71ab52024-03-12 02:48:052028 ),
2029 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:532030 pattern='BrowserUserData',
2031 explanation=
2032 ('Do not use BrowserUserData to store state on a Browser instance. '
2033 'Instead use BrowserWindowFeatures. BrowserWindowFeatures is '
2034 'functionally identical but has two benefits: it does not force a '
2035 'dependency onto class Browser, and lifetime semantics are explicit '
2036 'rather than implicit. See BrowserUserData header file for more '
2037 'details.', ),
2038 treat_as_error=False,
Mike Doughertyab1bdec2024-08-06 16:39:012039 excluded_paths=(
2040 # Exclude iOS as the iOS implementation of BrowserUserData is separate
2041 # and still in use.
2042 '^ios/',
2043 ),
Erik Chen87358e82024-06-04 02:13:122044 ),
Tom Sepezea67b6e2024-08-08 18:17:272045 BanRule(
Tom Sepezd3272cd2025-02-21 19:11:312046 pattern=r'subspan(0u,',
2047 explanation=
2048 ('Prefer first(n) over subspan(0u, n) as it is shorter, and the '
2049 'compiler may have to emit a branch for the n == dynamic_extent '
2050 'case of subspan().',
2051 ),
2052 treat_as_error=False,
2053 ),
2054 BanRule(
Tom Sepezea67b6e2024-08-08 18:17:272055 pattern=r'UNSAFE_TODO(',
2056 explanation=
2057 ('Do not use UNSAFE_TODO() to write new unsafe code. Use only when '
Tom Sepeza90f92b2024-08-15 16:01:352058 'removing a pre-existing file-wide allow_unsafe_buffers pragma, or '
2059 'when incrementally converting code off of unsafe interfaces',
Tom Sepezea67b6e2024-08-08 18:17:272060 ),
2061 treat_as_error=False,
2062 ),
2063 BanRule(
2064 pattern=r'UNSAFE_BUFFERS(',
2065 explanation=
Tom Sepeza90f92b2024-08-15 16:01:352066 ('Try to avoid using UNSAFE_BUFFERS() if at all possible. Otherwise, '
2067 'be sure to justify in a // SAFETY comment why other options are not '
2068 'available, and why the code is safe.',
Tom Sepezea67b6e2024-08-08 18:17:272069 ),
2070 treat_as_error=False,
2071 ),
Erik Chend086ae02024-08-20 22:53:332072 BanRule(
2073 pattern='BrowserWithTestWindowTest',
2074 explanation=
2075 ('Do not use BrowserWithTestWindowTest. By instantiating an instance '
2076 'of class Browser, the test is no longer a unit test but is instead a '
2077 'browser test. The class BrowserWithTestWindowTest forces production '
2078 'logic to take on test-only conditionals, which is an anti-pattern. '
2079 'Features should be performing dependency injection rather than '
2080 'directly using class Browser. See '
mikt19226ff22024-08-27 05:28:212081 'docs/chrome_browser_design_principles.md for more details.',
Erik Chend086ae02024-08-20 22:53:332082 ),
2083 treat_as_error=False,
2084 ),
Erik Chen8cf3a652024-08-23 17:13:302085 BanRule(
Erik Chen959cdd72024-08-29 02:11:212086 pattern='TestWithBrowserView',
2087 explanation=
2088 ('Do not use TestWithBrowserView. See '
2089 'docs/chrome_browser_design_principles.md for details. If you want '
2090 'to write a test that has both a Browser and a BrowserView, create '
2091 'a browser_test. If you want to write a unit_test, your code must '
Erik Chendba23692024-09-26 06:43:362092 'not reference Browser*.',
Erik Chen959cdd72024-08-29 02:11:212093 ),
2094 treat_as_error=False,
2095 ),
2096 BanRule(
Erik Chene89ebe32025-02-22 02:46:492097 pattern='CreateBrowserWithTestWindow',
2098 explanation=
2099 ('Do not use CreateBrowserWithTestWindow. See '
2100 'docs/chrome_browser_design_principles.md for details. If you want '
2101 'to write a test that has a Browser, create a browser_test. If you '
2102 'want to write a unit_test, your code must not reference Browser*.',
2103 ),
2104 treat_as_error=False,
2105 ),
2106 BanRule(
Erik Chenf12a06642025-03-13 23:30:342107 pattern='CreateBrowserWithTestWindowForParams',
2108 explanation=
2109 ('Do not use CreateBrowserWithTestWindowForParams. See '
2110 'docs/chrome_browser_design_principles.md for details. If you want '
2111 'to write a test that has a Browser, create a browser_test and use '
2112 'Browser::Browser. If you want to write a unit_test, your code must '
2113 'not reference Browser*.',
2114 ),
2115 treat_as_error=False,
2116 ),
2117 BanRule(
Erik Chen8cf3a652024-08-23 17:13:302118 pattern='RunUntilIdle',
2119 explanation=
2120 ('Do not RunUntilIdle. If possible, explicitly quit the run loop using '
2121 'run_loop.Quit() or run_loop.QuitClosure() if completion can be '
2122 'observed using a lambda or callback. Otherwise, wait for the '
mikt19226ff22024-08-27 05:28:212123 'condition to be true via base::test::RunUntil().',
Erik Chen8cf3a652024-08-23 17:13:302124 ),
2125 treat_as_error=False,
2126 ),
Daniel Chengddde13a2024-09-05 21:39:282127 BanRule(
2128 pattern=r'/\bstd::(literals|string_literals|string_view_literals)\b',
2129 explanation = (
2130 'User-defined literals are banned by the Google C++ style guide. '
2131 'Exceptions are provided in Chrome for string and string_view '
2132 'literals that embed \\0.',
2133 ),
2134 treat_as_error=True,
2135 excluded_paths=(
2136 # Various tests or test helpers that embed NUL in strings or
2137 # string_views.
Daniel Chengddde13a2024-09-05 21:39:282138 r'^base/strings/string_util_unittest\.cc',
2139 r'^base/strings/utf_string_conversions_unittest\.cc',
2140 r'^chrome/browser/ash/crosapi/browser_data_back_migrator_unittest\.cc',
2141 r'^chrome/browser/ash/crosapi/browser_data_migrator_util_unittest\.cc',
2142 r'^chrome/browser/ash/crosapi/move_migrator_unittest\.cc',
Hidehiko Abe51601812025-01-12 16:17:352143 r'^chromeos/ash/experiences/arc/session/serial_number_util_unittest\.cc',
Daniel Chengddde13a2024-09-05 21:39:282144 r'^components/history/core/browser/visit_annotations_database\.cc',
2145 r'^components/history/core/browser/visit_annotations_database_unittest\.cc',
2146 r'^components/os_crypt/sync/os_crypt_unittest\.cc',
2147 r'^components/password_manager/core/browser/credentials_cleaner_unittest\.cc',
2148 r'^content/browser/file_system_access/file_system_access_file_writer_impl_unittest\.cc',
2149 r'^net/cookies/parsed_cookie_unittest\.cc',
2150 r'^third_party/blink/renderer/modules/webcodecs/test_helpers\.cc',
2151 r'^third_party/blink/renderer/modules/websockets/websocket_channel_impl_test\.cc',
2152 ),
Erik Chenba8b0cd32024-10-01 08:36:362153 ),
2154 BanRule(
2155 pattern='BUILDFLAG(GOOGLE_CHROME_BRANDING)',
2156 explanation=
2157 ('Code gated by GOOGLE_CHROME_BRANDING is effectively untested. This '
2158 'is typically wrong. Valid use cases are glue for private modules '
2159 'shipped alongside Chrome, and installation-related logic.',
2160 ),
2161 treat_as_error=False,
2162 ),
2163 BanRule(
2164 pattern='defined(OFFICIAL_BUILD)',
2165 explanation=
2166 ('Code gated by OFFICIAL_BUILD is effectively untested. This '
2167 'is typically wrong. One valid use case is low-level code that '
2168 'handles subtleties related to high-levels of optimizations that come '
2169 'with OFFICIAL_BUILD.',
2170 ),
2171 treat_as_error=False,
2172 ),
Erik Chen95b9c782024-11-08 03:26:272173 BanRule(
2174 pattern='WebContentsDestroyed',
2175 explanation=
2176 ('Do not use this method. It is invoked half-way through the '
2177 'destructor of WebContentsImpl and using it often results in crashes '
2178 'or surprising behavior. Conceptually, this is only necessary by '
2179 'objects that depend on, but outlive the WebContents. These objects '
2180 'should instead coordinate with the owner of the WebContents which is '
2181 'responsible for destroying the WebContents.',
2182 ),
2183 treat_as_error=False,
2184 ),
Maksim Sisovc98fdfa2024-11-16 20:12:272185 BanRule(
Georg Neisa7f94e62025-02-28 07:01:482186 pattern='IS_CHROMEOS_ASH',
Maksim Sisovc98fdfa2024-11-16 20:12:272187 explanation=
Georg Neisa7f94e62025-02-28 07:01:482188 ('IS_CHROMEOS_ASH is deprecated. Please use the equivalent IS_CHROMEOS '
2189 'instead (Lacros is gone).',
Maksim Sisovc98fdfa2024-11-16 20:12:272190 ),
2191 treat_as_error=False,
2192 ),
Erik Chen1396bbe2025-01-27 23:39:362193 BanRule(
2194 pattern=(r'namespace {'),
2195 explanation=
2196 ('Anonymous namespaces are disallowed in C++ header files. See '
2197 'https://google.github.io/styleguide/cppguide.html#Internal_Linkage '
2198 ' for details.',
2199 ),
2200 treat_as_error=False,
2201 excluded_paths=[
2202 _THIRD_PARTY_EXCEPT_BLINK, # Don't warn in third_party folders.
2203 r'^(?!.*\.h$).*$', # Exclude all files except those that end in .h
2204 ],
2205 ),
Keren Zhuf06d757d2025-03-04 05:32:362206 BanRule(
2207 pattern=('AddChildViewRaw'),
2208 explanation=(
2209 'Do not use AddChildViewRaw. It is prone to memory leaks and '
2210 'use-after-free bugs. Instead, use AddChildView(std::unique_ptr). '
2211 'See https://crbug.com/40485510 for more details.', ),
2212 treat_as_error=False,
2213 ),
Nate Fischerd541ff82025-03-11 21:34:192214 BanRule(
2215 pattern=(r'IS_DESKTOP_ANDROID'),
2216 explanation=(
2217 'Features which depend on IS_DESKTOP_ANDROID should only exist in '
2218 'chrome/ layer and similar layers. Lower layers such as content/ '
2219 'should not have features which are only designed for '
2220 'desktop-android builds. See https://crbug.com/401628399.', ),
2221 treat_as_error=False,
2222 excluded_paths=[
2223 _THIRD_PARTY_EXCEPT_BLINK, # Don't warn in third_party folders.
2224 r'^build/', # This is permitted in build/ folder.
2225 r'^chrome/', # This is permitted in chrome/ folder.
2226 r'^components/', # This is permitted only for components/ that are not shared by WebView.
2227 r'^extensions/', # This is permitted in chrome/ folder.
2228 r'^infra/', # This is permitted in infra/ folder.
2229 r'^tools/', # This is permitted in tools/ folder.
2230 ],
2231 ),
[email protected]127f18ec2012-06-16 05:05:592232)
2233
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152234_DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING = (
2235 'Used a predicate related to signin::ConsentLevel::kSync which will always '
2236 'return false in the future (crbug.com/40066949). Prefer using a predicate '
2237 'that also supports signin::ConsentLevel::kSignin when appropriate. It is '
2238 'safe to ignore this warning if you are just moving an existing call, or if '
2239 'you want special handling for users in the legacy state. In doubt, reach '
Victor Hugo Vianna Silvae2292972024-06-04 17:11:552240 'out to //components/sync/OWNERS.',
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152241)
2242
2243# C++ functions related to signin::ConsentLevel::kSync which are deprecated.
2244_DEPRECATED_SYNC_CONSENT_CPP_FUNCTIONS : Sequence[BanRule] = (
2245 BanRule(
2246 'HasSyncConsent',
2247 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2248 False,
2249 ),
2250 BanRule(
2251 'CanSyncFeatureStart',
2252 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2253 False,
2254 ),
2255 BanRule(
2256 'IsSyncFeatureEnabled',
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152257 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152258 False,
2259 ),
2260 BanRule(
2261 'IsSyncFeatureActive',
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152262 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152263 False,
2264 ),
2265)
2266
2267# Java functions related to signin::ConsentLevel::kSync which are deprecated.
2268_DEPRECATED_SYNC_CONSENT_JAVA_FUNCTIONS : Sequence[BanRule] = (
2269 BanRule(
2270 'hasSyncConsent',
2271 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2272 False,
2273 ),
2274 BanRule(
2275 'canSyncFeatureStart',
2276 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2277 False,
2278 ),
2279 BanRule(
2280 'isSyncFeatureEnabled',
2281 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2282 False,
2283 ),
2284 BanRule(
2285 'isSyncFeatureActive',
2286 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2287 False,
2288 ),
2289)
2290
Justin Lulejian09fd06872025-04-01 22:03:282291_BANNED_MOJOM_PATTERNS: Sequence[BanRule] = (
Daniel Cheng92c15e32022-03-16 17:48:222292 BanRule(
2293 'handle<shared_buffer>',
2294 (
Justin Lulejian09fd06872025-04-01 22:03:282295 'Please use one of the more specific shared memory types instead:',
2296 ' mojo_base.mojom.ReadOnlySharedMemoryRegion',
2297 ' mojo_base.mojom.WritableSharedMemoryRegion',
2298 ' mojo_base.mojom.UnsafeSharedMemoryRegion',
Daniel Cheng92c15e32022-03-16 17:48:222299 ),
2300 True,
2301 ),
Justin Lulejian09fd06872025-04-01 22:03:282302 BanRule(
2303 'string extension_id',
2304 (
2305 'Please use the extensions::mojom::ExtensionId struct when '
2306 'passing extensions::ExtensionIds as mojom messages in order to ',
2307 'provide message validation.',
2308 ),
2309 True,
2310 # Only apply this to (mojom) files in a subdirectory of extensions.
2311 excluded_paths=(r'^((?!extensions/).)*$', ),
2312 ),
Daniel Cheng92c15e32022-03-16 17:48:222313)
2314
mlamouria82272622014-09-16 18:45:042315_IPC_ENUM_TRAITS_DEPRECATED = (
2316 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:502317 'See http://www.chromium.org/Home/chromium-security/education/'
2318 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:042319
Stephen Martinis97a394142018-06-07 23:06:052320_LONG_PATH_ERROR = (
2321 'Some files included in this CL have file names that are too long (> 200'
2322 ' characters). If committed, these files will cause issues on Windows. See'
2323 ' https://crbug.com/612667 for more details.'
2324)
2325
Shenghua Zhangbfaa38b82017-11-16 21:58:022326_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Bruce Dawson40fece62022-09-16 19:58:312327 r".*/BuildHooksAndroidImpl\.java",
2328 r".*/LicenseContentProvider\.java",
2329 r".*/PlatformServiceBridgeImpl.java",
2330 r".*chrome/android/feed/dummy/.*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:022331]
[email protected]127f18ec2012-06-16 05:05:592332
Mohamed Heikald048240a2019-11-12 16:57:372333# List of image extensions that are used as resources in chromium.
2334_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
2335
Sean Kau46e29bc2017-08-28 16:31:162336# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:402337_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Bruce Dawson40fece62022-09-16 19:58:312338 r'test/data/',
2339 r'testing/buildbot/',
2340 r'^components/policy/resources/policy_templates\.json$',
2341 r'^third_party/protobuf/',
Camillo Bruni1411a352023-05-24 12:39:032342 r'^third_party/blink/perf_tests/speedometer.*/resources/todomvc/learn\.json',
Bruce Dawson40fece62022-09-16 19:58:312343 r'^third_party/blink/renderer/devtools/protocol\.json$',
2344 r'^third_party/blink/web_tests/external/wpt/',
2345 r'^tools/perf/',
2346 r'^tools/traceline/svgui/startup-release.json',
Daniel Cheng2d4c2d192022-07-01 01:38:312347 # vscode configuration files allow comments
Bruce Dawson40fece62022-09-16 19:58:312348 r'^tools/vscode/',
Sean Kau46e29bc2017-08-28 16:31:162349]
2350
Andrew Grieveb773bad2020-06-05 18:00:382351# These are not checked on the public chromium-presubmit trybot.
2352# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:042353# checkouts.
agrievef32bcc72016-04-04 14:57:402354_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:382355 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382356]
2357
2358
2359_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:042360 'android_webview/tools/run_cts.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:362361 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042362 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362363 'build/android/gyp/aar.pydeps',
2364 'build/android/gyp/aidl.pydeps',
2365 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:382366 'build/android/gyp/assert_static_initializers.pydeps',
Mohamed Heikal133e1f22023-04-18 20:04:372367 'build/android/gyp/binary_baseline_profile.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:022368 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:222369 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieveacac4242024-12-20 19:39:422370 'build/android/gyp/check_for_missing_direct_deps.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:112371 'build/android/gyp/compile_java.pydeps',
Peter Weneaa963f2023-01-20 19:40:302372 'build/android/gyp/compile_kt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362373 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362374 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362375 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:112376 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042377 'build/android/gyp/create_app_bundle_apks.pydeps',
2378 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362379 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:122380 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:092381 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:222382 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve2d972e5f2025-01-28 18:28:142383 'build/android/gyp/create_stub_manifest.pydeps',
Peter Wene6e017e2022-07-27 21:40:402384 'build/android/gyp/create_test_apk_wrapper_script.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002385 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362386 'build/android/gyp/dex.pydeps',
2387 'build/android/gyp/dist_aar.pydeps',
Andrew Grieve651ddb32025-01-23 03:27:342388 'build/android/gyp/errorprone.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362389 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:212390 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362391 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:362392 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362393 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:582394 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362395 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:142396 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:262397 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:472398 'build/android/gyp/java_google_api_keys.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042399 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362400 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362401 'build/android/gyp/merge_manifest.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:102402 'build/android/gyp/optimize_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362403 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:222404 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362405 'build/android/gyp/proguard.pydeps',
Mohamed Heikaldd52b452024-09-10 17:10:502406 'build/android/gyp/rename_java_classes.pydeps',
Andrew Grievee3a775ab2022-05-16 15:59:222407 'build/android/gyp/system_image_apks.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:102408 'build/android/gyp/trace_event_bytecode_rewriter.pydeps',
Andrew Grieve170b9782025-02-03 15:54:532409 'build/android/gyp/tracereferences.pydeps',
Peter Wen578730b2020-03-19 19:55:462410 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:302411 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:242412 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362413 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:462414 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:562415 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362416 'build/android/incremental_install/generate_android_manifest.pydeps',
2417 'build/android/incremental_install/write_installer_json.pydeps',
Stephanie Kim392913b452022-06-15 17:25:322418 'build/android/pylib/results/presentation/test_results_presentation.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042419 'build/android/resource_sizes.pydeps',
2420 'build/android/test_runner.pydeps',
2421 'build/android/test_wrapper/logdog_wrapper.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362422 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:322423 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:272424 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
2425 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Bailey Myers-Morganbd122132025-03-26 23:09:162426 'chrome/test/media_router/performance/performance_test.pydeps',
Junbo Kedcd3a452021-03-19 17:55:042427 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Mohannad Farrag19102742023-12-01 01:16:302428 'components/cronet/tools/check_combined_proguard_file.pydeps',
2429 'components/cronet/tools/generate_proguard_file.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002430 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382431 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002432 'content/public/android/generate_child_service.pydeps',
Hzj_jie77bdb802024-07-22 18:14:512433 'fuchsia_web/av_testing/av_sync_tests.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382434 'net/tools/testserver/testserver.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:182435 'testing/scripts/run_isolated_script_test.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:412436 'testing/merge_scripts/standard_isolated_script_merge.pydeps',
2437 'testing/merge_scripts/standard_gtest_merge.pydeps',
2438 'testing/merge_scripts/code_coverage/merge_results.pydeps',
2439 'testing/merge_scripts/code_coverage/merge_steps.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042440 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:422441 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
Yuki Shiino38eeaad12022-08-11 06:40:252442 'third_party/blink/renderer/bindings/scripts/check_generated_file_list.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:422443 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:132444 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Yuki Shiinoea477d32023-08-21 06:24:342445 'third_party/blink/renderer/bindings/scripts/generate_event_interface_names.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:502446 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:412447 'third_party/blink/tools/blinkpy/web_tests/merge_results.pydeps',
2448 'third_party/blink/tools/merge_web_test_results.pydeps',
John Budorickbc3571aa2019-04-25 02:20:062449 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:222450 'tools/binary_size/supersize.pydeps',
Peter Wen2dcfa6e2025-03-04 22:42:522451 'tools/cygprofile/generate_orderfile.pydeps',
Ben Pastene028104a2022-08-10 19:17:452452 'tools/perf/process_perf_results.pydeps',
Peter Wence103e12024-10-09 19:23:512453 'tools/pgo/generate_profile.pydeps',
agrievef32bcc72016-04-04 14:57:402454]
2455
wnwenbdc444e2016-05-25 13:44:152456
agrievef32bcc72016-04-04 14:57:402457_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
2458
2459
Eric Boren6fd2b932018-01-25 15:05:082460# Bypass the AUTHORS check for these accounts.
2461_KNOWN_ROBOTS = set(
Shuai Xia0d99ebf2025-02-11 23:47:592462 ) | set('%[email protected]' % s for s in ('findit-for-me',
2463 'luci-bisection',
2464 'predator-for-me-staging',
2465 'predator-for-me')
Achuith Bhandarkar35905562018-07-25 19:28:452466 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:592467 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:522468 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:232469 'wpt-autoroller', 'chrome-weblayer-builder',
Georg Neise5817eb2025-02-06 03:47:312470 'skylab-test-cros-roller', 'infra-try-recipes-tester',
2471 'chrome-automated-expectation',
Stephanie Kimb49bdd242023-04-28 16:46:042472 'chromium-automated-expectation', 'chrome-branch-day',
2473 'chromium-autosharder')
Eric Boren835d71f2018-09-07 21:09:042474 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:272475 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:042476 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:162477 for s in ('chromium-internal-autoroll',)
Kyungjun Lee3b7c9352024-04-02 23:59:142478 ) | set('%[email protected]' % s
2479 for s in ('chrome-screen-ai-releaser',)
Yulan Lineb0cfba2021-04-09 18:43:162480 ) | set('%[email protected]' % s
Chong Gub277e342022-10-15 03:30:552481 for s in ('swarming-tasks',)
2482 ) | set('%[email protected]' % s
2483 for s in ('global-integration-try-builder',
Joey Scarr1103c5d2023-09-14 01:17:552484 'global-integration-ci-builder')
Suma Kasa3b9cf7a2023-09-21 22:05:542485 ) | set('%[email protected]' % s
2486 for s in ('chops-security-borg',
2487 'chops-security-cronjobs-cpesuggest'))
Eric Boren6fd2b932018-01-25 15:05:082488
Matt Stark6ef08872021-07-29 01:21:462489_INVALID_GRD_FILE_LINE = [
2490 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
2491]
Eric Boren6fd2b932018-01-25 15:05:082492
Daniel Bratell65b033262019-04-23 08:17:062493def _IsCPlusPlusFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502494 """Returns True if this file contains C++-like code (and not Python,
2495 Go, Java, MarkDown, ...)"""
Daniel Bratell65b033262019-04-23 08:17:062496
Sam Maiera6e76d72022-02-11 21:43:502497 ext = input_api.os_path.splitext(file_path)[1]
2498 # This list is compatible with CppChecker.IsCppFile but we should
2499 # consider adding ".c" to it. If we do that we can use this function
2500 # at more places in the code.
2501 return ext in (
2502 '.h',
2503 '.cc',
2504 '.cpp',
2505 '.m',
2506 '.mm',
2507 )
2508
Daniel Bratell65b033262019-04-23 08:17:062509
2510def _IsCPlusPlusHeaderFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502511 return input_api.os_path.splitext(file_path)[1] == ".h"
Daniel Bratell65b033262019-04-23 08:17:062512
2513
2514def _IsJavaFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502515 return input_api.os_path.splitext(file_path)[1] == ".java"
Daniel Bratell65b033262019-04-23 08:17:062516
2517
2518def _IsProtoFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502519 return input_api.os_path.splitext(file_path)[1] == ".proto"
Daniel Bratell65b033262019-04-23 08:17:062520
Mohamed Heikal5e5b7922020-10-29 18:57:592521
Erik Staabc734cd7a2021-11-23 03:11:522522def _IsXmlOrGrdFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502523 ext = input_api.os_path.splitext(file_path)[1]
2524 return ext in ('.grd', '.xml')
Erik Staabc734cd7a2021-11-23 03:11:522525
2526
Sven Zheng76a79ea2022-12-21 21:25:242527def _IsMojomFile(input_api, file_path):
2528 return input_api.os_path.splitext(file_path)[1] == ".mojom"
2529
2530
Mohamed Heikal5e5b7922020-10-29 18:57:592531def CheckNoUpstreamDepsOnClank(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502532 """Prevent additions of dependencies from the upstream repo on //clank."""
2533 # clank can depend on clank
2534 if input_api.change.RepositoryRoot().endswith('clank'):
2535 return []
2536 build_file_patterns = [
2537 r'(.+/)?BUILD\.gn',
2538 r'.+\.gni',
2539 ]
2540 excluded_files = [r'build[/\\]config[/\\]android[/\\]config\.gni']
2541 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
Mohamed Heikal5e5b7922020-10-29 18:57:592542
Sam Maiera6e76d72022-02-11 21:43:502543 error_message = 'Disallowed import on //clank in an upstream build file:'
Mohamed Heikal5e5b7922020-10-29 18:57:592544
Sam Maiera6e76d72022-02-11 21:43:502545 def FilterFile(affected_file):
2546 return input_api.FilterSourceFile(affected_file,
2547 files_to_check=build_file_patterns,
2548 files_to_skip=excluded_files)
Mohamed Heikal5e5b7922020-10-29 18:57:592549
Sam Maiera6e76d72022-02-11 21:43:502550 problems = []
2551 for f in input_api.AffectedSourceFiles(FilterFile):
2552 local_path = f.LocalPath()
2553 for line_number, line in f.ChangedContents():
2554 if (bad_pattern.search(line)):
2555 problems.append('%s:%d\n %s' %
2556 (local_path, line_number, line.strip()))
2557 if problems:
2558 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
2559 else:
2560 return []
Mohamed Heikal5e5b7922020-10-29 18:57:592561
2562
Saagar Sanghavifceeaae2020-08-12 16:40:362563def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502564 """Attempts to prevent use of functions intended only for testing in
2565 non-testing code. For now this is just a best-effort implementation
2566 that ignores header files and may have some false positives. A
2567 better implementation would probably need a proper C++ parser.
2568 """
2569 # We only scan .cc files and the like, as the declaration of
2570 # for-testing functions in header files are hard to distinguish from
2571 # calls to such functions without a proper C++ parser.
2572 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:192573
Sam Maiera6e76d72022-02-11 21:43:502574 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
2575 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' %
2576 base_function_pattern)
2577 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
2578 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
2579 exclusion_pattern = input_api.re.compile(
2580 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' %
2581 (base_function_pattern, base_function_pattern))
2582 # Avoid a false positive in this case, where the method name, the ::, and
2583 # the closing { are all on different lines due to line wrapping.
2584 # HelperClassForTesting::
2585 # HelperClassForTesting(
2586 # args)
2587 # : member(0) {}
2588 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:192589
Sam Maiera6e76d72022-02-11 21:43:502590 def FilterFile(affected_file):
2591 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2592 input_api.DEFAULT_FILES_TO_SKIP)
2593 return input_api.FilterSourceFile(
2594 affected_file,
2595 files_to_check=file_inclusion_pattern,
2596 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:192597
Sam Maiera6e76d72022-02-11 21:43:502598 problems = []
2599 for f in input_api.AffectedSourceFiles(FilterFile):
2600 local_path = f.LocalPath()
2601 in_method_defn = False
2602 for line_number, line in f.ChangedContents():
2603 if (inclusion_pattern.search(line)
2604 and not comment_pattern.search(line)
2605 and not exclusion_pattern.search(line)
2606 and not allowlist_pattern.search(line)
2607 and not in_method_defn):
2608 problems.append('%s:%d\n %s' %
2609 (local_path, line_number, line.strip()))
2610 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:192611
Sam Maiera6e76d72022-02-11 21:43:502612 if problems:
2613 return [
2614 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
2615 ]
2616 else:
2617 return []
[email protected]55459852011-08-10 15:17:192618
2619
Saagar Sanghavifceeaae2020-08-12 16:40:362620def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502621 """This is a simplified version of
2622 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
2623 """
2624 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
2625 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
2626 name_pattern = r'ForTest(s|ing)?'
2627 # Describes an occurrence of "ForTest*" inside a // comment.
2628 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
2629 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
2630 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
2631 # Catch calls.
2632 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
2633 # Ignore definitions. (Comments are ignored separately.)
2634 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
Andrew Grieve40f451d2023-07-06 19:46:512635 allowlist_re = input_api.re.compile(r'// IN-TEST$')
Vaclav Brozek7dbc28c2018-03-27 08:35:232636
Sam Maiera6e76d72022-02-11 21:43:502637 problems = []
2638 sources = lambda x: input_api.FilterSourceFile(
2639 x,
2640 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
2641 DEFAULT_FILES_TO_SKIP),
2642 files_to_check=[r'.*\.java$'])
2643 for f in input_api.AffectedFiles(include_deletes=False,
2644 file_filter=sources):
2645 local_path = f.LocalPath()
Vaclav Brozek7dbc28c2018-03-27 08:35:232646 is_inside_javadoc = False
Sam Maiera6e76d72022-02-11 21:43:502647 for line_number, line in f.ChangedContents():
2648 if is_inside_javadoc and javadoc_end_re.search(line):
2649 is_inside_javadoc = False
2650 if not is_inside_javadoc and javadoc_start_re.search(line):
2651 is_inside_javadoc = True
2652 if is_inside_javadoc:
2653 continue
2654 if (inclusion_re.search(line) and not comment_re.search(line)
2655 and not annotation_re.search(line)
Andrew Grieve40f451d2023-07-06 19:46:512656 and not allowlist_re.search(line)
Sam Maiera6e76d72022-02-11 21:43:502657 and not exclusion_re.search(line)):
2658 problems.append('%s:%d\n %s' %
2659 (local_path, line_number, line.strip()))
Vaclav Brozek7dbc28c2018-03-27 08:35:232660
Sam Maiera6e76d72022-02-11 21:43:502661 if problems:
2662 return [
2663 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
2664 ]
2665 else:
2666 return []
Vaclav Brozek7dbc28c2018-03-27 08:35:232667
2668
Saagar Sanghavifceeaae2020-08-12 16:40:362669def CheckNoIOStreamInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502670 """Checks to make sure no .h files include <iostream>."""
2671 files = []
2672 pattern = input_api.re.compile(r'^#include\s*<iostream>',
2673 input_api.re.MULTILINE)
2674 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2675 if not f.LocalPath().endswith('.h'):
2676 continue
2677 contents = input_api.ReadFile(f)
2678 if pattern.search(contents):
2679 files.append(f)
[email protected]10689ca2011-09-02 02:31:542680
Sam Maiera6e76d72022-02-11 21:43:502681 if len(files):
2682 return [
2683 output_api.PresubmitError(
2684 'Do not #include <iostream> in header files, since it inserts static '
2685 'initialization into every file including the header. Instead, '
2686 '#include <ostream>. See http://crbug.com/94794', files)
2687 ]
2688 return []
2689
[email protected]10689ca2011-09-02 02:31:542690
Aleksey Khoroshilov9b28c032022-06-03 16:35:322691def CheckNoStrCatRedefines(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502692 """Checks no windows headers with StrCat redefined are included directly."""
2693 files = []
Aleksey Khoroshilov9b28c032022-06-03 16:35:322694 files_to_check = (r'.+%s' % _HEADER_EXTENSIONS,
2695 r'.+%s' % _IMPLEMENTATION_EXTENSIONS)
2696 files_to_skip = (input_api.DEFAULT_FILES_TO_SKIP +
2697 _NON_BASE_DEPENDENT_PATHS)
2698 sources_filter = lambda f: input_api.FilterSourceFile(
2699 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
2700
Sam Maiera6e76d72022-02-11 21:43:502701 pattern_deny = input_api.re.compile(
2702 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
2703 input_api.re.MULTILINE)
2704 pattern_allow = input_api.re.compile(
2705 r'^#include\s"base/win/windows_defines.inc"', input_api.re.MULTILINE)
Aleksey Khoroshilov9b28c032022-06-03 16:35:322706 for f in input_api.AffectedSourceFiles(sources_filter):
Sam Maiera6e76d72022-02-11 21:43:502707 contents = input_api.ReadFile(f)
2708 if pattern_deny.search(
2709 contents) and not pattern_allow.search(contents):
2710 files.append(f.LocalPath())
Danil Chapovalov3518f362018-08-11 16:13:432711
Sam Maiera6e76d72022-02-11 21:43:502712 if len(files):
2713 return [
2714 output_api.PresubmitError(
2715 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
2716 'directly since they pollute code with StrCat macro. Instead, '
2717 'include matching header from base/win. See http://crbug.com/856536',
2718 files)
2719 ]
2720 return []
Danil Chapovalov3518f362018-08-11 16:13:432721
[email protected]10689ca2011-09-02 02:31:542722
Andrew Williamsc9f69b482023-07-10 16:07:362723def _CheckNoUNIT_TESTInSourceFiles(input_api, f):
2724 problems = []
2725
2726 unit_test_macro = input_api.re.compile(
Riley Wong49be8a882025-02-27 00:38:232727 r'^\s*#.*(?:ifn?def\s+UNIT_TEST|defined\s*\(?\s*UNIT_TEST\s*\)?)(?:$|\s+)')
Andrew Williamsc9f69b482023-07-10 16:07:362728 for line_num, line in f.ChangedContents():
2729 if unit_test_macro.match(line):
2730 problems.append(' %s:%d' % (f.LocalPath(), line_num))
2731
2732 return problems
2733
2734
Saagar Sanghavifceeaae2020-08-12 16:40:362735def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502736 """Checks to make sure no source files use UNIT_TEST."""
2737 problems = []
2738 for f in input_api.AffectedFiles():
2739 if (not f.LocalPath().endswith(('.cc', '.mm'))):
2740 continue
Andrew Williamsc9f69b482023-07-10 16:07:362741 problems.extend(
2742 _CheckNoUNIT_TESTInSourceFiles(input_api, f))
[email protected]72df4e782012-06-21 16:28:182743
Sam Maiera6e76d72022-02-11 21:43:502744 if not problems:
2745 return []
2746 return [
2747 output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
2748 '\n'.join(problems))
2749 ]
2750
[email protected]72df4e782012-06-21 16:28:182751
Saagar Sanghavifceeaae2020-08-12 16:40:362752def CheckNoDISABLETypoInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502753 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
Dominic Battre033531052018-09-24 15:45:342754
Sam Maiera6e76d72022-02-11 21:43:502755 This test warns if somebody tries to disable a test with the DISABLE_ prefix
2756 instead of DISABLED_. To filter false positives, reports are only generated
2757 if a corresponding MAYBE_ line exists.
2758 """
2759 problems = []
Dominic Battre033531052018-09-24 15:45:342760
Sam Maiera6e76d72022-02-11 21:43:502761 # The following two patterns are looked for in tandem - is a test labeled
2762 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
2763 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
2764 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
Dominic Battre033531052018-09-24 15:45:342765
Sam Maiera6e76d72022-02-11 21:43:502766 # This is for the case that a test is disabled on all platforms.
2767 full_disable_pattern = input_api.re.compile(
2768 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
2769 input_api.re.MULTILINE)
Dominic Battre033531052018-09-24 15:45:342770
Arthur Sonzognic66e9c82024-04-23 07:53:042771 for f in input_api.AffectedFiles(include_deletes=False):
Sam Maiera6e76d72022-02-11 21:43:502772 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2773 continue
Dominic Battre033531052018-09-24 15:45:342774
Arthur Sonzognic66e9c82024-04-23 07:53:042775 # Search for MAYBE_, DISABLE_ pairs.
Sam Maiera6e76d72022-02-11 21:43:502776 disable_lines = {} # Maps of test name to line number.
2777 maybe_lines = {}
2778 for line_num, line in f.ChangedContents():
2779 disable_match = disable_pattern.search(line)
2780 if disable_match:
2781 disable_lines[disable_match.group(1)] = line_num
2782 maybe_match = maybe_pattern.search(line)
2783 if maybe_match:
2784 maybe_lines[maybe_match.group(1)] = line_num
Dominic Battre033531052018-09-24 15:45:342785
Sam Maiera6e76d72022-02-11 21:43:502786 # Search for DISABLE_ occurrences within a TEST() macro.
2787 disable_tests = set(disable_lines.keys())
2788 maybe_tests = set(maybe_lines.keys())
2789 for test in disable_tests.intersection(maybe_tests):
2790 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
Dominic Battre033531052018-09-24 15:45:342791
Sam Maiera6e76d72022-02-11 21:43:502792 contents = input_api.ReadFile(f)
2793 full_disable_match = full_disable_pattern.search(contents)
2794 if full_disable_match:
2795 problems.append(' %s' % f.LocalPath())
Dominic Battre033531052018-09-24 15:45:342796
Sam Maiera6e76d72022-02-11 21:43:502797 if not problems:
2798 return []
2799 return [
2800 output_api.PresubmitPromptWarning(
2801 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
2802 '\n'.join(problems))
2803 ]
2804
Dominic Battre033531052018-09-24 15:45:342805
Nina Satragnof7660532021-09-20 18:03:352806def CheckForgettingMAYBEInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502807 """Checks to make sure tests disabled conditionally are not missing a
2808 corresponding MAYBE_ prefix.
2809 """
2810 # Expect at least a lowercase character in the test name. This helps rule out
2811 # false positives with macros wrapping the actual tests name.
2812 define_maybe_pattern = input_api.re.compile(
2813 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
Bruce Dawsonffc55292022-04-20 04:18:192814 # The test_maybe_pattern needs to handle all of these forms. The standard:
2815 # IN_PROC_TEST_F(SyncTest, MAYBE_Start) {
2816 # With a wrapper macro around the test name:
2817 # IN_PROC_TEST_F(SyncTest, E2E_ENABLED(MAYBE_Start)) {
2818 # And the odd-ball NACL_BROWSER_TEST_f format:
2819 # NACL_BROWSER_TEST_F(NaClBrowserTest, SimpleLoad, {
2820 # The optional E2E_ENABLED-style is handled with (\w*\()?
2821 # The NACL_BROWSER_TEST_F pattern is handled by allowing a trailing comma or
2822 # trailing ')'.
2823 test_maybe_pattern = (
2824 r'^\s*\w*TEST[^(]*\(\s*\w+,\s*(\w*\()?MAYBE_{test_name}[\),]')
Sam Maiera6e76d72022-02-11 21:43:502825 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
2826 warnings = []
Nina Satragnof7660532021-09-20 18:03:352827
Sam Maiera6e76d72022-02-11 21:43:502828 # Read the entire files. We can't just read the affected lines, forgetting to
2829 # add MAYBE_ on a change would not show up otherwise.
Arthur Sonzognic66e9c82024-04-23 07:53:042830 for f in input_api.AffectedFiles(include_deletes=False):
Sam Maiera6e76d72022-02-11 21:43:502831 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2832 continue
2833 contents = input_api.ReadFile(f)
2834 lines = contents.splitlines(True)
2835 current_position = 0
2836 warning_test_names = set()
2837 for line_num, line in enumerate(lines, start=1):
2838 current_position += len(line)
2839 maybe_match = define_maybe_pattern.search(line)
2840 if maybe_match:
2841 test_name = maybe_match.group('test_name')
2842 # Do not warn twice for the same test.
2843 if (test_name in warning_test_names):
2844 continue
2845 warning_test_names.add(test_name)
Nina Satragnof7660532021-09-20 18:03:352846
Sam Maiera6e76d72022-02-11 21:43:502847 # Attempt to find the corresponding MAYBE_ test or suite, starting from
2848 # the current position.
2849 test_match = input_api.re.compile(
2850 test_maybe_pattern.format(test_name=test_name),
2851 input_api.re.MULTILINE).search(contents, current_position)
2852 suite_match = input_api.re.compile(
2853 suite_maybe_pattern.format(test_name=test_name),
2854 input_api.re.MULTILINE).search(contents, current_position)
2855 if not test_match and not suite_match:
2856 warnings.append(
2857 output_api.PresubmitPromptWarning(
2858 '%s:%d found MAYBE_ defined without corresponding test %s'
2859 % (f.LocalPath(), line_num, test_name)))
2860 return warnings
2861
[email protected]72df4e782012-06-21 16:28:182862
Saagar Sanghavifceeaae2020-08-12 16:40:362863def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502864 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
2865 errors = []
Kalvin Lee4a3b79de2022-05-26 16:00:162866 pattern = input_api.re.compile(r'\bDCHECK_IS_ON\b(?!\(\))',
Sam Maiera6e76d72022-02-11 21:43:502867 input_api.re.MULTILINE)
2868 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2869 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
2870 continue
2871 for lnum, line in f.ChangedContents():
2872 if input_api.re.search(pattern, line):
2873 errors.append(
2874 output_api.PresubmitError((
2875 '%s:%d: Use of DCHECK_IS_ON() must be written as "#if '
2876 + 'DCHECK_IS_ON()", not forgetting the parentheses.') %
2877 (f.LocalPath(), lnum)))
2878 return errors
danakj61c1aa22015-10-26 19:55:522879
2880
Weilun Shia487fad2020-10-28 00:10:342881# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
2882# more reliable way. See
2883# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:192884
wnwenbdc444e2016-05-25 13:44:152885
Saagar Sanghavifceeaae2020-08-12 16:40:362886def CheckFlakyTestUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502887 """Check that FlakyTest annotation is our own instead of the android one"""
2888 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
2889 files = []
2890 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2891 if f.LocalPath().endswith('Test.java'):
2892 if pattern.search(input_api.ReadFile(f)):
2893 files.append(f)
2894 if len(files):
2895 return [
2896 output_api.PresubmitError(
2897 'Use org.chromium.base.test.util.FlakyTest instead of '
2898 'android.test.FlakyTest', files)
2899 ]
2900 return []
mcasasb7440c282015-02-04 14:52:192901
wnwenbdc444e2016-05-25 13:44:152902
Saagar Sanghavifceeaae2020-08-12 16:40:362903def CheckNoDEPSGIT(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502904 """Make sure .DEPS.git is never modified manually."""
2905 if any(f.LocalPath().endswith('.DEPS.git')
2906 for f in input_api.AffectedFiles()):
2907 return [
2908 output_api.PresubmitError(
2909 'Never commit changes to .DEPS.git. This file is maintained by an\n'
2910 'automated system based on what\'s in DEPS and your changes will be\n'
2911 'overwritten.\n'
2912 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
2913 'get-the-code#Rolling_DEPS\n'
2914 'for more information')
2915 ]
2916 return []
[email protected]2a8ac9c2011-10-19 17:20:442917
2918
Sven Zheng76a79ea2022-12-21 21:25:242919def CheckCrosApiNeedBrowserTest(input_api, output_api):
2920 """Check new crosapi should add browser test."""
2921 has_new_crosapi = False
2922 has_browser_test = False
2923 for f in input_api.AffectedFiles():
Anton Bershanskyi4253349482025-02-11 21:01:272924 path = f.UnixLocalPath()
Sven Zheng76a79ea2022-12-21 21:25:242925 if (path.startswith('chromeos/crosapi/mojom') and
2926 _IsMojomFile(input_api, path) and f.Action() == 'A'):
2927 has_new_crosapi = True
2928 if path.endswith('browsertest.cc') or path.endswith('browser_test.cc'):
2929 has_browser_test = True
2930 if has_new_crosapi and not has_browser_test:
2931 return [
2932 output_api.PresubmitPromptWarning(
2933 'You are adding a new crosapi, but there is no file ends with '
2934 'browsertest.cc file being added or modified. It is important '
2935 'to add crosapi browser test coverage to avoid version '
2936 ' skew issues.\n'
2937 'Check //docs/lacros/test_instructions.md for more information.'
2938 )
2939 ]
2940 return []
2941
2942
Saagar Sanghavifceeaae2020-08-12 16:40:362943def CheckValidHostsInDEPSOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502944 """Checks that DEPS file deps are from allowed_hosts."""
2945 # Run only if DEPS file has been modified to annoy fewer bystanders.
2946 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
2947 return []
2948 # Outsource work to gclient verify
2949 try:
2950 gclient_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
2951 'third_party', 'depot_tools',
2952 'gclient.py')
2953 input_api.subprocess.check_output(
Bruce Dawson8a43cf72022-05-13 17:10:322954 [input_api.python3_executable, gclient_path, 'verify'],
Sam Maiera6e76d72022-02-11 21:43:502955 stderr=input_api.subprocess.STDOUT)
2956 return []
2957 except input_api.subprocess.CalledProcessError as error:
2958 return [
2959 output_api.PresubmitError(
2960 'DEPS file must have only git dependencies.',
2961 long_text=error.output)
2962 ]
tandriief664692014-09-23 14:51:472963
2964
Mario Sanchez Prada2472cab2019-09-18 10:58:312965def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152966 ban_rule):
Allen Bauer84778682022-09-22 16:28:562967 """Helper method for checking for banned constructs.
Mario Sanchez Prada2472cab2019-09-18 10:58:312968
Sam Maiera6e76d72022-02-11 21:43:502969 Returns an string composed of the name of the file, the line number where the
2970 match has been found and the additional text passed as |message| in case the
2971 target type name matches the text inside the line passed as parameter.
2972 """
2973 result = []
Peng Huang9c5949a02020-06-11 19:20:542974
Daniel Chenga44a1bcd2022-03-15 20:00:152975 # Ignore comments about banned types.
2976 if input_api.re.search(r"^ *//", line):
Sam Maiera6e76d72022-02-11 21:43:502977 return result
Daniel Chenga44a1bcd2022-03-15 20:00:152978 # A // nocheck comment will bypass this error.
2979 if line.endswith(" nocheck"):
Sam Maiera6e76d72022-02-11 21:43:502980 return result
2981
2982 matched = False
Daniel Chenga44a1bcd2022-03-15 20:00:152983 if ban_rule.pattern[0:1] == '/':
2984 regex = ban_rule.pattern[1:]
Sam Maiera6e76d72022-02-11 21:43:502985 if input_api.re.search(regex, line):
2986 matched = True
Daniel Chenga44a1bcd2022-03-15 20:00:152987 elif ban_rule.pattern in line:
Sam Maiera6e76d72022-02-11 21:43:502988 matched = True
2989
2990 if matched:
2991 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
Daniel Chenga44a1bcd2022-03-15 20:00:152992 for line in ban_rule.explanation:
2993 result.append(' %s' % line)
Sam Maiera6e76d72022-02-11 21:43:502994
danakjd18e8892020-12-17 17:42:012995 return result
Mario Sanchez Prada2472cab2019-09-18 10:58:312996
2997
Saagar Sanghavifceeaae2020-08-12 16:40:362998def CheckNoBannedFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502999 """Make sure that banned functions are not used."""
3000 warnings = []
3001 errors = []
[email protected]127f18ec2012-06-16 05:05:593002
Sam Maiera6e76d72022-02-11 21:43:503003 def IsExcludedFile(affected_file, excluded_paths):
Daniel Chenga44a1bcd2022-03-15 20:00:153004 if not excluded_paths:
3005 return False
3006
Anton Bershanskyi4253349482025-02-11 21:01:273007 local_path = affected_file.UnixLocalPath()
Sam Maiera6e76d72022-02-11 21:43:503008 for item in excluded_paths:
3009 if input_api.re.match(item, local_path):
3010 return True
3011 return False
wnwenbdc444e2016-05-25 13:44:153012
Sam Maiera6e76d72022-02-11 21:43:503013 def IsIosObjcFile(affected_file):
3014 local_path = affected_file.LocalPath()
3015 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m',
3016 '.h'):
3017 return False
3018 basename = input_api.os_path.basename(local_path)
3019 if 'ios' in basename.split('_'):
3020 return True
3021 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
3022 if sep and 'ios' in local_path.split(sep):
3023 return True
3024 return False
Sylvain Defresnea8b73d252018-02-28 15:45:543025
Daniel Chenga44a1bcd2022-03-15 20:00:153026 def CheckForMatch(affected_file, line_num: int, line: str,
3027 ban_rule: BanRule):
3028 if IsExcludedFile(affected_file, ban_rule.excluded_paths):
3029 return
3030
Sam Maiera6e76d72022-02-11 21:43:503031 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
Daniel Chenga44a1bcd2022-03-15 20:00:153032 ban_rule)
Sam Maiera6e76d72022-02-11 21:43:503033 if problems:
Daniel Chenga44a1bcd2022-03-15 20:00:153034 if ban_rule.treat_as_error is not None and ban_rule.treat_as_error:
Sam Maiera6e76d72022-02-11 21:43:503035 errors.extend(problems)
3036 else:
3037 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:153038
Sam Maiera6e76d72022-02-11 21:43:503039 file_filter = lambda f: f.LocalPath().endswith(('.java'))
3040 for f in input_api.AffectedFiles(file_filter=file_filter):
3041 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:153042 for ban_rule in _BANNED_JAVA_FUNCTIONS:
3043 CheckForMatch(f, line_num, line, ban_rule)
Eric Stevensona9a980972017-09-23 00:04:413044
Clement Yan9b330cb2022-11-17 05:25:293045 file_filter = lambda f: f.LocalPath().endswith(('.js', '.ts'))
3046 for f in input_api.AffectedFiles(file_filter=file_filter):
3047 for line_num, line in f.ChangedContents():
3048 for ban_rule in _BANNED_JAVASCRIPT_FUNCTIONS:
3049 CheckForMatch(f, line_num, line, ban_rule)
3050
Sam Maiera6e76d72022-02-11 21:43:503051 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
3052 for f in input_api.AffectedFiles(file_filter=file_filter):
3053 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:153054 for ban_rule in _BANNED_OBJC_FUNCTIONS:
3055 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:593056
Sam Maiera6e76d72022-02-11 21:43:503057 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
3058 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:153059 for ban_rule in _BANNED_IOS_OBJC_FUNCTIONS:
3060 CheckForMatch(f, line_num, line, ban_rule)
Sylvain Defresnea8b73d252018-02-28 15:45:543061
Sam Maiera6e76d72022-02-11 21:43:503062 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
3063 for f in input_api.AffectedFiles(file_filter=egtest_filter):
3064 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:153065 for ban_rule in _BANNED_IOS_EGTEST_FUNCTIONS:
3066 CheckForMatch(f, line_num, line, ban_rule)
Peter K. Lee6c03ccff2019-07-15 14:40:053067
Sam Maiera6e76d72022-02-11 21:43:503068 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
3069 for f in input_api.AffectedFiles(file_filter=file_filter):
3070 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:153071 for ban_rule in _BANNED_CPP_FUNCTIONS:
3072 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:593073
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:153074 # As of 05/2024, iOS fully migrated ConsentLevel::kSync to kSignin, and
3075 # Android is in the process of preventing new users from entering kSync.
3076 # So the warning is restricted to those platforms.
Riley Wong49be8a882025-02-27 00:38:233077 ios_pattern = input_api.re.compile(r'(^|[\W_])ios[\W_]')
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:153078 file_filter = lambda f: (f.LocalPath().endswith(('.cc', '.mm', '.h')) and
3079 ('android' in f.LocalPath() or
3080 # Simply checking for an 'ios' substring would
3081 # catch unrelated cases, use a regex.
3082 ios_pattern.search(f.LocalPath())))
3083 for f in input_api.AffectedFiles(file_filter=file_filter):
3084 for line_num, line in f.ChangedContents():
3085 for ban_rule in _DEPRECATED_SYNC_CONSENT_CPP_FUNCTIONS:
3086 CheckForMatch(f, line_num, line, ban_rule)
3087
3088 file_filter = lambda f: f.LocalPath().endswith(('.java'))
3089 for f in input_api.AffectedFiles(file_filter=file_filter):
3090 for line_num, line in f.ChangedContents():
3091 for ban_rule in _DEPRECATED_SYNC_CONSENT_JAVA_FUNCTIONS:
3092 CheckForMatch(f, line_num, line, ban_rule)
3093
Daniel Cheng92c15e32022-03-16 17:48:223094 file_filter = lambda f: f.LocalPath().endswith(('.mojom'))
3095 for f in input_api.AffectedFiles(file_filter=file_filter):
3096 for line_num, line in f.ChangedContents():
3097 for ban_rule in _BANNED_MOJOM_PATTERNS:
3098 CheckForMatch(f, line_num, line, ban_rule)
3099
3100
Sam Maiera6e76d72022-02-11 21:43:503101 result = []
3102 if (warnings):
3103 result.append(
3104 output_api.PresubmitPromptWarning('Banned functions were used.\n' +
3105 '\n'.join(warnings)))
3106 if (errors):
3107 result.append(
3108 output_api.PresubmitError('Banned functions were used.\n' +
3109 '\n'.join(errors)))
3110 return result
[email protected]127f18ec2012-06-16 05:05:593111
Michael Thiessen44457642020-02-06 00:24:153112def _CheckAndroidNoBannedImports(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503113 """Make sure that banned java imports are not used."""
3114 errors = []
Michael Thiessen44457642020-02-06 00:24:153115
Sam Maiera6e76d72022-02-11 21:43:503116 file_filter = lambda f: f.LocalPath().endswith(('.java'))
3117 for f in input_api.AffectedFiles(file_filter=file_filter):
3118 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:153119 for ban_rule in _BANNED_JAVA_IMPORTS:
3120 # Consider merging this into the above function. There is no
3121 # real difference anymore other than helping with a little
3122 # bit of boilerplate text. Doing so means things like
3123 # `treat_as_error` will also be uniformly handled.
Sam Maiera6e76d72022-02-11 21:43:503124 problems = _GetMessageForMatchingType(input_api, f, line_num,
Daniel Chenga44a1bcd2022-03-15 20:00:153125 line, ban_rule)
Sam Maiera6e76d72022-02-11 21:43:503126 if problems:
3127 errors.extend(problems)
3128 result = []
3129 if (errors):
3130 result.append(
3131 output_api.PresubmitError('Banned imports were used.\n' +
3132 '\n'.join(errors)))
3133 return result
Michael Thiessen44457642020-02-06 00:24:153134
3135
Saagar Sanghavifceeaae2020-08-12 16:40:363136def CheckNoPragmaOnce(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503137 """Make sure that banned functions are not used."""
3138 files = []
3139 pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
3140 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
3141 if not f.LocalPath().endswith('.h'):
3142 continue
Bruce Dawson4c4c2922022-05-02 18:07:333143 if f.LocalPath().endswith('com_imported_mstscax.h'):
3144 continue
Sam Maiera6e76d72022-02-11 21:43:503145 contents = input_api.ReadFile(f)
3146 if pattern.search(contents):
3147 files.append(f)
[email protected]6c063c62012-07-11 19:11:063148
Sam Maiera6e76d72022-02-11 21:43:503149 if files:
3150 return [
3151 output_api.PresubmitError(
3152 'Do not use #pragma once in header files.\n'
3153 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
3154 files)
3155 ]
3156 return []
[email protected]6c063c62012-07-11 19:11:063157
[email protected]127f18ec2012-06-16 05:05:593158
Saagar Sanghavifceeaae2020-08-12 16:40:363159def CheckNoTrinaryTrueFalse(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503160 """Checks to make sure we don't introduce use of foo ? true : false."""
3161 problems = []
3162 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
3163 for f in input_api.AffectedFiles():
3164 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
3165 continue
[email protected]e7479052012-09-19 00:26:123166
Sam Maiera6e76d72022-02-11 21:43:503167 for line_num, line in f.ChangedContents():
3168 if pattern.match(line):
3169 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]e7479052012-09-19 00:26:123170
Sam Maiera6e76d72022-02-11 21:43:503171 if not problems:
3172 return []
3173 return [
3174 output_api.PresubmitPromptWarning(
3175 'Please consider avoiding the "? true : false" pattern if possible.\n'
3176 + '\n'.join(problems))
3177 ]
[email protected]e7479052012-09-19 00:26:123178
3179
Saagar Sanghavifceeaae2020-08-12 16:40:363180def CheckUnwantedDependencies(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503181 """Runs checkdeps on #include and import statements added in this
3182 change. Breaking - rules is an error, breaking ! rules is a
3183 warning.
3184 """
3185 # Return early if no relevant file types were modified.
3186 for f in input_api.AffectedFiles():
3187 path = f.LocalPath()
3188 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path)
3189 or _IsJavaFile(input_api, path)):
3190 break
[email protected]55f9f382012-07-31 11:02:183191 else:
Sam Maiera6e76d72022-02-11 21:43:503192 return []
rhalavati08acd232017-04-03 07:23:283193
Sam Maiera6e76d72022-02-11 21:43:503194 import sys
3195 # We need to wait until we have an input_api object and use this
3196 # roundabout construct to import checkdeps because this file is
3197 # eval-ed and thus doesn't have __file__.
3198 original_sys_path = sys.path
3199 try:
3200 sys.path = sys.path + [
3201 input_api.os_path.join(input_api.PresubmitLocalPath(),
3202 'buildtools', 'checkdeps')
3203 ]
3204 import checkdeps
3205 from rules import Rule
3206 finally:
3207 # Restore sys.path to what it was before.
3208 sys.path = original_sys_path
[email protected]55f9f382012-07-31 11:02:183209
Sam Maiera6e76d72022-02-11 21:43:503210 added_includes = []
3211 added_imports = []
3212 added_java_imports = []
3213 for f in input_api.AffectedFiles():
3214 if _IsCPlusPlusFile(input_api, f.LocalPath()):
3215 changed_lines = [line for _, line in f.ChangedContents()]
3216 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
3217 elif _IsProtoFile(input_api, f.LocalPath()):
3218 changed_lines = [line for _, line in f.ChangedContents()]
3219 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
3220 elif _IsJavaFile(input_api, f.LocalPath()):
3221 changed_lines = [line for _, line in f.ChangedContents()]
3222 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:243223
Sam Maiera6e76d72022-02-11 21:43:503224 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
3225
3226 error_descriptions = []
3227 warning_descriptions = []
3228 error_subjects = set()
3229 warning_subjects = set()
3230
3231 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
3232 added_includes):
3233 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3234 description_with_path = '%s\n %s' % (path, rule_description)
3235 if rule_type == Rule.DISALLOW:
3236 error_descriptions.append(description_with_path)
3237 error_subjects.add("#includes")
3238 else:
3239 warning_descriptions.append(description_with_path)
3240 warning_subjects.add("#includes")
3241
3242 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
3243 added_imports):
3244 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3245 description_with_path = '%s\n %s' % (path, rule_description)
3246 if rule_type == Rule.DISALLOW:
3247 error_descriptions.append(description_with_path)
3248 error_subjects.add("imports")
3249 else:
3250 warning_descriptions.append(description_with_path)
3251 warning_subjects.add("imports")
3252
3253 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
3254 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
3255 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3256 description_with_path = '%s\n %s' % (path, rule_description)
3257 if rule_type == Rule.DISALLOW:
3258 error_descriptions.append(description_with_path)
3259 error_subjects.add("imports")
3260 else:
3261 warning_descriptions.append(description_with_path)
3262 warning_subjects.add("imports")
3263
3264 results = []
3265 if error_descriptions:
3266 results.append(
3267 output_api.PresubmitError(
3268 'You added one or more %s that violate checkdeps rules.' %
3269 " and ".join(error_subjects), error_descriptions))
3270 if warning_descriptions:
3271 results.append(
3272 output_api.PresubmitPromptOrNotify(
3273 'You added one or more %s of files that are temporarily\n'
3274 'allowed but being removed. Can you avoid introducing the\n'
3275 '%s? See relevant DEPS file(s) for details and contacts.' %
3276 (" and ".join(warning_subjects), "/".join(warning_subjects)),
3277 warning_descriptions))
3278 return results
[email protected]55f9f382012-07-31 11:02:183279
3280
Saagar Sanghavifceeaae2020-08-12 16:40:363281def CheckFilePermissions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503282 """Check that all files have their permissions properly set."""
3283 if input_api.platform == 'win32':
3284 return []
3285 checkperms_tool = input_api.os_path.join(input_api.PresubmitLocalPath(),
3286 'tools', 'checkperms',
3287 'checkperms.py')
3288 args = [
Bruce Dawson8a43cf72022-05-13 17:10:323289 input_api.python3_executable, checkperms_tool, '--root',
Sam Maiera6e76d72022-02-11 21:43:503290 input_api.change.RepositoryRoot()
3291 ]
3292 with input_api.CreateTemporaryFile() as file_list:
3293 for f in input_api.AffectedFiles():
3294 # checkperms.py file/directory arguments must be relative to the
3295 # repository.
3296 file_list.write((f.LocalPath() + '\n').encode('utf8'))
3297 file_list.close()
3298 args += ['--file-list', file_list.name]
3299 try:
3300 input_api.subprocess.check_output(args)
3301 return []
3302 except input_api.subprocess.CalledProcessError as error:
3303 return [
3304 output_api.PresubmitError('checkperms.py failed:',
3305 long_text=error.output.decode(
3306 'utf-8', 'ignore'))
3307 ]
[email protected]fbcafe5a2012-08-08 15:31:223308
3309
Saagar Sanghavifceeaae2020-08-12 16:40:363310def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503311 """Makes sure we don't include ui/aura/window_property.h
3312 in header files.
3313 """
3314 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
3315 errors = []
3316 for f in input_api.AffectedFiles():
3317 if not f.LocalPath().endswith('.h'):
3318 continue
3319 for line_num, line in f.ChangedContents():
3320 if pattern.match(line):
3321 errors.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]c8278b32012-10-30 20:35:493322
Sam Maiera6e76d72022-02-11 21:43:503323 results = []
3324 if errors:
3325 results.append(
3326 output_api.PresubmitError(
3327 'Header files should not include ui/aura/window_property.h',
3328 errors))
3329 return results
[email protected]c8278b32012-10-30 20:35:493330
3331
Omer Katzcc77ea92021-04-26 10:23:283332def CheckNoInternalHeapIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503333 """Makes sure we don't include any headers from
3334 third_party/blink/renderer/platform/heap/impl or
3335 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
3336 third_party/blink/renderer/platform/heap
3337 """
3338 impl_pattern = input_api.re.compile(
3339 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
3340 v8_wrapper_pattern = input_api.re.compile(
3341 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"'
3342 )
3343 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:313344 r"^third_party/blink/renderer/platform/heap/.*",
Anton Bershanskyi4253349482025-02-11 21:01:273345 f.UnixLocalPath())
Sam Maiera6e76d72022-02-11 21:43:503346 errors = []
Omer Katzcc77ea92021-04-26 10:23:283347
Sam Maiera6e76d72022-02-11 21:43:503348 for f in input_api.AffectedFiles(file_filter=file_filter):
3349 for line_num, line in f.ChangedContents():
3350 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
3351 errors.append(' %s:%d' % (f.LocalPath(), line_num))
Omer Katzcc77ea92021-04-26 10:23:283352
Sam Maiera6e76d72022-02-11 21:43:503353 results = []
3354 if errors:
3355 results.append(
3356 output_api.PresubmitError(
3357 'Do not include files from third_party/blink/renderer/platform/heap/impl'
3358 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
3359 'relevant counterparts from third_party/blink/renderer/platform/heap',
3360 errors))
3361 return results
Omer Katzcc77ea92021-04-26 10:23:283362
3363
[email protected]70ca77752012-11-20 03:45:033364def _CheckForVersionControlConflictsInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:503365 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
3366 errors = []
3367 for line_num, line in f.ChangedContents():
3368 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
3369 # First-level headers in markdown look a lot like version control
3370 # conflict markers. http://daringfireball.net/projects/markdown/basics
3371 continue
3372 if pattern.match(line):
3373 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
3374 return errors
[email protected]70ca77752012-11-20 03:45:033375
3376
Saagar Sanghavifceeaae2020-08-12 16:40:363377def CheckForVersionControlConflicts(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503378 """Usually this is not intentional and will cause a compile failure."""
3379 errors = []
3380 for f in input_api.AffectedFiles():
3381 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
[email protected]70ca77752012-11-20 03:45:033382
Sam Maiera6e76d72022-02-11 21:43:503383 results = []
3384 if errors:
3385 results.append(
3386 output_api.PresubmitError(
3387 'Version control conflict markers found, please resolve.',
3388 errors))
3389 return results
[email protected]70ca77752012-11-20 03:45:033390
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203391
Saagar Sanghavifceeaae2020-08-12 16:40:363392def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
Dirk Prankee4df27972025-02-26 18:39:353393 pattern = input_api.re.compile(r'support\.google\.com\/chrome.*/answer')
Sam Maiera6e76d72022-02-11 21:43:503394 errors = []
3395 for f in input_api.AffectedFiles():
3396 for line_num, line in f.ChangedContents():
3397 if pattern.search(line):
3398 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
estadee17314a02017-01-12 16:22:163399
Sam Maiera6e76d72022-02-11 21:43:503400 results = []
3401 if errors:
3402 results.append(
3403 output_api.PresubmitPromptWarning(
3404 'Found Google support URL addressed by answer number. Please replace '
3405 'with a p= identifier instead. See crbug.com/679462\n',
3406 errors))
3407 return results
estadee17314a02017-01-12 16:22:163408
[email protected]70ca77752012-11-20 03:45:033409
Saagar Sanghavifceeaae2020-08-12 16:40:363410def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503411 def FilterFile(affected_file):
3412 """Filter function for use with input_api.AffectedSourceFiles,
3413 below. This filters out everything except non-test files from
3414 top-level directories that generally speaking should not hard-code
3415 service URLs (e.g. src/android_webview/, src/content/ and others).
3416 """
3417 return input_api.FilterSourceFile(
3418 affected_file,
Bruce Dawson40fece62022-09-16 19:58:313419 files_to_check=[r'^(android_webview|base|content|net)/.*'],
Sam Maiera6e76d72022-02-11 21:43:503420 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3421 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:443422
Dirk Prankee4df27972025-02-26 18:39:353423 base_pattern = (r'"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
3424 r'\.(com|net)[^"]*"')
Sam Maiera6e76d72022-02-11 21:43:503425 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
3426 pattern = input_api.re.compile(base_pattern)
3427 problems = [] # items are (filename, line_number, line)
3428 for f in input_api.AffectedSourceFiles(FilterFile):
3429 for line_num, line in f.ChangedContents():
3430 if not comment_pattern.search(line) and pattern.search(line):
3431 problems.append((f.LocalPath(), line_num, line))
[email protected]06e6d0ff2012-12-11 01:36:443432
Sam Maiera6e76d72022-02-11 21:43:503433 if problems:
3434 return [
3435 output_api.PresubmitPromptOrNotify(
3436 'Most layers below src/chrome/ should not hardcode service URLs.\n'
3437 'Are you sure this is correct?', [
3438 ' %s:%d: %s' % (problem[0], problem[1], problem[2])
3439 for problem in problems
3440 ])
3441 ]
3442 else:
3443 return []
[email protected]06e6d0ff2012-12-11 01:36:443444
3445
Saagar Sanghavifceeaae2020-08-12 16:40:363446def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503447 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
James Cook6b6597c2019-11-06 22:05:293448
Sam Maiera6e76d72022-02-11 21:43:503449 def FileFilter(affected_file):
3450 """Includes directories known to be Chrome OS only."""
3451 return input_api.FilterSourceFile(
3452 affected_file,
3453 files_to_check=(
3454 '^ash/',
3455 '^chromeos/', # Top-level src/chromeos.
3456 '.*/chromeos/', # Any path component.
3457 '^components/arc',
3458 '^components/exo'),
3459 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:293460
Sam Maiera6e76d72022-02-11 21:43:503461 prefs = []
3462 priority_prefs = []
3463 for f in input_api.AffectedFiles(file_filter=FileFilter):
3464 for line_num, line in f.ChangedContents():
3465 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF',
3466 line):
3467 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
3468 prefs.append(' %s' % line)
3469 if input_api.re.search(
3470 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
3471 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
3472 priority_prefs.append(' %s' % line)
3473
3474 results = []
3475 if (prefs):
3476 results.append(
3477 output_api.PresubmitPromptWarning(
3478 'Preferences were registered as SYNCABLE_PREF and will be controlled '
3479 'by browser sync settings. If these prefs should be controlled by OS '
3480 'sync settings use SYNCABLE_OS_PREF instead.\n' +
3481 '\n'.join(prefs)))
3482 if (priority_prefs):
3483 results.append(
3484 output_api.PresubmitPromptWarning(
3485 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
3486 'controlled by browser sync settings. If these prefs should be '
3487 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
3488 'instead.\n' + '\n'.join(prefs)))
3489 return results
James Cook6b6597c2019-11-06 22:05:293490
3491
Saagar Sanghavifceeaae2020-08-12 16:40:363492def CheckNoAbbreviationInPngFileName(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503493 """Makes sure there are no abbreviations in the name of PNG files.
3494 The native_client_sdk directory is excluded because it has auto-generated PNG
3495 files for documentation.
3496 """
3497 errors = []
Yuanqing Zhu9eef02832022-12-04 14:42:173498 files_to_check = [r'.*\.png$']
Bruce Dawson40fece62022-09-16 19:58:313499 files_to_skip = [r'^native_client_sdk/',
3500 r'^services/test/',
3501 r'^third_party/blink/web_tests/',
Bruce Dawson3db456212022-05-02 05:34:183502 ]
Sam Maiera6e76d72022-02-11 21:43:503503 file_filter = lambda f: input_api.FilterSourceFile(
3504 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Dirk Prankee4df27972025-02-26 18:39:353505 abbreviation = input_api.re.compile(r'.+_[a-z]\.png|.+_[a-z]_.*\.png')
Sam Maiera6e76d72022-02-11 21:43:503506 for f in input_api.AffectedFiles(include_deletes=False,
3507 file_filter=file_filter):
Yuanqing Zhu9eef02832022-12-04 14:42:173508 file_name = input_api.os_path.split(f.LocalPath())[1]
3509 if abbreviation.search(file_name):
3510 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:273511
Sam Maiera6e76d72022-02-11 21:43:503512 results = []
3513 if errors:
3514 results.append(
3515 output_api.PresubmitError(
3516 'The name of PNG files should not have abbreviations. \n'
3517 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
3518 'Contact [email protected] if you have questions.', errors))
3519 return results
[email protected]d2530012013-01-25 16:39:273520
Evan Stade7cd4a2c2022-08-04 23:37:253521def CheckNoProductIconsAddedToPublicRepo(input_api, output_api):
3522 """Heuristically identifies product icons based on their file name and reminds
3523 contributors not to add them to the Chromium repository.
3524 """
3525 errors = []
3526 files_to_check = [r'.*google.*\.png$|.*google.*\.svg$|.*google.*\.icon$']
3527 file_filter = lambda f: input_api.FilterSourceFile(
3528 f, files_to_check=files_to_check)
3529 for f in input_api.AffectedFiles(include_deletes=False,
3530 file_filter=file_filter):
3531 errors.append(' %s' % f.LocalPath())
3532
3533 results = []
3534 if errors:
Bruce Dawson3bcf0c92022-08-12 00:03:083535 # Give warnings instead of errors on presubmit --all and presubmit
3536 # --files.
3537 message_type = (output_api.PresubmitNotifyResult if input_api.no_diffs
3538 else output_api.PresubmitError)
Evan Stade7cd4a2c2022-08-04 23:37:253539 results.append(
Bruce Dawson3bcf0c92022-08-12 00:03:083540 message_type(
Evan Stade7cd4a2c2022-08-04 23:37:253541 'Trademarked images should not be added to the public repo. '
3542 'See crbug.com/944754', errors))
3543 return results
3544
[email protected]d2530012013-01-25 16:39:273545
Daniel Cheng4dcdb6b2017-04-13 08:30:173546def _ExtractAddRulesFromParsedDeps(parsed_deps):
Sam Maiera6e76d72022-02-11 21:43:503547 """Extract the rules that add dependencies from a parsed DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:173548
Sam Maiera6e76d72022-02-11 21:43:503549 Args:
3550 parsed_deps: the locals dictionary from evaluating the DEPS file."""
3551 add_rules = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:173552 add_rules.update([
Sam Maiera6e76d72022-02-11 21:43:503553 rule[1:] for rule in parsed_deps.get('include_rules', [])
Daniel Cheng4dcdb6b2017-04-13 08:30:173554 if rule.startswith('+') or rule.startswith('!')
3555 ])
Sam Maiera6e76d72022-02-11 21:43:503556 for _, rules in parsed_deps.get('specific_include_rules', {}).items():
3557 add_rules.update([
3558 rule[1:] for rule in rules
3559 if rule.startswith('+') or rule.startswith('!')
3560 ])
3561 return add_rules
Daniel Cheng4dcdb6b2017-04-13 08:30:173562
3563
3564def _ParseDeps(contents):
Sam Maiera6e76d72022-02-11 21:43:503565 """Simple helper for parsing DEPS files."""
Daniel Cheng4dcdb6b2017-04-13 08:30:173566
Sam Maiera6e76d72022-02-11 21:43:503567 # Stubs for handling special syntax in the root DEPS file.
3568 class _VarImpl:
3569 def __init__(self, local_scope):
3570 self._local_scope = local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:173571
Sam Maiera6e76d72022-02-11 21:43:503572 def Lookup(self, var_name):
3573 """Implements the Var syntax."""
3574 try:
3575 return self._local_scope['vars'][var_name]
3576 except KeyError:
3577 raise Exception('Var is not defined: %s' % var_name)
Daniel Cheng4dcdb6b2017-04-13 08:30:173578
Sam Maiera6e76d72022-02-11 21:43:503579 local_scope = {}
3580 global_scope = {
3581 'Var': _VarImpl(local_scope).Lookup,
3582 'Str': str,
3583 }
Dirk Pranke1b9e06382021-05-14 01:16:223584
Sam Maiera6e76d72022-02-11 21:43:503585 exec(contents, global_scope, local_scope)
3586 return local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:173587
3588
Andrew Grieveb77ac762024-11-29 15:01:483589def _FindAllDepsFilesForSubpath(input_api, subpath):
3590 ret = []
3591 while subpath:
3592 cur = input_api.os_path.join(input_api.change.RepositoryRoot(), subpath, 'DEPS')
Joanna Wang130e7bdd2024-12-10 17:39:033593 if input_api.os_path.isfile(cur):
Andrew Grieveb77ac762024-11-29 15:01:483594 ret.append(cur)
3595 subpath = input_api.os_path.dirname(subpath)
3596 return ret
3597
3598
3599def _FindAddedDepsThatRequireReview(input_api, depended_on_paths):
3600 """Filters to those whose DEPS set new_usages_require_review=True"""
3601 ret = set()
3602 cache = {}
3603 for target_path in depended_on_paths:
3604 for subpath in _FindAllDepsFilesForSubpath(input_api, target_path):
3605 config = cache.get(subpath)
3606 if config is None:
3607 config = _ParseDeps(input_api.ReadFile(subpath))
3608 cache[subpath] = config
3609 if config.get('new_usages_require_review'):
3610 ret.add(target_path)
3611 break
3612 return ret
3613
3614
Daniel Cheng4dcdb6b2017-04-13 08:30:173615def _CalculateAddedDeps(os_path, old_contents, new_contents):
Sam Maiera6e76d72022-02-11 21:43:503616 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
3617 a set of DEPS entries that we should look up.
[email protected]14a6131c2014-01-08 01:15:413618
Sam Maiera6e76d72022-02-11 21:43:503619 For a directory (rather than a specific filename) we fake a path to
3620 a specific filename by adding /DEPS. This is chosen as a file that
3621 will seldom or never be subject to per-file include_rules.
3622 """
3623 # We ignore deps entries on auto-generated directories.
3624 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:083625
Sam Maiera6e76d72022-02-11 21:43:503626 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
3627 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
Daniel Cheng4dcdb6b2017-04-13 08:30:173628
Sam Maiera6e76d72022-02-11 21:43:503629 added_deps = new_deps.difference(old_deps)
Daniel Cheng4dcdb6b2017-04-13 08:30:173630
Sam Maiera6e76d72022-02-11 21:43:503631 results = set()
3632 for added_dep in added_deps:
3633 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
3634 continue
3635 # Assume that a rule that ends in .h is a rule for a specific file.
3636 if added_dep.endswith('.h'):
3637 results.add(added_dep)
3638 else:
3639 results.add(os_path.join(added_dep, 'DEPS'))
3640 return results
[email protected]f32e2d1e2013-07-26 21:39:083641
Stephanie Kimec4f55a2024-04-24 16:54:023642def CheckForNewDEPSDownloadFromGoogleStorageHooks(input_api, output_api):
3643 """Checks that there are no new download_from_google_storage hooks"""
3644 for f in input_api.AffectedFiles(include_deletes=False):
3645 if f.LocalPath() == 'DEPS':
3646 old_hooks = _ParseDeps('\n'.join(f.OldContents()))['hooks']
3647 new_hooks = _ParseDeps('\n'.join(f.NewContents()))['hooks']
3648 old_name_to_hook = {hook['name']: hook for hook in old_hooks}
3649 new_name_to_hook = {hook['name']: hook for hook in new_hooks}
3650 added_hook_names = set(new_name_to_hook.keys()) - set(
3651 old_name_to_hook.keys())
3652 if not added_hook_names:
3653 return []
3654 new_download_from_google_storage_hooks = []
3655 for new_hook in added_hook_names:
3656 hook = new_name_to_hook[new_hook]
3657 action_cmd = hook['action']
3658 if any('download_from_google_storage' in arg
3659 for arg in action_cmd):
3660 new_download_from_google_storage_hooks.append(new_hook)
3661 if new_download_from_google_storage_hooks:
3662 return [
3663 output_api.PresubmitError(
3664 'Please do not add new download_from_google_storage '
3665 'hooks. Instead, add a `gcs` dep_type entry to `deps`. '
3666 'See https://chromium.googlesource.com/chromium/src.git'
3667 '/+/refs/heads/main/docs/gcs_dependencies.md for more '
3668 'info. Added hooks:',
3669 items=new_download_from_google_storage_hooks)
3670 ]
3671 return []
3672
[email protected]f32e2d1e2013-07-26 21:39:083673
Rasika Navarangec2d33d22024-05-23 15:19:023674def CheckEachPerfettoTestDataFileHasDepsEntry(input_api, output_api):
3675 test_data_filter = lambda f: input_api.FilterSourceFile(
Rasika Navarange08e542162024-05-31 13:31:263676 f, files_to_check=[r'^base/tracing/test/data_sha256/.*\.sha256'])
Rasika Navarangec2d33d22024-05-23 15:19:023677 if not any(input_api.AffectedFiles(file_filter=test_data_filter)):
3678 return []
3679
3680 # Find DEPS entry
3681 deps_entry = []
Rasika Navarange277cd662024-06-04 10:14:593682 old_deps_entry = []
Rasika Navarangec2d33d22024-05-23 15:19:023683 for f in input_api.AffectedFiles(include_deletes=False):
3684 if f.LocalPath() == 'DEPS':
3685 new_deps = _ParseDeps('\n'.join(f.NewContents()))['deps']
3686 deps_entry = new_deps['src/base/tracing/test/data']
Rasika Navarange277cd662024-06-04 10:14:593687 old_deps = _ParseDeps('\n'.join(f.OldContents()))['deps']
3688 old_deps_entry = old_deps['src/base/tracing/test/data']
Rasika Navarangec2d33d22024-05-23 15:19:023689 if not deps_entry:
Rasika Navarange08e542162024-05-31 13:31:263690 # TODO(312895063):Add back error when .sha256 files have been moved.
Rasika Navaranged977df342024-06-05 10:01:273691 return [output_api.PresubmitError(
Rasika Navarangec2d33d22024-05-23 15:19:023692 'You must update the DEPS file when you update a '
Rasika Navarange08e542162024-05-31 13:31:263693 '.sha256 file in base/tracing/test/data_sha256'
Rasika Navarangec2d33d22024-05-23 15:19:023694 )]
3695
3696 output = []
3697 for f in input_api.AffectedFiles(file_filter=test_data_filter):
3698 objects = deps_entry['objects']
3699 if not f.NewContents():
3700 # Deleted file so check that DEPS entry removed
3701 sha256_from_file = f.OldContents()[0]
3702 object_entry = next(
3703 (item for item in objects if item["sha256sum"] == sha256_from_file),
3704 None)
Rasika Navarange277cd662024-06-04 10:14:593705 old_entry = next(
3706 (item for item in old_deps_entry['objects'] if item["sha256sum"] == sha256_from_file),
3707 None)
Rasika Navarangec2d33d22024-05-23 15:19:023708 if object_entry:
Rasika Navarange277cd662024-06-04 10:14:593709 # Allow renaming of objects with the same hash
3710 if object_entry['object_name'] != old_entry['object_name']:
3711 continue
Rasika Navarangec2d33d22024-05-23 15:19:023712 output.append(output_api.PresubmitError(
3713 'You deleted %s so you must also remove the corresponding DEPS entry.'
3714 % f.LocalPath()
3715 ))
3716 continue
3717
3718 sha256_from_file = f.NewContents()[0]
3719 object_entry = next(
3720 (item for item in objects if item["sha256sum"] == sha256_from_file),
3721 None)
3722 if not object_entry:
3723 output.append(output_api.PresubmitError(
3724 'No corresponding DEPS entry found for %s. '
3725 'Run `base/tracing/test/test_data.py get_deps --filepath %s` '
3726 'to generate the DEPS entry.'
3727 % (f.LocalPath(), f.LocalPath())
3728 ))
3729
3730 if output:
3731 output.append(output_api.PresubmitError(
3732 'The DEPS entry for `src/base/tracing/test/data` in the DEPS file has not been '
3733 'updated properly. Run `base/tracing/test/test_data.py get_all_deps` to see what '
3734 'the DEPS entry should look like.'
3735 ))
3736 return output
3737
3738
Saagar Sanghavifceeaae2020-08-12 16:40:363739def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503740 """When a dependency prefixed with + is added to a DEPS file, we
3741 want to make sure that the change is reviewed by an OWNER of the
3742 target file or directory, to avoid layering violations from being
3743 introduced. This check verifies that this happens.
3744 """
3745 # We rely on Gerrit's code-owners to check approvals.
3746 # input_api.gerrit is always set for Chromium, but other projects
3747 # might not use Gerrit.
Bruce Dawson344ab262022-06-04 11:35:103748 if not input_api.gerrit or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:503749 return []
Bruce Dawsonb357aeb2022-08-09 15:38:303750 if 'PRESUBMIT_SKIP_NETWORK' in input_api.environ:
Sam Maiera6e76d72022-02-11 21:43:503751 return []
Bruce Dawsonb357aeb2022-08-09 15:38:303752 try:
3753 if (input_api.change.issue and
3754 input_api.gerrit.IsOwnersOverrideApproved(
3755 input_api.change.issue)):
3756 # Skip OWNERS check when Owners-Override label is approved. This is
3757 # intended for global owners, trusted bots, and on-call sheriffs.
3758 # Review is still required for these changes.
3759 return []
3760 except Exception as e:
Sam Maier4cef9242022-10-03 14:21:243761 return [output_api.PresubmitPromptWarning(
3762 'Failed to retrieve owner override status - %s' % str(e))]
Edward Lesmes6fba51082021-01-20 04:20:233763
Andrew Grieveb77ac762024-11-29 15:01:483764 # A set of paths (that might not exist) that are being added as DEPS
3765 # (via lines like "+foo/bar/baz").
3766 depended_on_paths = set()
jochen53efcdd2016-01-29 05:09:243767
Sam Maiera6e76d72022-02-11 21:43:503768 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:313769 r"^third_party/blink/.*",
Anton Bershanskyi4253349482025-02-11 21:01:273770 f.UnixLocalPath())
Sam Maiera6e76d72022-02-11 21:43:503771 for f in input_api.AffectedFiles(include_deletes=False,
3772 file_filter=file_filter):
3773 filename = input_api.os_path.basename(f.LocalPath())
3774 if filename == 'DEPS':
Andrew Grieveb77ac762024-11-29 15:01:483775 depended_on_paths.update(
Sam Maiera6e76d72022-02-11 21:43:503776 _CalculateAddedDeps(input_api.os_path,
3777 '\n'.join(f.OldContents()),
3778 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:553779
Andrew Grieveb77ac762024-11-29 15:01:483780 # Requiring reviews is opt-in as of https://crbug.com/365797506
3781 depended_on_paths = _FindAddedDepsThatRequireReview(input_api, depended_on_paths)
3782 if not depended_on_paths:
Sam Maiera6e76d72022-02-11 21:43:503783 return []
[email protected]e871964c2013-05-13 14:14:553784
Sam Maiera6e76d72022-02-11 21:43:503785 if input_api.is_committing:
3786 if input_api.tbr:
3787 return [
3788 output_api.PresubmitNotifyResult(
3789 '--tbr was specified, skipping OWNERS check for DEPS additions'
3790 )
3791 ]
Daniel Cheng3008dc12022-05-13 04:02:113792 # TODO(dcheng): Make this generate an error on dry runs if the reviewer
3793 # is not added, to prevent review serialization.
Sam Maiera6e76d72022-02-11 21:43:503794 if input_api.dry_run:
3795 return [
3796 output_api.PresubmitNotifyResult(
3797 'This is a dry run, skipping OWNERS check for DEPS additions'
3798 )
3799 ]
3800 if not input_api.change.issue:
3801 return [
3802 output_api.PresubmitError(
3803 "DEPS approval by OWNERS check failed: this change has "
3804 "no change number, so we can't check it for approvals.")
3805 ]
3806 output = output_api.PresubmitError
[email protected]14a6131c2014-01-08 01:15:413807 else:
Sam Maiera6e76d72022-02-11 21:43:503808 output = output_api.PresubmitNotifyResult
[email protected]e871964c2013-05-13 14:14:553809
Sam Maiera6e76d72022-02-11 21:43:503810 owner_email, reviewers = (
3811 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3812 input_api, None, approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:553813
Sam Maiera6e76d72022-02-11 21:43:503814 owner_email = owner_email or input_api.change.author_email
3815
3816 approval_status = input_api.owners_client.GetFilesApprovalStatus(
Andrew Grieveb77ac762024-11-29 15:01:483817 depended_on_paths, reviewers.union([owner_email]), [])
Sam Maiera6e76d72022-02-11 21:43:503818 missing_files = [
Andrew Grieveb77ac762024-11-29 15:01:483819 p for p in depended_on_paths
3820 if approval_status[p] != input_api.owners_client.APPROVED
Sam Maiera6e76d72022-02-11 21:43:503821 ]
3822
3823 # We strip the /DEPS part that was added by
3824 # _FilesToCheckForIncomingDeps to fake a path to a file in a
3825 # directory.
3826 def StripDeps(path):
3827 start_deps = path.rfind('/DEPS')
3828 if start_deps != -1:
3829 return path[:start_deps]
3830 else:
3831 return path
3832
Scott Leebf6a0942024-06-26 22:59:393833 submodule_paths = set(input_api.ListSubmodules())
3834 def is_from_submodules(path, submodule_paths):
3835 path = input_api.os_path.normpath(path)
3836 while path:
3837 if path in submodule_paths:
3838 return True
3839
3840 # All deps should be a relative path from the checkout.
3841 # i.e., shouldn't start with "/" or "c:\", for example.
3842 #
3843 # That said, this is to prevent an infinite loop, just in case
3844 # an input dep path starts with "/", because
3845 # os.path.dirname("/") => "/"
3846 parent = input_api.os_path.dirname(path)
3847 if parent == path:
3848 break
3849 path = parent
3850
3851 return False
3852
Sam Maiera6e76d72022-02-11 21:43:503853 unapproved_dependencies = [
3854 "'+%s'," % StripDeps(path) for path in missing_files
Scott Leebf6a0942024-06-26 22:59:393855 # if a newly added dep is from a submodule, it becomes trickier
3856 # to get suggested owners, especially it is from a different host.
3857 #
3858 # skip the review enforcement for cross-repo deps.
3859 if not is_from_submodules(path, submodule_paths)
Sam Maiera6e76d72022-02-11 21:43:503860 ]
3861
3862 if unapproved_dependencies:
3863 output_list = [
3864 output(
3865 'You need LGTM from owners of depends-on paths in DEPS that were '
3866 'modified in this CL:\n %s' %
3867 '\n '.join(sorted(unapproved_dependencies)))
3868 ]
3869 suggested_owners = input_api.owners_client.SuggestOwners(
3870 missing_files, exclude=[owner_email])
3871 output_list.append(
3872 output('Suggested missing target path OWNERS:\n %s' %
3873 '\n '.join(suggested_owners or [])))
3874 return output_list
3875
3876 return []
[email protected]e871964c2013-05-13 14:14:553877
3878
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493879# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:363880def CheckSpamLogging(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503881 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3882 files_to_skip = (
3883 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3884 input_api.DEFAULT_FILES_TO_SKIP + (
Jaewon Jung2f323bb2022-12-07 23:55:013885 r"^base/fuchsia/scoped_fx_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313886 r"^base/logging\.h$",
3887 r"^base/logging\.cc$",
3888 r"^base/task/thread_pool/task_tracker\.cc$",
3889 r"^chrome/app/chrome_main_delegate\.cc$",
Yao Li359937b2023-02-15 23:43:033890 r"^chrome/browser/ash/arc/enterprise/cert_store/arc_cert_installer\.cc$",
3891 r"^chrome/browser/ash/policy/remote_commands/user_command_arc_job\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313892 r"^chrome/browser/chrome_browser_main\.cc$",
3893 r"^chrome/browser/ui/startup/startup_browser_creator\.cc$",
3894 r"^chrome/browser/browser_switcher/bho/.*",
3895 r"^chrome/browser/diagnostics/diagnostics_writer\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313896 r"^chrome/chrome_elf/dll_hash/dll_hash_main\.cc$",
3897 r"^chrome/installer/setup/.*",
Daniel Ruberyad36eea2024-08-01 01:38:323898 # crdmg runs as a separate binary which intentionally does
3899 # not depend on base logging.
3900 r"^chrome/utility/safe_browsing/mac/crdmg\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313901 r"^chromecast/",
Vigen Issahhanjane2d93822023-06-30 15:57:203902 r"^components/cast",
Bruce Dawson40fece62022-09-16 19:58:313903 r"^components/media_control/renderer/media_playback_options\.cc$",
Salma Elmahallawy52976452023-01-27 17:04:493904 r"^components/policy/core/common/policy_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313905 r"^components/viz/service/display/"
Sam Maiera6e76d72022-02-11 21:43:503906 r"overlay_strategy_underlay_cast\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313907 r"^components/zucchini/.*",
Sam Maiera6e76d72022-02-11 21:43:503908 # TODO(peter): Remove exception. https://crbug.com/534537
Bruce Dawson40fece62022-09-16 19:58:313909 r"^content/browser/notifications/"
Sam Maiera6e76d72022-02-11 21:43:503910 r"notification_event_dispatcher_impl\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313911 r"^content/common/gpu/client/gl_helper_benchmark\.cc$",
3912 r"^courgette/courgette_minimal_tool\.cc$",
3913 r"^courgette/courgette_tool\.cc$",
3914 r"^extensions/renderer/logging_native_handler\.cc$",
3915 r"^fuchsia_web/common/init_logging\.cc$",
3916 r"^fuchsia_web/runners/common/web_component\.cc$",
Caroline Liua7050132023-02-13 22:23:153917 r"^fuchsia_web/shell/.*\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313918 r"^headless/app/headless_shell\.cc$",
3919 r"^ipc/ipc_logging\.cc$",
3920 r"^native_client_sdk/",
3921 r"^remoting/base/logging\.h$",
3922 r"^remoting/host/.*",
3923 r"^sandbox/linux/.*",
Austin Sullivana6054e02024-05-20 16:31:293924 r"^services/webnn/tflite/graph_impl_tflite\.cc$",
3925 r"^services/webnn/coreml/graph_impl_coreml\.mm$",
Bruce Dawson40fece62022-09-16 19:58:313926 r"^storage/browser/file_system/dump_file_system\.cc$",
Steinar H. Gundersone5689e42024-08-07 18:17:193927 r"^testing/perf/",
Bruce Dawson40fece62022-09-16 19:58:313928 r"^tools/",
3929 r"^ui/base/resource/data_pack\.cc$",
3930 r"^ui/aura/bench/bench_main\.cc$",
3931 r"^ui/ozone/platform/cast/",
3932 r"^ui/base/x/xwmstartupcheck/"
Sam Maiera6e76d72022-02-11 21:43:503933 r"xwmstartupcheck\.cc$"))
3934 source_file_filter = lambda x: input_api.FilterSourceFile(
3935 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:403936
Sam Maiera6e76d72022-02-11 21:43:503937 log_info = set([])
3938 printf = set([])
[email protected]85218562013-11-22 07:41:403939
Sam Maiera6e76d72022-02-11 21:43:503940 for f in input_api.AffectedSourceFiles(source_file_filter):
3941 for _, line in f.ChangedContents():
3942 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
3943 log_info.add(f.LocalPath())
3944 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
3945 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:373946
Sam Maiera6e76d72022-02-11 21:43:503947 if input_api.re.search(r"\bprintf\(", line):
3948 printf.add(f.LocalPath())
3949 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
3950 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:403951
Sam Maiera6e76d72022-02-11 21:43:503952 if log_info:
3953 return [
3954 output_api.PresubmitError(
3955 'These files spam the console log with LOG(INFO):',
3956 items=log_info)
3957 ]
3958 if printf:
3959 return [
3960 output_api.PresubmitError(
3961 'These files spam the console log with printf/fprintf:',
3962 items=printf)
3963 ]
3964 return []
[email protected]85218562013-11-22 07:41:403965
3966
Saagar Sanghavifceeaae2020-08-12 16:40:363967def CheckForAnonymousVariables(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503968 """These types are all expected to hold locks while in scope and
3969 so should never be anonymous (which causes them to be immediately
3970 destroyed)."""
3971 they_who_must_be_named = [
3972 'base::AutoLock',
3973 'base::AutoReset',
3974 'base::AutoUnlock',
3975 'SkAutoAlphaRestore',
3976 'SkAutoBitmapShaderInstall',
3977 'SkAutoBlitterChoose',
3978 'SkAutoBounderCommit',
3979 'SkAutoCallProc',
3980 'SkAutoCanvasRestore',
3981 'SkAutoCommentBlock',
3982 'SkAutoDescriptor',
3983 'SkAutoDisableDirectionCheck',
3984 'SkAutoDisableOvalCheck',
3985 'SkAutoFree',
3986 'SkAutoGlyphCache',
3987 'SkAutoHDC',
3988 'SkAutoLockColors',
3989 'SkAutoLockPixels',
3990 'SkAutoMalloc',
3991 'SkAutoMaskFreeImage',
3992 'SkAutoMutexAcquire',
3993 'SkAutoPathBoundsUpdate',
3994 'SkAutoPDFRelease',
3995 'SkAutoRasterClipValidate',
3996 'SkAutoRef',
3997 'SkAutoTime',
3998 'SkAutoTrace',
3999 'SkAutoUnref',
4000 ]
4001 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
4002 # bad: base::AutoLock(lock.get());
4003 # not bad: base::AutoLock lock(lock.get());
4004 bad_pattern = input_api.re.compile(anonymous)
4005 # good: new base::AutoLock(lock.get())
4006 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
4007 errors = []
[email protected]49aa76a2013-12-04 06:59:164008
Sam Maiera6e76d72022-02-11 21:43:504009 for f in input_api.AffectedFiles():
4010 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
4011 continue
4012 for linenum, line in f.ChangedContents():
4013 if bad_pattern.search(line) and not good_pattern.search(line):
4014 errors.append('%s:%d' % (f.LocalPath(), linenum))
[email protected]49aa76a2013-12-04 06:59:164015
Sam Maiera6e76d72022-02-11 21:43:504016 if errors:
4017 return [
4018 output_api.PresubmitError(
4019 'These lines create anonymous variables that need to be named:',
4020 items=errors)
4021 ]
4022 return []
[email protected]49aa76a2013-12-04 06:59:164023
4024
Saagar Sanghavifceeaae2020-08-12 16:40:364025def CheckUniquePtrOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504026 # Returns whether |template_str| is of the form <T, U...> for some types T
Glen Robertson9142ffd72024-05-16 01:37:474027 # and U, or is invalid due to mismatched angle bracket pairs. Assumes that
4028 # |template_str| is already in the form <...>.
4029 def HasMoreThanOneArgOrInvalid(template_str):
Sam Maiera6e76d72022-02-11 21:43:504030 # Level of <...> nesting.
4031 nesting = 0
4032 for c in template_str:
4033 if c == '<':
4034 nesting += 1
4035 elif c == '>':
4036 nesting -= 1
4037 elif c == ',' and nesting == 1:
4038 return True
Glen Robertson9142ffd72024-05-16 01:37:474039 if nesting != 0:
Daniel Cheng566634ff2024-06-29 14:56:534040 # Invalid.
4041 return True
Sam Maiera6e76d72022-02-11 21:43:504042 return False
Vaclav Brozekb7fadb692018-08-30 06:39:534043
Sam Maiera6e76d72022-02-11 21:43:504044 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
4045 sources = lambda affected_file: input_api.FilterSourceFile(
4046 affected_file,
4047 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4048 DEFAULT_FILES_TO_SKIP),
4049 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:554050
Sam Maiera6e76d72022-02-11 21:43:504051 # Pattern to capture a single "<...>" block of template arguments. It can
4052 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
4053 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
4054 # latter would likely require counting that < and > match, which is not
4055 # expressible in regular languages. Should the need arise, one can introduce
4056 # limited counting (matching up to a total number of nesting depth), which
4057 # should cover all practical cases for already a low nesting limit.
4058 template_arg_pattern = (
4059 r'<[^>]*' # Opening block of <.
4060 r'>([^<]*>)?') # Closing block of >.
4061 # Prefix expressing that whatever follows is not already inside a <...>
4062 # block.
4063 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
4064 null_construct_pattern = input_api.re.compile(
4065 not_inside_template_arg_pattern + r'\bstd::unique_ptr' +
4066 template_arg_pattern + r'\(\)')
Vaclav Brozeka54c528b2018-04-06 19:23:554067
Sam Maiera6e76d72022-02-11 21:43:504068 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
4069 template_arg_no_array_pattern = (
4070 r'<[^>]*[^]]' # Opening block of <.
4071 r'>([^(<]*[^]]>)?') # Closing block of >.
4072 # Prefix saying that what follows is the start of an expression.
4073 start_of_expr_pattern = r'(=|\breturn|^)\s*'
4074 # Suffix saying that what follows are call parentheses with a non-empty list
4075 # of arguments.
4076 nonempty_arg_list_pattern = r'\(([^)]|$)'
4077 # Put the template argument into a capture group for deeper examination later.
4078 return_construct_pattern = input_api.re.compile(
4079 start_of_expr_pattern + r'std::unique_ptr' + '(?P<template_arg>' +
4080 template_arg_no_array_pattern + ')' + nonempty_arg_list_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:554081
Sam Maiera6e76d72022-02-11 21:43:504082 problems_constructor = []
4083 problems_nullptr = []
4084 for f in input_api.AffectedSourceFiles(sources):
4085 for line_number, line in f.ChangedContents():
4086 # Disallow:
4087 # return std::unique_ptr<T>(foo);
4088 # bar = std::unique_ptr<T>(foo);
4089 # But allow:
4090 # return std::unique_ptr<T[]>(foo);
4091 # bar = std::unique_ptr<T[]>(foo);
4092 # And also allow cases when the second template argument is present. Those
4093 # cases cannot be handled by std::make_unique:
4094 # return std::unique_ptr<T, U>(foo);
4095 # bar = std::unique_ptr<T, U>(foo);
4096 local_path = f.LocalPath()
4097 return_construct_result = return_construct_pattern.search(line)
Glen Robertson9142ffd72024-05-16 01:37:474098 if return_construct_result and not HasMoreThanOneArgOrInvalid(
Sam Maiera6e76d72022-02-11 21:43:504099 return_construct_result.group('template_arg')):
4100 problems_constructor.append(
4101 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4102 # Disallow:
4103 # std::unique_ptr<T>()
4104 if null_construct_pattern.search(line):
4105 problems_nullptr.append(
4106 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Vaclav Brozek851d9602018-04-04 16:13:054107
Sam Maiera6e76d72022-02-11 21:43:504108 errors = []
4109 if problems_nullptr:
4110 errors.append(
4111 output_api.PresubmitPromptWarning(
4112 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
4113 problems_nullptr))
4114 if problems_constructor:
4115 errors.append(
4116 output_api.PresubmitError(
4117 'The following files use explicit std::unique_ptr constructor. '
4118 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
4119 'std::make_unique is not an option.', problems_constructor))
4120 return errors
Peter Kasting4844e46e2018-02-23 07:27:104121
4122
Saagar Sanghavifceeaae2020-08-12 16:40:364123def CheckUserActionUpdate(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504124 """Checks if any new user action has been added."""
4125 if any('actions.xml' == input_api.os_path.basename(f)
4126 for f in input_api.LocalPaths()):
4127 # If actions.xml is already included in the changelist, the PRESUBMIT
4128 # for actions.xml will do a more complete presubmit check.
4129 return []
4130
4131 file_inclusion_pattern = [r'.*\.(cc|mm)$']
4132 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
4133 input_api.DEFAULT_FILES_TO_SKIP)
4134 file_filter = lambda f: input_api.FilterSourceFile(
4135 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
4136
4137 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
4138 current_actions = None
4139 for f in input_api.AffectedFiles(file_filter=file_filter):
4140 for line_num, line in f.ChangedContents():
4141 match = input_api.re.search(action_re, line)
4142 if match:
4143 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
4144 # loaded only once.
4145 if not current_actions:
Bruce Dawson6cb2d4d2023-03-01 21:35:094146 with open('tools/metrics/actions/actions.xml',
4147 encoding='utf-8') as actions_f:
Sam Maiera6e76d72022-02-11 21:43:504148 current_actions = actions_f.read()
4149 # Search for the matched user action name in |current_actions|.
4150 for action_name in match.groups():
4151 action = 'name="{0}"'.format(action_name)
4152 if action not in current_actions:
4153 return [
4154 output_api.PresubmitPromptWarning(
4155 'File %s line %d: %s is missing in '
4156 'tools/metrics/actions/actions.xml. Please run '
4157 'tools/metrics/actions/extract_actions.py to update.'
4158 % (f.LocalPath(), line_num, action_name))
4159 ]
[email protected]999261d2014-03-03 20:08:084160 return []
4161
[email protected]999261d2014-03-03 20:08:084162
Daniel Cheng13ca61a882017-08-25 15:11:254163def _ImportJSONCommentEater(input_api):
Sam Maiera6e76d72022-02-11 21:43:504164 import sys
4165 sys.path = sys.path + [
4166 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4167 'json_comment_eater')
4168 ]
4169 import json_comment_eater
4170 return json_comment_eater
Daniel Cheng13ca61a882017-08-25 15:11:254171
4172
[email protected]99171a92014-06-03 08:44:474173def _GetJSONParseError(input_api, filename, eat_comments=True):
dchenge07de812016-06-20 19:27:174174 try:
Sam Maiera6e76d72022-02-11 21:43:504175 contents = input_api.ReadFile(filename)
4176 if eat_comments:
4177 json_comment_eater = _ImportJSONCommentEater(input_api)
4178 contents = json_comment_eater.Nom(contents)
dchenge07de812016-06-20 19:27:174179
Sam Maiera6e76d72022-02-11 21:43:504180 input_api.json.loads(contents)
4181 except ValueError as e:
4182 return e
Andrew Grieve4deedb12022-02-03 21:34:504183 return None
4184
4185
Sam Maiera6e76d72022-02-11 21:43:504186def _GetIDLParseError(input_api, filename):
4187 try:
4188 contents = input_api.ReadFile(filename)
Devlin Croninf7582a12022-04-21 21:14:284189 for i, char in enumerate(contents):
Daniel Chenga37c03db2022-05-12 17:20:344190 if not char.isascii():
4191 return (
4192 'Non-ascii character "%s" (ord %d) found at offset %d.' %
4193 (char, ord(char), i))
Sam Maiera6e76d72022-02-11 21:43:504194 idl_schema = input_api.os_path.join(input_api.PresubmitLocalPath(),
4195 'tools', 'json_schema_compiler',
4196 'idl_schema.py')
4197 process = input_api.subprocess.Popen(
Bruce Dawson679fb082022-04-14 00:47:284198 [input_api.python3_executable, idl_schema],
Sam Maiera6e76d72022-02-11 21:43:504199 stdin=input_api.subprocess.PIPE,
4200 stdout=input_api.subprocess.PIPE,
4201 stderr=input_api.subprocess.PIPE,
4202 universal_newlines=True)
4203 (_, error) = process.communicate(input=contents)
4204 return error or None
4205 except ValueError as e:
4206 return e
agrievef32bcc72016-04-04 14:57:404207
agrievef32bcc72016-04-04 14:57:404208
Sam Maiera6e76d72022-02-11 21:43:504209def CheckParseErrors(input_api, output_api):
4210 """Check that IDL and JSON files do not contain syntax errors."""
4211 actions = {
4212 '.idl': _GetIDLParseError,
4213 '.json': _GetJSONParseError,
4214 }
4215 # Most JSON files are preprocessed and support comments, but these do not.
4216 json_no_comments_patterns = [
Bruce Dawson40fece62022-09-16 19:58:314217 r'^testing/',
Sam Maiera6e76d72022-02-11 21:43:504218 ]
4219 # Only run IDL checker on files in these directories.
4220 idl_included_patterns = [
Bruce Dawson40fece62022-09-16 19:58:314221 r'^chrome/common/extensions/api/',
4222 r'^extensions/common/api/',
Sam Maiera6e76d72022-02-11 21:43:504223 ]
agrievef32bcc72016-04-04 14:57:404224
Sam Maiera6e76d72022-02-11 21:43:504225 def get_action(affected_file):
4226 filename = affected_file.LocalPath()
4227 return actions.get(input_api.os_path.splitext(filename)[1])
agrievef32bcc72016-04-04 14:57:404228
Sam Maiera6e76d72022-02-11 21:43:504229 def FilterFile(affected_file):
4230 action = get_action(affected_file)
4231 if not action:
4232 return False
Anton Bershanskyi4253349482025-02-11 21:01:274233 path = affected_file.UnixLocalPath()
agrievef32bcc72016-04-04 14:57:404234
Sam Maiera6e76d72022-02-11 21:43:504235 if _MatchesFile(input_api,
4236 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS, path):
4237 return False
4238
4239 if (action == _GetIDLParseError
4240 and not _MatchesFile(input_api, idl_included_patterns, path)):
4241 return False
4242 return True
4243
4244 results = []
4245 for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
4246 include_deletes=False):
4247 action = get_action(affected_file)
4248 kwargs = {}
4249 if (action == _GetJSONParseError
4250 and _MatchesFile(input_api, json_no_comments_patterns,
Anton Bershanskyi4253349482025-02-11 21:01:274251 affected_file.UnixLocalPath())):
Sam Maiera6e76d72022-02-11 21:43:504252 kwargs['eat_comments'] = False
4253 parse_error = action(input_api, affected_file.AbsoluteLocalPath(),
4254 **kwargs)
4255 if parse_error:
4256 results.append(
4257 output_api.PresubmitError(
4258 '%s could not be parsed: %s' %
4259 (affected_file.LocalPath(), parse_error)))
4260 return results
4261
4262
4263def CheckJavaStyle(input_api, output_api):
4264 """Runs checkstyle on changed java files and returns errors if any exist."""
4265
4266 # Return early if no java files were modified.
4267 if not any(
4268 _IsJavaFile(input_api, f.LocalPath())
4269 for f in input_api.AffectedFiles()):
4270 return []
4271
4272 import sys
4273 original_sys_path = sys.path
4274 try:
4275 sys.path = sys.path + [
4276 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4277 'android', 'checkstyle')
4278 ]
4279 import checkstyle
4280 finally:
4281 # Restore sys.path to what it was before.
4282 sys.path = original_sys_path
4283
Andrew Grieve4f88e3ca2022-11-22 19:09:204284 return checkstyle.run_presubmit(
Sam Maiera6e76d72022-02-11 21:43:504285 input_api,
4286 output_api,
Sam Maiera6e76d72022-02-11 21:43:504287 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
4288
4289
4290def CheckPythonDevilInit(input_api, output_api):
4291 """Checks to make sure devil is initialized correctly in python scripts."""
4292 script_common_initialize_pattern = input_api.re.compile(
4293 r'script_common\.InitializeEnvironment\(')
4294 devil_env_config_initialize = input_api.re.compile(
4295 r'devil_env\.config\.Initialize\(')
4296
4297 errors = []
4298
4299 sources = lambda affected_file: input_api.FilterSourceFile(
4300 affected_file,
4301 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314302 r'^build/android/devil_chromium\.py',
Sven Zheng8e079562024-05-10 20:11:064303 r'^tools/bisect-builds\.py',
Bruce Dawson40fece62022-09-16 19:58:314304 r'^third_party/.*',
Sam Maiera6e76d72022-02-11 21:43:504305 )),
4306 files_to_check=[r'.*\.py$'])
4307
4308 for f in input_api.AffectedSourceFiles(sources):
4309 for line_num, line in f.ChangedContents():
4310 if (script_common_initialize_pattern.search(line)
4311 or devil_env_config_initialize.search(line)):
4312 errors.append("%s:%d" % (f.LocalPath(), line_num))
4313
4314 results = []
4315
4316 if errors:
4317 results.append(
4318 output_api.PresubmitError(
4319 'Devil initialization should always be done using '
4320 'devil_chromium.Initialize() in the chromium project, to use better '
4321 'defaults for dependencies (ex. up-to-date version of adb).',
4322 errors))
4323
4324 return results
4325
4326
4327def _MatchesFile(input_api, patterns, path):
4328 for pattern in patterns:
4329 if input_api.re.search(pattern, path):
4330 return True
4331 return False
4332
4333
Daniel Chenga37c03db2022-05-12 17:20:344334def _ChangeHasSecurityReviewer(input_api, owners_file):
4335 """Returns True iff the CL has a reviewer from SECURITY_OWNERS.
Sam Maiera6e76d72022-02-11 21:43:504336
Daniel Chenga37c03db2022-05-12 17:20:344337 Args:
4338 input_api: The presubmit input API.
4339 owners_file: OWNERS file with required reviewers. Typically, this is
4340 something like ipc/SECURITY_OWNERS.
4341
4342 Note: if the presubmit is running for commit rather than for upload, this
4343 only returns True if a security reviewer has also approved the CL.
Sam Maiera6e76d72022-02-11 21:43:504344 """
Daniel Chengd88244472022-05-16 09:08:474345 # Owners-Override should bypass all additional OWNERS enforcement checks.
4346 # A CR+1 vote will still be required to land this change.
4347 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
4348 input_api.change.issue)):
4349 return True
4350
Daniel Chenga37c03db2022-05-12 17:20:344351 owner_email, reviewers = (
4352 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
Daniel Cheng3008dc12022-05-13 04:02:114353 input_api,
4354 None,
4355 approval_needed=input_api.is_committing and not input_api.dry_run))
Sam Maiera6e76d72022-02-11 21:43:504356
Daniel Chenga37c03db2022-05-12 17:20:344357 security_owners = input_api.owners_client.ListOwners(owners_file)
4358 return any(owner in reviewers for owner in security_owners)
Sam Maiera6e76d72022-02-11 21:43:504359
Daniel Chenga37c03db2022-05-12 17:20:344360
4361@dataclass
Daniel Cheng171dad8d2022-05-21 00:40:254362class _SecurityProblemWithItems:
4363 problem: str
4364 items: Sequence[str]
4365
4366
4367@dataclass
Daniel Chenga37c03db2022-05-12 17:20:344368class _MissingSecurityOwnersResult:
Daniel Cheng171dad8d2022-05-21 00:40:254369 owners_file_problems: Sequence[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:344370 has_security_sensitive_files: bool
Daniel Cheng171dad8d2022-05-21 00:40:254371 missing_reviewer_problem: Optional[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:344372
4373
4374def _FindMissingSecurityOwners(input_api,
4375 output_api,
4376 file_patterns: Sequence[str],
4377 excluded_patterns: Sequence[str],
4378 required_owners_file: str,
4379 custom_rule_function: Optional[Callable] = None
4380 ) -> _MissingSecurityOwnersResult:
4381 """Find OWNERS files missing per-file rules for security-sensitive files.
4382
4383 Args:
4384 input_api: the PRESUBMIT input API object.
4385 output_api: the PRESUBMIT output API object.
4386 file_patterns: basename patterns that require a corresponding per-file
4387 security restriction.
4388 excluded_patterns: path patterns that should be exempted from
4389 requiring a security restriction.
4390 required_owners_file: path to the required OWNERS file, e.g.
4391 ipc/SECURITY_OWNERS
4392 cc_alias: If not None, email that will be CCed automatically if the
4393 change contains security-sensitive files, as determined by
4394 `file_patterns` and `excluded_patterns`.
4395 custom_rule_function: If not None, will be called with `input_api` and
4396 the current file under consideration. Returning True will add an
4397 exact match per-file rule check for the current file.
4398 """
4399
4400 # `to_check` is a mapping of an OWNERS file path to Patterns.
4401 #
4402 # Patterns is a dictionary mapping glob patterns (suitable for use in
4403 # per-file rules) to a PatternEntry.
4404 #
Sam Maiera6e76d72022-02-11 21:43:504405 # PatternEntry is a dictionary with two keys:
4406 # - 'files': the files that are matched by this pattern
4407 # - 'rules': the per-file rules needed for this pattern
Daniel Chenga37c03db2022-05-12 17:20:344408 #
Sam Maiera6e76d72022-02-11 21:43:504409 # For example, if we expect OWNERS file to contain rules for *.mojom and
4410 # *_struct_traits*.*, Patterns might look like this:
4411 # {
4412 # '*.mojom': {
4413 # 'files': ...,
4414 # 'rules': [
4415 # 'per-file *.mojom=set noparent',
4416 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
4417 # ],
4418 # },
4419 # '*_struct_traits*.*': {
4420 # 'files': ...,
4421 # 'rules': [
4422 # 'per-file *_struct_traits*.*=set noparent',
4423 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
4424 # ],
4425 # },
4426 # }
4427 to_check = {}
Daniel Chenga37c03db2022-05-12 17:20:344428 files_to_review = []
Sam Maiera6e76d72022-02-11 21:43:504429
Daniel Chenga37c03db2022-05-12 17:20:344430 def AddPatternToCheck(file, pattern):
Sam Maiera6e76d72022-02-11 21:43:504431 owners_file = input_api.os_path.join(
Daniel Chengd88244472022-05-16 09:08:474432 input_api.os_path.dirname(file.LocalPath()), 'OWNERS')
Sam Maiera6e76d72022-02-11 21:43:504433 if owners_file not in to_check:
4434 to_check[owners_file] = {}
4435 if pattern not in to_check[owners_file]:
4436 to_check[owners_file][pattern] = {
4437 'files': [],
4438 'rules': [
Daniel Chenga37c03db2022-05-12 17:20:344439 f'per-file {pattern}=set noparent',
4440 f'per-file {pattern}=file://{required_owners_file}',
Sam Maiera6e76d72022-02-11 21:43:504441 ]
4442 }
Daniel Chenged57a162022-05-25 02:56:344443 to_check[owners_file][pattern]['files'].append(file.LocalPath())
Daniel Chenga37c03db2022-05-12 17:20:344444 files_to_review.append(file.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:504445
Daniel Chenga37c03db2022-05-12 17:20:344446 # Only enforce security OWNERS rules for a directory if that directory has a
4447 # file that matches `file_patterns`. For example, if a directory only
4448 # contains *.mojom files and no *_messages*.h files, the check should only
4449 # ensure that rules for *.mojom files are present.
4450 for file in input_api.AffectedFiles(include_deletes=False):
4451 file_basename = input_api.os_path.basename(file.LocalPath())
4452 if custom_rule_function is not None and custom_rule_function(
4453 input_api, file):
4454 AddPatternToCheck(file, file_basename)
4455 continue
Sam Maiera6e76d72022-02-11 21:43:504456
Daniel Chenga37c03db2022-05-12 17:20:344457 if any(
4458 input_api.fnmatch.fnmatch(file.LocalPath(), pattern)
4459 for pattern in excluded_patterns):
Sam Maiera6e76d72022-02-11 21:43:504460 continue
4461
4462 for pattern in file_patterns:
Daniel Chenga37c03db2022-05-12 17:20:344463 # Unlike `excluded_patterns`, `file_patterns` is checked only against the
4464 # file's basename.
4465 if input_api.fnmatch.fnmatch(file_basename, pattern):
4466 AddPatternToCheck(file, pattern)
Sam Maiera6e76d72022-02-11 21:43:504467 break
4468
Daniel Chenga37c03db2022-05-12 17:20:344469 has_security_sensitive_files = bool(to_check)
Daniel Cheng171dad8d2022-05-21 00:40:254470
4471 # Check if any newly added lines in OWNERS files intersect with required
4472 # per-file OWNERS lines. If so, ensure that a security reviewer is included.
4473 # This is a hack, but is needed because the OWNERS check (by design) ignores
4474 # new OWNERS entries; otherwise, a non-owner could add someone as a new
4475 # OWNER and have that newly-added OWNER self-approve their own addition.
4476 newly_covered_files = []
4477 for file in input_api.AffectedFiles(include_deletes=False):
4478 if not file.LocalPath() in to_check:
4479 continue
4480 for _, line in file.ChangedContents():
4481 for _, entry in to_check[file.LocalPath()].items():
4482 if line in entry['rules']:
4483 newly_covered_files.extend(entry['files'])
4484
4485 missing_reviewer_problems = None
4486 if newly_covered_files and not _ChangeHasSecurityReviewer(
Daniel Chenga37c03db2022-05-12 17:20:344487 input_api, required_owners_file):
Daniel Cheng171dad8d2022-05-21 00:40:254488 missing_reviewer_problems = _SecurityProblemWithItems(
4489 f'Review from an owner in {required_owners_file} is required for '
4490 'the following newly-added files:',
4491 [f'{file}' for file in sorted(set(newly_covered_files))])
Sam Maiera6e76d72022-02-11 21:43:504492
4493 # Go through the OWNERS files to check, filtering out rules that are already
4494 # present in that OWNERS file.
4495 for owners_file, patterns in to_check.items():
4496 try:
Daniel Cheng171dad8d2022-05-21 00:40:254497 lines = set(
4498 input_api.ReadFile(
4499 input_api.os_path.join(input_api.change.RepositoryRoot(),
4500 owners_file)).splitlines())
4501 for entry in patterns.values():
4502 entry['rules'] = [
4503 rule for rule in entry['rules'] if rule not in lines
4504 ]
Sam Maiera6e76d72022-02-11 21:43:504505 except IOError:
4506 # No OWNERS file, so all the rules are definitely missing.
4507 continue
4508
4509 # All the remaining lines weren't found in OWNERS files, so emit an error.
Daniel Cheng171dad8d2022-05-21 00:40:254510 owners_file_problems = []
Daniel Chenga37c03db2022-05-12 17:20:344511
Sam Maiera6e76d72022-02-11 21:43:504512 for owners_file, patterns in to_check.items():
4513 missing_lines = []
4514 files = []
4515 for _, entry in patterns.items():
Daniel Chenged57a162022-05-25 02:56:344516 files.extend(entry['files'])
Sam Maiera6e76d72022-02-11 21:43:504517 missing_lines.extend(entry['rules'])
Sam Maiera6e76d72022-02-11 21:43:504518 if missing_lines:
Daniel Cheng171dad8d2022-05-21 00:40:254519 joined_missing_lines = '\n'.join(line for line in missing_lines)
4520 owners_file_problems.append(
4521 _SecurityProblemWithItems(
4522 'Found missing OWNERS lines for security-sensitive files. '
4523 f'Please add the following lines to {owners_file}:\n'
4524 f'{joined_missing_lines}\n\nTo ensure security review for:',
4525 files))
Daniel Chenga37c03db2022-05-12 17:20:344526
Daniel Cheng171dad8d2022-05-21 00:40:254527 return _MissingSecurityOwnersResult(owners_file_problems,
Daniel Chenga37c03db2022-05-12 17:20:344528 has_security_sensitive_files,
Daniel Cheng171dad8d2022-05-21 00:40:254529 missing_reviewer_problems)
Daniel Chenga37c03db2022-05-12 17:20:344530
4531
4532def _CheckChangeForIpcSecurityOwners(input_api, output_api):
4533 # Whether or not a file affects IPC is (mostly) determined by a simple list
4534 # of filename patterns.
4535 file_patterns = [
4536 # Legacy IPC:
4537 '*_messages.cc',
4538 '*_messages*.h',
4539 '*_param_traits*.*',
4540 # Mojo IPC:
4541 '*.mojom',
4542 '*_mojom_traits*.*',
4543 '*_type_converter*.*',
4544 # Android native IPC:
4545 '*.aidl',
4546 ]
4547
Daniel Chenga37c03db2022-05-12 17:20:344548 excluded_patterns = [
Daniel Cheng518943f2022-05-12 22:15:464549 # These third_party directories do not contain IPCs, but contain files
4550 # matching the above patterns, which trigger false positives.
Daniel Chenga37c03db2022-05-12 17:20:344551 'third_party/crashpad/*',
4552 'third_party/blink/renderer/platform/bindings/*',
Evan Stade23a77da2025-02-06 21:15:314553 'third_party/protobuf/*',
Daniel Chenga37c03db2022-05-12 17:20:344554 'third_party/win_build_output/*',
Daniel Chengd88244472022-05-16 09:08:474555 # Enum-only mojoms used for web metrics, so no security review needed.
4556 'third_party/blink/public/mojom/use_counter/metrics/*',
Daniel Chenga37c03db2022-05-12 17:20:344557 # These files are just used to communicate between class loaders running
4558 # in the same process.
4559 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
4560 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
4561 ]
4562
4563 def IsMojoServiceManifestFile(input_api, file):
Dirk Prankee4df27972025-02-26 18:39:354564 manifest_pattern = input_api.re.compile(r'manifests?\.(cc|h)$')
4565 test_manifest_pattern = input_api.re.compile(r'test_manifests?\.(cc|h)')
Daniel Chenga37c03db2022-05-12 17:20:344566 if not manifest_pattern.search(file.LocalPath()):
4567 return False
4568
4569 if test_manifest_pattern.search(file.LocalPath()):
4570 return False
4571
4572 # All actual service manifest files should contain at least one
4573 # qualified reference to service_manager::Manifest.
4574 return any('service_manager::Manifest' in line
4575 for line in file.NewContents())
4576
4577 return _FindMissingSecurityOwners(
4578 input_api,
4579 output_api,
4580 file_patterns,
4581 excluded_patterns,
4582 'ipc/SECURITY_OWNERS',
4583 custom_rule_function=IsMojoServiceManifestFile)
4584
4585
4586def _CheckChangeForFuchsiaSecurityOwners(input_api, output_api):
4587 file_patterns = [
4588 # Component specifications.
4589 '*.cml', # Component Framework v2.
4590 '*.cmx', # Component Framework v1.
4591
4592 # Fuchsia IDL protocol specifications.
4593 '*.fidl',
4594 ]
4595
4596 # Don't check for owners files for changes in these directories.
4597 excluded_patterns = [
4598 'third_party/crashpad/*',
4599 ]
4600
4601 return _FindMissingSecurityOwners(input_api, output_api, file_patterns,
4602 excluded_patterns,
4603 'build/fuchsia/SECURITY_OWNERS')
4604
4605
4606def CheckSecurityOwners(input_api, output_api):
4607 """Checks that various security-sensitive files have an IPC OWNERS rule."""
4608 ipc_results = _CheckChangeForIpcSecurityOwners(input_api, output_api)
4609 fuchsia_results = _CheckChangeForFuchsiaSecurityOwners(
4610 input_api, output_api)
4611
4612 if ipc_results.has_security_sensitive_files:
4613 output_api.AppendCC('[email protected]')
Sam Maiera6e76d72022-02-11 21:43:504614
4615 results = []
Daniel Chenga37c03db2022-05-12 17:20:344616
Daniel Cheng171dad8d2022-05-21 00:40:254617 missing_reviewer_problems = []
4618 if ipc_results.missing_reviewer_problem:
4619 missing_reviewer_problems.append(ipc_results.missing_reviewer_problem)
4620 if fuchsia_results.missing_reviewer_problem:
4621 missing_reviewer_problems.append(
4622 fuchsia_results.missing_reviewer_problem)
Daniel Chenga37c03db2022-05-12 17:20:344623
Daniel Cheng171dad8d2022-05-21 00:40:254624 # Missing reviewers are an error unless there's no issue number
4625 # associated with this branch; in that case, the presubmit is being run
4626 # with --all or --files.
4627 #
4628 # Note that upload should never be an error; otherwise, it would be
4629 # impossible to upload changes at all.
4630 if input_api.is_committing and input_api.change.issue:
4631 make_presubmit_message = output_api.PresubmitError
4632 else:
4633 make_presubmit_message = output_api.PresubmitNotifyResult
4634 for problem in missing_reviewer_problems:
Sam Maiera6e76d72022-02-11 21:43:504635 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:254636 make_presubmit_message(problem.problem, items=problem.items))
Daniel Chenga37c03db2022-05-12 17:20:344637
Daniel Cheng171dad8d2022-05-21 00:40:254638 owners_file_problems = []
4639 owners_file_problems.extend(ipc_results.owners_file_problems)
4640 owners_file_problems.extend(fuchsia_results.owners_file_problems)
Daniel Chenga37c03db2022-05-12 17:20:344641
Daniel Cheng171dad8d2022-05-21 00:40:254642 for problem in owners_file_problems:
Daniel Cheng3008dc12022-05-13 04:02:114643 # Missing per-file rules are always an error. While swarming and caching
4644 # means that uploading a patchset with updated OWNERS files and sending
4645 # it to the CQ again should not have a large incremental cost, it is
4646 # still frustrating to discover the error only after the change has
4647 # already been uploaded.
Daniel Chenga37c03db2022-05-12 17:20:344648 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:254649 output_api.PresubmitError(problem.problem, items=problem.items))
Sam Maiera6e76d72022-02-11 21:43:504650
4651 return results
4652
4653
4654def _GetFilesUsingSecurityCriticalFunctions(input_api):
4655 """Checks affected files for changes to security-critical calls. This
4656 function checks the full change diff, to catch both additions/changes
4657 and removals.
4658
4659 Returns a dict keyed by file name, and the value is a set of detected
4660 functions.
4661 """
4662 # Map of function pretty name (displayed in an error) to the pattern to
4663 # match it with.
4664 _PATTERNS_TO_CHECK = {
4665 'content::GetServiceSandboxType<>()': 'GetServiceSandboxType\\<'
4666 }
4667 _PATTERNS_TO_CHECK = {
4668 k: input_api.re.compile(v)
4669 for k, v in _PATTERNS_TO_CHECK.items()
4670 }
4671
Sam Maiera6e76d72022-02-11 21:43:504672 # We don't want to trigger on strings within this file.
4673 def presubmit_file_filter(f):
Daniel Chenga37c03db2022-05-12 17:20:344674 return 'PRESUBMIT.py' != input_api.os_path.split(f.LocalPath())[1]
Sam Maiera6e76d72022-02-11 21:43:504675
4676 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
4677 files_to_functions = {}
4678 for f in input_api.AffectedFiles(file_filter=presubmit_file_filter):
4679 diff = f.GenerateScmDiff()
4680 for line in diff.split('\n'):
4681 # Not using just RightHandSideLines() because removing a
4682 # call to a security-critical function can be just as important
4683 # as adding or changing the arguments.
4684 if line.startswith('-') or (line.startswith('+')
4685 and not line.startswith('++')):
4686 for name, pattern in _PATTERNS_TO_CHECK.items():
4687 if pattern.search(line):
4688 path = f.LocalPath()
4689 if not path in files_to_functions:
4690 files_to_functions[path] = set()
4691 files_to_functions[path].add(name)
4692 return files_to_functions
4693
4694
4695def CheckSecurityChanges(input_api, output_api):
4696 """Checks that changes involving security-critical functions are reviewed
4697 by the security team.
4698 """
4699 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
4700 if not len(files_to_functions):
4701 return []
4702
Sam Maiera6e76d72022-02-11 21:43:504703 owners_file = 'ipc/SECURITY_OWNERS'
Daniel Chenga37c03db2022-05-12 17:20:344704 if _ChangeHasSecurityReviewer(input_api, owners_file):
Sam Maiera6e76d72022-02-11 21:43:504705 return []
4706
Daniel Chenga37c03db2022-05-12 17:20:344707 msg = 'The following files change calls to security-sensitive functions\n' \
Sam Maiera6e76d72022-02-11 21:43:504708 'that need to be reviewed by {}.\n'.format(owners_file)
4709 for path, names in files_to_functions.items():
4710 msg += ' {}\n'.format(path)
4711 for name in names:
4712 msg += ' {}\n'.format(name)
4713 msg += '\n'
4714
4715 if input_api.is_committing:
4716 output = output_api.PresubmitError
Mohamed Heikale217fc852020-07-06 19:44:034717 else:
Sam Maiera6e76d72022-02-11 21:43:504718 output = output_api.PresubmitNotifyResult
4719 return [output(msg)]
4720
4721
4722def CheckSetNoParent(input_api, output_api):
4723 """Checks that set noparent is only used together with an OWNERS file in
4724 //build/OWNERS.setnoparent (see also
4725 //docs/code_reviews.md#owners-files-details)
4726 """
4727 # Return early if no OWNERS files were modified.
4728 if not any(f.LocalPath().endswith('OWNERS')
4729 for f in input_api.AffectedFiles(include_deletes=False)):
4730 return []
4731
4732 errors = []
4733
4734 allowed_owners_files_file = 'build/OWNERS.setnoparent'
4735 allowed_owners_files = set()
Bruce Dawson58a45d22023-02-27 11:24:164736 with open(allowed_owners_files_file, 'r', encoding='utf-8') as f:
Sam Maiera6e76d72022-02-11 21:43:504737 for line in f:
4738 line = line.strip()
4739 if not line or line.startswith('#'):
4740 continue
4741 allowed_owners_files.add(line)
4742
4743 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
4744
4745 for f in input_api.AffectedFiles(include_deletes=False):
4746 if not f.LocalPath().endswith('OWNERS'):
4747 continue
4748
4749 found_owners_files = set()
4750 found_set_noparent_lines = dict()
4751
4752 # Parse the OWNERS file.
4753 for lineno, line in enumerate(f.NewContents(), 1):
4754 line = line.strip()
4755 if line.startswith('set noparent'):
4756 found_set_noparent_lines[''] = lineno
4757 if line.startswith('file://'):
4758 if line in allowed_owners_files:
4759 found_owners_files.add('')
4760 if line.startswith('per-file'):
4761 match = per_file_pattern.match(line)
4762 if match:
4763 glob = match.group(1).strip()
4764 directive = match.group(2).strip()
4765 if directive == 'set noparent':
4766 found_set_noparent_lines[glob] = lineno
4767 if directive.startswith('file://'):
4768 if directive in allowed_owners_files:
4769 found_owners_files.add(glob)
4770
4771 # Check that every set noparent line has a corresponding file:// line
4772 # listed in build/OWNERS.setnoparent. An exception is made for top level
4773 # directories since src/OWNERS shouldn't review them.
Anton Bershanskyi4253349482025-02-11 21:01:274774 linux_path = f.UnixLocalPath()
Bruce Dawson6bb0d672022-04-06 15:13:494775 if (linux_path.count('/') != 1
4776 and (not linux_path in _EXCLUDED_SET_NO_PARENT_PATHS)):
Sam Maiera6e76d72022-02-11 21:43:504777 for set_noparent_line in found_set_noparent_lines:
4778 if set_noparent_line in found_owners_files:
4779 continue
4780 errors.append(' %s:%d' %
Bruce Dawson6bb0d672022-04-06 15:13:494781 (linux_path,
Sam Maiera6e76d72022-02-11 21:43:504782 found_set_noparent_lines[set_noparent_line]))
4783
4784 results = []
4785 if errors:
4786 if input_api.is_committing:
4787 output = output_api.PresubmitError
4788 else:
4789 output = output_api.PresubmitPromptWarning
4790 results.append(
4791 output(
4792 'Found the following "set noparent" restrictions in OWNERS files that '
4793 'do not include owners from build/OWNERS.setnoparent:',
4794 long_text='\n\n'.join(errors)))
4795 return results
4796
4797
4798def CheckUselessForwardDeclarations(input_api, output_api):
4799 """Checks that added or removed lines in non third party affected
4800 header files do not lead to new useless class or struct forward
4801 declaration.
4802 """
4803 results = []
4804 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
4805 input_api.re.MULTILINE)
4806 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
4807 input_api.re.MULTILINE)
4808 for f in input_api.AffectedFiles(include_deletes=False):
Anton Bershanskyi4253349482025-02-11 21:01:274809 local_path = f.UnixLocalPath()
4810 if (local_path.startswith('third_party')
4811 and not local_path.startswith('third_party/blink')):
Sam Maiera6e76d72022-02-11 21:43:504812 continue
4813
Anton Bershanskyi4253349482025-02-11 21:01:274814 if not local_path.endswith('.h'):
Sam Maiera6e76d72022-02-11 21:43:504815 continue
4816
4817 contents = input_api.ReadFile(f)
4818 fwd_decls = input_api.re.findall(class_pattern, contents)
4819 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
4820
4821 useless_fwd_decls = []
4822 for decl in fwd_decls:
4823 count = sum(1 for _ in input_api.re.finditer(
4824 r'\b%s\b' % input_api.re.escape(decl), contents))
4825 if count == 1:
4826 useless_fwd_decls.append(decl)
4827
4828 if not useless_fwd_decls:
4829 continue
4830
4831 for line in f.GenerateScmDiff().splitlines():
4832 if (line.startswith('-') and not line.startswith('--')
4833 or line.startswith('+') and not line.startswith('++')):
4834 for decl in useless_fwd_decls:
4835 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
4836 results.append(
4837 output_api.PresubmitPromptWarning(
4838 '%s: %s forward declaration is no longer needed'
4839 % (f.LocalPath(), decl)))
4840 useless_fwd_decls.remove(decl)
4841
4842 return results
4843
4844
4845def _CheckAndroidDebuggableBuild(input_api, output_api):
4846 """Checks that code uses BuildInfo.isDebugAndroid() instead of
4847 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
4848 this is a debuggable build of Android.
4849 """
4850 build_type_check_pattern = input_api.re.compile(
4851 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
4852
4853 errors = []
4854
4855 sources = lambda affected_file: input_api.FilterSourceFile(
4856 affected_file,
4857 files_to_skip=(
4858 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4859 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314860 r"^android_webview/support_library/boundary_interfaces/",
4861 r"^chrome/android/webapk/.*",
4862 r'^third_party/.*',
4863 r"tools/android/customtabs_benchmark/.*",
4864 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504865 )),
4866 files_to_check=[r'.*\.java$'])
4867
4868 for f in input_api.AffectedSourceFiles(sources):
4869 for line_num, line in f.ChangedContents():
4870 if build_type_check_pattern.search(line):
4871 errors.append("%s:%d" % (f.LocalPath(), line_num))
4872
4873 results = []
4874
4875 if errors:
4876 results.append(
4877 output_api.PresubmitPromptWarning(
4878 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
4879 ' Please use BuildInfo.isDebugAndroid() instead.', errors))
4880
4881 return results
4882
4883# TODO: add unit tests
4884def _CheckAndroidToastUsage(input_api, output_api):
4885 """Checks that code uses org.chromium.ui.widget.Toast instead of
4886 android.widget.Toast (Chromium Toast doesn't force hardware
4887 acceleration on low-end devices, saving memory).
4888 """
4889 toast_import_pattern = input_api.re.compile(
4890 r'^import android\.widget\.Toast;$')
4891
4892 errors = []
4893
4894 sources = lambda affected_file: input_api.FilterSourceFile(
4895 affected_file,
4896 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
Bruce Dawson40fece62022-09-16 19:58:314897 DEFAULT_FILES_TO_SKIP + (r'^chromecast/.*',
4898 r'^remoting/.*')),
Sam Maiera6e76d72022-02-11 21:43:504899 files_to_check=[r'.*\.java$'])
4900
4901 for f in input_api.AffectedSourceFiles(sources):
4902 for line_num, line in f.ChangedContents():
4903 if toast_import_pattern.search(line):
4904 errors.append("%s:%d" % (f.LocalPath(), line_num))
4905
4906 results = []
4907
4908 if errors:
4909 results.append(
4910 output_api.PresubmitError(
4911 'android.widget.Toast usage is detected. Android toasts use hardware'
4912 ' acceleration, and can be\ncostly on low-end devices. Please use'
4913 ' org.chromium.ui.widget.Toast instead.\n'
4914 'Contact [email protected] if you have any questions.',
4915 errors))
4916
4917 return results
4918
4919
4920def _CheckAndroidCrLogUsage(input_api, output_api):
4921 """Checks that new logs using org.chromium.base.Log:
4922 - Are using 'TAG' as variable name for the tags (warn)
4923 - Are using a tag that is shorter than 20 characters (error)
4924 """
4925
4926 # Do not check format of logs in the given files
4927 cr_log_check_excluded_paths = [
4928 # //chrome/android/webapk cannot depend on //base
Bruce Dawson40fece62022-09-16 19:58:314929 r"^chrome/android/webapk/.*",
Sam Maiera6e76d72022-02-11 21:43:504930 # WebView license viewer code cannot depend on //base; used in stub APK.
Bruce Dawson40fece62022-09-16 19:58:314931 r"^android_webview/glue/java/src/com/android/"
4932 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504933 # The customtabs_benchmark is a small app that does not depend on Chromium
4934 # java pieces.
Bruce Dawson40fece62022-09-16 19:58:314935 r"tools/android/customtabs_benchmark/.*",
Sam Maiera6e76d72022-02-11 21:43:504936 ]
4937
4938 cr_log_import_pattern = input_api.re.compile(
4939 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
4940 class_in_base_pattern = input_api.re.compile(
4941 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
4942 has_some_log_import_pattern = input_api.re.compile(r'^import .*\.Log;$',
4943 input_api.re.MULTILINE)
4944 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
4945 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
4946 log_decl_pattern = input_api.re.compile(
4947 r'static final String TAG = "(?P<name>(.*))"')
4948 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
4949
4950 REF_MSG = ('See docs/android_logging.md for more info.')
4951 sources = lambda x: input_api.FilterSourceFile(
4952 x,
4953 files_to_check=[r'.*\.java$'],
4954 files_to_skip=cr_log_check_excluded_paths)
4955
4956 tag_decl_errors = []
Andrew Grieved3a35d82024-01-02 21:24:384957 tag_length_errors = []
Sam Maiera6e76d72022-02-11 21:43:504958 tag_errors = []
4959 tag_with_dot_errors = []
4960 util_log_errors = []
4961
4962 for f in input_api.AffectedSourceFiles(sources):
4963 file_content = input_api.ReadFile(f)
4964 has_modified_logs = False
4965 # Per line checks
4966 if (cr_log_import_pattern.search(file_content)
4967 or (class_in_base_pattern.search(file_content)
4968 and not has_some_log_import_pattern.search(file_content))):
4969 # Checks to run for files using cr log
4970 for line_num, line in f.ChangedContents():
4971 if rough_log_decl_pattern.search(line):
4972 has_modified_logs = True
4973
4974 # Check if the new line is doing some logging
4975 match = log_call_pattern.search(line)
4976 if match:
4977 has_modified_logs = True
4978
4979 # Make sure it uses "TAG"
4980 if not match.group('tag') == 'TAG':
4981 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
4982 else:
4983 # Report non cr Log function calls in changed lines
4984 for line_num, line in f.ChangedContents():
4985 if log_call_pattern.search(line):
4986 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
4987
4988 # Per file checks
4989 if has_modified_logs:
4990 # Make sure the tag is using the "cr" prefix and is not too long
4991 match = log_decl_pattern.search(file_content)
4992 tag_name = match.group('name') if match else None
4993 if not tag_name:
4994 tag_decl_errors.append(f.LocalPath())
Andrew Grieved3a35d82024-01-02 21:24:384995 elif len(tag_name) > 20:
4996 tag_length_errors.append(f.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:504997 elif '.' in tag_name:
4998 tag_with_dot_errors.append(f.LocalPath())
4999
5000 results = []
5001 if tag_decl_errors:
5002 results.append(
5003 output_api.PresubmitPromptWarning(
5004 'Please define your tags using the suggested format: .\n'
5005 '"private static final String TAG = "<package tag>".\n'
5006 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
5007 tag_decl_errors))
5008
Andrew Grieved3a35d82024-01-02 21:24:385009 if tag_length_errors:
5010 results.append(
5011 output_api.PresubmitError(
5012 'The tag length is restricted by the system to be at most '
5013 '20 characters.\n' + REF_MSG, tag_length_errors))
5014
Sam Maiera6e76d72022-02-11 21:43:505015 if tag_errors:
5016 results.append(
5017 output_api.PresubmitPromptWarning(
5018 'Please use a variable named "TAG" for your log tags.\n' +
5019 REF_MSG, tag_errors))
5020
5021 if util_log_errors:
5022 results.append(
5023 output_api.PresubmitPromptWarning(
5024 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
5025 util_log_errors))
5026
5027 if tag_with_dot_errors:
5028 results.append(
5029 output_api.PresubmitPromptWarning(
5030 'Dot in log tags cause them to be elided in crash reports.\n' +
5031 REF_MSG, tag_with_dot_errors))
5032
5033 return results
5034
5035
Sam Maiera6e76d72022-02-11 21:43:505036def _CheckAndroidTestAnnotationUsage(input_api, output_api):
5037 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
5038 deprecated_annotation_import_pattern = input_api.re.compile(
5039 r'^import android\.test\.suitebuilder\.annotation\..*;',
5040 input_api.re.MULTILINE)
5041 sources = lambda x: input_api.FilterSourceFile(
5042 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
5043 errors = []
5044 for f in input_api.AffectedFiles(file_filter=sources):
5045 for line_num, line in f.ChangedContents():
5046 if deprecated_annotation_import_pattern.search(line):
5047 errors.append("%s:%d" % (f.LocalPath(), line_num))
5048
5049 results = []
5050 if errors:
5051 results.append(
5052 output_api.PresubmitError(
5053 'Annotations in android.test.suitebuilder.annotation have been'
Mohamed Heikal3d7a94c2023-03-28 16:55:245054 ' deprecated since API level 24. Please use androidx.test.filters'
5055 ' from //third_party/androidx:androidx_test_runner_java instead.'
Sam Maiera6e76d72022-02-11 21:43:505056 ' Contact [email protected] if you have any questions.',
5057 errors))
5058 return results
5059
5060
5061def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
5062 """Checks if MDPI assets are placed in a correct directory."""
Anton Bershanskyi4253349482025-02-11 21:01:275063 file_filter = lambda f: (f.UnixLocalPath().endswith(
5064 '.png') and ('/res/drawable/' in f.
5065 UnixLocalPath() or '/res/drawable-ldrtl/' in f.UnixLocalPath()))
Sam Maiera6e76d72022-02-11 21:43:505066 errors = []
5067 for f in input_api.AffectedFiles(include_deletes=False,
5068 file_filter=file_filter):
5069 errors.append(' %s' % f.LocalPath())
5070
5071 results = []
5072 if errors:
5073 results.append(
5074 output_api.PresubmitError(
5075 'MDPI assets should be placed in /res/drawable-mdpi/ or '
5076 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
5077 '/res/drawable-ldrtl/.\n'
5078 'Contact [email protected] if you have questions.', errors))
5079 return results
5080
5081
5082def _CheckAndroidWebkitImports(input_api, output_api):
5083 """Checks that code uses org.chromium.base.Callback instead of
5084 android.webview.ValueCallback except in the WebView glue layer
5085 and WebLayer.
5086 """
5087 valuecallback_import_pattern = input_api.re.compile(
5088 r'^import android\.webkit\.ValueCallback;$')
5089
5090 errors = []
5091
5092 sources = lambda affected_file: input_api.FilterSourceFile(
5093 affected_file,
5094 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
5095 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:315096 r'^android_webview/glue/.*',
elabadysayedcbbaea72024-08-01 16:10:425097 r'^android_webview/support_library/.*',
Bruce Dawson40fece62022-09-16 19:58:315098 r'^weblayer/.*',
Sam Maiera6e76d72022-02-11 21:43:505099 )),
5100 files_to_check=[r'.*\.java$'])
5101
5102 for f in input_api.AffectedSourceFiles(sources):
5103 for line_num, line in f.ChangedContents():
5104 if valuecallback_import_pattern.search(line):
5105 errors.append("%s:%d" % (f.LocalPath(), line_num))
5106
5107 results = []
5108
5109 if errors:
5110 results.append(
5111 output_api.PresubmitError(
5112 'android.webkit.ValueCallback usage is detected outside of the glue'
5113 ' layer. To stay compatible with the support library, android.webkit.*'
5114 ' classes should only be used inside the glue layer and'
5115 ' org.chromium.base.Callback should be used instead.', errors))
5116
5117 return results
5118
5119
5120def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
5121 """Checks Android XML styles """
5122
5123 # Return early if no relevant files were modified.
5124 if not any(
5125 _IsXmlOrGrdFile(input_api, f.LocalPath())
5126 for f in input_api.AffectedFiles(include_deletes=False)):
5127 return []
5128
5129 import sys
5130 original_sys_path = sys.path
5131 try:
5132 sys.path = sys.path + [
5133 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5134 'android', 'checkxmlstyle')
5135 ]
5136 import checkxmlstyle
5137 finally:
5138 # Restore sys.path to what it was before.
5139 sys.path = original_sys_path
5140
5141 if is_check_on_upload:
5142 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
5143 else:
5144 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
5145
5146
5147def _CheckAndroidInfoBarDeprecation(input_api, output_api):
5148 """Checks Android Infobar Deprecation """
5149
5150 import sys
5151 original_sys_path = sys.path
5152 try:
5153 sys.path = sys.path + [
5154 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5155 'android', 'infobar_deprecation')
5156 ]
5157 import infobar_deprecation
5158 finally:
5159 # Restore sys.path to what it was before.
5160 sys.path = original_sys_path
5161
5162 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
5163
5164
5165class _PydepsCheckerResult:
5166 def __init__(self, cmd, pydeps_path, process, old_contents):
5167 self._cmd = cmd
5168 self._pydeps_path = pydeps_path
5169 self._process = process
5170 self._old_contents = old_contents
5171
5172 def GetError(self):
5173 """Returns an error message, or None."""
5174 import difflib
Andrew Grieved27620b62023-07-13 16:35:075175 new_contents = self._process.stdout.read().splitlines()[2:]
Sam Maiera6e76d72022-02-11 21:43:505176 if self._process.wait() != 0:
5177 # STDERR should already be printed.
5178 return 'Command failed: ' + self._cmd
Sam Maiera6e76d72022-02-11 21:43:505179 if self._old_contents != new_contents:
5180 diff = '\n'.join(
5181 difflib.context_diff(self._old_contents, new_contents))
5182 return ('File is stale: {}\n'
5183 'Diff (apply to fix):\n'
5184 '{}\n'
5185 'To regenerate, run:\n\n'
5186 ' {}').format(self._pydeps_path, diff, self._cmd)
5187 return None
5188
5189
5190class PydepsChecker:
5191 def __init__(self, input_api, pydeps_files):
5192 self._file_cache = {}
5193 self._input_api = input_api
5194 self._pydeps_files = pydeps_files
5195
5196 def _LoadFile(self, path):
5197 """Returns the list of paths within a .pydeps file relative to //."""
5198 if path not in self._file_cache:
5199 with open(path, encoding='utf-8') as f:
5200 self._file_cache[path] = f.read()
5201 return self._file_cache[path]
5202
5203 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
Gao Shenga79ebd42022-08-08 17:25:595204 """Returns an iterable of paths within the .pydep, relativized to //."""
Sam Maiera6e76d72022-02-11 21:43:505205 pydeps_data = self._LoadFile(pydeps_path)
5206 uses_gn_paths = '--gn-paths' in pydeps_data
5207 entries = (l for l in pydeps_data.splitlines()
5208 if not l.startswith('#'))
5209 if uses_gn_paths:
5210 # Paths look like: //foo/bar/baz
5211 return (e[2:] for e in entries)
5212 else:
5213 # Paths look like: path/relative/to/file.pydeps
5214 os_path = self._input_api.os_path
5215 pydeps_dir = os_path.dirname(pydeps_path)
5216 return (os_path.normpath(os_path.join(pydeps_dir, e))
5217 for e in entries)
5218
5219 def _CreateFilesToPydepsMap(self):
5220 """Returns a map of local_path -> list_of_pydeps."""
5221 ret = {}
5222 for pydep_local_path in self._pydeps_files:
5223 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
5224 ret.setdefault(path, []).append(pydep_local_path)
5225 return ret
5226
5227 def ComputeAffectedPydeps(self):
5228 """Returns an iterable of .pydeps files that might need regenerating."""
5229 affected_pydeps = set()
5230 file_to_pydeps_map = None
5231 for f in self._input_api.AffectedFiles(include_deletes=True):
5232 local_path = f.LocalPath()
5233 # Changes to DEPS can lead to .pydeps changes if any .py files are in
5234 # subrepositories. We can't figure out which files change, so re-check
5235 # all files.
5236 # Changes to print_python_deps.py affect all .pydeps.
5237 if local_path in ('DEPS', 'PRESUBMIT.py'
5238 ) or local_path.endswith('print_python_deps.py'):
5239 return self._pydeps_files
5240 elif local_path.endswith('.pydeps'):
5241 if local_path in self._pydeps_files:
5242 affected_pydeps.add(local_path)
5243 elif local_path.endswith('.py'):
5244 if file_to_pydeps_map is None:
5245 file_to_pydeps_map = self._CreateFilesToPydepsMap()
5246 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
5247 return affected_pydeps
5248
5249 def DetermineIfStaleAsync(self, pydeps_path):
5250 """Runs print_python_deps.py to see if the files is stale."""
5251 import os
5252
5253 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
5254 if old_pydeps_data:
5255 cmd = old_pydeps_data[1][1:].strip()
5256 if '--output' not in cmd:
5257 cmd += ' --output ' + pydeps_path
5258 old_contents = old_pydeps_data[2:]
5259 else:
5260 # A default cmd that should work in most cases (as long as pydeps filename
5261 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
5262 # file is empty/new.
5263 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
5264 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
5265 old_contents = []
5266 env = dict(os.environ)
5267 env['PYTHONDONTWRITEBYTECODE'] = '1'
5268 process = self._input_api.subprocess.Popen(
5269 cmd + ' --output ""',
5270 shell=True,
5271 env=env,
5272 stdout=self._input_api.subprocess.PIPE,
5273 encoding='utf-8')
5274 return _PydepsCheckerResult(cmd, pydeps_path, process, old_contents)
agrievef32bcc72016-04-04 14:57:405275
5276
Tibor Goldschwendt360793f72019-06-25 18:23:495277def _ParseGclientArgs():
Sam Maiera6e76d72022-02-11 21:43:505278 args = {}
5279 with open('build/config/gclient_args.gni', 'r') as f:
5280 for line in f:
5281 line = line.strip()
5282 if not line or line.startswith('#'):
5283 continue
5284 attribute, value = line.split('=')
5285 args[attribute.strip()] = value.strip()
5286 return args
Tibor Goldschwendt360793f72019-06-25 18:23:495287
5288
Saagar Sanghavifceeaae2020-08-12 16:40:365289def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
Sam Maiera6e76d72022-02-11 21:43:505290 """Checks if a .pydeps file needs to be regenerated."""
5291 # This check is for Python dependency lists (.pydeps files), and involves
5292 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
5293 # doesn't work on Windows and Mac, so skip it on other platforms.
5294 if not input_api.platform.startswith('linux'):
5295 return []
Erik Staabc734cd7a2021-11-23 03:11:525296
Sam Maiera6e76d72022-02-11 21:43:505297 results = []
5298 # First, check for new / deleted .pydeps.
5299 for f in input_api.AffectedFiles(include_deletes=True):
5300 # Check whether we are running the presubmit check for a file in src.
Sam Maiera6e76d72022-02-11 21:43:505301 if f.LocalPath().endswith('.pydeps'):
Andrew Grieve713b89b2024-10-15 20:20:085302 # f.LocalPath is relative to repo (src, or internal repo).
5303 # os_path.exists is relative to src repo.
5304 # Therefore if os_path.exists is true, it means f.LocalPath is relative
5305 # to src and we can conclude that the pydeps is in src.
5306 exists = input_api.os_path.exists(f.LocalPath())
5307 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
5308 results.append(
5309 output_api.PresubmitError(
5310 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
5311 'remove %s' % f.LocalPath()))
5312 elif (f.Action() != 'D' and exists
5313 and f.LocalPath() not in _ALL_PYDEPS_FILES):
5314 results.append(
5315 output_api.PresubmitError(
5316 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
5317 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:405318
Sam Maiera6e76d72022-02-11 21:43:505319 if results:
5320 return results
5321
Gavin Mak23884402024-07-25 20:39:265322 try:
5323 parsed_args = _ParseGclientArgs()
5324 except FileNotFoundError:
5325 message = (
5326 'build/config/gclient_args.gni not found. Please make sure your '
5327 'workspace has been initialized with gclient sync.'
5328 )
5329 import sys
5330 original_sys_path = sys.path
5331 try:
5332 sys.path = sys.path + [
5333 input_api.os_path.join(input_api.PresubmitLocalPath(),
5334 'third_party', 'depot_tools')
5335 ]
5336 import gclient_utils
5337 if gclient_utils.IsEnvCog():
5338 # Users will always hit this when they run presubmits before cog
5339 # workspace initialization finishes. The check shouldn't fail in
5340 # this case. This is an unavoidable workaround that's needed for
5341 # good presubmit UX for cog.
5342 results.append(output_api.PresubmitPromptWarning(message))
5343 else:
5344 results.append(output_api.PresubmitError(message))
5345 return results
5346 finally:
5347 # Restore sys.path to what it was before.
5348 sys.path = original_sys_path
5349
5350 is_android = parsed_args.get('checkout_android', 'false') == 'true'
Sam Maiera6e76d72022-02-11 21:43:505351 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
5352 affected_pydeps = set(checker.ComputeAffectedPydeps())
5353 affected_android_pydeps = affected_pydeps.intersection(
5354 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
5355 if affected_android_pydeps and not is_android:
5356 results.append(
5357 output_api.PresubmitPromptOrNotify(
5358 'You have changed python files that may affect pydeps for android\n'
Gao Shenga79ebd42022-08-08 17:25:595359 'specific scripts. However, the relevant presubmit check cannot be\n'
Sam Maiera6e76d72022-02-11 21:43:505360 'run because you are not using an Android checkout. To validate that\n'
5361 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
5362 'use the android-internal-presubmit optional trybot.\n'
5363 'Possibly stale pydeps files:\n{}'.format(
5364 '\n'.join(affected_android_pydeps))))
5365
5366 all_pydeps = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
5367 pydeps_to_check = affected_pydeps.intersection(all_pydeps)
5368 # Process these concurrently, as each one takes 1-2 seconds.
5369 pydep_results = [checker.DetermineIfStaleAsync(p) for p in pydeps_to_check]
5370 for result in pydep_results:
5371 error_msg = result.GetError()
5372 if error_msg:
5373 results.append(output_api.PresubmitError(error_msg))
5374
agrievef32bcc72016-04-04 14:57:405375 return results
5376
agrievef32bcc72016-04-04 14:57:405377
Saagar Sanghavifceeaae2020-08-12 16:40:365378def CheckSingletonInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505379 """Checks to make sure no header files have |Singleton<|."""
5380
5381 def FileFilter(affected_file):
5382 # It's ok for base/memory/singleton.h to have |Singleton<|.
5383 files_to_skip = (_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
Bruce Dawson40fece62022-09-16 19:58:315384 (r"^base/memory/singleton\.h$",
5385 r"^net/quic/platform/impl/quic_singleton_impl\.h$"))
Sam Maiera6e76d72022-02-11 21:43:505386 return input_api.FilterSourceFile(affected_file,
5387 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:435388
Sam Maiera6e76d72022-02-11 21:43:505389 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
5390 files = []
5391 for f in input_api.AffectedSourceFiles(FileFilter):
5392 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx')
5393 or f.LocalPath().endswith('.hpp')
5394 or f.LocalPath().endswith('.inl')):
5395 contents = input_api.ReadFile(f)
5396 for line in contents.splitlines(False):
5397 if (not line.lstrip().startswith('//')
5398 and # Strip C++ comment.
5399 pattern.search(line)):
5400 files.append(f)
5401 break
glidere61efad2015-02-18 17:39:435402
Sam Maiera6e76d72022-02-11 21:43:505403 if files:
5404 return [
5405 output_api.PresubmitError(
5406 'Found base::Singleton<T> in the following header files.\n' +
5407 'Please move them to an appropriate source file so that the ' +
5408 'template gets instantiated in a single compilation unit.',
5409 files)
5410 ]
5411 return []
glidere61efad2015-02-18 17:39:435412
5413
[email protected]fd20b902014-05-09 02:14:535414_DEPRECATED_CSS = [
5415 # Values
5416 ( "-webkit-box", "flex" ),
5417 ( "-webkit-inline-box", "inline-flex" ),
5418 ( "-webkit-flex", "flex" ),
5419 ( "-webkit-inline-flex", "inline-flex" ),
5420 ( "-webkit-min-content", "min-content" ),
5421 ( "-webkit-max-content", "max-content" ),
5422
5423 # Properties
5424 ( "-webkit-background-clip", "background-clip" ),
5425 ( "-webkit-background-origin", "background-origin" ),
5426 ( "-webkit-background-size", "background-size" ),
5427 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:445428 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:535429
5430 # Functions
5431 ( "-webkit-gradient", "gradient" ),
5432 ( "-webkit-repeating-gradient", "repeating-gradient" ),
5433 ( "-webkit-linear-gradient", "linear-gradient" ),
5434 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
5435 ( "-webkit-radial-gradient", "radial-gradient" ),
5436 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
5437]
5438
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:205439
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:495440# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:365441def CheckNoDeprecatedCss(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505442 """ Make sure that we don't use deprecated CSS
5443 properties, functions or values. Our external
5444 documentation and iOS CSS for dom distiller
5445 (reader mode) are ignored by the hooks as it
5446 needs to be consumed by WebKit. """
5447 results = []
5448 file_inclusion_pattern = [r".+\.css$"]
5449 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
5450 input_api.DEFAULT_FILES_TO_SKIP +
dpapad7fcdfc42024-12-06 01:21:385451 (# Legacy CSS file using deprecated CSS.
5452 r"^chrome/browser/resources/chromeos/arc_support/cr_overlay.css$",
5453 r"^chrome/common/extensions/docs", r"^chrome/docs",
Teresa Mao1d910882024-04-26 21:06:255454 r"^native_client_sdk",
5455 # The NTP team prefers reserving -webkit-line-clamp for
5456 # ellipsis effect which can only be used with -webkit-box.
5457 r"ui/webui/resources/cr_components/most_visited/.*\.css$"))
Sam Maiera6e76d72022-02-11 21:43:505458 file_filter = lambda f: input_api.FilterSourceFile(
5459 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
5460 for fpath in input_api.AffectedFiles(file_filter=file_filter):
5461 for line_num, line in fpath.ChangedContents():
5462 for (deprecated_value, value) in _DEPRECATED_CSS:
5463 if deprecated_value in line:
5464 results.append(
5465 output_api.PresubmitError(
5466 "%s:%d: Use of deprecated CSS %s, use %s instead" %
5467 (fpath.LocalPath(), line_num, deprecated_value,
5468 value)))
5469 return results
[email protected]fd20b902014-05-09 02:14:535470
mohan.reddyf21db962014-10-16 12:26:475471
Saagar Sanghavifceeaae2020-08-12 16:40:365472def CheckForRelativeIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505473 bad_files = {}
5474 for f in input_api.AffectedFiles(include_deletes=False):
Anton Bershanskyi4253349482025-02-11 21:01:275475 if (f.UnixLocalPath().startswith('third_party')
5476 and not f.LocalPath().startswith('third_party/blink')):
Sam Maiera6e76d72022-02-11 21:43:505477 continue
rlanday6802cf632017-05-30 17:48:365478
Sam Maiera6e76d72022-02-11 21:43:505479 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
5480 continue
rlanday6802cf632017-05-30 17:48:365481
Sam Maiera6e76d72022-02-11 21:43:505482 relative_includes = [
5483 line for _, line in f.ChangedContents()
5484 if "#include" in line and "../" in line
5485 ]
5486 if not relative_includes:
5487 continue
5488 bad_files[f.LocalPath()] = relative_includes
rlanday6802cf632017-05-30 17:48:365489
Sam Maiera6e76d72022-02-11 21:43:505490 if not bad_files:
5491 return []
rlanday6802cf632017-05-30 17:48:365492
Sam Maiera6e76d72022-02-11 21:43:505493 error_descriptions = []
5494 for file_path, bad_lines in bad_files.items():
5495 error_description = file_path
5496 for line in bad_lines:
5497 error_description += '\n ' + line
5498 error_descriptions.append(error_description)
rlanday6802cf632017-05-30 17:48:365499
Sam Maiera6e76d72022-02-11 21:43:505500 results = []
5501 results.append(
5502 output_api.PresubmitError(
5503 'You added one or more relative #include paths (including "../").\n'
5504 'These shouldn\'t be used because they can be used to include headers\n'
5505 'from code that\'s not correctly specified as a dependency in the\n'
5506 'relevant BUILD.gn file(s).', error_descriptions))
rlanday6802cf632017-05-30 17:48:365507
Sam Maiera6e76d72022-02-11 21:43:505508 return results
rlanday6802cf632017-05-30 17:48:365509
Takeshi Yoshinoe387aa32017-08-02 13:16:135510
Saagar Sanghavifceeaae2020-08-12 16:40:365511def CheckForCcIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505512 """Check that nobody tries to include a cc file. It's a relatively
5513 common error which results in duplicate symbols in object
5514 files. This may not always break the build until someone later gets
5515 very confusing linking errors."""
5516 results = []
5517 for f in input_api.AffectedFiles(include_deletes=False):
5518 # We let third_party code do whatever it wants
Anton Bershanskyi4253349482025-02-11 21:01:275519 if (f.UnixLocalPath().startswith('third_party')
5520 and not f.LocalPath().startswith('third_party/blink')):
Sam Maiera6e76d72022-02-11 21:43:505521 continue
Daniel Bratell65b033262019-04-23 08:17:065522
Sam Maiera6e76d72022-02-11 21:43:505523 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
5524 continue
Daniel Bratell65b033262019-04-23 08:17:065525
Sam Maiera6e76d72022-02-11 21:43:505526 for _, line in f.ChangedContents():
5527 if line.startswith('#include "'):
5528 included_file = line.split('"')[1]
5529 if _IsCPlusPlusFile(input_api, included_file):
5530 # The most common naming for external files with C++ code,
5531 # apart from standard headers, is to call them foo.inc, but
5532 # Chromium sometimes uses foo-inc.cc so allow that as well.
5533 if not included_file.endswith(('.h', '-inc.cc')):
5534 results.append(
5535 output_api.PresubmitError(
5536 'Only header files or .inc files should be included in other\n'
5537 'C++ files. Compiling the contents of a cc file more than once\n'
5538 'will cause duplicate information in the build which may later\n'
5539 'result in strange link_errors.\n' +
5540 f.LocalPath() + ':\n ' + line))
Daniel Bratell65b033262019-04-23 08:17:065541
Sam Maiera6e76d72022-02-11 21:43:505542 return results
Daniel Bratell65b033262019-04-23 08:17:065543
5544
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205545def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
Sam Maiera6e76d72022-02-11 21:43:505546 if not isinstance(key, ast.Str):
5547 return 'Key at line %d must be a string literal' % key.lineno
5548 if not isinstance(value, ast.Dict):
5549 return 'Value at line %d must be a dict' % value.lineno
5550 if len(value.keys) != 1:
5551 return 'Dict at line %d must have single entry' % value.lineno
5552 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
5553 return (
5554 'Entry at line %d must have a string literal \'filepath\' as key' %
5555 value.lineno)
5556 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:135557
Takeshi Yoshinoe387aa32017-08-02 13:16:135558
Sergey Ulanov4af16052018-11-08 02:41:465559def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Sam Maiera6e76d72022-02-11 21:43:505560 if not isinstance(key, ast.Str):
5561 return 'Key at line %d must be a string literal' % key.lineno
5562 if not isinstance(value, ast.List):
5563 return 'Value at line %d must be a list' % value.lineno
5564 for element in value.elts:
5565 if not isinstance(element, ast.Str):
5566 return 'Watchlist elements on line %d is not a string' % key.lineno
5567 if not email_regex.match(element.s):
5568 return ('Watchlist element on line %d doesn\'t look like a valid '
5569 + 'email: %s') % (key.lineno, element.s)
5570 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:135571
Takeshi Yoshinoe387aa32017-08-02 13:16:135572
Sergey Ulanov4af16052018-11-08 02:41:465573def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Sam Maiera6e76d72022-02-11 21:43:505574 mismatch_template = (
5575 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
5576 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:135577
Sam Maiera6e76d72022-02-11 21:43:505578 email_regex = input_api.re.compile(
5579 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
Sergey Ulanov4af16052018-11-08 02:41:465580
Sam Maiera6e76d72022-02-11 21:43:505581 ast = input_api.ast
5582 i = 0
5583 last_key = ''
5584 while True:
5585 if i >= len(wd_dict.keys):
5586 if i >= len(w_dict.keys):
5587 return None
5588 return mismatch_template % ('missing',
5589 'line %d' % w_dict.keys[i].lineno)
5590 elif i >= len(w_dict.keys):
5591 return (mismatch_template %
5592 ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:135593
Sam Maiera6e76d72022-02-11 21:43:505594 wd_key = wd_dict.keys[i]
5595 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:135596
Sam Maiera6e76d72022-02-11 21:43:505597 result = _CheckWatchlistDefinitionsEntrySyntax(wd_key,
5598 wd_dict.values[i], ast)
5599 if result is not None:
5600 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:135601
Sam Maiera6e76d72022-02-11 21:43:505602 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast,
5603 email_regex)
5604 if result is not None:
5605 return 'Bad entry in WATCHLISTS dict: %s' % result
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205606
Sam Maiera6e76d72022-02-11 21:43:505607 if wd_key.s != w_key.s:
5608 return mismatch_template % ('%s at line %d' %
5609 (wd_key.s, wd_key.lineno),
5610 '%s at line %d' %
5611 (w_key.s, w_key.lineno))
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205612
Sam Maiera6e76d72022-02-11 21:43:505613 if wd_key.s < last_key:
5614 return (
5615 'WATCHLISTS dict is not sorted lexicographically at line %d and %d'
5616 % (wd_key.lineno, w_key.lineno))
5617 last_key = wd_key.s
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205618
Sam Maiera6e76d72022-02-11 21:43:505619 i = i + 1
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205620
5621
Sergey Ulanov4af16052018-11-08 02:41:465622def _CheckWATCHLISTSSyntax(expression, input_api):
Sam Maiera6e76d72022-02-11 21:43:505623 ast = input_api.ast
5624 if not isinstance(expression, ast.Expression):
5625 return 'WATCHLISTS file must contain a valid expression'
5626 dictionary = expression.body
5627 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
5628 return 'WATCHLISTS file must have single dict with exactly two entries'
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205629
Sam Maiera6e76d72022-02-11 21:43:505630 first_key = dictionary.keys[0]
5631 first_value = dictionary.values[0]
5632 second_key = dictionary.keys[1]
5633 second_value = dictionary.values[1]
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205634
Sam Maiera6e76d72022-02-11 21:43:505635 if (not isinstance(first_key, ast.Str)
5636 or first_key.s != 'WATCHLIST_DEFINITIONS'
5637 or not isinstance(first_value, ast.Dict)):
5638 return ('The first entry of the dict in WATCHLISTS file must be '
5639 'WATCHLIST_DEFINITIONS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205640
Sam Maiera6e76d72022-02-11 21:43:505641 if (not isinstance(second_key, ast.Str) or second_key.s != 'WATCHLISTS'
5642 or not isinstance(second_value, ast.Dict)):
5643 return ('The second entry of the dict in WATCHLISTS file must be '
5644 'WATCHLISTS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205645
Sam Maiera6e76d72022-02-11 21:43:505646 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:135647
5648
Saagar Sanghavifceeaae2020-08-12 16:40:365649def CheckWATCHLISTS(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505650 for f in input_api.AffectedFiles(include_deletes=False):
5651 if f.LocalPath() == 'WATCHLISTS':
5652 contents = input_api.ReadFile(f, 'r')
Takeshi Yoshinoe387aa32017-08-02 13:16:135653
Sam Maiera6e76d72022-02-11 21:43:505654 try:
5655 # First, make sure that it can be evaluated.
5656 input_api.ast.literal_eval(contents)
5657 # Get an AST tree for it and scan the tree for detailed style checking.
5658 expression = input_api.ast.parse(contents,
5659 filename='WATCHLISTS',
5660 mode='eval')
5661 except ValueError as e:
5662 return [
5663 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5664 long_text=repr(e))
5665 ]
5666 except SyntaxError as e:
5667 return [
5668 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5669 long_text=repr(e))
5670 ]
5671 except TypeError as e:
5672 return [
5673 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5674 long_text=repr(e))
5675 ]
Takeshi Yoshinoe387aa32017-08-02 13:16:135676
Sam Maiera6e76d72022-02-11 21:43:505677 result = _CheckWATCHLISTSSyntax(expression, input_api)
5678 if result is not None:
5679 return [output_api.PresubmitError(result)]
5680 break
Takeshi Yoshinoe387aa32017-08-02 13:16:135681
Sam Maiera6e76d72022-02-11 21:43:505682 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:135683
Sean Kaucb7c9b32022-10-25 21:25:525684def CheckGnRebasePath(input_api, output_api):
Terrence Reilly313f44ff2025-01-22 15:10:145685 """Checks that target_gen_dir is not used with "//" in rebase_path().
Sean Kaucb7c9b32022-10-25 21:25:525686
5687 Developers should use root_build_dir instead of "//" when using target_gen_dir because
5688 Chromium is sometimes built outside of the source tree.
5689 """
5690
5691 def gn_files(f):
5692 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
5693
5694 rebase_path_regex = input_api.re.compile(r'rebase_path\(("\$target_gen_dir"|target_gen_dir), ("/"|"//")\)')
5695 problems = []
5696 for f in input_api.AffectedSourceFiles(gn_files):
5697 for line_num, line in f.ChangedContents():
5698 if rebase_path_regex.search(line):
5699 problems.append(
5700 'Absolute path in rebase_path() in %s:%d' %
5701 (f.LocalPath(), line_num))
5702
5703 if problems:
5704 return [
5705 output_api.PresubmitPromptWarning(
5706 'Using an absolute path in rebase_path()',
5707 items=sorted(problems),
5708 long_text=(
5709 'rebase_path() should use root_build_dir instead of "/" ',
5710 'since builds can be initiated from outside of the source ',
5711 'root.'))
5712 ]
5713 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:135714
Andrew Grieve1b290e4a22020-11-24 20:07:015715def CheckGnGlobForward(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505716 """Checks that forward_variables_from(invoker, "*") follows best practices.
Andrew Grieve1b290e4a22020-11-24 20:07:015717
Sam Maiera6e76d72022-02-11 21:43:505718 As documented at //build/docs/writing_gn_templates.md
5719 """
Andrew Grieve1b290e4a22020-11-24 20:07:015720
Sam Maiera6e76d72022-02-11 21:43:505721 def gn_files(f):
5722 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
Andrew Grieve1b290e4a22020-11-24 20:07:015723
Sam Maiera6e76d72022-02-11 21:43:505724 problems = []
5725 for f in input_api.AffectedSourceFiles(gn_files):
5726 for line_num, line in f.ChangedContents():
5727 if 'forward_variables_from(invoker, "*")' in line:
5728 problems.append(
5729 'Bare forward_variables_from(invoker, "*") in %s:%d' %
5730 (f.LocalPath(), line_num))
5731
5732 if problems:
5733 return [
5734 output_api.PresubmitPromptWarning(
5735 'forward_variables_from("*") without exclusions',
5736 items=sorted(problems),
5737 long_text=(
Gao Shenga79ebd42022-08-08 17:25:595738 'The variables "visibility" and "test_only" should be '
Sam Maiera6e76d72022-02-11 21:43:505739 'explicitly listed in forward_variables_from(). For more '
5740 'details, see:\n'
5741 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
5742 'build/docs/writing_gn_templates.md'
5743 '#Using-forward_variables_from'))
5744 ]
5745 return []
Andrew Grieve1b290e4a22020-11-24 20:07:015746
Saagar Sanghavifceeaae2020-08-12 16:40:365747def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505748 """Checks that newly added header files have corresponding GN changes.
5749 Note that this is only a heuristic. To be precise, run script:
5750 build/check_gn_headers.py.
5751 """
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195752
Sam Maiera6e76d72022-02-11 21:43:505753 def headers(f):
5754 return input_api.FilterSourceFile(
5755 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195756
Sam Maiera6e76d72022-02-11 21:43:505757 new_headers = []
5758 for f in input_api.AffectedSourceFiles(headers):
5759 if f.Action() != 'A':
5760 continue
5761 new_headers.append(f.LocalPath())
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195762
Sam Maiera6e76d72022-02-11 21:43:505763 def gn_files(f):
5764 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195765
Sam Maiera6e76d72022-02-11 21:43:505766 all_gn_changed_contents = ''
5767 for f in input_api.AffectedSourceFiles(gn_files):
5768 for _, line in f.ChangedContents():
5769 all_gn_changed_contents += line
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195770
Sam Maiera6e76d72022-02-11 21:43:505771 problems = []
5772 for header in new_headers:
5773 basename = input_api.os_path.basename(header)
5774 if basename not in all_gn_changed_contents:
5775 problems.append(header)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195776
Sam Maiera6e76d72022-02-11 21:43:505777 if problems:
5778 return [
5779 output_api.PresubmitPromptWarning(
5780 'Missing GN changes for new header files',
5781 items=sorted(problems),
5782 long_text=
5783 'Please double check whether newly added header files need '
5784 'corresponding changes in gn or gni files.\nThis checking is only a '
5785 'heuristic. Run build/check_gn_headers.py to be precise.\n'
5786 'Read https://crbug.com/661774 for more info.')
5787 ]
5788 return []
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195789
5790
Saagar Sanghavifceeaae2020-08-12 16:40:365791def CheckCorrectProductNameInMessages(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505792 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
Michael Giuffridad3bc8672018-10-25 22:48:025793
Sam Maiera6e76d72022-02-11 21:43:505794 This assumes we won't intentionally reference one product from the other
5795 product.
5796 """
5797 all_problems = []
5798 test_cases = [{
5799 "filename_postfix": "google_chrome_strings.grd",
5800 "correct_name": "Chrome",
5801 "incorrect_name": "Chromium",
5802 }, {
Thiago Perrotta099034f2023-06-05 18:10:205803 "filename_postfix": "google_chrome_strings.grd",
5804 "correct_name": "Chrome",
5805 "incorrect_name": "Chrome for Testing",
5806 }, {
Sam Maiera6e76d72022-02-11 21:43:505807 "filename_postfix": "chromium_strings.grd",
5808 "correct_name": "Chromium",
5809 "incorrect_name": "Chrome",
5810 }]
Michael Giuffridad3bc8672018-10-25 22:48:025811
Sam Maiera6e76d72022-02-11 21:43:505812 for test_case in test_cases:
5813 problems = []
5814 filename_filter = lambda x: x.LocalPath().endswith(test_case[
5815 "filename_postfix"])
Michael Giuffridad3bc8672018-10-25 22:48:025816
Sam Maiera6e76d72022-02-11 21:43:505817 # Check each new line. Can yield false positives in multiline comments, but
5818 # easier than trying to parse the XML because messages can have nested
5819 # children, and associating message elements with affected lines is hard.
5820 for f in input_api.AffectedSourceFiles(filename_filter):
5821 for line_num, line in f.ChangedContents():
5822 if "<message" in line or "<!--" in line or "-->" in line:
5823 continue
5824 if test_case["incorrect_name"] in line:
Thiago Perrotta099034f2023-06-05 18:10:205825 # Chrome for Testing is a special edge case: https://goo.gle/chrome-for-testing#bookmark=id.n1rat320av91
5826 if (test_case["correct_name"] == "Chromium" and line.count("Chrome") == line.count("Chrome for Testing")):
5827 continue
Sam Maiera6e76d72022-02-11 21:43:505828 problems.append("Incorrect product name in %s:%d" %
5829 (f.LocalPath(), line_num))
Michael Giuffridad3bc8672018-10-25 22:48:025830
Sam Maiera6e76d72022-02-11 21:43:505831 if problems:
5832 message = (
5833 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
5834 % (test_case["correct_name"], test_case["correct_name"],
5835 test_case["incorrect_name"]))
5836 all_problems.append(
5837 output_api.PresubmitPromptWarning(message, items=problems))
Michael Giuffridad3bc8672018-10-25 22:48:025838
Sam Maiera6e76d72022-02-11 21:43:505839 return all_problems
Michael Giuffridad3bc8672018-10-25 22:48:025840
5841
Saagar Sanghavifceeaae2020-08-12 16:40:365842def CheckForTooLargeFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505843 """Avoid large files, especially binary files, in the repository since
5844 git doesn't scale well for those. They will be in everyone's repo
5845 clones forever, forever making Chromium slower to clone and work
5846 with."""
Daniel Bratell93eb6c62019-04-29 20:13:365847
Sam Maiera6e76d72022-02-11 21:43:505848 # Uploading files to cloud storage is not trivial so we don't want
5849 # to set the limit too low, but the upper limit for "normal" large
5850 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
5851 # anything over 20 MB is exceptional.
Bruce Dawsonbb414db2022-12-27 20:21:255852 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024
Daniel Bratell93eb6c62019-04-29 20:13:365853
Sam Maiera6e76d72022-02-11 21:43:505854 too_large_files = []
5855 for f in input_api.AffectedFiles():
5856 # Check both added and modified files (but not deleted files).
5857 if f.Action() in ('A', 'M'):
5858 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Joe DeBlasio10a832f2023-04-21 20:20:185859 if size > TOO_LARGE_FILE_SIZE_LIMIT:
Sam Maiera6e76d72022-02-11 21:43:505860 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
Daniel Bratell93eb6c62019-04-29 20:13:365861
Sam Maiera6e76d72022-02-11 21:43:505862 if too_large_files:
5863 message = (
5864 'Do not commit large files to git since git scales badly for those.\n'
5865 +
5866 'Instead put the large files in cloud storage and use DEPS to\n' +
5867 'fetch them.\n' + '\n'.join(too_large_files))
5868 return [
5869 output_api.PresubmitError('Too large files found in commit',
5870 long_text=message + '\n')
5871 ]
5872 else:
5873 return []
Daniel Bratell93eb6c62019-04-29 20:13:365874
Max Morozb47503b2019-08-08 21:03:275875
Saagar Sanghavifceeaae2020-08-12 16:40:365876def CheckFuzzTargetsOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505877 """Checks specific for fuzz target sources."""
5878 EXPORTED_SYMBOLS = [
5879 'LLVMFuzzerInitialize',
5880 'LLVMFuzzerCustomMutator',
5881 'LLVMFuzzerCustomCrossOver',
5882 'LLVMFuzzerMutate',
5883 ]
Max Morozb47503b2019-08-08 21:03:275884
Sam Maiera6e76d72022-02-11 21:43:505885 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
Max Morozb47503b2019-08-08 21:03:275886
Sam Maiera6e76d72022-02-11 21:43:505887 def FilterFile(affected_file):
5888 """Ignore libFuzzer source code."""
5889 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
Bruce Dawson40fece62022-09-16 19:58:315890 files_to_skip = r"^third_party/libFuzzer"
Max Morozb47503b2019-08-08 21:03:275891
Sam Maiera6e76d72022-02-11 21:43:505892 return input_api.FilterSourceFile(affected_file,
5893 files_to_check=[files_to_check],
5894 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:275895
Sam Maiera6e76d72022-02-11 21:43:505896 files_with_missing_header = []
5897 for f in input_api.AffectedSourceFiles(FilterFile):
5898 contents = input_api.ReadFile(f, 'r')
5899 if REQUIRED_HEADER in contents:
5900 continue
Max Morozb47503b2019-08-08 21:03:275901
Sam Maiera6e76d72022-02-11 21:43:505902 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
5903 files_with_missing_header.append(f.LocalPath())
Max Morozb47503b2019-08-08 21:03:275904
Sam Maiera6e76d72022-02-11 21:43:505905 if not files_with_missing_header:
5906 return []
Max Morozb47503b2019-08-08 21:03:275907
Sam Maiera6e76d72022-02-11 21:43:505908 long_text = (
5909 'If you define any of the libFuzzer optional functions (%s), it is '
5910 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
5911 'work incorrectly on Mac (crbug.com/687076).\nNote that '
5912 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
5913 'to access command line arguments passed to the fuzzer. Instead, prefer '
5914 'static initialization and shared resources as documented in '
5915 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
5916 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n'
5917 % (', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER))
Max Morozb47503b2019-08-08 21:03:275918
Sam Maiera6e76d72022-02-11 21:43:505919 return [
5920 output_api.PresubmitPromptWarning(message="Missing '%s' in:" %
5921 REQUIRED_HEADER,
5922 items=files_with_missing_header,
5923 long_text=long_text)
5924 ]
Max Morozb47503b2019-08-08 21:03:275925
5926
Mohamed Heikald048240a2019-11-12 16:57:375927def _CheckNewImagesWarning(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505928 """
5929 Warns authors who add images into the repo to make sure their images are
5930 optimized before committing.
5931 """
5932 images_added = False
5933 image_paths = []
5934 errors = []
5935 filter_lambda = lambda x: input_api.FilterSourceFile(
5936 x,
5937 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
5938 DEFAULT_FILES_TO_SKIP),
5939 files_to_check=[r'.*\/(drawable|mipmap)'])
5940 for f in input_api.AffectedFiles(include_deletes=False,
5941 file_filter=filter_lambda):
5942 local_path = f.LocalPath().lower()
5943 if any(
5944 local_path.endswith(extension)
5945 for extension in _IMAGE_EXTENSIONS):
5946 images_added = True
5947 image_paths.append(f)
5948 if images_added:
5949 errors.append(
5950 output_api.PresubmitPromptWarning(
5951 'It looks like you are trying to commit some images. If these are '
5952 'non-test-only images, please make sure to read and apply the tips in '
5953 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
5954 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
5955 'FYI only and will not block your CL on the CQ.', image_paths))
5956 return errors
Mohamed Heikald048240a2019-11-12 16:57:375957
5958
Saagar Sanghavifceeaae2020-08-12 16:40:365959def ChecksAndroidSpecificOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505960 """Groups upload checks that target android code."""
5961 results = []
5962 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
5963 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
5964 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
5965 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505966 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
5967 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
5968 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
5969 results.extend(_CheckNewImagesWarning(input_api, output_api))
5970 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
5971 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
Henrique Nakashima224ee2482025-03-21 18:35:025972 results.extend(_CheckAndroidNullAwayAnnotatedClasses(input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505973 return results
5974
Becky Zhou7c69b50992018-12-10 19:37:575975
Saagar Sanghavifceeaae2020-08-12 16:40:365976def ChecksAndroidSpecificOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505977 """Groups commit checks that target android code."""
5978 results = []
5979 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
5980 return results
dgnaa68d5e2015-06-10 10:08:225981
Chris Hall59f8d0c72020-05-01 07:31:195982# TODO(chrishall): could we additionally match on any path owned by
5983# ui/accessibility/OWNERS ?
5984_ACCESSIBILITY_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:315985 r"^chrome/browser.*/accessibility/",
5986 r"^chrome/browser/extensions/api/automation.*/",
5987 r"^chrome/renderer/extensions/accessibility_.*",
5988 r"^chrome/tests/data/accessibility/",
5989 r"^content/browser/accessibility/",
5990 r"^content/renderer/accessibility/",
5991 r"^content/tests/data/accessibility/",
5992 r"^extensions/renderer/api/automation/",
Katie Dektar58ef07b2022-09-27 13:19:175993 r"^services/accessibility/",
Abigail Klein7a63c572024-02-28 20:45:095994 r"^services/screen_ai/",
Bruce Dawson40fece62022-09-16 19:58:315995 r"^ui/accessibility/",
5996 r"^ui/views/accessibility/",
Chris Hall59f8d0c72020-05-01 07:31:195997)
5998
Saagar Sanghavifceeaae2020-08-12 16:40:365999def CheckAccessibilityRelnotesField(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506000 """Checks that commits to accessibility code contain an AX-Relnotes field in
6001 their commit message."""
Chris Hall59f8d0c72020-05-01 07:31:196002
Sam Maiera6e76d72022-02-11 21:43:506003 def FileFilter(affected_file):
6004 paths = _ACCESSIBILITY_PATHS
6005 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:196006
Sam Maiera6e76d72022-02-11 21:43:506007 # Only consider changes affecting accessibility paths.
6008 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
6009 return []
Akihiro Ota08108e542020-05-20 15:30:536010
Sam Maiera6e76d72022-02-11 21:43:506011 # AX-Relnotes can appear in either the description or the footer.
6012 # When searching the description, require 'AX-Relnotes:' to appear at the
6013 # beginning of a line.
6014 ax_regex = input_api.re.compile('ax-relnotes[:=]')
6015 description_has_relnotes = any(
6016 ax_regex.match(line)
6017 for line in input_api.change.DescriptionText().lower().splitlines())
Chris Hall59f8d0c72020-05-01 07:31:196018
Sam Maiera6e76d72022-02-11 21:43:506019 footer_relnotes = input_api.change.GitFootersFromDescription().get(
6020 'AX-Relnotes', [])
6021 if description_has_relnotes or footer_relnotes:
6022 return []
Chris Hall59f8d0c72020-05-01 07:31:196023
Sam Maiera6e76d72022-02-11 21:43:506024 # TODO(chrishall): link to Relnotes documentation in message.
6025 message = (
6026 "Missing 'AX-Relnotes:' field required for accessibility changes"
6027 "\n please add 'AX-Relnotes: [release notes].' to describe any "
6028 "user-facing changes"
6029 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
6030 "user-facing effects"
6031 "\n if this is confusing or annoying then please contact members "
6032 "of ui/accessibility/OWNERS.")
6033
6034 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:226035
Mark Schillaci44c90b42024-11-22 20:44:386036
6037_ACCESSIBILITY_ARIA_METHOD_CANDIDATES_PATTERNS = r'(\-\>|\.)(get|has|FastGet|FastHas)Attribute\('
6038
6039_ACCESSIBILITY_ARIA_BAD_PARAMS_PATTERNS = (
6040 r"\(html_names::kAria(.*)Attr\)",
6041 r"\(html_names::kRoleAttr\)"
6042)
6043
6044_ACCESSIBILITY_ARIA_FILE_CANDIDATES_PATTERNS = (
6045 r".*/accessibility/.*.(cc|h)",
6046 r".*/ax_.*.(cc|h)"
6047)
6048
6049def CheckAccessibilityAriaElementAttributeGetters(input_api, output_api):
6050 """Checks that the blink accessibility code follows the defined patterns
6051 for checking aria attributes, so that ElementInternals is not bypassed."""
6052
6053 # Limit to accessibility-related files.
6054 def FileFilter(affected_file):
6055 paths = _ACCESSIBILITY_ARIA_FILE_CANDIDATES_PATTERNS
6056 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
6057
6058 aria_method_regex = input_api.re.compile(_ACCESSIBILITY_ARIA_METHOD_CANDIDATES_PATTERNS)
6059 aria_bad_params_regex = input_api.re.compile(
6060 "|".join(_ACCESSIBILITY_ARIA_BAD_PARAMS_PATTERNS)
6061 )
6062 problems = []
6063
6064 for f in input_api.AffectedSourceFiles(FileFilter):
6065 for line_num, line in f.ChangedContents():
6066 if aria_method_regex.search(line) and aria_bad_params_regex.search(line):
6067 problems.append(f"{f.LocalPath()}:{line_num}\n {line.strip()}")
6068
6069 if problems:
6070 return [
6071 output_api.PresubmitPromptWarning(
6072 "Accessibility code should not use element methods to get or check"
6073 "\nthe presence of aria attributes"
6074 "\nPlease use ARIA-specific attribute access, e.g. HasAriaAttribute(),"
6075 "\nAriaTokenAttribute(), AriaBoolAttribute(), AriaBooleanAttribute(),"
6076 "\nAriaFloatAttribute().",
6077 problems,
6078 )
6079 ]
6080 return []
6081
seanmccullough4a9356252021-04-08 19:54:096082# string pattern, sequence of strings to show when pattern matches,
6083# error flag. True if match is a presubmit error, otherwise it's a warning.
6084_NON_INCLUSIVE_TERMS = (
6085 (
6086 # Note that \b pattern in python re is pretty particular. In this
6087 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
6088 # ...' will not. This may require some tweaking to catch these cases
6089 # without triggering a lot of false positives. Leaving it naive and
6090 # less matchy for now.
Josip Sokcevic9d2806a02023-12-13 03:04:026091 r'/(?i)\b((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:096092 (
6093 'Please don\'t use blacklist, whitelist, ' # nocheck
6094 'or slave in your', # nocheck
6095 'code and make every effort to use other terms. Using "// nocheck"',
6096 '"# nocheck" or "<!-- nocheck -->"',
6097 'at the end of the offending line will bypass this PRESUBMIT error',
6098 'but avoid using this whenever possible. Reach out to',
6099 '[email protected] if you have questions'),
6100 True),)
6101
Saagar Sanghavifceeaae2020-08-12 16:40:366102def ChecksCommon(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506103 """Checks common to both upload and commit."""
6104 results = []
Eric Boren6fd2b932018-01-25 15:05:086105 results.extend(
Sam Maiera6e76d72022-02-11 21:43:506106 input_api.canned_checks.PanProjectChecks(
6107 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:086108
Sam Maiera6e76d72022-02-11 21:43:506109 author = input_api.change.author_email
6110 if author and author not in _KNOWN_ROBOTS:
6111 results.extend(
6112 input_api.canned_checks.CheckAuthorizedAuthor(
6113 input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:246114
Sam Maiera6e76d72022-02-11 21:43:506115 results.extend(
6116 input_api.canned_checks.CheckChangeHasNoTabs(
6117 input_api,
6118 output_api,
6119 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
6120 results.extend(
6121 input_api.RunTests(
6122 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Edward Lesmesce51df52020-08-04 22:10:176123
Bruce Dawsonc8054482022-03-28 15:33:376124 dirmd = 'dirmd.bat' if input_api.is_windows else 'dirmd'
Sam Maiera6e76d72022-02-11 21:43:506125 dirmd_bin = input_api.os_path.join(input_api.PresubmitLocalPath(),
Bruce Dawsonc8054482022-03-28 15:33:376126 'third_party', 'depot_tools', dirmd)
Sam Maiera6e76d72022-02-11 21:43:506127 results.extend(
6128 input_api.RunTests(
6129 input_api.canned_checks.CheckDirMetadataFormat(
6130 input_api, output_api, dirmd_bin)))
6131 results.extend(
6132 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
6133 input_api, output_api))
6134 results.extend(
6135 input_api.canned_checks.CheckNoNewMetadataInOwners(
6136 input_api, output_api))
6137 results.extend(
6138 input_api.canned_checks.CheckInclusiveLanguage(
6139 input_api,
6140 output_api,
6141 excluded_directories_relative_path=[
6142 'infra', 'inclusive_language_presubmit_exempt_dirs.txt'
6143 ],
6144 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Yiwei Zhang5341bf02025-03-20 16:34:136145 results.extend(
6146 input_api.canned_checks.CheckNewDEPSHooksHasRequiredReviewers(
6147 input_api, output_api))
Dirk Prankee3c9c62d2021-05-18 18:35:596148
Aleksey Khoroshilov2978c942022-06-13 16:14:126149 presubmit_py_filter = lambda f: input_api.FilterSourceFile(
Bruce Dawson696963f2022-09-13 01:15:476150 f, files_to_check=[r'.*PRESUBMIT\.py$'])
Aleksey Khoroshilov2978c942022-06-13 16:14:126151 for f in input_api.AffectedFiles(include_deletes=False,
6152 file_filter=presubmit_py_filter):
6153 full_path = input_api.os_path.dirname(f.AbsoluteLocalPath())
6154 test_file = input_api.os_path.join(full_path, 'PRESUBMIT_test.py')
6155 # The PRESUBMIT.py file (and the directory containing it) might have
6156 # been affected by being moved or removed, so only try to run the tests
6157 # if they still exist.
6158 if not input_api.os_path.exists(test_file):
6159 continue
Sam Maiera6e76d72022-02-11 21:43:506160
Aleksey Khoroshilov2978c942022-06-13 16:14:126161 results.extend(
6162 input_api.canned_checks.RunUnitTestsInDirectory(
6163 input_api,
6164 output_api,
6165 full_path,
Takuto Ikuta40def482023-06-02 02:23:496166 files_to_check=[r'^PRESUBMIT_test\.py$']))
Sam Maiera6e76d72022-02-11 21:43:506167 return results
[email protected]1f7b4172010-01-28 01:17:346168
[email protected]b337cb5b2011-01-23 21:24:056169
Saagar Sanghavifceeaae2020-08-12 16:40:366170def CheckPatchFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506171 problems = [
6172 f.LocalPath() for f in input_api.AffectedFiles()
6173 if f.LocalPath().endswith(('.orig', '.rej'))
6174 ]
6175 # Cargo.toml.orig files are part of third-party crates downloaded from
6176 # crates.io and should be included.
6177 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
6178 if problems:
6179 return [
6180 output_api.PresubmitError("Don't commit .rej and .orig files.",
6181 problems)
6182 ]
6183 else:
6184 return []
[email protected]b8079ae4a2012-12-05 19:56:496185
6186
Saagar Sanghavifceeaae2020-08-12 16:40:366187def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506188 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
6189 macro_re = input_api.re.compile(
6190 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
6191 include_re = input_api.re.compile(r'^#include\s+"build/build_config.h"',
6192 input_api.re.MULTILINE)
6193 extension_re = input_api.re.compile(r'\.[a-z]+$')
6194 errors = []
Bruce Dawsonf7679202022-08-09 20:24:006195 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:506196 for f in input_api.AffectedFiles(include_deletes=False):
Bruce Dawsonf7679202022-08-09 20:24:006197 # The build-config macros are allowed to be used in build_config.h
6198 # without including itself.
6199 if f.LocalPath() == config_h_file:
6200 continue
Sam Maiera6e76d72022-02-11 21:43:506201 if not f.LocalPath().endswith(
6202 ('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
6203 continue
Arthur Sonzognia3dec412024-04-29 12:05:376204
Sam Maiera6e76d72022-02-11 21:43:506205 found_line_number = None
6206 found_macro = None
6207 all_lines = input_api.ReadFile(f, 'r').splitlines()
6208 for line_num, line in enumerate(all_lines):
6209 match = macro_re.search(line)
6210 if match:
6211 found_line_number = line_num
6212 found_macro = match.group(2)
6213 break
6214 if not found_line_number:
6215 continue
Kent Tamura5a8755d2017-06-29 23:37:076216
Sam Maiera6e76d72022-02-11 21:43:506217 found_include_line = -1
6218 for line_num, line in enumerate(all_lines):
6219 if include_re.search(line):
6220 found_include_line = line_num
6221 break
6222 if found_include_line >= 0 and found_include_line < found_line_number:
6223 continue
Kent Tamura5a8755d2017-06-29 23:37:076224
Sam Maiera6e76d72022-02-11 21:43:506225 if not f.LocalPath().endswith('.h'):
6226 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
6227 try:
6228 content = input_api.ReadFile(primary_header_path, 'r')
6229 if include_re.search(content):
6230 continue
6231 except IOError:
6232 pass
6233 errors.append('%s:%d %s macro is used without first including build/'
6234 'build_config.h.' %
6235 (f.LocalPath(), found_line_number, found_macro))
6236 if errors:
6237 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
6238 return []
Kent Tamura5a8755d2017-06-29 23:37:076239
6240
Lei Zhang1c12a22f2021-05-12 11:28:456241def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506242 stl_include_re = input_api.re.compile(r'^#include\s+<('
6243 r'algorithm|'
6244 r'array|'
6245 r'limits|'
6246 r'list|'
6247 r'map|'
6248 r'memory|'
6249 r'queue|'
6250 r'set|'
6251 r'string|'
6252 r'unordered_map|'
6253 r'unordered_set|'
6254 r'utility|'
6255 r'vector)>')
6256 std_namespace_re = input_api.re.compile(r'std::')
6257 errors = []
6258 for f in input_api.AffectedFiles():
6259 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
6260 continue
Lei Zhang1c12a22f2021-05-12 11:28:456261
Sam Maiera6e76d72022-02-11 21:43:506262 uses_std_namespace = False
6263 has_stl_include = False
6264 for line in f.NewContents():
6265 if has_stl_include and uses_std_namespace:
6266 break
Lei Zhang1c12a22f2021-05-12 11:28:456267
Sam Maiera6e76d72022-02-11 21:43:506268 if not has_stl_include and stl_include_re.search(line):
6269 has_stl_include = True
6270 continue
Lei Zhang1c12a22f2021-05-12 11:28:456271
Bruce Dawson4a5579a2022-04-08 17:11:366272 if not uses_std_namespace and (std_namespace_re.search(line)
6273 or 'no-std-usage-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:506274 uses_std_namespace = True
6275 continue
Lei Zhang1c12a22f2021-05-12 11:28:456276
Sam Maiera6e76d72022-02-11 21:43:506277 if has_stl_include and not uses_std_namespace:
6278 errors.append(
6279 '%s: Includes STL header(s) but does not reference std::' %
6280 f.LocalPath())
6281 if errors:
6282 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
6283 return []
Lei Zhang1c12a22f2021-05-12 11:28:456284
6285
Xiaohan Wang42d96c22022-01-20 17:23:116286def _CheckForDeprecatedOSMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:506287 """Check for sensible looking, totally invalid OS macros."""
6288 preprocessor_statement = input_api.re.compile(r'^\s*#')
6289 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
6290 results = []
6291 for lnum, line in f.ChangedContents():
6292 if preprocessor_statement.search(line):
6293 for match in os_macro.finditer(line):
6294 results.append(
6295 ' %s:%d: %s' %
6296 (f.LocalPath(), lnum, 'defined(OS_' + match.group(1) +
6297 ') -> BUILDFLAG(IS_' + match.group(1) + ')'))
6298 return results
[email protected]b00342e7f2013-03-26 16:21:546299
6300
Xiaohan Wang42d96c22022-01-20 17:23:116301def CheckForDeprecatedOSMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506302 """Check all affected files for invalid OS macros."""
6303 bad_macros = []
Bruce Dawsonf7679202022-08-09 20:24:006304 # The OS_ macros are allowed to be used in build/build_config.h.
6305 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:506306 for f in input_api.AffectedSourceFiles(None):
Bruce Dawsonf7679202022-08-09 20:24:006307 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')) \
6308 and f.LocalPath() != config_h_file:
Sam Maiera6e76d72022-02-11 21:43:506309 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
[email protected]b00342e7f2013-03-26 16:21:546310
Sam Maiera6e76d72022-02-11 21:43:506311 if not bad_macros:
6312 return []
[email protected]b00342e7f2013-03-26 16:21:546313
Sam Maiera6e76d72022-02-11 21:43:506314 return [
6315 output_api.PresubmitError(
6316 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
6317 'defined in build_config.h):', bad_macros)
6318 ]
[email protected]b00342e7f2013-03-26 16:21:546319
lliabraa35bab3932014-10-01 12:16:446320
6321def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:506322 """Check all affected files for invalid "if defined" macros."""
6323 ALWAYS_DEFINED_MACROS = (
6324 "TARGET_CPU_PPC",
6325 "TARGET_CPU_PPC64",
6326 "TARGET_CPU_68K",
6327 "TARGET_CPU_X86",
6328 "TARGET_CPU_ARM",
6329 "TARGET_CPU_MIPS",
6330 "TARGET_CPU_SPARC",
6331 "TARGET_CPU_ALPHA",
6332 "TARGET_IPHONE_SIMULATOR",
6333 "TARGET_OS_EMBEDDED",
6334 "TARGET_OS_IPHONE",
6335 "TARGET_OS_MAC",
6336 "TARGET_OS_UNIX",
6337 "TARGET_OS_WIN32",
6338 )
6339 ifdef_macro = input_api.re.compile(
6340 r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
6341 results = []
6342 for lnum, line in f.ChangedContents():
6343 for match in ifdef_macro.finditer(line):
6344 if match.group(1) in ALWAYS_DEFINED_MACROS:
6345 always_defined = ' %s is always defined. ' % match.group(1)
6346 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
6347 results.append(
6348 ' %s:%d %s\n\t%s' %
6349 (f.LocalPath(), lnum, always_defined, did_you_mean))
6350 return results
lliabraa35bab3932014-10-01 12:16:446351
6352
Saagar Sanghavifceeaae2020-08-12 16:40:366353def CheckForInvalidIfDefinedMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506354 """Check all affected files for invalid "if defined" macros."""
Arthur Sonzogni4fd14fd2024-06-02 18:42:526355 SKIPPED_PATHS = [
6356 'base/allocator/partition_allocator/src/partition_alloc/build_config.h',
6357 'build/build_config.h',
6358 'third_party/abseil-cpp/',
6359 'third_party/sqlite/',
6360 ]
6361 def affected_files_filter(f):
6362 # Normalize the local path to Linux-style path separators so that the
6363 # path comparisons work on Windows as well.
Anton Bershanskyi4253349482025-02-11 21:01:276364 path = f.UnixLocalPath()
Arthur Sonzogni4fd14fd2024-06-02 18:42:526365
6366 for skipped_path in SKIPPED_PATHS:
6367 if path.startswith(skipped_path):
6368 return False
6369
6370 return path.endswith(('.h', '.c', '.cc', '.m', '.mm'))
6371
Sam Maiera6e76d72022-02-11 21:43:506372 bad_macros = []
Arthur Sonzogni4fd14fd2024-06-02 18:42:526373 for f in input_api.AffectedSourceFiles(affected_files_filter):
6374 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
lliabraa35bab3932014-10-01 12:16:446375
Sam Maiera6e76d72022-02-11 21:43:506376 if not bad_macros:
6377 return []
lliabraa35bab3932014-10-01 12:16:446378
Sam Maiera6e76d72022-02-11 21:43:506379 return [
6380 output_api.PresubmitError(
6381 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
6382 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
6383 bad_macros)
6384 ]
lliabraa35bab3932014-10-01 12:16:446385
Saagar Sanghavifceeaae2020-08-12 16:40:366386def CheckForIPCRules(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506387 """Check for same IPC rules described in
6388 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
6389 """
6390 base_pattern = r'IPC_ENUM_TRAITS\('
6391 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
6392 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
mlamouria82272622014-09-16 18:45:046393
Sam Maiera6e76d72022-02-11 21:43:506394 problems = []
6395 for f in input_api.AffectedSourceFiles(None):
6396 local_path = f.LocalPath()
6397 if not local_path.endswith('.h'):
6398 continue
6399 for line_number, line in f.ChangedContents():
6400 if inclusion_pattern.search(
6401 line) and not comment_pattern.search(line):
6402 problems.append('%s:%d\n %s' %
6403 (local_path, line_number, line.strip()))
mlamouria82272622014-09-16 18:45:046404
Sam Maiera6e76d72022-02-11 21:43:506405 if problems:
6406 return [
6407 output_api.PresubmitPromptWarning(_IPC_ENUM_TRAITS_DEPRECATED,
6408 problems)
6409 ]
6410 else:
6411 return []
mlamouria82272622014-09-16 18:45:046412
[email protected]b00342e7f2013-03-26 16:21:546413
Saagar Sanghavifceeaae2020-08-12 16:40:366414def CheckForLongPathnames(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506415 """Check to make sure no files being submitted have long paths.
6416 This causes issues on Windows.
6417 """
6418 problems = []
6419 for f in input_api.AffectedTestableFiles():
6420 local_path = f.LocalPath()
6421 # Windows has a path limit of 260 characters. Limit path length to 200 so
6422 # that we have some extra for the prefix on dev machines and the bots.
Weizhong Xia8b461f12024-06-21 21:46:336423 if (local_path.startswith('third_party/blink/web_tests/platform/') and
6424 not local_path.startswith('third_party/blink/web_tests/platform/win')):
6425 # Do not check length of the path for files not used by Windows
6426 continue
Sam Maiera6e76d72022-02-11 21:43:506427 if len(local_path) > 200:
6428 problems.append(local_path)
Stephen Martinis97a394142018-06-07 23:06:056429
Sam Maiera6e76d72022-02-11 21:43:506430 if problems:
6431 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
6432 else:
6433 return []
Stephen Martinis97a394142018-06-07 23:06:056434
6435
Saagar Sanghavifceeaae2020-08-12 16:40:366436def CheckForIncludeGuards(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506437 """Check that header files have proper guards against multiple inclusion.
6438 If a file should not have such guards (and it probably should) then it
Bruce Dawson4a5579a2022-04-08 17:11:366439 should include the string "no-include-guard-because-multiply-included" or
6440 "no-include-guard-because-pch-file".
Sam Maiera6e76d72022-02-11 21:43:506441 """
Daniel Bratell8ba52722018-03-02 16:06:146442
Sam Maiera6e76d72022-02-11 21:43:506443 def is_chromium_header_file(f):
6444 # We only check header files under the control of the Chromium
mikt84d6c712024-03-27 13:29:036445 # project. This excludes:
6446 # - third_party/*, except blink.
6447 # - base/allocator/partition_allocator/: PartitionAlloc is a standalone
6448 # library used outside of Chrome. Includes are referenced from its
6449 # own base directory. It has its own `CheckForIncludeGuards`
6450 # PRESUBMIT.py check.
6451 # - *_message_generator.h: They use include guards in a special,
6452 # non-typical way.
Sam Maiera6e76d72022-02-11 21:43:506453 file_with_path = input_api.os_path.normpath(f.LocalPath())
6454 return (file_with_path.endswith('.h')
6455 and not file_with_path.endswith('_message_generator.h')
Bruce Dawson4c4c2922022-05-02 18:07:336456 and not file_with_path.endswith('com_imported_mstscax.h')
Peter Kasting66c1f752024-12-02 15:28:376457 and not file_with_path.startswith(
6458 input_api.os_path.join('base', 'allocator',
6459 'partition_allocator'))
Sam Maiera6e76d72022-02-11 21:43:506460 and (not file_with_path.startswith('third_party')
6461 or file_with_path.startswith(
6462 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:146463
Sam Maiera6e76d72022-02-11 21:43:506464 def replace_special_with_underscore(string):
6465 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:146466
Sam Maiera6e76d72022-02-11 21:43:506467 errors = []
Daniel Bratell8ba52722018-03-02 16:06:146468
Sam Maiera6e76d72022-02-11 21:43:506469 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
6470 guard_name = None
6471 guard_line_number = None
6472 seen_guard_end = False
Lei Zhangd84f9512024-05-28 19:43:306473 bypass_checks_at_end_of_file = False
Daniel Bratell8ba52722018-03-02 16:06:146474
Sam Maiera6e76d72022-02-11 21:43:506475 file_with_path = input_api.os_path.normpath(f.LocalPath())
6476 base_file_name = input_api.os_path.splitext(
6477 input_api.os_path.basename(file_with_path))[0]
6478 upper_base_file_name = base_file_name.upper()
Daniel Bratell8ba52722018-03-02 16:06:146479
Sam Maiera6e76d72022-02-11 21:43:506480 expected_guard = replace_special_with_underscore(
6481 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:146482
Sam Maiera6e76d72022-02-11 21:43:506483 # For "path/elem/file_name.h" we should really only accept
6484 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
6485 # are too many (1000+) files with slight deviations from the
6486 # coding style. The most important part is that the include guard
6487 # is there, and that it's unique, not the name so this check is
6488 # forgiving for existing files.
6489 #
6490 # As code becomes more uniform, this could be made stricter.
Daniel Bratell8ba52722018-03-02 16:06:146491
Sam Maiera6e76d72022-02-11 21:43:506492 guard_name_pattern_list = [
6493 # Anything with the right suffix (maybe with an extra _).
6494 r'\w+_H__?',
Daniel Bratell8ba52722018-03-02 16:06:146495
Sam Maiera6e76d72022-02-11 21:43:506496 # To cover include guards with old Blink style.
6497 r'\w+_h',
Daniel Bratell8ba52722018-03-02 16:06:146498
Sam Maiera6e76d72022-02-11 21:43:506499 # Anything including the uppercase name of the file.
6500 r'\w*' + input_api.re.escape(
6501 replace_special_with_underscore(upper_base_file_name)) +
6502 r'\w*',
6503 ]
6504 guard_name_pattern = '|'.join(guard_name_pattern_list)
6505 guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
6506 guard_name_pattern + ')')
Daniel Bratell8ba52722018-03-02 16:06:146507
Sam Maiera6e76d72022-02-11 21:43:506508 for line_number, line in enumerate(f.NewContents()):
Bruce Dawson4a5579a2022-04-08 17:11:366509 if ('no-include-guard-because-multiply-included' in line
6510 or 'no-include-guard-because-pch-file' in line):
Lei Zhangd84f9512024-05-28 19:43:306511 bypass_checks_at_end_of_file = True
Sam Maiera6e76d72022-02-11 21:43:506512 break
Daniel Bratell8ba52722018-03-02 16:06:146513
Sam Maiera6e76d72022-02-11 21:43:506514 if guard_name is None:
6515 match = guard_pattern.match(line)
6516 if match:
6517 guard_name = match.group(1)
6518 guard_line_number = line_number
Daniel Bratell8ba52722018-03-02 16:06:146519
Sam Maiera6e76d72022-02-11 21:43:506520 # We allow existing files to use include guards whose names
6521 # don't match the chromium style guide, but new files should
6522 # get it right.
Bruce Dawson6cc154e2022-04-12 20:39:496523 if guard_name != expected_guard:
Bruce Dawson95eb7562022-09-14 15:27:166524 if f.Action() == 'A': # If file was just 'A'dded
Sam Maiera6e76d72022-02-11 21:43:506525 errors.append(
6526 output_api.PresubmitPromptWarning(
6527 'Header using the wrong include guard name %s'
6528 % guard_name, [
6529 '%s:%d' %
6530 (f.LocalPath(), line_number + 1)
6531 ], 'Expected: %r\nFound: %r' %
6532 (expected_guard, guard_name)))
6533 else:
6534 # The line after #ifndef should have a #define of the same name.
6535 if line_number == guard_line_number + 1:
6536 expected_line = '#define %s' % guard_name
6537 if line != expected_line:
6538 errors.append(
6539 output_api.PresubmitPromptWarning(
6540 'Missing "%s" for include guard' %
6541 expected_line,
6542 ['%s:%d' % (f.LocalPath(), line_number + 1)],
6543 'Expected: %r\nGot: %r' %
6544 (expected_line, line)))
Daniel Bratell8ba52722018-03-02 16:06:146545
Sam Maiera6e76d72022-02-11 21:43:506546 if not seen_guard_end and line == '#endif // %s' % guard_name:
6547 seen_guard_end = True
6548 elif seen_guard_end:
6549 if line.strip() != '':
6550 errors.append(
6551 output_api.PresubmitPromptWarning(
6552 'Include guard %s not covering the whole file'
6553 % (guard_name), [f.LocalPath()]))
6554 break # Nothing else to check and enough to warn once.
Daniel Bratell8ba52722018-03-02 16:06:146555
Lei Zhangd84f9512024-05-28 19:43:306556 if bypass_checks_at_end_of_file:
6557 continue
6558
Sam Maiera6e76d72022-02-11 21:43:506559 if guard_name is None:
6560 errors.append(
6561 output_api.PresubmitPromptWarning(
Bruce Dawson32114b62022-04-11 16:45:496562 'Missing include guard in %s\n'
Sam Maiera6e76d72022-02-11 21:43:506563 'Recommended name: %s\n'
6564 'This check can be disabled by having the string\n'
Bruce Dawson4a5579a2022-04-08 17:11:366565 '"no-include-guard-because-multiply-included" or\n'
6566 '"no-include-guard-because-pch-file" in the header.'
Sam Maiera6e76d72022-02-11 21:43:506567 % (f.LocalPath(), expected_guard)))
Lei Zhangd84f9512024-05-28 19:43:306568 elif not seen_guard_end:
6569 errors.append(
6570 output_api.PresubmitPromptWarning(
6571 'Incorrect or missing include guard #endif in %s\n'
6572 'Recommended #endif comment: // %s'
6573 % (f.LocalPath(), expected_guard)))
Sam Maiera6e76d72022-02-11 21:43:506574
6575 return errors
Daniel Bratell8ba52722018-03-02 16:06:146576
6577
Saagar Sanghavifceeaae2020-08-12 16:40:366578def CheckForWindowsLineEndings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506579 """Check source code and known ascii text files for Windows style line
6580 endings.
6581 """
Bruce Dawson5efbdc652022-04-11 19:29:516582 known_text_files = r'.*\.(txt|html|htm|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:236583
dpapadfd421fb2025-02-13 00:47:326584 _WEBUI_FILES_EXTENSIONS = r'\.(css|html|js|ts|svg)$'
6585
Sam Maiera6e76d72022-02-11 21:43:506586 file_inclusion_pattern = (known_text_files,
6587 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
dpapadfd421fb2025-02-13 00:47:326588 r'.+%s' % _HEADER_EXTENSIONS,
6589 r'.+%s' % _WEBUI_FILES_EXTENSIONS)
6590
6591 # Exclude folder that contains .ts files that are actually binary video
6592 # format and not TypeScript.
6593 file_exclusion_pattern = (r'media/test/data/')
mostynbb639aca52015-01-07 20:31:236594
Sam Maiera6e76d72022-02-11 21:43:506595 problems = []
6596 source_file_filter = lambda f: input_api.FilterSourceFile(
dpapadfd421fb2025-02-13 00:47:326597 f, files_to_check=file_inclusion_pattern,
6598 files_to_skip=file_exclusion_pattern)
Sam Maiera6e76d72022-02-11 21:43:506599 for f in input_api.AffectedSourceFiles(source_file_filter):
Bruce Dawson5efbdc652022-04-11 19:29:516600 # Ignore test files that contain crlf intentionally.
6601 if f.LocalPath().endswith('crlf.txt'):
Daniel Chenga37c03db2022-05-12 17:20:346602 continue
Sam Maiera6e76d72022-02-11 21:43:506603 include_file = False
6604 for line in input_api.ReadFile(f, 'r').splitlines(True):
6605 if line.endswith('\r\n'):
6606 include_file = True
6607 if include_file:
6608 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:236609
Sam Maiera6e76d72022-02-11 21:43:506610 if problems:
6611 return [
6612 output_api.PresubmitPromptWarning(
6613 'Are you sure that you want '
6614 'these files to contain Windows style line endings?\n' +
6615 '\n'.join(problems))
6616 ]
mostynbb639aca52015-01-07 20:31:236617
Sam Maiera6e76d72022-02-11 21:43:506618 return []
6619
mostynbb639aca52015-01-07 20:31:236620
Evan Stade6cfc964c12021-05-18 20:21:166621def CheckIconFilesForLicenseHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506622 """Check that .icon files (which are fragments of C++) have license headers.
6623 """
Evan Stade6cfc964c12021-05-18 20:21:166624
Sam Maiera6e76d72022-02-11 21:43:506625 icon_files = (r'.*\.icon$', )
Evan Stade6cfc964c12021-05-18 20:21:166626
Sam Maiera6e76d72022-02-11 21:43:506627 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
6628 return input_api.canned_checks.CheckLicense(input_api,
6629 output_api,
6630 source_file_filter=icons)
6631
Evan Stade6cfc964c12021-05-18 20:21:166632
Jose Magana2b456f22021-03-09 23:26:406633def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506634 """Check source code for use of Chrome App technologies being
6635 deprecated.
6636 """
Jose Magana2b456f22021-03-09 23:26:406637
Sam Maiera6e76d72022-02-11 21:43:506638 def _CheckForDeprecatedTech(input_api,
6639 output_api,
6640 detection_list,
6641 files_to_check=None,
6642 files_to_skip=None):
Jose Magana2b456f22021-03-09 23:26:406643
Sam Maiera6e76d72022-02-11 21:43:506644 if (files_to_check or files_to_skip):
6645 source_file_filter = lambda f: input_api.FilterSourceFile(
6646 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
6647 else:
6648 source_file_filter = None
6649
6650 problems = []
6651
6652 for f in input_api.AffectedSourceFiles(source_file_filter):
6653 if f.Action() == 'D':
6654 continue
6655 for _, line in f.ChangedContents():
6656 if any(detect in line for detect in detection_list):
6657 problems.append(f.LocalPath())
6658
6659 return problems
6660
6661 # to avoid this presubmit script triggering warnings
6662 files_to_skip = ['PRESUBMIT.py', 'PRESUBMIT_test.py']
Jose Magana2b456f22021-03-09 23:26:406663
6664 problems = []
6665
Sam Maiera6e76d72022-02-11 21:43:506666 # NMF: any files with extensions .nmf or NMF
6667 _NMF_FILES = r'\.(nmf|NMF)$'
6668 problems += _CheckForDeprecatedTech(
6669 input_api,
6670 output_api,
6671 detection_list=[''], # any change to the file will trigger warning
6672 files_to_check=[r'.+%s' % _NMF_FILES])
Jose Magana2b456f22021-03-09 23:26:406673
Sam Maiera6e76d72022-02-11 21:43:506674 # MANIFEST: any manifest.json that in its diff includes "app":
6675 _MANIFEST_FILES = r'(manifest\.json)$'
6676 problems += _CheckForDeprecatedTech(
6677 input_api,
6678 output_api,
6679 detection_list=['"app":'],
6680 files_to_check=[r'.*%s' % _MANIFEST_FILES])
Jose Magana2b456f22021-03-09 23:26:406681
Sam Maiera6e76d72022-02-11 21:43:506682 # NaCl / PNaCl: any file that in its diff contains the strings in the list
6683 problems += _CheckForDeprecatedTech(
6684 input_api,
6685 output_api,
6686 detection_list=['config=nacl', 'enable-nacl', 'cpu=pnacl', 'nacl_io'],
Bruce Dawson40fece62022-09-16 19:58:316687 files_to_skip=files_to_skip + [r"^native_client_sdk/"])
Jose Magana2b456f22021-03-09 23:26:406688
Gao Shenga79ebd42022-08-08 17:25:596689 # PPAPI: any C/C++ file that in its diff includes a ppapi library
Sam Maiera6e76d72022-02-11 21:43:506690 problems += _CheckForDeprecatedTech(
6691 input_api,
6692 output_api,
6693 detection_list=['#include "ppapi', '#include <ppapi'],
6694 files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,
6695 r'.+%s' % _IMPLEMENTATION_EXTENSIONS),
Bruce Dawson40fece62022-09-16 19:58:316696 files_to_skip=[r"^ppapi/"])
Jose Magana2b456f22021-03-09 23:26:406697
Sam Maiera6e76d72022-02-11 21:43:506698 if problems:
6699 return [
6700 output_api.PresubmitPromptWarning(
6701 'You are adding/modifying code'
6702 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
6703 ' PNaCl, PPAPI). See this blog post for more details:\n'
6704 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
6705 'and this documentation for options to replace these technologies:\n'
6706 'https://developer.chrome.com/docs/apps/migration/\n' +
6707 '\n'.join(problems))
6708 ]
Jose Magana2b456f22021-03-09 23:26:406709
Sam Maiera6e76d72022-02-11 21:43:506710 return []
Jose Magana2b456f22021-03-09 23:26:406711
mostynbb639aca52015-01-07 20:31:236712
Saagar Sanghavifceeaae2020-08-12 16:40:366713def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
Sam Maiera6e76d72022-02-11 21:43:506714 """Checks that all source files use SYSLOG properly."""
6715 syslog_files = []
6716 for f in input_api.AffectedSourceFiles(src_file_filter):
6717 for line_number, line in f.ChangedContents():
6718 if 'SYSLOG' in line:
6719 syslog_files.append(f.LocalPath() + ':' + str(line_number))
pastarmovj032ba5bc2017-01-12 10:41:566720
Sam Maiera6e76d72022-02-11 21:43:506721 if syslog_files:
6722 return [
6723 output_api.PresubmitPromptWarning(
6724 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
6725 ' calls.\nFiles to check:\n',
6726 items=syslog_files)
6727 ]
6728 return []
pastarmovj89f7ee12016-09-20 14:58:136729
6730
[email protected]1f7b4172010-01-28 01:17:346731def CheckChangeOnUpload(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 ]
6739 results = []
6740 results.extend(
6741 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
6742 return results
[email protected]ca8d1982009-02-19 16:33:126743
6744
6745def CheckChangeOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506746 if input_api.version < [2, 0, 0]:
6747 return [
6748 output_api.PresubmitError(
6749 "Your depot_tools is out of date. "
6750 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
6751 "but your version is %d.%d.%d" % tuple(input_api.version))
6752 ]
Saagar Sanghavifceeaae2020-08-12 16:40:366753
Sam Maiera6e76d72022-02-11 21:43:506754 results = []
6755 # Make sure the tree is 'open'.
6756 results.extend(
6757 input_api.canned_checks.CheckTreeIsOpen(
6758 input_api,
6759 output_api,
6760 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:276761
Sam Maiera6e76d72022-02-11 21:43:506762 results.extend(
6763 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
6764 results.extend(
6765 input_api.canned_checks.CheckChangeHasBugField(input_api, output_api))
6766 results.extend(
6767 input_api.canned_checks.CheckChangeHasNoUnwantedTags(
6768 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:506769 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146770
6771
Saagar Sanghavifceeaae2020-08-12 16:40:366772def CheckStrings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506773 """Check string ICU syntax validity and if translation screenshots exist."""
6774 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
6775 # footer is set to true.
6776 git_footers = input_api.change.GitFootersFromDescription()
6777 skip_screenshot_check_footer = [
6778 footer.lower() for footer in git_footers.get(
6779 u'Skip-Translation-Screenshots-Check', [])
6780 ]
6781 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:026782
Sam Maiera6e76d72022-02-11 21:43:506783 import os
6784 import re
6785 import sys
6786 from io import StringIO
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146787
Sam Maiera6e76d72022-02-11 21:43:506788 new_or_added_paths = set(f.LocalPath() for f in input_api.AffectedFiles()
6789 if (f.Action() == 'A' or f.Action() == 'M'))
6790 removed_paths = set(f.LocalPath()
6791 for f in input_api.AffectedFiles(include_deletes=True)
6792 if f.Action() == 'D')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146793
Sam Maiera6e76d72022-02-11 21:43:506794 affected_grds = [
6795 f for f in input_api.AffectedFiles()
6796 if f.LocalPath().endswith(('.grd', '.grdp'))
6797 ]
6798 affected_grds = [
6799 f for f in affected_grds if not 'testdata' in f.LocalPath()
6800 ]
6801 if not affected_grds:
6802 return []
meacer8c0d3832019-12-26 21:46:166803
Sam Maiera6e76d72022-02-11 21:43:506804 affected_png_paths = [
Andrew Grieve713b89b2024-10-15 20:20:086805 f.LocalPath() for f in input_api.AffectedFiles()
6806 if f.LocalPath().endswith('.png')
Sam Maiera6e76d72022-02-11 21:43:506807 ]
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146808
Sam Maiera6e76d72022-02-11 21:43:506809 # Check for screenshots. Developers can upload screenshots using
6810 # tools/translation/upload_screenshots.py which finds and uploads
6811 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
6812 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
6813 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
6814 #
6815 # The logic here is as follows:
6816 #
6817 # - If the CL has a .png file under the screenshots directory for a grd
6818 # file, warn the developer. Actual images should never be checked into the
6819 # Chrome repo.
6820 #
6821 # - If the CL contains modified or new messages in grd files and doesn't
6822 # contain the corresponding .sha1 files, warn the developer to add images
6823 # and upload them via tools/translation/upload_screenshots.py.
6824 #
6825 # - If the CL contains modified or new messages in grd files and the
6826 # corresponding .sha1 files, everything looks good.
6827 #
6828 # - If the CL contains removed messages in grd files but the corresponding
6829 # .sha1 files aren't removed, warn the developer to remove them.
6830 unnecessary_screenshots = []
Jens Mueller054652c2023-05-10 15:12:306831 invalid_sha1 = []
Sam Maiera6e76d72022-02-11 21:43:506832 missing_sha1 = []
Bruce Dawson55776c42022-12-09 17:23:476833 missing_sha1_modified = []
Sam Maiera6e76d72022-02-11 21:43:506834 unnecessary_sha1_files = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146835
Sam Maiera6e76d72022-02-11 21:43:506836 # This checks verifies that the ICU syntax of messages this CL touched is
6837 # valid, and reports any found syntax errors.
6838 # Without this presubmit check, ICU syntax errors in Chromium strings can land
6839 # without developers being aware of them. Later on, such ICU syntax errors
6840 # break message extraction for translation, hence would block Chromium
6841 # translations until they are fixed.
6842 icu_syntax_errors = []
Jens Mueller054652c2023-05-10 15:12:306843 sha1_pattern = input_api.re.compile(r'^[a-fA-F0-9]{40}$',
6844 input_api.re.MULTILINE)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146845
Sam Maiera6e76d72022-02-11 21:43:506846 def _CheckScreenshotAdded(screenshots_dir, message_id):
6847 sha1_path = input_api.os_path.join(screenshots_dir,
6848 message_id + '.png.sha1')
6849 if sha1_path not in new_or_added_paths:
6850 missing_sha1.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306851 elif not _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256852 invalid_sha1.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146853
Bruce Dawson55776c42022-12-09 17:23:476854 def _CheckScreenshotModified(screenshots_dir, message_id):
6855 sha1_path = input_api.os_path.join(screenshots_dir,
6856 message_id + '.png.sha1')
6857 if sha1_path not in new_or_added_paths:
6858 missing_sha1_modified.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306859 elif not _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256860 invalid_sha1.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306861
6862 def _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256863 return sha1_pattern.search(
6864 next("\n".join(f.NewContents()) for f in input_api.AffectedFiles()
6865 if f.LocalPath() == sha1_path))
Bruce Dawson55776c42022-12-09 17:23:476866
Sam Maiera6e76d72022-02-11 21:43:506867 def _CheckScreenshotRemoved(screenshots_dir, message_id):
6868 sha1_path = input_api.os_path.join(screenshots_dir,
6869 message_id + '.png.sha1')
6870 if input_api.os_path.exists(
6871 sha1_path) and sha1_path not in removed_paths:
6872 unnecessary_sha1_files.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146873
Sam Maiera6e76d72022-02-11 21:43:506874 def _ValidateIcuSyntax(text, level, signatures):
6875 """Validates ICU syntax of a text string.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146876
Sam Maiera6e76d72022-02-11 21:43:506877 Check if text looks similar to ICU and checks for ICU syntax correctness
6878 in this case. Reports various issues with ICU syntax and values of
6879 variants. Supports checking of nested messages. Accumulate information of
6880 each ICU messages found in the text for further checking.
Rainhard Findlingfc31844c52020-05-15 09:58:266881
Sam Maiera6e76d72022-02-11 21:43:506882 Args:
6883 text: a string to check.
6884 level: a number of current nesting level.
6885 signatures: an accumulator, a list of tuple of (level, variable,
6886 kind, variants).
Rainhard Findlingfc31844c52020-05-15 09:58:266887
Sam Maiera6e76d72022-02-11 21:43:506888 Returns:
6889 None if a string is not ICU or no issue detected.
6890 A tuple of (message, start index, end index) if an issue detected.
6891 """
6892 valid_types = {
6893 'plural': (frozenset(
Rainhard Findling3cde3ef02024-02-05 18:40:326894 ['=0', '=1', '=2', '=3', 'zero', 'one', 'two', 'few', 'many',
Sam Maiera6e76d72022-02-11 21:43:506895 'other']), frozenset(['=1', 'other'])),
6896 'selectordinal': (frozenset(
Rainhard Findling3cde3ef02024-02-05 18:40:326897 ['=0', '=1', '=2', '=3', 'zero', 'one', 'two', 'few', 'many',
Sam Maiera6e76d72022-02-11 21:43:506898 'other']), frozenset(['one', 'other'])),
6899 'select': (frozenset(), frozenset(['other'])),
6900 }
Rainhard Findlingfc31844c52020-05-15 09:58:266901
Sam Maiera6e76d72022-02-11 21:43:506902 # Check if the message looks like an attempt to use ICU
6903 # plural. If yes - check if its syntax strictly matches ICU format.
6904 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b',
6905 text)
6906 if not like:
6907 signatures.append((level, None, None, None))
6908 return
Rainhard Findlingfc31844c52020-05-15 09:58:266909
Sam Maiera6e76d72022-02-11 21:43:506910 # Check for valid prefix and suffix
6911 m = re.match(
6912 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
6913 r'(plural|selectordinal|select),\s*'
6914 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
6915 if not m:
6916 return (('This message looks like an ICU plural, '
6917 'but does not follow ICU syntax.'), like.start(),
6918 like.end())
6919 starting, variable, kind, variant_pairs = m.groups()
6920 variants, depth, last_pos = _ParseIcuVariants(variant_pairs,
6921 m.start(4))
6922 if depth:
6923 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
6924 len(text))
6925 first = text[0]
6926 ending = text[last_pos:]
6927 if not starting:
6928 return ('Invalid ICU format. No initial opening bracket',
6929 last_pos - 1, last_pos)
6930 if not ending or '}' not in ending:
6931 return ('Invalid ICU format. No final closing bracket',
6932 last_pos - 1, last_pos)
6933 elif first != '{':
6934 return ((
6935 'Invalid ICU format. Extra characters at the start of a complex '
6936 'message (go/icu-message-migration): "%s"') % starting, 0,
6937 len(starting))
6938 elif ending != '}':
6939 return ((
6940 'Invalid ICU format. Extra characters at the end of a complex '
6941 'message (go/icu-message-migration): "%s"') % ending,
6942 last_pos - 1, len(text) - 1)
6943 if kind not in valid_types:
6944 return (('Unknown ICU message type %s. '
6945 'Valid types are: plural, select, selectordinal') % kind,
6946 0, 0)
6947 known, required = valid_types[kind]
6948 defined_variants = set()
6949 for variant, variant_range, value, value_range in variants:
6950 start, end = variant_range
6951 if variant in defined_variants:
6952 return ('Variant "%s" is defined more than once' % variant,
6953 start, end)
6954 elif known and variant not in known:
6955 return ('Variant "%s" is not valid for %s message' %
6956 (variant, kind), start, end)
6957 defined_variants.add(variant)
6958 # Check for nested structure
6959 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
6960 if res:
6961 return (res[0], res[1] + value_range[0] + 1,
6962 res[2] + value_range[0] + 1)
6963 missing = required - defined_variants
6964 if missing:
6965 return ('Required variants missing: %s' % ', '.join(missing), 0,
6966 len(text))
6967 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:266968
Sam Maiera6e76d72022-02-11 21:43:506969 def _ParseIcuVariants(text, offset=0):
6970 """Parse variants part of ICU complex message.
Rainhard Findlingfc31844c52020-05-15 09:58:266971
Sam Maiera6e76d72022-02-11 21:43:506972 Builds a tuple of variant names and values, as well as
6973 their offsets in the input string.
Rainhard Findlingfc31844c52020-05-15 09:58:266974
Sam Maiera6e76d72022-02-11 21:43:506975 Args:
6976 text: a string to parse
6977 offset: additional offset to add to positions in the text to get correct
6978 position in the complete ICU string.
Rainhard Findlingfc31844c52020-05-15 09:58:266979
Sam Maiera6e76d72022-02-11 21:43:506980 Returns:
6981 List of tuples, each tuple consist of four fields: variant name,
6982 variant name span (tuple of two integers), variant value, value
6983 span (tuple of two integers).
6984 """
6985 depth, start, end = 0, -1, -1
6986 variants = []
6987 key = None
6988 for idx, char in enumerate(text):
6989 if char == '{':
6990 if not depth:
6991 start = idx
6992 chunk = text[end + 1:start]
6993 key = chunk.strip()
6994 pos = offset + end + 1 + chunk.find(key)
6995 span = (pos, pos + len(key))
6996 depth += 1
6997 elif char == '}':
6998 if not depth:
6999 return variants, depth, offset + idx
7000 depth -= 1
7001 if not depth:
7002 end = idx
7003 variants.append((key, span, text[start:end + 1],
7004 (offset + start, offset + end + 1)))
7005 return variants, depth, offset + end + 1
Rainhard Findlingfc31844c52020-05-15 09:58:267006
Terrence Reilly313f44ff2025-01-22 15:10:147007 old_sys_path = sys.path
Sam Maiera6e76d72022-02-11 21:43:507008 try:
Sam Maiera6e76d72022-02-11 21:43:507009 sys.path = sys.path + [
7010 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
7011 'translation')
7012 ]
7013 from helper import grd_helper
7014 finally:
7015 sys.path = old_sys_path
Rainhard Findlingfc31844c52020-05-15 09:58:267016
Sam Maiera6e76d72022-02-11 21:43:507017 for f in affected_grds:
7018 file_path = f.LocalPath()
7019 old_id_to_msg_map = {}
7020 new_id_to_msg_map = {}
7021 # Note that this code doesn't check if the file has been deleted. This is
7022 # OK because it only uses the old and new file contents and doesn't load
7023 # the file via its path.
7024 # It's also possible that a file's content refers to a renamed or deleted
7025 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
7026 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
7027 # .grdp files.
7028 if file_path.endswith('.grdp'):
7029 if f.OldContents():
7030 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
7031 '\n'.join(f.OldContents()))
7032 if f.NewContents():
7033 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
7034 '\n'.join(f.NewContents()))
7035 else:
7036 file_dir = input_api.os_path.dirname(file_path) or '.'
7037 if f.OldContents():
7038 old_id_to_msg_map = grd_helper.GetGrdMessages(
7039 StringIO('\n'.join(f.OldContents())), file_dir)
7040 if f.NewContents():
7041 new_id_to_msg_map = grd_helper.GetGrdMessages(
7042 StringIO('\n'.join(f.NewContents())), file_dir)
Rainhard Findlingfc31844c52020-05-15 09:58:267043
Sam Maiera6e76d72022-02-11 21:43:507044 grd_name, ext = input_api.os_path.splitext(
7045 input_api.os_path.basename(file_path))
7046 screenshots_dir = input_api.os_path.join(
7047 input_api.os_path.dirname(file_path),
7048 grd_name + ext.replace('.', '_'))
Rainhard Findlingfc31844c52020-05-15 09:58:267049
Sam Maiera6e76d72022-02-11 21:43:507050 # Compute added, removed and modified message IDs.
7051 old_ids = set(old_id_to_msg_map)
7052 new_ids = set(new_id_to_msg_map)
7053 added_ids = new_ids - old_ids
7054 removed_ids = old_ids - new_ids
7055 modified_ids = set([])
7056 for key in old_ids.intersection(new_ids):
7057 if (old_id_to_msg_map[key].ContentsAsXml('', True) !=
7058 new_id_to_msg_map[key].ContentsAsXml('', True)):
7059 # The message content itself changed. Require an updated screenshot.
7060 modified_ids.add(key)
7061 elif old_id_to_msg_map[key].attrs['meaning'] != \
7062 new_id_to_msg_map[key].attrs['meaning']:
Jens Mueller054652c2023-05-10 15:12:307063 # The message meaning changed. We later check for a screenshot.
7064 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147065
Sam Maiera6e76d72022-02-11 21:43:507066 if run_screenshot_check:
7067 # Check the screenshot directory for .png files. Warn if there is any.
7068 for png_path in affected_png_paths:
7069 if png_path.startswith(screenshots_dir):
7070 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147071
Sam Maiera6e76d72022-02-11 21:43:507072 for added_id in added_ids:
7073 _CheckScreenshotAdded(screenshots_dir, added_id)
Rainhard Findlingd8d04372020-08-13 13:30:097074
Sam Maiera6e76d72022-02-11 21:43:507075 for modified_id in modified_ids:
Bruce Dawson55776c42022-12-09 17:23:477076 _CheckScreenshotModified(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147077
Sam Maiera6e76d72022-02-11 21:43:507078 for removed_id in removed_ids:
7079 _CheckScreenshotRemoved(screenshots_dir, removed_id)
7080
7081 # Check new and changed strings for ICU syntax errors.
7082 for key in added_ids.union(modified_ids):
7083 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
7084 err = _ValidateIcuSyntax(msg, 0, [])
7085 if err is not None:
7086 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
7087
7088 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:267089 if run_screenshot_check:
Sam Maiera6e76d72022-02-11 21:43:507090 if unnecessary_screenshots:
7091 results.append(
7092 output_api.PresubmitError(
7093 'Do not include actual screenshots in the changelist. Run '
7094 'tools/translate/upload_screenshots.py to upload them instead:',
7095 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147096
Sam Maiera6e76d72022-02-11 21:43:507097 if missing_sha1:
7098 results.append(
7099 output_api.PresubmitError(
Bruce Dawson55776c42022-12-09 17:23:477100 'You are adding UI strings.\n'
Sam Maiera6e76d72022-02-11 21:43:507101 'To ensure the best translations, take screenshots of the relevant UI '
7102 '(https://g.co/chrome/translation) and add these files to your '
7103 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147104
Jens Mueller054652c2023-05-10 15:12:307105 if invalid_sha1:
7106 results.append(
7107 output_api.PresubmitError(
7108 'The following files do not seem to contain valid sha1 hashes. '
7109 'Make sure they contain hashes created by '
7110 'tools/translate/upload_screenshots.py:', sorted(invalid_sha1)))
7111
Bruce Dawson55776c42022-12-09 17:23:477112 if missing_sha1_modified:
7113 results.append(
7114 output_api.PresubmitError(
7115 'You are modifying UI strings or their meanings.\n'
7116 'To ensure the best translations, take screenshots of the relevant UI '
7117 '(https://g.co/chrome/translation) and add these files to your '
7118 'changelist:', sorted(missing_sha1_modified)))
7119
Sam Maiera6e76d72022-02-11 21:43:507120 if unnecessary_sha1_files:
7121 results.append(
7122 output_api.PresubmitError(
7123 'You removed strings associated with these files. Remove:',
7124 sorted(unnecessary_sha1_files)))
7125 else:
7126 results.append(
7127 output_api.PresubmitPromptOrNotify('Skipping translation '
7128 'screenshots check.'))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147129
Sam Maiera6e76d72022-02-11 21:43:507130 if icu_syntax_errors:
7131 results.append(
7132 output_api.PresubmitPromptWarning(
7133 'ICU syntax errors were found in the following strings (problems or '
7134 'feedback? Contact [email protected]):',
7135 items=icu_syntax_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:267136
Sam Maiera6e76d72022-02-11 21:43:507137 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:127138
7139
Saagar Sanghavifceeaae2020-08-12 16:40:367140def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:127141 repo_root=None,
7142 translation_expectations_path=None,
7143 grd_files=None):
Sam Maiera6e76d72022-02-11 21:43:507144 import sys
7145 affected_grds = [
7146 f for f in input_api.AffectedFiles()
7147 if (f.LocalPath().endswith('.grd') or f.LocalPath().endswith('.grdp'))
7148 ]
7149 if not affected_grds:
7150 return []
7151
Terrence Reilly313f44ff2025-01-22 15:10:147152 old_sys_path = sys.path
Sam Maiera6e76d72022-02-11 21:43:507153 try:
Sam Maiera6e76d72022-02-11 21:43:507154 sys.path = sys.path + [
7155 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
7156 'translation')
7157 ]
Terrence Reilly313f44ff2025-01-22 15:10:147158 sys.path = sys.path + [
7159 input_api.os_path.join(input_api.PresubmitLocalPath(),
7160 'third_party', 'depot_tools')
7161 ]
Sam Maiera6e76d72022-02-11 21:43:507162 from helper import git_helper
7163 from helper import translation_helper
Terrence Reilly313f44ff2025-01-22 15:10:147164 import gclient_utils
Sam Maiera6e76d72022-02-11 21:43:507165 finally:
7166 sys.path = old_sys_path
7167
7168 # Check that translation expectations can be parsed and we can get a list of
7169 # translatable grd files. |repo_root| and |translation_expectations_path| are
7170 # only passed by tests.
7171 if not repo_root:
7172 repo_root = input_api.PresubmitLocalPath()
7173 if not translation_expectations_path:
7174 translation_expectations_path = input_api.os_path.join(
7175 repo_root, 'tools', 'gritsettings', 'translation_expectations.pyl')
Terrence Reilly313f44ff2025-01-22 15:10:147176 is_cog = gclient_utils.IsEnvCog()
7177 # Git is not available in cog workspaces.
7178 if not grd_files and not is_cog:
Sam Maiera6e76d72022-02-11 21:43:507179 grd_files = git_helper.list_grds_in_repository(repo_root)
Terrence Reilly313f44ff2025-01-22 15:10:147180 if not grd_files:
7181 grd_files = []
Sam Maiera6e76d72022-02-11 21:43:507182
7183 # Ignore bogus grd files used only for testing
Gao Shenga79ebd42022-08-08 17:25:597184 # ui/webui/resources/tools/generate_grd.py.
Sam Maiera6e76d72022-02-11 21:43:507185 ignore_path = input_api.os_path.join('ui', 'webui', 'resources', 'tools',
7186 'tests')
7187 grd_files = [p for p in grd_files if ignore_path not in p]
7188
7189 try:
7190 translation_helper.get_translatable_grds(
Terrence Reilly313f44ff2025-01-22 15:10:147191 repo_root, grd_files, translation_expectations_path, is_cog)
Sam Maiera6e76d72022-02-11 21:43:507192 except Exception as e:
7193 return [
7194 output_api.PresubmitNotifyResult(
7195 'Failed to get a list of translatable grd files. This happens when:\n'
7196 ' - One of the modified grd or grdp files cannot be parsed or\n'
7197 ' - %s is not updated.\n'
7198 'Stack:\n%s' % (translation_expectations_path, str(e)))
7199 ]
Mustafa Emre Acer51f2f742020-03-09 19:41:127200 return []
7201
Ken Rockotc31f4832020-05-29 18:58:517202
Saagar Sanghavifceeaae2020-08-12 16:40:367203def CheckStableMojomChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507204 """Changes to [Stable] mojom types must preserve backward-compatibility."""
7205 changed_mojoms = input_api.AffectedFiles(
7206 include_deletes=True,
7207 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:527208
Bruce Dawson344ab262022-06-04 11:35:107209 if not changed_mojoms or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:507210 return []
7211
7212 delta = []
7213 for mojom in changed_mojoms:
Sam Maiera6e76d72022-02-11 21:43:507214 delta.append({
7215 'filename': mojom.LocalPath(),
7216 'old': '\n'.join(mojom.OldContents()) or None,
7217 'new': '\n'.join(mojom.NewContents()) or None,
7218 })
7219
7220 process = input_api.subprocess.Popen([
Takuto Ikutadca10222022-04-13 02:51:217221 input_api.python3_executable,
Sam Maiera6e76d72022-02-11 21:43:507222 input_api.os_path.join(
7223 input_api.PresubmitLocalPath(), 'mojo', 'public', 'tools', 'mojom',
7224 'check_stable_mojom_compatibility.py'), '--src-root',
7225 input_api.PresubmitLocalPath()
7226 ],
7227 stdin=input_api.subprocess.PIPE,
7228 stdout=input_api.subprocess.PIPE,
7229 stderr=input_api.subprocess.PIPE,
7230 universal_newlines=True)
7231 (x, error) = process.communicate(input=input_api.json.dumps(delta))
7232 if process.returncode:
7233 return [
7234 output_api.PresubmitError(
7235 'One or more [Stable] mojom definitions appears to have been changed '
Alex Goughc99921652024-02-15 22:59:127236 'in a way that is not backward-compatible. See '
7237 'https://chromium.googlesource.com/chromium/src/+/HEAD/mojo/public/tools/bindings/README.md#versioning'
7238 ' for details.',
Sam Maiera6e76d72022-02-11 21:43:507239 long_text=error)
7240 ]
Erik Staabc734cd7a2021-11-23 03:11:527241 return []
7242
Dominic Battre645d42342020-12-04 16:14:107243def CheckDeprecationOfPreferences(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507244 """Removing a preference should come with a deprecation."""
Dominic Battre645d42342020-12-04 16:14:107245
Sam Maiera6e76d72022-02-11 21:43:507246 def FilterFile(affected_file):
7247 """Accept only .cc files and the like."""
7248 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
7249 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
7250 input_api.DEFAULT_FILES_TO_SKIP)
7251 return input_api.FilterSourceFile(
7252 affected_file,
7253 files_to_check=file_inclusion_pattern,
7254 files_to_skip=files_to_skip)
Dominic Battre645d42342020-12-04 16:14:107255
Sam Maiera6e76d72022-02-11 21:43:507256 def ModifiedLines(affected_file):
7257 """Returns a list of tuples (line number, line text) of added and removed
7258 lines.
Dominic Battre645d42342020-12-04 16:14:107259
Sam Maiera6e76d72022-02-11 21:43:507260 Deleted lines share the same line number as the previous line.
Dominic Battre645d42342020-12-04 16:14:107261
Sam Maiera6e76d72022-02-11 21:43:507262 This relies on the scm diff output describing each changed code section
7263 with a line of the form
Dominic Battre645d42342020-12-04 16:14:107264
Sam Maiera6e76d72022-02-11 21:43:507265 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
7266 """
7267 line_num = 0
7268 modified_lines = []
7269 for line in affected_file.GenerateScmDiff().splitlines():
7270 # Extract <new line num> of the patch fragment (see format above).
7271 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@',
7272 line)
7273 if m:
7274 line_num = int(m.groups(1)[0])
7275 continue
7276 if ((line.startswith('+') and not line.startswith('++'))
7277 or (line.startswith('-') and not line.startswith('--'))):
7278 modified_lines.append((line_num, line))
Dominic Battre645d42342020-12-04 16:14:107279
Sam Maiera6e76d72022-02-11 21:43:507280 if not line.startswith('-'):
7281 line_num += 1
7282 return modified_lines
Dominic Battre645d42342020-12-04 16:14:107283
Sam Maiera6e76d72022-02-11 21:43:507284 def FindLineWith(lines, needle):
7285 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
Dominic Battre645d42342020-12-04 16:14:107286
Sam Maiera6e76d72022-02-11 21:43:507287 If 0 or >1 lines contain `needle`, -1 is returned.
7288 """
7289 matching_line_numbers = [
7290 # + 1 for 1-based counting of line numbers.
7291 i + 1 for i, line in enumerate(lines) if needle in line
7292 ]
7293 return matching_line_numbers[0] if len(
7294 matching_line_numbers) == 1 else -1
Dominic Battre645d42342020-12-04 16:14:107295
Sam Maiera6e76d72022-02-11 21:43:507296 def ModifiedPrefMigration(affected_file):
7297 """Returns whether the MigrateObsolete.*Pref functions were modified."""
7298 # Determine first and last lines of MigrateObsolete.*Pref functions.
7299 new_contents = affected_file.NewContents()
7300 range_1 = (FindLineWith(new_contents,
7301 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
7302 FindLineWith(new_contents,
7303 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
7304 range_2 = (FindLineWith(new_contents,
7305 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
7306 FindLineWith(new_contents,
7307 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
7308 if (-1 in range_1 + range_2):
7309 raise Exception(
7310 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.'
7311 )
Dominic Battre645d42342020-12-04 16:14:107312
Sam Maiera6e76d72022-02-11 21:43:507313 # Check whether any of the modified lines are part of the
7314 # MigrateObsolete.*Pref functions.
7315 for line_nr, line in ModifiedLines(affected_file):
7316 if (range_1[0] <= line_nr <= range_1[1]
7317 or range_2[0] <= line_nr <= range_2[1]):
7318 return True
7319 return False
Dominic Battre645d42342020-12-04 16:14:107320
Sam Maiera6e76d72022-02-11 21:43:507321 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
7322 browser_prefs_file_pattern = input_api.re.compile(
7323 r'chrome/browser/prefs/browser_prefs.cc')
Dominic Battre645d42342020-12-04 16:14:107324
Sam Maiera6e76d72022-02-11 21:43:507325 changes = input_api.AffectedFiles(include_deletes=True,
7326 file_filter=FilterFile)
7327 potential_problems = []
7328 for f in changes:
7329 for line in f.GenerateScmDiff().splitlines():
7330 # Check deleted lines for pref registrations.
7331 if (line.startswith('-') and not line.startswith('--')
7332 and register_pref_pattern.search(line)):
7333 potential_problems.append('%s: %s' % (f.LocalPath(), line))
Dominic Battre645d42342020-12-04 16:14:107334
Sam Maiera6e76d72022-02-11 21:43:507335 if browser_prefs_file_pattern.search(f.LocalPath()):
7336 # If the developer modified the MigrateObsolete.*Prefs() functions, we
7337 # assume that they knew that they have to deprecate preferences and don't
7338 # warn.
7339 try:
7340 if ModifiedPrefMigration(f):
7341 return []
7342 except Exception as e:
7343 return [output_api.PresubmitError(str(e))]
Dominic Battre645d42342020-12-04 16:14:107344
Sam Maiera6e76d72022-02-11 21:43:507345 if potential_problems:
7346 return [
7347 output_api.PresubmitPromptWarning(
7348 'Discovered possible removal of preference registrations.\n\n'
7349 'Please make sure to properly deprecate preferences by clearing their\n'
7350 'value for a couple of milestones before finally removing the code.\n'
7351 'Otherwise data may stay in the preferences files forever. See\n'
7352 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
7353 'chrome/browser/prefs/README.md for examples.\n'
7354 'This may be a false positive warning (e.g. if you move preference\n'
7355 'registrations to a different place).\n', potential_problems)
7356 ]
7357 return []
7358
Matt Stark6ef08872021-07-29 01:21:467359
7360def CheckConsistentGrdChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507361 """Changes to GRD files must be consistent for tools to read them."""
7362 changed_grds = input_api.AffectedFiles(
7363 include_deletes=False,
7364 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
7365 errors = []
7366 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
7367 for matcher, msg in _INVALID_GRD_FILE_LINE]
7368 for grd in changed_grds:
7369 for i, line in enumerate(grd.NewContents()):
7370 for matcher, msg in invalid_file_regexes:
7371 if matcher.search(line):
7372 errors.append(
7373 output_api.PresubmitError(
7374 'Problem on {grd}:{i} - {msg}'.format(
7375 grd=grd.LocalPath(), i=i + 1, msg=msg)))
7376 return errors
7377
Kevin McNee967dd2d22021-11-15 16:09:297378
Henrique Ferreiro2a4b55942021-11-29 23:45:367379def CheckAssertAshOnlyCode(input_api, output_api):
7380 """Errors if a BUILD.gn file in an ash/ directory doesn't include
Georg Neis94f87f02024-10-22 08:20:137381 assert(is_chromeos).
7382 For a transition period, assert(is_chromeos_ash) is also accepted.
Henrique Ferreiro2a4b55942021-11-29 23:45:367383 """
7384
7385 def FileFilter(affected_file):
7386 """Includes directories known to be Ash only."""
7387 return input_api.FilterSourceFile(
7388 affected_file,
7389 files_to_check=(
7390 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
7391 r'.*/ash/.*BUILD\.gn'), # Any path component.
7392 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
7393
7394 errors = []
Georg Neis94f87f02024-10-22 08:20:137395 pattern = input_api.re.compile(r'assert\(is_chromeos(_ash)?\b')
Jameson Thies0ce669f2021-12-09 15:56:567396 for f in input_api.AffectedFiles(include_deletes=False,
7397 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:367398 if (not pattern.search(input_api.ReadFile(f))):
7399 errors.append(
7400 output_api.PresubmitError(
Georg Neis94f87f02024-10-22 08:20:137401 'Please add assert(is_chromeos) to %s. If that\'s not '
7402 'possible, please create an issue and add a comment such '
Alison Galed6b25fe2024-04-17 13:59:047403 'as:\n # TODO(crbug.com/XXX): add '
Georg Neis94f87f02024-10-22 08:20:137404 'assert(is_chromeos) when ...' % f.LocalPath()))
Henrique Ferreiro2a4b55942021-11-29 23:45:367405 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:277406
7407
Kalvin Lee84ad17a2023-09-25 11:14:417408def _IsMiraclePtrDisallowed(input_api, affected_file):
Anton Bershanskyi4253349482025-02-11 21:01:277409 path = affected_file.UnixLocalPath()
Sam Maiera6e76d72022-02-11 21:43:507410 if not _IsCPlusPlusFile(input_api, path):
7411 return False
7412
Bartek Nowierski49b1a452024-06-08 00:24:357413 # Renderer-only code is generally allowed to use MiraclePtr. These
7414 # directories, however, are specifically disallowed, for perf reasons.
Kalvin Lee84ad17a2023-09-25 11:14:417415 if ("third_party/blink/renderer/core/" in path
7416 or "third_party/blink/renderer/platform/heap/" in path
Bartek Nowierski49b1a452024-06-08 00:24:357417 or "third_party/blink/renderer/platform/wtf/" in path
7418 or "third_party/blink/renderer/platform/fonts/" in path):
7419 return True
7420
7421 # The below paths are an explicitly listed subset of Renderer-only code,
7422 # because the plan is to Oilpanize it.
7423 # TODO(crbug.com/330759291): Remove once Oilpanization is completed or
7424 # abandoned.
7425 if ("third_party/blink/renderer/core/paint/" in path
7426 or "third_party/blink/renderer/platform/graphics/compositing/" in path
7427 or "third_party/blink/renderer/platform/graphics/paint/" in path):
Sam Maiera6e76d72022-02-11 21:43:507428 return True
7429
Sam Maiera6e76d72022-02-11 21:43:507430 # We assume that everything else may be used outside of Renderer processes.
Lukasz Anforowicz7016d05e2021-11-30 03:56:277431 return False
7432
Alison Galed6b25fe2024-04-17 13:59:047433# TODO(crbug.com/40206238): Remove these checks, once they are replaced
Lukasz Anforowicz7016d05e2021-11-30 03:56:277434# by the Chromium Clang Plugin (which will be preferable because it will
7435# 1) report errors earlier - at compile-time and 2) cover more rules).
7436def CheckRawPtrUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507437 """Rough checks that raw_ptr<T> usage guidelines are followed."""
7438 errors = []
7439 # The regex below matches "raw_ptr<" following a word boundary, but not in a
7440 # C++ comment.
7441 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
Kalvin Lee84ad17a2023-09-25 11:14:417442 file_filter = lambda f: _IsMiraclePtrDisallowed(input_api, f)
Sam Maiera6e76d72022-02-11 21:43:507443 for f, line_num, line in input_api.RightHandSideLines(file_filter):
7444 if raw_ptr_matcher.search(line):
7445 errors.append(
7446 output_api.PresubmitError(
7447 'Problem on {path}:{line} - '\
Kalvin Lee84ad17a2023-09-25 11:14:417448 'raw_ptr<T> should not be used in this renderer code '\
Sam Maiera6e76d72022-02-11 21:43:507449 '(as documented in the "Pointers to unprotected memory" '\
7450 'section in //base/memory/raw_ptr.md)'.format(
7451 path=f.LocalPath(), line=line_num)))
7452 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:567453
mikt9337567c2023-09-08 18:38:177454def CheckAdvancedMemorySafetyChecksUsage(input_api, output_api):
7455 """Checks that ADVANCED_MEMORY_SAFETY_CHECKS() macro is neither added nor
7456 removed as it is managed by the memory safety team internally.
7457 Do not add / remove it manually."""
7458 paths = set([])
7459 # The regex below matches "ADVANCED_MEMORY_SAFETY_CHECKS(" following a word
7460 # boundary, but not in a C++ comment.
7461 macro_matcher = input_api.re.compile(
7462 r'^((?!//).)*\bADVANCED_MEMORY_SAFETY_CHECKS\(', input_api.re.MULTILINE)
7463 for f in input_api.AffectedFiles():
7464 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
7465 continue
7466 if macro_matcher.search(f.GenerateScmDiff()):
7467 paths.add(f.LocalPath())
7468 if not paths:
7469 return []
7470 return [output_api.PresubmitPromptWarning(
7471 'ADVANCED_MEMORY_SAFETY_CHECKS() macro is managed by ' \
7472 'the memory safety team (chrome-memory-safety@). ' \
7473 'Please contact us to add/delete the uses of the macro.',
7474 paths)]
Henrique Ferreirof9819f2e32021-11-30 13:31:567475
7476def CheckPythonShebang(input_api, output_api):
7477 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
7478 system-wide python.
7479 """
7480 errors = []
7481 sources = lambda affected_file: input_api.FilterSourceFile(
7482 affected_file,
7483 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
7484 r'third_party/blink/web_tests/external/') + input_api.
7485 DEFAULT_FILES_TO_SKIP),
7486 files_to_check=[r'.*\.py$'])
7487 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:277488 for line_num, line in f.ChangedContents():
7489 if line_num == 1 and line.startswith('#!/usr/bin/python'):
7490 errors.append(f.LocalPath())
7491 break
Henrique Ferreirof9819f2e32021-11-30 13:31:567492
7493 result = []
7494 for file in errors:
7495 result.append(
7496 output_api.PresubmitError(
7497 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
7498 file))
7499 return result
James Shen81cc0e22022-06-15 21:10:457500
7501
Andrew Grieve5a66ae72024-12-13 15:21:537502def CheckAndroidTestAnnotations(input_api, output_api):
James Shen81cc0e22022-06-15 21:10:457503 """Checks that tests have either @Batch or @DoNotBatch annotation. If this
7504 is not an instrumentation test, disregard."""
7505
7506 batch_annotation = input_api.re.compile(r'^\s*@Batch')
7507 do_not_batch_annotation = input_api.re.compile(r'^\s*@DoNotBatch')
Andrew Grieve5a66ae72024-12-13 15:21:537508 robolectric_test = input_api.re.compile(r'@RunWith\((.*?)RobolectricTestRunner')
James Shen81cc0e22022-06-15 21:10:457509 test_class_declaration = input_api.re.compile(r'^\s*public\sclass.*Test')
7510 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
Mark Schillaci8ef0d872023-07-18 22:07:597511 test_annotation_declaration = input_api.re.compile(r'^\s*public\s@interface\s.*{')
James Shen81cc0e22022-06-15 21:10:457512
ckitagawae8fd23b2022-06-17 15:29:387513 missing_annotation_errors = []
7514 extra_annotation_errors = []
Andrew Grieve5a66ae72024-12-13 15:21:537515 wrong_robolectric_test_runner_errors = []
James Shen81cc0e22022-06-15 21:10:457516
7517 def _FilterFile(affected_file):
7518 return input_api.FilterSourceFile(
7519 affected_file,
7520 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
7521 files_to_check=[r'.*Test\.java$'])
7522
7523 for f in input_api.AffectedSourceFiles(_FilterFile):
7524 batch_matched = None
7525 do_not_batch_matched = None
7526 is_instrumentation_test = True
Mark Schillaci8ef0d872023-07-18 22:07:597527 test_annotation_declaration_matched = None
Andrew Grieve5a66ae72024-12-13 15:21:537528 has_base_robolectric_rule = False
James Shen81cc0e22022-06-15 21:10:457529 for line in f.NewContents():
Andrew Grieve5a66ae72024-12-13 15:21:537530 if 'BaseRobolectricTestRule' in line:
7531 has_base_robolectric_rule = True
7532 continue
7533 if m := robolectric_test.search(line):
7534 is_instrumentation_test = False
7535 if m.group(1) == '' and not has_base_robolectric_rule:
Yiwei Zhang5341bf02025-03-20 16:34:137536 path = str(f.LocalPath())
7537 # These two spots cannot use it.
7538 if 'webapk' not in path and 'build' not in path:
7539 wrong_robolectric_test_runner_errors.append(path)
Andrew Grieve5a66ae72024-12-13 15:21:537540 break
7541 if uiautomator_test.search(line):
James Shen81cc0e22022-06-15 21:10:457542 is_instrumentation_test = False
7543 break
7544 if not batch_matched:
7545 batch_matched = batch_annotation.search(line)
7546 if not do_not_batch_matched:
7547 do_not_batch_matched = do_not_batch_annotation.search(line)
7548 test_class_declaration_matched = test_class_declaration.search(
7549 line)
Mark Schillaci8ef0d872023-07-18 22:07:597550 test_annotation_declaration_matched = test_annotation_declaration.search(line)
7551 if test_class_declaration_matched or test_annotation_declaration_matched:
James Shen81cc0e22022-06-15 21:10:457552 break
Mark Schillaci8ef0d872023-07-18 22:07:597553 if test_annotation_declaration_matched:
7554 continue
James Shen81cc0e22022-06-15 21:10:457555 if (is_instrumentation_test and
7556 not batch_matched and
7557 not do_not_batch_matched):
Sam Maier4cef9242022-10-03 14:21:247558 missing_annotation_errors.append(str(f.LocalPath()))
ckitagawae8fd23b2022-06-17 15:29:387559 if (not is_instrumentation_test and
7560 (batch_matched or
7561 do_not_batch_matched)):
Sam Maier4cef9242022-10-03 14:21:247562 extra_annotation_errors.append(str(f.LocalPath()))
James Shen81cc0e22022-06-15 21:10:457563
7564 results = []
7565
ckitagawae8fd23b2022-06-17 15:29:387566 if missing_annotation_errors:
James Shen81cc0e22022-06-15 21:10:457567 results.append(
7568 output_api.PresubmitPromptWarning(
7569 """
Andrew Grieve43a5cf82023-09-08 15:09:467570A change was made to an on-device test that has neither been annotated with
7571@Batch nor @DoNotBatch. If this is a new test, please add the annotation. If
7572this is an existing test, please consider adding it if you are sufficiently
7573familiar with the test (but do so as a separate change).
7574
Jens Mueller2085ff82023-02-27 11:54:497575See https://source.chromium.org/chromium/chromium/src/+/main:docs/testing/batching_instrumentation_tests.md
ckitagawae8fd23b2022-06-17 15:29:387576""", missing_annotation_errors))
7577 if extra_annotation_errors:
7578 results.append(
7579 output_api.PresubmitPromptWarning(
7580 """
7581Robolectric tests do not need a @Batch or @DoNotBatch annotations.
7582""", extra_annotation_errors))
Andrew Grieve5a66ae72024-12-13 15:21:537583 if wrong_robolectric_test_runner_errors:
7584 results.append(
7585 output_api.PresubmitPromptWarning(
7586 """
Wenyu Fu0005ab82025-01-03 18:13:267587Robolectric tests should use either @RunWith(BaseRobolectricTestRunner.class) (or
Andrew Grieve5a66ae72024-12-13 15:21:537588a subclass of it), or use "@Rule BaseRobolectricTestRule".
7589""", wrong_robolectric_test_runner_errors))
James Shen81cc0e22022-06-15 21:10:457590
7591 return results
Sam Maier4cef9242022-10-03 14:21:247592
7593
Henrique Nakashima224ee2482025-03-21 18:35:027594def _CheckAndroidNullAwayAnnotatedClasses(input_api, output_api):
7595 """Checks that Java classes/interfaces/annotations are null-annotated."""
7596
7597 nullmarked_annotation = input_api.re.compile(r'^\s*@(NullMarked|NullUnmarked)')
7598
7599 missing_annotation_errors = []
7600
7601 def _FilterFile(affected_file):
7602 return input_api.FilterSourceFile(
7603 affected_file,
7604 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
7605 DEFAULT_FILES_TO_SKIP + (
7606 r'.*Test.*\.java',
7607 r'^android_webview/.*', # Temporary, crbug.com/389129271
7608 r'^build/.*',
7609 r'^chrome/.*', # Temporary, crbug.com/389129271
7610 r'^chromecast/.*',
7611 r'^components/cronet/.*',
7612 r'^tools/.*',
7613 )),
7614 files_to_check=[r'.*\.java$'])
7615
7616 for f in input_api.AffectedSourceFiles(_FilterFile):
7617 for line in f.NewContents():
7618 if nullmarked_annotation.search(line):
7619 break
7620 else:
7621 missing_annotation_errors.append(str(f.LocalPath()))
7622
7623 results = []
7624
7625 if missing_annotation_errors:
7626 results.append(
7627 output_api.PresubmitPromptWarning(
7628 """
7629Please add @NullMarked and fix the NullAway warnings in the following files
7630(see https://chromium.googlesource.com/chromium/src/+/main/styleguide/java/nullaway.md):
7631""", missing_annotation_errors))
7632
7633 return results
7634
7635
Mike Dougherty1b8be712022-10-20 00:15:137636def CheckNoJsInIos(input_api, output_api):
7637 """Checks to make sure that JavaScript files are not used on iOS."""
7638
7639 def _FilterFile(affected_file):
7640 return input_api.FilterSourceFile(
7641 affected_file,
7642 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP +
Daniel White44b8bd02023-08-22 16:20:367643 (r'^ios/third_party/*', r'^ios/tools/*', r'^third_party/*',
7644 r'^components/autofill/ios/form_util/resources/*'),
Mike Dougherty1b8be712022-10-20 00:15:137645 files_to_check=[r'^ios/.*\.js$', r'.*/ios/.*\.js$'])
7646
Mike Dougherty4d1050b2023-03-14 15:59:537647 deleted_files = []
7648
7649 # Collect filenames of all removed JS files.
Arthur Sonzognic66e9c82024-04-23 07:53:047650 for f in input_api.AffectedFiles(file_filter=_FilterFile):
Mike Dougherty4d1050b2023-03-14 15:59:537651 local_path = f.LocalPath()
7652
7653 if input_api.os_path.splitext(local_path)[1] == '.js' and f.Action() == 'D':
7654 deleted_files.append(input_api.os_path.basename(local_path))
7655
Mike Dougherty1b8be712022-10-20 00:15:137656 error_paths = []
Mike Dougherty4d1050b2023-03-14 15:59:537657 moved_paths = []
Mike Dougherty1b8be712022-10-20 00:15:137658 warning_paths = []
7659
7660 for f in input_api.AffectedSourceFiles(_FilterFile):
7661 local_path = f.LocalPath()
7662
7663 if input_api.os_path.splitext(local_path)[1] == '.js':
7664 if f.Action() == 'A':
Mike Dougherty4d1050b2023-03-14 15:59:537665 if input_api.os_path.basename(local_path) in deleted_files:
7666 # This script was probably moved rather than newly created.
7667 # Present a warning instead of an error for these cases.
7668 moved_paths.append(local_path)
7669 else:
7670 error_paths.append(local_path)
Mike Dougherty1b8be712022-10-20 00:15:137671 elif f.Action() != 'D':
7672 warning_paths.append(local_path)
7673
7674 results = []
7675
7676 if warning_paths:
7677 results.append(output_api.PresubmitPromptWarning(
7678 'TypeScript is now fully supported for iOS feature scripts. '
7679 'Consider converting JavaScript files to TypeScript. See '
7680 '//ios/web/public/js_messaging/README.md for more details.',
7681 warning_paths))
7682
Mike Dougherty4d1050b2023-03-14 15:59:537683 if moved_paths:
7684 results.append(output_api.PresubmitPromptWarning(
7685 'Do not use JavaScript on iOS for new files as TypeScript is '
7686 'fully supported. (If this is a moved file, you may leave the '
7687 'script unconverted.) See //ios/web/public/js_messaging/README.md '
7688 'for help using scripts on iOS.', moved_paths))
7689
Mike Dougherty1b8be712022-10-20 00:15:137690 if error_paths:
7691 results.append(output_api.PresubmitError(
7692 'Do not use JavaScript on iOS as TypeScript is fully supported. '
7693 'See //ios/web/public/js_messaging/README.md for help using '
7694 'scripts on iOS.', error_paths))
7695
7696 return results
Hans Wennborg23a81d52023-03-24 16:38:137697
7698def CheckLibcxxRevisionsMatch(input_api, output_api):
7699 """Check to make sure the libc++ version matches across deps files."""
Andrew Grieve21bb6792023-03-27 19:06:487700 # Disable check for changes to sub-repositories.
7701 if input_api.PresubmitLocalPath() != input_api.change.RepositoryRoot():
Sam Maierb926c58c2023-08-08 19:58:257702 return []
Hans Wennborg23a81d52023-03-24 16:38:137703
7704 DEPS_FILES = [ 'DEPS', 'buildtools/deps_revisions.gni' ]
7705
Anton Bershanskyi4253349482025-02-11 21:01:277706 file_filter = lambda f: f.UnixLocalPath() in DEPS_FILES
Hans Wennborg23a81d52023-03-24 16:38:137707 changed_deps_files = input_api.AffectedFiles(file_filter=file_filter)
7708 if not changed_deps_files:
7709 return []
7710
7711 def LibcxxRevision(file):
7712 file = input_api.os_path.join(input_api.PresubmitLocalPath(),
7713 *file.split('/'))
7714 return input_api.re.search(
7715 r'libcxx_revision.*[:=].*[\'"](\w+)[\'"]',
7716 input_api.ReadFile(file)).group(1)
7717
7718 if len(set([LibcxxRevision(f) for f in DEPS_FILES])) == 1:
7719 return []
7720
7721 return [output_api.PresubmitError(
7722 'libcxx_revision not equal across %s' % ', '.join(DEPS_FILES),
7723 changed_deps_files)]
Arthur Sonzogni7109bd32023-10-03 10:34:427724
7725
7726def CheckDanglingUntriaged(input_api, output_api):
7727 """Warn developers adding DanglingUntriaged raw_ptr."""
7728
7729 # Ignore during git presubmit --all.
7730 #
7731 # This would be too costly, because this would check every lines of every
7732 # C++ files. Check from _BANNED_CPP_FUNCTIONS are also reading the whole
7733 # source code, but only once to apply every checks. It seems the bots like
7734 # `win-presubmit` are particularly sensitive to reading the files. Adding
7735 # this check caused the bot to run 2x longer. See https://crbug.com/1486612.
7736 if input_api.no_diffs:
Arthur Sonzogni9eafd222023-11-10 08:50:397737 return []
Arthur Sonzogni7109bd32023-10-03 10:34:427738
7739 def FilterFile(file):
7740 return input_api.FilterSourceFile(
7741 file,
7742 files_to_check=[r".*\.(h|cc|cpp|cxx|m|mm)$"],
7743 files_to_skip=[r"^base/allocator.*"],
7744 )
7745
7746 count = 0
Arthur Sonzognic66e9c82024-04-23 07:53:047747 for f in input_api.AffectedFiles(file_filter=FilterFile):
Arthur Sonzogni9eafd222023-11-10 08:50:397748 count -= sum([l.count("DanglingUntriaged") for l in f.OldContents()])
7749 count += sum([l.count("DanglingUntriaged") for l in f.NewContents()])
Arthur Sonzogni7109bd32023-10-03 10:34:427750
7751 # Most likely, nothing changed:
7752 if count == 0:
7753 return []
7754
7755 # Congrats developers for improving it:
7756 if count < 0:
Arthur Sonzogni9eafd222023-11-10 08:50:397757 message = f"DanglingUntriaged pointers removed: {-count}\nThank you!"
Arthur Sonzogni7109bd32023-10-03 10:34:427758 return [output_api.PresubmitNotifyResult(message)]
7759
7760 # Check for 'DanglingUntriaged-notes' in the description:
7761 notes_regex = input_api.re.compile("DanglingUntriaged-notes[:=]")
7762 if any(
7763 notes_regex.match(line)
7764 for line in input_api.change.DescriptionText().splitlines()):
7765 return []
7766
7767 # Check for DanglingUntriaged-notes in the git footer:
7768 if input_api.change.GitFootersFromDescription().get(
7769 "DanglingUntriaged-notes", []):
7770 return []
7771
7772 message = (
Arthur Sonzogni9eafd222023-11-10 08:50:397773 "Unexpected new occurrences of `DanglingUntriaged` detected. Please\n" +
7774 "avoid adding new ones\n" +
7775 "\n" +
7776 "See documentation:\n" +
7777 "https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr.md\n" +
7778 "\n" +
7779 "See also the guide to fix dangling pointers:\n" +
7780 "https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr_guide.md\n" +
7781 "\n" +
7782 "To disable this warning, please add in the commit description:\n" +
Alex Gough26dcd852023-12-22 16:47:197783 "DanglingUntriaged-notes: <rationale for new untriaged dangling " +
Arthur Sonzogni9eafd222023-11-10 08:50:397784 "pointers>"
Arthur Sonzogni7109bd32023-10-03 10:34:427785 )
7786 return [output_api.PresubmitPromptWarning(message)]
Jan Keitel77be7522023-10-12 20:40:497787
7788def CheckInlineConstexprDefinitionsInHeaders(input_api, output_api):
7789 """Checks that non-static constexpr definitions in headers are inline."""
7790 # In a properly formatted file, constexpr definitions inside classes or
7791 # structs will have additional whitespace at the beginning of the line.
7792 # The pattern looks for variables initialized as constexpr kVar = ...; or
7793 # constexpr kVar{...};
7794 # The pattern does not match expressions that have braces in kVar to avoid
7795 # matching constexpr functions.
7796 pattern = input_api.re.compile(r'^constexpr (?!inline )[^\(\)]*[={]')
7797 attribute_pattern = input_api.re.compile(r'(\[\[[a-zA-Z_:]+\]\]|[A-Z]+[A-Z_]+) ')
7798 problems = []
7799 for f in input_api.AffectedFiles():
7800 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
7801 continue
7802
7803 for line_number, line in f.ChangedContents():
7804 line = attribute_pattern.sub('', line)
7805 if pattern.search(line):
7806 problems.append(
7807 f"{f.LocalPath()}: {line_number}\n {line}")
7808
7809 if problems:
7810 return [
7811 output_api.PresubmitPromptWarning(
7812 'Consider inlining constexpr variable definitions in headers '
7813 'outside of classes to avoid unnecessary copies of the '
7814 'constant. See https://abseil.io/tips/168 for more details.',
7815 problems)
7816 ]
7817 else:
7818 return []
Alison Galed6b25fe2024-04-17 13:59:047819
7820def CheckTodoBugReferences(input_api, output_api):
7821 """Checks that bugs in TODOs use updated issue tracker IDs."""
7822
Manish Goregaokardc9e3512025-02-03 15:30:587823 files_to_skip = ['PRESUBMIT_test.py', r"^third_party/rust/chromium_crates_io/vendor/.*"]
Alison Galed6b25fe2024-04-17 13:59:047824
7825 def _FilterFile(affected_file):
7826 return input_api.FilterSourceFile(
7827 affected_file,
7828 files_to_skip=files_to_skip)
7829
7830 # Monorail bug IDs are all less than or equal to 1524553 so check that all
7831 # bugs in TODOs are greater than that value.
Tom Sepez8e628582025-02-14 02:18:557832 pattern = input_api.re.compile(r'.*\bTODO\([^\)0-9]*([0-9]+)\).*')
Alison Galed6b25fe2024-04-17 13:59:047833 problems = []
7834 for f in input_api.AffectedSourceFiles(_FilterFile):
7835 for line_number, line in f.ChangedContents():
7836 match = pattern.match(line)
7837 if match and int(match.group(1)) <= 1524553:
7838 problems.append(
7839 f"{f.LocalPath()}: {line_number}\n {line}")
7840
7841 if problems:
7842 return [
7843 output_api.PresubmitPromptWarning(
Alison Galecb598de52024-04-26 17:03:257844 'TODOs should use the new Chromium Issue Tracker IDs which can '
7845 'be found by navigating to the bug. See '
7846 'https://crbug.com/336778624 for more details.',
Alison Galed6b25fe2024-04-17 13:59:047847 problems)
7848 ]
7849 else:
7850 return []