blob: 229d73e1f3598a3140c2984fa61326f087a2065c [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/'
157 'AndroidProxySelectorTest\.java'),
158 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 Newsoneb6f5ced2022-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 ),
Eric Stevensona9a980972017-09-23 00:04:41293)
294
Clement Yan9b330cb2022-11-17 05:25:29295_BANNED_JAVASCRIPT_FUNCTIONS : Sequence [BanRule] = (
296 BanRule(
297 r'/\bchrome\.send\b',
298 (
299 '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).',
300 'Please use mojo instead for new webuis. https://docs.google.com/document/d/1RF-GSUoveYa37eoyZ9EhwMtaIwoW7Z88pIgNZ9YzQi4/edit#heading=h.gkk22wgk6wff',
301 ),
302 True,
303 (
304 r'^(?!ash\/webui).+',
305 # TODO(crbug.com/1385601): pre-existing violations still need to be
306 # cleaned up.
Rebekah Potter57aa94df2022-12-13 20:30:58307 'ash/webui/common/resources/cr.m.js',
Clement Yan9b330cb2022-11-17 05:25:29308 'ash/webui/common/resources/multidevice_setup/multidevice_setup_browser_proxy.js',
Martin Bidlingmaiera921fee72023-06-03 07:52:22309 'ash/webui/common/resources/quick_unlock/lock_screen_constants.ts',
Clement Yan9b330cb2022-11-17 05:25:29310 'ash/webui/common/resources/smb_shares/smb_browser_proxy.js',
Chad Duffin06e47de2023-12-14 18:04:13311 'ash/webui/connectivity_diagnostics/resources/connectivity_diagnostics.ts',
Clement Yan9b330cb2022-11-17 05:25:29312 'ash/webui/diagnostics_ui/resources/diagnostics_browser_proxy.ts',
313 'ash/webui/multidevice_debug/resources/logs.js',
314 'ash/webui/multidevice_debug/resources/webui.js',
315 'ash/webui/projector_app/resources/annotator/trusted/annotator_browser_proxy.js',
316 'ash/webui/projector_app/resources/app/trusted/projector_browser_proxy.js',
Ashley Prasad71f9024e2023-09-25 22:33:55317 # TODO(b/301634378): Remove violation exception once Scanning App
318 # migrated off usage of `chrome.send`.
319 'ash/webui/scanning/resources/scanning_browser_proxy.ts',
Clement Yan9b330cb2022-11-17 05:25:29320 ),
321 ),
322)
323
Daniel Cheng917ce542022-03-15 20:46:57324_BANNED_OBJC_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15325 BanRule(
[email protected]127f18ec2012-06-16 05:05:59326 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20327 (
328 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59329 'prohibited. Please use CrTrackingArea instead.',
330 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
331 ),
332 False,
333 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15334 BanRule(
[email protected]eaae1972014-04-16 04:17:26335 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20336 (
337 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59338 'instead.',
339 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
340 ),
341 False,
342 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15343 BanRule(
[email protected]127f18ec2012-06-16 05:05:59344 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20345 (
346 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59347 'Please use |convertPoint:(point) fromView:nil| instead.',
348 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
349 ),
350 True,
351 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15352 BanRule(
[email protected]127f18ec2012-06-16 05:05:59353 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20354 (
355 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59356 'Please use |convertPoint:(point) toView:nil| instead.',
357 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
358 ),
359 True,
360 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15361 BanRule(
[email protected]127f18ec2012-06-16 05:05:59362 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20363 (
364 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59365 'Please use |convertRect:(point) fromView:nil| instead.',
366 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
367 ),
368 True,
369 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15370 BanRule(
[email protected]127f18ec2012-06-16 05:05:59371 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20372 (
373 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59374 'Please use |convertRect:(point) toView: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 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20381 (
382 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59383 'Please use |convertSize:(point) fromView: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 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20390 (
391 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59392 'Please use |convertSize:(point) toView: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(
jif65398702016-10-27 10:19:48398 r"/\s+UTF8String\s*]",
399 (
400 'The use of -[NSString UTF8String] is dangerous as it can return null',
401 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
402 'Please use |SysNSStringToUTF8| instead.',
403 ),
404 True,
Marijn Kruisselbrink1b7c48952023-08-31 16:58:34405 excluded_paths = (
406 '^third_party/ocmock/OCMock/',
407 ),
jif65398702016-10-27 10:19:48408 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15409 BanRule(
Sylvain Defresne4cf1d182017-09-18 14:16:34410 r'__unsafe_unretained',
411 (
412 'The use of __unsafe_unretained is almost certainly wrong, unless',
413 'when interacting with NSFastEnumeration or NSInvocation.',
414 'Please use __weak in files build with ARC, nothing otherwise.',
415 ),
416 False,
417 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15418 BanRule(
Avi Drissman7382afa02019-04-29 23:27:13419 'freeWhenDone:NO',
420 (
421 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
422 'Foundation types is prohibited.',
423 ),
424 True,
425 ),
Avi Drissman3d243a42023-08-01 16:53:59426 BanRule(
427 'This file requires ARC support.',
428 (
429 'ARC compilation is default in Chromium; do not add boilerplate to ',
430 'files that require ARC.',
431 ),
432 True,
433 ),
[email protected]127f18ec2012-06-16 05:05:59434)
435
Sylvain Defresnea8b73d252018-02-28 15:45:54436_BANNED_IOS_OBJC_FUNCTIONS = (
Daniel Chenga44a1bcd2022-03-15 20:00:15437 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54438 r'/\bTEST[(]',
439 (
440 'TEST() macro should not be used in Objective-C++ code as it does not ',
441 'drain the autorelease pool at the end of the test. Use TEST_F() ',
442 'macro instead with a fixture inheriting from PlatformTest (or a ',
443 'typedef).'
444 ),
445 True,
446 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15447 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54448 r'/\btesting::Test\b',
449 (
450 'testing::Test should not be used in Objective-C++ code as it does ',
451 'not drain the autorelease pool at the end of the test. Use ',
452 'PlatformTest instead.'
453 ),
454 True,
455 ),
Ewann2ecc8d72022-07-18 07:41:23456 BanRule(
457 ' systemImageNamed:',
458 (
459 '+[UIImage systemImageNamed:] should not be used to create symbols.',
460 'Instead use a wrapper defined in:',
Slobodan Pejic8ef56c702024-07-12 18:21:26461 'ios/chrome/browser/shared/ui/symbols/symbol_helpers.h'
Ewann2ecc8d72022-07-18 07:41:23462 ),
463 True,
Ewann450a2ef2022-07-19 14:38:23464 excluded_paths=(
Gauthier Ambard4d8756b2023-04-07 17:26:41465 'ios/chrome/browser/shared/ui/symbols/symbol_helpers.mm',
Slobodan Pejic8ef56c702024-07-12 18:21:26466 'ios/chrome/common',
Tommy Martino2a1182dc2024-11-20 19:34:42467 # App extensions have restricted dependencies and thus can't use the
468 # wrappers.
469 '^ios/chrome/\w+_extension/',
Ewann450a2ef2022-07-19 14:38:23470 ),
Ewann2ecc8d72022-07-18 07:41:23471 ),
Sylvain Defresne781b9f92024-12-11 09:36:18472 BanRule(
473 r'public (RefCounted)?BrowserStateKeyedServiceFactory',
474 (
475 'KeyedService factories in //ios/chrome/browser should inherit from',
476 '(Refcounted)?ProfileKeyedServieFactoryIOS, not directory from',
477 '(Refcounted)?BrowserStateKeyedServiceFactory.'
478 ),
479 treat_as_error=True,
480 excluded_paths=(
481 'ios/components',
482 'ios/web_view',
483 ),
484 ),
Sylvain Defresnea8b73d252018-02-28 15:45:54485)
486
Daniel Cheng917ce542022-03-15 20:46:57487_BANNED_IOS_EGTEST_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15488 BanRule(
Peter K. Lee6c03ccff2019-07-15 14:40:05489 r'/\bEXPECT_OCMOCK_VERIFY\b',
490 (
491 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
492 'it is meant for GTests. Use [mock verify] instead.'
493 ),
494 True,
495 ),
496)
497
Daniel Cheng566634ff2024-06-29 14:56:53498_BANNED_CPP_FUNCTIONS: Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15499 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53500 '%#0',
501 (
502 'Zero-padded values that use "#" to add prefixes don\'t exhibit ',
503 'consistent behavior, since the prefix is not prepended for zero ',
504 'values. Use "0x%0..." instead.',
505 ),
506 False,
507 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting7c0d98a2023-10-06 15:42:39508 ),
509 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53510 r'/\busing namespace ',
511 (
512 'Using directives ("using namespace x") are banned by the Google Style',
513 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
514 'Explicitly qualify symbols or use using declarations ("using x::foo").',
515 ),
516 True,
517 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting94a56c42019-10-25 21:54:04518 ),
Antonio Gomes07300d02019-03-13 20:59:57519 # Make sure that gtest's FRIEND_TEST() macro is not used; the
520 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
521 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
Daniel Chenga44a1bcd2022-03-15 20:00:15522 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53523 'FRIEND_TEST(',
524 (
525 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
526 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
527 ),
528 False,
529 excluded_paths=(
530 "base/gtest_prod_util.h",
531 "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/gtest_prod_util.h",
532 ),
[email protected]23e6cbc2012-06-16 18:51:20533 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15534 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53535 'setMatrixClip',
536 (
537 'Overriding setMatrixClip() is prohibited; ',
538 'the base function is deprecated. ',
539 ),
540 True,
541 (),
tomhudsone2c14d552016-05-26 17:07:46542 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15543 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53544 'SkRefPtr',
545 ('The use of SkRefPtr is prohibited. ', 'Please use sk_sp<> instead.'),
546 True,
547 (),
[email protected]52657f62013-05-20 05:30:31548 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15549 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53550 'SkAutoRef',
551 ('The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
552 'Please use sk_sp<> instead.'),
553 True,
554 (),
[email protected]52657f62013-05-20 05:30:31555 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15556 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53557 'SkAutoTUnref',
558 ('The use of SkAutoTUnref is dangerous because it implicitly ',
559 'converts to a raw pointer. Please use sk_sp<> instead.'),
560 True,
561 (),
[email protected]52657f62013-05-20 05:30:31562 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15563 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53564 'SkAutoUnref',
565 ('The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
566 'because it implicitly converts to a raw pointer. ',
567 'Please use sk_sp<> instead.'),
568 True,
569 (),
[email protected]52657f62013-05-20 05:30:31570 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15571 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53572 r'/HANDLE_EINTR\(.*close',
573 ('HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
574 'descriptor will be closed, and it is incorrect to retry the close.',
575 'Either call close directly and ignore its return value, or wrap close',
576 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
577 ),
578 True,
579 (),
[email protected]d89eec82013-12-03 14:10:59580 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15581 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53582 r'/IGNORE_EINTR\((?!.*close)',
583 (
584 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
585 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
586 ),
587 True,
588 (
589 # Files that #define IGNORE_EINTR.
590 r'^base/posix/eintr_wrapper\.h$',
591 r'^ppapi/tests/test_broker\.cc$',
592 ),
[email protected]d89eec82013-12-03 14:10:59593 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15594 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53595 r'/v8::Extension\(',
596 (
597 'Do not introduce new v8::Extensions into the code base, use',
598 'gin::Wrappable instead. See http://crbug.com/334679',
599 ),
600 True,
601 (r'extensions/renderer/safe_builtins\.*', ),
[email protected]ec5b3f02014-04-04 18:43:43602 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15603 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53604 '#pragma comment(lib,',
605 ('Specify libraries to link with in build files and not in the source.',
606 ),
607 True,
608 (
609 r'^base/third_party/symbolize/.*',
610 r'^third_party/abseil-cpp/.*',
611 ),
jame2d1a952016-04-02 00:27:10612 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15613 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53614 r'/base::SequenceChecker\b',
615 ('Consider using SEQUENCE_CHECKER macros instead of the class directly.',
616 ),
617 False,
618 (),
gabd52c912a2017-05-11 04:15:59619 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15620 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53621 r'/base::ThreadChecker\b',
622 ('Consider using THREAD_CHECKER macros instead of the class directly.',
623 ),
624 False,
625 (),
gabd52c912a2017-05-11 04:15:59626 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15627 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53628 r'/\b(?!(Sequenced|SingleThread))\w*TaskRunner::(GetCurrentDefault|CurrentDefaultHandle)',
629 (
630 'It is not allowed to call these methods from the subclasses ',
631 'of Sequenced or SingleThread task runners.',
632 ),
633 True,
634 (),
Sean Maher03efef12022-09-23 22:43:13635 ),
636 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53637 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
638 (
639 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
640 'deprecated (http://crbug.com/634507). Please avoid converting away',
641 'from the Time types in Chromium code, especially if any math is',
642 'being done on time values. For interfacing with platform/library',
643 'APIs, use base::Time::(From,To)DeltaSinceWindowsEpoch() or',
644 'base::{TimeDelta::In}Microseconds(), or one of the other type',
645 'converter methods instead. For faking TimeXXX values (for unit',
646 'testing only), use TimeXXX() + Microseconds(N). For',
647 'other use cases, please contact base/time/OWNERS.',
648 ),
649 False,
650 excluded_paths=(
651 "base/time/time.h",
652 "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/time/time.h",
653 ),
Yuri Wiitala2f8de5c2017-07-21 00:11:06654 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15655 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53656 'CallJavascriptFunctionUnsafe',
657 (
658 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
659 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
660 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
661 ),
662 False,
663 (
664 r'^content/browser/webui/web_ui_impl\.(cc|h)$',
665 r'^content/public/browser/web_ui\.h$',
666 r'^content/public/test/test_web_ui\.(cc|h)$',
667 ),
dbeamb6f4fde2017-06-15 04:03:06668 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15669 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53670 'leveldb::DB::Open',
671 (
672 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
673 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
674 "Chrome's tracing, making their memory usage visible.",
675 ),
676 True,
677 (r'^third_party/leveldatabase/.*\.(cc|h)$', ),
Gabriel Charette0592c3a2017-07-26 12:02:04678 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15679 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53680 'leveldb::NewMemEnv',
681 (
682 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
683 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
684 "to Chrome's tracing, making their memory usage visible.",
685 ),
686 True,
687 (r'^third_party/leveldatabase/.*\.(cc|h)$', ),
Chris Mumfordc38afb62017-10-09 17:55:08688 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15689 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53690 'base::ScopedMockTimeMessageLoopTaskRunner',
691 (
692 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
693 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
694 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
695 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
696 'with gab@ first if you think you need it)',
697 ),
698 False,
699 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57700 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15701 BanRule(
Peter Kasting5fdcd782025-01-13 14:57:07702 '\bstd::aligned_(storage|union)\b',
703 (
704 'std::aligned_storage and std::aligned_union are deprecated in',
705 'C++23. Use an aligned char array instead.'
706 ),
707 True,
708 (),
709 ),
710 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53711 'std::regex',
712 (
713 'Using std::regex adds unnecessary binary size to Chrome. Please use',
714 're2::RE2 instead (crbug.com/755321)',
715 ),
716 True,
717 [
718 # Abseil's benchmarks never linked into chrome.
719 'third_party/abseil-cpp/.*_benchmark.cc',
720 ],
Francois Doray43670e32017-09-27 12:40:38721 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15722 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53723 r'/\bstd::sto(i|l|ul|ll|ull)\b',
724 (
725 'std::sto{i,l,ul,ll,ull}() use exceptions to communicate results. ',
726 'Use base::StringTo[U]Int[64]() instead.',
727 ),
728 True,
729 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting991618a62019-06-17 22:00:09730 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15731 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53732 r'/\bstd::sto(f|d|ld)\b',
733 (
734 'std::sto{f,d,ld}() use exceptions to communicate results. ',
735 'For locale-independent values, e.g. reading numbers from disk',
736 'profiles, use base::StringToDouble().',
737 'For user-visible values, parse using ICU.',
738 ),
739 True,
740 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting991618a62019-06-17 22:00:09741 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15742 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53743 r'/\bstd::to_string\b',
744 (
745 'std::to_string() is locale dependent and slower than alternatives.',
746 'For locale-independent strings, e.g. writing numbers to disk',
747 'profiles, use base::NumberToString().',
748 'For user-visible strings, use base::FormatNumber() and',
749 'the related functions in base/i18n/number_formatting.h.',
750 ),
751 True,
752 [
753 # TODO(crbug.com/335672557): Please do not add to this list. Existing
754 # uses should removed.
Daniel Cheng566634ff2024-06-29 14:56:53755 "third_party/blink/renderer/core/css/parser/css_proto_converter.cc",
756 "third_party/blink/renderer/core/editing/ime/edit_context.cc",
757 "third_party/blink/renderer/platform/graphics/bitmap_image_test.cc",
Daniel Cheng566634ff2024-06-29 14:56:53758 _THIRD_PARTY_EXCEPT_BLINK
759 ],
Daniel Bratell69334cc2019-03-26 11:07:45760 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15761 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53762 r'/#include <(cctype|ctype\.h|cwctype|wctype.h)>',
763 (
764 '<cctype>/<ctype.h>/<cwctype>/<wctype.h> are banned. Use',
765 '"third_party/abseil-cpp/absl/strings/ascii.h" instead.',
766 ),
767 True,
768 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting6f79b202023-08-09 21:25:41769 ),
770 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53771 r'/\bstd::shared_ptr\b',
772 ('std::shared_ptr is banned. Use scoped_refptr instead.', ),
773 True,
774 [
775 # Needed for interop with third-party library.
776 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
777 'array_buffer_contents\.(cc|h)',
778 '^third_party/blink/renderer/core/typed_arrays/dom_array_buffer\.cc',
779 '^third_party/blink/renderer/bindings/core/v8/' +
780 'v8_wasm_response_extensions.cc',
781 '^gin/array_buffer\.(cc|h)',
782 '^gin/per_isolate_data\.(cc|h)',
783 '^chrome/services/sharing/nearby/',
784 # Needed for interop with third-party library libunwindstack.
785 '^base/profiler/libunwindstack_unwinder_android\.(cc|h)',
786 '^base/profiler/native_unwinder_android_memory_regions_map_impl.(cc|h)',
787 # Needed for interop with third-party boringssl cert verifier
788 '^third_party/boringssl/',
789 '^net/cert/',
790 '^net/tools/cert_verify_tool/',
791 '^services/cert_verifier/',
792 '^components/certificate_transparency/',
793 '^components/media_router/common/providers/cast/certificate/',
794 # gRPC provides some C++ libraries that use std::shared_ptr<>.
795 '^chromeos/ash/services/libassistant/grpc/',
796 '^chromecast/cast_core/grpc',
797 '^chromecast/cast_core/runtime/browser',
798 '^ios/chrome/test/earl_grey/chrome_egtest_plugin_client\.(mm|h)',
799 # Fuchsia provides C++ libraries that use std::shared_ptr<>.
800 '^base/fuchsia/.*\.(cc|h)',
801 '.*fuchsia.*test\.(cc|h)',
802 # Clang plugins have different build config.
803 '^tools/clang/plugins/',
804 _THIRD_PARTY_EXCEPT_BLINK
805 ], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21806 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15807 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53808 r'/\bstd::weak_ptr\b',
809 ('std::weak_ptr is banned. Use base::WeakPtr instead.', ),
810 True,
811 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting991618a62019-06-17 22:00:09812 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15813 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53814 r'/\blong long\b',
815 ('long long is banned. Use [u]int64_t instead.', ),
816 False, # Only a warning since it is already used.
817 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21818 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15819 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53820 r'/\b(absl|std)::any\b',
821 (
822 '{absl,std}::any are banned due to incompatibility with the component ',
823 'build.',
824 ),
825 True,
826 # Not an error in third party folders, though it probably should be :)
827 [_THIRD_PARTY_EXCEPT_BLINK],
Daniel Chengc05fcc62022-01-12 16:54:29828 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15829 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53830 r'/\bstd::bind\b',
831 (
832 'std::bind() is banned because of lifetime risks. Use ',
833 'base::Bind{Once,Repeating}() instead.',
834 ),
835 True,
836 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21837 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15838 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53839 (r'/\bstd::(?:'
840 r'linear_congruential_engine|mersenne_twister_engine|'
841 r'subtract_with_carry_engine|discard_block_engine|'
842 r'independent_bits_engine|shuffle_order_engine|'
843 r'minstd_rand0?|mt19937(_64)?|ranlux(24|48)(_base)?|knuth_b|'
844 r'default_random_engine|'
845 r'random_device|'
846 r'seed_seq'
847 r')\b'),
848 (
849 'STL random number engines and generators are banned. Use the ',
850 'helpers in base/rand_util.h instead, e.g. base::RandBytes() or ',
851 'base::RandomBitGenerator.'
852 '',
853 'Please reach out to [email protected] if the base APIs are ',
854 'insufficient for your needs.',
855 ),
856 True,
857 [
858 # Not an error in third_party folders.
859 _THIRD_PARTY_EXCEPT_BLINK,
860 # Various tools which build outside of Chrome.
861 r'testing/libfuzzer',
Steinar H. Gundersone5689e42024-08-07 18:17:19862 r'testing/perf/confidence',
Daniel Cheng566634ff2024-06-29 14:56:53863 r'tools/android/io_benchmark/',
864 # Fuzzers are allowed to use standard library random number generators
865 # since fuzzing speed + reproducibility is important.
866 r'tools/ipc_fuzzer/',
867 r'.+_fuzzer\.cc$',
868 r'.+_fuzzertest\.cc$',
869 # TODO(https://crbug.com/1380528): These are all unsanctioned uses of
870 # the standard library's random number generators, and should be
871 # migrated to the //base equivalent.
872 r'ash/ambient/model/ambient_topic_queue\.cc',
873 r'base/allocator/partition_allocator/src/partition_alloc/partition_alloc_unittest\.cc',
Daniel Cheng566634ff2024-06-29 14:56:53874 r'base/test/launcher/test_launcher\.cc',
875 r'cc/metrics/video_playback_roughness_reporter_unittest\.cc',
876 r'chrome/browser/apps/app_service/metrics/website_metrics\.cc',
877 r'chrome/browser/ash/power/auto_screen_brightness/monotone_cubic_spline_unittest\.cc',
878 r'chrome/browser/ash/printing/zeroconf_printer_detector_unittest\.cc',
879 r'chrome/browser/nearby_sharing/contacts/nearby_share_contact_manager_impl_unittest\.cc',
880 r'chrome/browser/nearby_sharing/contacts/nearby_share_contacts_sorter_unittest\.cc',
881 r'chrome/browser/privacy_budget/mesa_distribution_unittest\.cc',
882 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
883 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
884 r'chrome/browser/win/conflicts/module_blocklist_cache_util_unittest\.cc',
885 r'chromeos/ash/components/memory/userspace_swap/swap_storage_unittest\.cc',
886 r'chromeos/ash/components/memory/userspace_swap/userspace_swap\.cc',
887 r'components/metrics/metrics_state_manager\.cc',
888 r'components/omnibox/browser/history_quick_provider_performance_unittest\.cc',
889 r'components/zucchini/disassembler_elf_unittest\.cc',
890 r'content/browser/webid/federated_auth_request_impl\.cc',
891 r'content/browser/webid/federated_auth_request_impl\.cc',
892 r'media/cast/test/utility/udp_proxy\.h',
893 r'sql/recover_module/module_unittest\.cc',
894 r'components/search_engines/template_url_prepopulate_data.cc',
895 # Do not add new entries to this list. If you have a use case which is
896 # not satisfied by the current APIs (i.e. you need an explicitly-seeded
897 # sequence, or stability of some sort is required), please contact
898 # [email protected].
899 ],
Daniel Cheng192683f2022-11-01 20:52:44900 ),
901 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53902 r'/\b(absl,std)::bind_front\b',
903 ('{absl,std}::bind_front() are banned. Use base::Bind{Once,Repeating}() '
904 'instead.', ),
905 True,
906 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12907 ),
908 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53909 r'/\bABSL_FLAG\b',
910 ('ABSL_FLAG is banned. Use base::CommandLine instead.', ),
911 True,
912 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12913 ),
914 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53915 r'/\babsl::c_',
916 (
Peter Kasting3b811ffd2025-01-29 22:20:16917 'Abseil container utilities are banned. Use std::ranges:: instead.',
Daniel Cheng566634ff2024-06-29 14:56:53918 ),
919 True,
920 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12921 ),
922 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53923 r'/\babsl::FixedArray\b',
924 ('absl::FixedArray is banned. Use base::FixedArray instead.', ),
925 True,
926 [
927 # base::FixedArray provides canonical access.
928 r'^base/types/fixed_array.h',
929 # Not an error in third_party folders.
930 _THIRD_PARTY_EXCEPT_BLINK,
931 ],
Peter Kasting431239a2023-09-29 03:11:44932 ),
933 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53934 r'/\babsl::FunctionRef\b',
935 ('absl::FunctionRef is banned. Use base::FunctionRef instead.', ),
936 True,
937 [
938 # base::Bind{Once,Repeating} references absl::FunctionRef to disallow
939 # interoperability.
940 r'^base/functional/bind_internal\.h',
941 # base::FunctionRef is implemented on top of absl::FunctionRef.
942 r'^base/functional/function_ref.*\..+',
943 # Not an error in third_party folders.
944 _THIRD_PARTY_EXCEPT_BLINK,
945 ],
Peter Kasting4f35bfc2022-10-18 18:39:12946 ),
947 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53948 r'/\babsl::(Insecure)?BitGen\b',
949 ('absl random number generators are banned. Use the helpers in '
950 'base/rand_util.h instead, e.g. base::RandBytes() or ',
951 'base::RandomBitGenerator.'),
952 True,
953 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12954 ),
955 BanRule(
Peter Kasting3b77a0c2024-08-22 00:22:26956 pattern=
957 r'/\babsl::(optional|nullopt|make_optional)\b',
958 explanation=('absl::optional is banned. Use std::optional instead.', ),
959 treat_as_error=True,
960 excluded_paths=[
961 _THIRD_PARTY_EXCEPT_BLINK,
962 ]),
963 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53964 r'/(\babsl::Span\b|#include <span>|\bstd::span\b)',
965 (
Peter Kastinge73b89d2024-11-26 19:35:52966 'absl::Span and std::span are banned. Use base::span instead.',
Daniel Cheng566634ff2024-06-29 14:56:53967 ),
968 True,
969 [
970 # Included for conversions between base and std.
971 r'base/containers/span.h',
972 # Test base::span<> compatibility against std::span<>.
973 r'base/containers/span_unittest.cc',
974 # //base/numerics can't use base or absl. So it uses std.
975 r'base/numerics/.*'
Lei Zhang1f9d9ec42024-06-20 18:42:27976
Daniel Cheng566634ff2024-06-29 14:56:53977 # Needed to use QUICHE API.
Ciara McMullinc029c8e2024-08-21 14:22:32978 r'android_webview/browser/ip_protection/.*',
Daniel Cheng566634ff2024-06-29 14:56:53979 r'chrome/browser/ip_protection/.*',
980 r'components/ip_protection/.*',
981 r'net/third_party/quiche/overrides/quiche_platform_impl/quiche_stack_trace_impl\.*',
982 r'services/network/web_transport\.cc',
Lei Zhang1f9d9ec42024-06-20 18:42:27983
Daniel Cheng566634ff2024-06-29 14:56:53984 # Not an error in third_party folders.
985 _THIRD_PARTY_EXCEPT_BLINK,
986 ],
Peter Kasting4f35bfc2022-10-18 18:39:12987 ),
988 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53989 r'/\babsl::StatusOr\b',
990 ('absl::StatusOr is banned. Use base::expected instead.', ),
991 True,
992 [
993 # Needed to use liburlpattern API.
994 r'components/url_pattern/.*',
995 r'services/network/shared_dictionary/simple_url_pattern_matcher\.cc',
996 r'third_party/blink/renderer/core/url_pattern/.*',
997 r'third_party/blink/renderer/modules/manifest/manifest_parser\.cc',
Lei Zhang1f9d9ec42024-06-20 18:42:27998
Daniel Cheng566634ff2024-06-29 14:56:53999 # Needed to use QUICHE API.
Ciara McMullinc029c8e2024-08-21 14:22:321000 r'android_webview/browser/ip_protection/.*',
Daniel Cheng566634ff2024-06-29 14:56:531001 r'chrome/browser/ip_protection/.*',
1002 r'components/ip_protection/.*',
Lei Zhang1f9d9ec42024-06-20 18:42:271003
Daniel Cheng566634ff2024-06-29 14:56:531004 # Needed to use MediaPipe API.
1005 r'components/media_effects/.*\.cc',
1006 # Not an error in third_party folders.
1007 _THIRD_PARTY_EXCEPT_BLINK
1008 ],
Peter Kasting4f35bfc2022-10-18 18:39:121009 ),
1010 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531011 r'/\babsl::(StrSplit|StrJoin|StrCat|StrAppend|Substitute|StrContains)\b',
1012 ('Abseil string utilities are banned. Use base/strings instead.', ),
1013 True,
1014 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:121015 ),
1016 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531017 r'/\babsl::(Mutex|CondVar|Notification|Barrier|BlockingCounter)\b',
1018 (
1019 'Abseil synchronization primitives are banned. Use',
1020 'base/synchronization instead.',
1021 ),
1022 True,
1023 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:121024 ),
1025 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531026 r'/\babsl::(Duration|Time|TimeZone|CivilDay)\b',
1027 ('Abseil\'s time library is banned. Use base/time instead.', ),
1028 True,
1029 [
1030 # Needed to use QUICHE API.
Ciara McMullinc029c8e2024-08-21 14:22:321031 r'android_webview/browser/ip_protection/.*',
Daniel Cheng566634ff2024-06-29 14:56:531032 r'chrome/browser/ip_protection/.*',
1033 r'components/ip_protection/.*',
Lei Zhang1f9d9ec42024-06-20 18:42:271034
Daniel Cheng566634ff2024-06-29 14:56:531035 # Needed to integrate with //third_party/nearby
1036 r'components/cross_device/nearby/system_clock.cc',
1037 _THIRD_PARTY_EXCEPT_BLINK # Not an error in third_party folders.
1038 ],
1039 ),
1040 BanRule(
1041 r'/#include <chrono>',
1042 ('<chrono> is banned. Use base/time instead.', ),
1043 True,
1044 [
1045 # Not an error in third_party folders:
1046 _THIRD_PARTY_EXCEPT_BLINK,
Daniel Cheng566634ff2024-06-29 14:56:531047 # This uses openscreen API depending on std::chrono.
1048 "components/openscreen_platform/task_runner.cc",
1049 ]),
1050 BanRule(
1051 r'/#include <exception>',
1052 ('Exceptions are banned and disabled in Chromium.', ),
1053 True,
1054 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1055 ),
1056 BanRule(
1057 r'/\bstd::function\b',
1058 ('std::function is banned. Use base::{Once,Repeating}Callback instead.',
1059 ),
1060 True,
1061 [
1062 # Has tests that template trait helpers don't unintentionally match
1063 # std::function.
1064 r'base/functional/callback_helpers_unittest\.cc',
1065 # Required to implement interfaces from the third-party perfetto
1066 # library.
1067 r'base/tracing/perfetto_task_runner\.cc',
1068 r'base/tracing/perfetto_task_runner\.h',
1069 # Needed for interop with the third-party nearby library type
1070 # location::nearby::connections::ResultCallback.
1071 'chrome/services/sharing/nearby/nearby_connections_conversions\.cc'
1072 # Needed for interop with the internal libassistant library.
1073 'chromeos/ash/services/libassistant/callback_utils\.h',
1074 # Needed for interop with Fuchsia fidl APIs.
1075 'fuchsia_web/webengine/browser/context_impl_browsertest\.cc',
1076 'fuchsia_web/webengine/browser/cookie_manager_impl_unittest\.cc',
1077 'fuchsia_web/webengine/browser/media_player_impl_unittest\.cc',
1078 # Required to interop with interfaces from the third-party ChromeML
1079 # library API.
1080 'services/on_device_model/ml/chrome_ml_api\.h',
1081 'services/on_device_model/ml/on_device_model_executor\.cc',
1082 'services/on_device_model/ml/on_device_model_executor\.h',
1083 # Required to interop with interfaces from the third-party perfetto
1084 # library.
Greg Thompson90ea3c22024-12-11 13:56:421085 'components/tracing/common/etw_consumer_win_unittest\.cc',
Daniel Cheng566634ff2024-06-29 14:56:531086 'services/tracing/public/cpp/perfetto/custom_event_recorder\.cc',
1087 'services/tracing/public/cpp/perfetto/perfetto_traced_process\.cc',
1088 'services/tracing/public/cpp/perfetto/perfetto_traced_process\.h',
1089 'services/tracing/public/cpp/perfetto/perfetto_tracing_backend\.cc',
1090 'services/tracing/public/cpp/perfetto/producer_client\.cc',
1091 'services/tracing/public/cpp/perfetto/producer_client\.h',
1092 'services/tracing/public/cpp/perfetto/producer_test_utils\.cc',
1093 'services/tracing/public/cpp/perfetto/producer_test_utils\.h',
1094 # Required for interop with the third-party webrtc library.
1095 'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.cc',
1096 'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.h',
1097 # TODO(https://crbug.com/1364577): Various uses that should be
1098 # migrated to something else.
1099 # Should use base::OnceCallback or base::RepeatingCallback.
1100 'base/allocator/dispatcher/initializer_unittest\.cc',
1101 'chrome/browser/ash/accessibility/speech_monitor\.cc',
1102 'chrome/browser/ash/accessibility/speech_monitor\.h',
1103 'chrome/browser/ash/login/ash_hud_login_browsertest\.cc',
1104 'chromecast/base/observer_unittest\.cc',
1105 'chromecast/browser/cast_web_view\.h',
1106 'chromecast/public/cast_media_shlib\.h',
1107 'device/bluetooth/floss/exported_callback_manager\.h',
1108 'device/bluetooth/floss/floss_dbus_client\.h',
1109 'device/fido/cable/v2_handshake_unittest\.cc',
1110 'device/fido/pin\.cc',
1111 'services/tracing/perfetto/test_utils\.h',
1112 # Should use base::FunctionRef.
1113 'chrome/browser/media/webrtc/test_stats_dictionary\.cc',
1114 'chrome/browser/media/webrtc/test_stats_dictionary\.h',
1115 'chromeos/ash/services/libassistant/device_settings_controller\.cc',
1116 'components/browser_ui/client_certificate/android/ssl_client_certificate_request\.cc',
1117 'components/gwp_asan/client/sampling_malloc_shims_unittest\.cc',
1118 'content/browser/font_unique_name_lookup/font_unique_name_lookup_unittest\.cc',
1119 # Does not need std::function at all.
1120 'components/omnibox/browser/autocomplete_result\.cc',
1121 'device/fido/win/webauthn_api\.cc',
1122 'media/audio/alsa/alsa_util\.cc',
1123 'media/remoting/stream_provider\.h',
1124 'sql/vfs_wrapper\.cc',
1125 # TODO(https://crbug.com/1364585): Remove usage and exception list
1126 # entries.
1127 'extensions/renderer/api/automation/automation_internal_custom_bindings\.cc',
1128 'extensions/renderer/api/automation/automation_internal_custom_bindings\.h',
1129 # TODO(https://crbug.com/1364579): Remove usage and exception list
1130 # entry.
1131 'ui/views/controls/focus_ring\.h',
Lei Zhang1f9d9ec42024-06-20 18:42:271132
Daniel Cheng566634ff2024-06-29 14:56:531133 # Various pre-existing uses in //tools that is low-priority to fix.
1134 'tools/binary_size/libsupersize/viewer/caspian/diff\.cc',
1135 'tools/binary_size/libsupersize/viewer/caspian/model\.cc',
1136 'tools/binary_size/libsupersize/viewer/caspian/model\.h',
1137 'tools/binary_size/libsupersize/viewer/caspian/tree_builder\.h',
1138 'tools/clang/base_bind_rewriters/BaseBindRewriters\.cpp',
Daniel Chenge5583e3c2022-09-22 00:19:411139
Daniel Cheng566634ff2024-06-29 14:56:531140 # Not an error in third_party folders.
1141 _THIRD_PARTY_EXCEPT_BLINK
1142 ],
Daniel Bratell609102be2019-03-27 20:53:211143 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151144 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531145 r'/#include <X11/',
1146 ('Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.', ),
1147 True,
1148 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Tom Andersona95e12042020-09-09 23:08:001149 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151150 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531151 r'/\bstd::ratio\b',
1152 ('std::ratio is banned by the Google Style Guide.', ),
1153 True,
1154 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:451155 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151156 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531157 r'/\bstd::aligned_alloc\b',
1158 (
1159 'std::aligned_alloc() is not yet allowed (crbug.com/1412818). Use ',
1160 'base::AlignedAlloc() instead.',
1161 ),
1162 True,
1163 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181164 ),
1165 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531166 r'/#include <(barrier|latch|semaphore|stop_token)>',
1167 ('The thread support library is banned. Use base/synchronization '
1168 'instead.', ),
1169 True,
1170 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181171 ),
1172 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531173 r'/\bstd::execution::(par|seq)\b',
1174 ('std::execution::(par|seq) is banned; they do not fit into '
1175 ' Chrome\'s threading model, and libc++ doesn\'t have full '
mikt19226ff22024-08-27 05:28:211176 'support.', ),
Daniel Cheng566634ff2024-06-29 14:56:531177 True,
1178 [_THIRD_PARTY_EXCEPT_BLINK],
Helmut Januschka7cc8a84f2024-02-07 22:50:411179 ),
1180 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531181 r'/\bstd::bit_cast\b',
1182 ('std::bit_cast is banned; use base::bit_cast instead for values and '
1183 'standard C++ casting when pointers are involved.', ),
1184 True,
1185 [
1186 # Don't warn in third_party folders.
1187 _THIRD_PARTY_EXCEPT_BLINK,
1188 # //base/numerics can't use base or absl.
1189 r'base/numerics/.*'
1190 ],
Avi Drissman70cb7f72023-12-12 17:44:371191 ),
1192 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531193 r'/\bstd::(c8rtomb|mbrtoc8)\b',
1194 ('std::c8rtomb() and std::mbrtoc8() are banned.', ),
1195 True,
1196 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181197 ),
1198 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531199 r'/\bchar8_t|std::u8string\b',
1200 (
1201 'char8_t and std::u8string are not yet allowed. Can you use [unsigned]',
1202 ' char and std::string instead?',
1203 ),
1204 True,
1205 [
1206 # The demangler does not use this type but needs to know about it.
1207 'base/third_party/symbolize/demangle\.cc',
1208 # Don't warn in third_party folders.
1209 _THIRD_PARTY_EXCEPT_BLINK
1210 ],
Peter Kastinge2c5ee82023-02-15 17:23:081211 ),
1212 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531213 r'/(\b(co_await|co_return|co_yield)\b|#include <coroutine>)',
1214 ('Coroutines are not yet allowed (https://crbug.com/1403840).', ),
1215 True,
1216 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081217 ),
1218 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531219 r'/^\s*(export\s|import\s+["<:\w]|module(;|\s+[:\w]))',
1220 ('Modules are disallowed for now due to lack of toolchain support.', ),
1221 True,
1222 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting69357dc2023-03-14 01:34:291223 ),
1224 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531225 r'/\[\[(\w*::)?no_unique_address\]\]',
1226 (
1227 '[[no_unique_address]] does not work as expected on Windows ',
1228 '(https://crbug.com/1414621). Use NO_UNIQUE_ADDRESS instead.',
1229 ),
1230 True,
1231 [
1232 # NO_UNIQUE_ADDRESS / PA_NO_UNIQUE_ADDRESS provide canonical access.
1233 r'^base/compiler_specific\.h',
1234 r'^base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/compiler_specific\.h',
1235 # Not an error in third_party folders.
1236 _THIRD_PARTY_EXCEPT_BLINK,
1237 ],
Peter Kasting8bc046d22023-11-14 00:38:031238 ),
1239 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531240 r'/#include <format>',
1241 ('<format> is not yet allowed. Use base::StringPrintf() instead.', ),
1242 True,
1243 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081244 ),
1245 BanRule(
Daniel Cheng89719222024-07-04 04:59:291246 pattern='std::views',
1247 explanation=(
1248 'Use of std::views is banned in Chrome. If you need this '
1249 'functionality, please contact [email protected].',
1250 ),
1251 treat_as_error=True,
1252 excluded_paths=[
1253 # Don't warn in third_party folders.
1254 _THIRD_PARTY_EXCEPT_BLINK
1255 ],
1256 ),
1257 BanRule(
1258 # Ban everything except specifically allowlisted constructs.
1259 pattern=r'/std::ranges::(?!' + '|'.join((
1260 # From https://en.cppreference.com/w/cpp/ranges:
1261 # Range access
1262 'begin',
1263 'end',
1264 'cbegin',
1265 'cend',
1266 'rbegin',
1267 'rend',
1268 'crbegin',
1269 'crend',
1270 'size',
1271 'ssize',
1272 'empty',
1273 'data',
1274 'cdata',
1275 # Range primitives
1276 'iterator_t',
1277 'const_iterator_t',
1278 'sentinel_t',
1279 'const_sentinel_t',
1280 'range_difference_t',
1281 'range_size_t',
1282 'range_value_t',
1283 'range_reference_t',
1284 'range_const_reference_t',
1285 'range_rvalue_reference_t',
1286 'range_common_reference_t',
1287 # Dangling iterator handling
1288 'dangling',
1289 'borrowed_iterator_t',
1290 # Banned: borrowed_subrange_t
1291 # Range concepts
1292 'range',
1293 'borrowed_range',
1294 'sized_range',
1295 'view',
1296 'input_range',
1297 'output_range',
1298 'forward_range',
1299 'bidirectional_range',
1300 'random_access_range',
1301 'contiguous_range',
1302 'common_range',
1303 'viewable_range',
1304 'constant_range',
1305 # Banned: Views
1306 # Banned: Range factories
1307 # Banned: Range adaptors
Peter Kastinga7f93752024-10-24 22:15:401308 # Incidentally listed on
1309 # https://en.cppreference.com/w/cpp/header/ranges:
1310 'enable_borrowed_range',
1311 'enable_view',
Daniel Cheng89719222024-07-04 04:59:291312 # From https://en.cppreference.com/w/cpp/algorithm/ranges:
1313 # Constrained algorithms: non-modifying sequence operations
1314 'all_of',
1315 'any_of',
1316 'none_of',
1317 'for_each',
1318 'for_each_n',
1319 'count',
1320 'count_if',
1321 'mismatch',
1322 'equal',
1323 'lexicographical_compare',
1324 'find',
1325 'find_if',
1326 'find_if_not',
1327 'find_end',
1328 'find_first_of',
1329 'adjacent_find',
1330 'search',
1331 'search_n',
1332 # Constrained algorithms: modifying sequence operations
1333 'copy',
1334 'copy_if',
1335 'copy_n',
1336 'copy_backward',
1337 'move',
1338 'move_backward',
1339 'fill',
1340 'fill_n',
1341 'transform',
1342 'generate',
1343 'generate_n',
1344 'remove',
1345 'remove_if',
1346 'remove_copy',
1347 'remove_copy_if',
1348 'replace',
1349 'replace_if',
1350 'replace_copy',
1351 'replace_copy_if',
1352 'swap_ranges',
1353 'reverse',
1354 'reverse_copy',
1355 'rotate',
1356 'rotate_copy',
1357 'shuffle',
1358 'sample',
1359 'unique',
1360 'unique_copy',
1361 # Constrained algorithms: partitioning operations
1362 'is_partitioned',
1363 'partition',
1364 'partition_copy',
1365 'stable_partition',
1366 'partition_point',
1367 # Constrained algorithms: sorting operations
1368 'is_sorted',
1369 'is_sorted_until',
1370 'sort',
1371 'partial_sort',
1372 'partial_sort_copy',
1373 'stable_sort',
1374 'nth_element',
1375 # Constrained algorithms: binary search operations (on sorted ranges)
1376 'lower_bound',
1377 'upper_bound',
1378 'binary_search',
1379 'equal_range',
1380 # Constrained algorithms: set operations (on sorted ranges)
1381 'merge',
1382 'inplace_merge',
1383 'includes',
1384 'set_difference',
1385 'set_intersection',
1386 'set_symmetric_difference',
1387 'set_union',
1388 # Constrained algorithms: heap operations
1389 'is_heap',
1390 'is_heap_until',
1391 'make_heap',
1392 'push_heap',
1393 'pop_heap',
1394 'sort_heap',
1395 # Constrained algorithms: minimum/maximum operations
1396 'max',
1397 'max_element',
1398 'min',
1399 'min_element',
1400 'minmax',
1401 'minmax_element',
1402 'clamp',
1403 # Constrained algorithms: permutation operations
1404 'is_permutation',
1405 'next_permutation',
1406 'prev_premutation',
1407 # Constrained uninitialized memory algorithms
1408 'uninitialized_copy',
1409 'uninitialized_copy_n',
1410 'uninitialized_fill',
1411 'uninitialized_fill_n',
1412 'uninitialized_move',
1413 'uninitialized_move_n',
1414 'uninitialized_default_construct',
1415 'uninitialized_default_construct_n',
1416 'uninitialized_value_construct',
1417 'uninitialized_value_construct_n',
1418 'destroy',
1419 'destroy_n',
1420 'destroy_at',
1421 'construct_at',
1422 # Return types
1423 'in_fun_result',
1424 'in_in_result',
1425 'in_out_result',
1426 'in_in_out_result',
1427 'in_out_out_result',
1428 'min_max_result',
1429 'in_found_result',
Peter Kastingf379c022025-01-13 14:01:001430 # From https://en.cppreference.com/w/cpp/header/functional
1431 'equal_to',
1432 'not_equal_to',
1433 'greater',
1434 'less',
1435 'greater_equal',
1436 'less_equal',
danakj91c715b2024-07-10 13:24:261437 # From https://en.cppreference.com/w/cpp/iterator
1438 'advance',
1439 'distance',
1440 'next',
1441 'prev',
Daniel Cheng89719222024-07-04 04:59:291442 )) + r')\w+',
1443 explanation=(
1444 'Use of range views and associated helpers is banned in Chrome. '
1445 'If you need this functionality, please contact [email protected].',
1446 ),
1447 treat_as_error=True,
1448 excluded_paths=[
1449 # Don't warn in third_party folders.
1450 _THIRD_PARTY_EXCEPT_BLINK
1451 ],
Peter Kastinge2c5ee82023-02-15 17:23:081452 ),
1453 BanRule(
Peter Kasting31879d82024-10-07 20:18:391454 r'/#include <regex>',
1455 ('<regex> is not allowed. Use third_party/re2 instead.',
1456 ),
1457 True,
1458 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1459 ),
1460 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531461 r'/#include <source_location>',
1462 ('<source_location> is not yet allowed. Use base/location.h instead.',
1463 ),
1464 True,
1465 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081466 ),
1467 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531468 r'/\bstd::to_address\b',
1469 (
1470 'std::to_address is banned because it is not guaranteed to be',
1471 'SFINAE-compatible. Use base::to_address from base/types/to_address.h',
1472 'instead.',
1473 ),
1474 True,
1475 [
1476 # Needed in base::to_address implementation.
1477 r'base/types/to_address.h',
1478 _THIRD_PARTY_EXCEPT_BLINK
1479 ], # Not an error in third_party folders.
Nick Diego Yamanee522ae82024-02-27 04:23:221480 ),
1481 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531482 r'/#include <syncstream>',
1483 ('<syncstream> is banned.', ),
1484 True,
1485 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181486 ),
1487 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531488 r'/\bRunMessageLoop\b',
1489 ('RunMessageLoop is deprecated, use RunLoop instead.', ),
1490 False,
1491 (),
Gabriel Charette147335ea2018-03-22 15:59:191492 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151493 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531494 'RunAllPendingInMessageLoop()',
1495 (
1496 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
1497 "if you're convinced you need this.",
1498 ),
1499 False,
1500 (),
Gabriel Charette147335ea2018-03-22 15:59:191501 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151502 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531503 'RunAllPendingInMessageLoop(BrowserThread',
1504 (
1505 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
1506 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
1507 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
1508 'async events instead of flushing threads.',
1509 ),
1510 False,
1511 (),
Gabriel Charette147335ea2018-03-22 15:59:191512 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151513 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531514 r'MessageLoopRunner',
1515 ('MessageLoopRunner is deprecated, use RunLoop instead.', ),
1516 False,
1517 (),
Gabriel Charette147335ea2018-03-22 15:59:191518 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151519 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531520 'GetDeferredQuitTaskForRunLoop',
1521 (
1522 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
1523 "gab@ if you found a use case where this is the only solution.",
1524 ),
1525 False,
1526 (),
Gabriel Charette147335ea2018-03-22 15:59:191527 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151528 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531529 'sqlite3_initialize(',
1530 (
1531 'Instead of calling sqlite3_initialize(), depend on //sql, ',
1532 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
1533 ),
1534 True,
1535 (
1536 r'^sql/initialization\.(cc|h)$',
1537 r'^third_party/sqlite/.*\.(c|cc|h)$',
1538 ),
Victor Costan3653df62018-02-08 21:38:161539 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151540 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531541 'CREATE VIEW',
1542 (
1543 'SQL views are disabled in Chromium feature code',
1544 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-views',
1545 ),
1546 True,
1547 (
1548 _THIRD_PARTY_EXCEPT_BLINK,
1549 # sql/ itself uses views when using memory-mapped IO.
1550 r'^sql/.*',
1551 # Various performance tools that do not build as part of Chrome.
1552 r'^infra/.*',
1553 r'^tools/perf.*',
1554 r'.*perfetto.*',
1555 ),
Austin Sullivand661ab52022-11-16 08:55:151556 ),
1557 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531558 'CREATE VIRTUAL TABLE',
1559 (
1560 'SQL virtual tables are disabled in Chromium feature code',
1561 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-virtual-tables',
1562 ),
1563 True,
1564 (
1565 _THIRD_PARTY_EXCEPT_BLINK,
1566 # sql/ itself uses virtual tables in the recovery module and tests.
1567 r'^sql/.*',
1568 # TODO(https://crbug.com/695592): Remove once WebSQL is deprecated.
1569 r'third_party/blink/web_tests/storage/websql/.*'
1570 # Various performance tools that do not build as part of Chrome.
1571 r'^tools/perf.*',
1572 r'.*perfetto.*',
1573 ),
Austin Sullivand661ab52022-11-16 08:55:151574 ),
1575 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531576 'std::random_shuffle',
1577 ('std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
1578 'base::RandomShuffle instead.'),
1579 True,
1580 (),
tzik5de2157f2018-05-08 03:42:471581 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151582 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531583 'ios/web/public/test/http_server',
1584 ('web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
1585 ),
1586 False,
1587 (),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:241588 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151589 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531590 'GetAddressOf',
1591 ('Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
1592 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
1593 'operator& is generally recommended. So always use operator& instead. ',
1594 'See http://crbug.com/914910 for more conversion guidance.'),
1595 True,
1596 (),
Robert Liao764c9492019-01-24 18:46:281597 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151598 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531599 'SHFileOperation',
1600 ('SHFileOperation was deprecated in Windows Vista, and there are less ',
1601 'complex functions to achieve the same goals. Use IFileOperation for ',
1602 'any esoteric actions instead.'),
1603 True,
1604 (),
Ben Lewisa9514602019-04-29 17:53:051605 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151606 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531607 'StringFromGUID2',
1608 ('StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
1609 'Use base::win::WStringFromGUID instead.'),
1610 True,
1611 (r'/base/win/win_util_unittest.cc', ),
Cliff Smolinsky81951642019-04-30 21:39:511612 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151613 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531614 'StringFromCLSID',
1615 ('StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
1616 'Use base::win::WStringFromGUID instead.'),
1617 True,
1618 (r'/base/win/win_util_unittest.cc', ),
Cliff Smolinsky81951642019-04-30 21:39:511619 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151620 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531621 'kCFAllocatorNull',
1622 (
1623 'The use of kCFAllocatorNull with the NoCopy creation of ',
1624 'CoreFoundation types is prohibited.',
1625 ),
1626 True,
1627 (),
Avi Drissman7382afa02019-04-29 23:27:131628 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151629 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531630 'mojo::ConvertTo',
1631 ('mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1632 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1633 'StringTraits if you would like to convert between custom types and',
1634 'the wire format of mojom types.'),
1635 False,
1636 (
1637 r'^fuchsia_web/webengine/browser/url_request_rewrite_rules_manager\.cc$',
1638 r'^fuchsia_web/webengine/url_request_rewrite_type_converters\.cc$',
1639 r'^third_party/blink/.*\.(cc|h)$',
1640 r'^content/renderer/.*\.(cc|h)$',
1641 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291642 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151643 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531644 'GetInterfaceProvider',
1645 ('InterfaceProvider is deprecated.',
1646 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1647 'or Platform::GetBrowserInterfaceBroker.'),
1648 False,
1649 (),
Oksana Zhuravlovac8222d22019-12-19 19:21:161650 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151651 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531652 'CComPtr',
1653 ('New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1654 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1655 'details.'),
1656 False,
1657 (),
Robert Liao1d78df52019-11-11 20:02:011658 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151659 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531660 r'/\b(IFACE|STD)METHOD_?\(',
1661 ('IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1662 'Instead, always use IFACEMETHODIMP in the declaration.'),
1663 False,
1664 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Xiaohan Wang72bd2ba2020-02-18 21:38:201665 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151666 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531667 'set_owned_by_client',
1668 ('set_owned_by_client is deprecated.',
1669 'views::View already owns the child views by default. This introduces ',
1670 'a competing ownership model which makes the code difficult to reason ',
1671 'about. See http://crbug.com/1044687 for more details.'),
1672 False,
1673 (),
Allen Bauer53b43fb12020-03-12 17:21:471674 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151675 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531676 'RemoveAllChildViewsWithoutDeleting',
1677 ('RemoveAllChildViewsWithoutDeleting is deprecated.',
1678 'This method is deemed dangerous as, unless raw pointers are re-added,',
1679 'calls to this method introduce memory leaks.'),
1680 False,
1681 (),
Peter Boström7ff41522021-07-29 03:43:271682 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151683 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531684 r'/\bTRACE_EVENT_ASYNC_',
1685 (
1686 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1687 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1688 ),
1689 False,
1690 (
1691 r'^base/trace_event/.*',
1692 r'^base/tracing/.*',
1693 ),
Eric Secklerbe6f48d2020-05-06 18:09:121694 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151695 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531696 'RoInitialize',
1697 ('Improper use of [base::win]::RoInitialize() has been implicated in a ',
1698 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
1699 'instead. See http://crbug.com/1197722 for more information.'),
1700 True,
1701 (
1702 r'^base/win/scoped_winrt_initializer\.cc$',
1703 r'^third_party/abseil-cpp/absl/.*',
1704 ),
Robert Liao22f66a52021-04-10 00:57:521705 ),
Patrick Monettec343bb982022-06-01 17:18:451706 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531707 r'base::Watchdog',
1708 (
1709 'base::Watchdog is deprecated because it creates its own thread.',
1710 'Instead, manually start a timer on a SequencedTaskRunner.',
1711 ),
1712 False,
1713 (),
Patrick Monettec343bb982022-06-01 17:18:451714 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091715 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531716 'base::Passed',
1717 ('Do not use base::Passed. It is a legacy helper for capturing ',
1718 'move-only types with base::BindRepeating, but invoking the ',
1719 'resulting RepeatingCallback moves the captured value out of ',
1720 'the callback storage, and subsequent invocations may pass the ',
1721 'value in a valid but undefined state. Prefer base::BindOnce().',
1722 'See http://crbug.com/1326449 for context.'),
1723 False,
1724 (
1725 # False positive, but it is also fine to let bind internals reference
1726 # base::Passed.
1727 r'^base[\\/]functional[\\/]bind\.h',
1728 r'^base[\\/]functional[\\/]bind_internal\.h',
1729 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091730 ),
Daniel Cheng2248b332022-07-27 06:16:591731 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531732 r'base::Feature k',
1733 ('Please use BASE_DECLARE_FEATURE() or BASE_FEATURE() instead of ',
1734 'directly declaring/defining features.'),
1735 True,
1736 [
1737 # Implements BASE_DECLARE_FEATURE().
1738 r'^base/feature_list\.h',
1739 ],
Daniel Chengba3bc2e2022-10-03 02:45:431740 ),
Robert Ogden92101dcb2022-10-19 23:49:361741 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531742 r'/\bchartorune\b',
1743 ('chartorune is not memory-safe, unless you can guarantee the input ',
1744 'string is always null-terminated. Otherwise, please use charntorune ',
1745 'from libphonenumber instead.'),
1746 True,
1747 [
1748 _THIRD_PARTY_EXCEPT_BLINK,
1749 # Exceptions to this rule should have a fuzzer.
1750 ],
Robert Ogden92101dcb2022-10-19 23:49:361751 ),
Arthur Sonzogni1da65fa2023-03-27 16:01:521752 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531753 r'/\b#include "base/atomicops\.h"\b',
1754 ('Do not use base::subtle atomics, but std::atomic, which are simpler '
1755 'to use, have better understood, clearer and richer semantics, and are '
1756 'harder to mis-use. See details in base/atomicops.h.', ),
1757 False,
1758 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Benoit Lize79cf0592023-01-27 10:01:571759 ),
Daniel Cheng566634ff2024-06-29 14:56:531760 BanRule(r'CrossThreadPersistent<', (
Arthur Sonzogni60348572e2023-04-07 10:22:521761 'Do not use blink::CrossThreadPersistent, but '
Daniel Cheng566634ff2024-06-29 14:56:531762 'blink::CrossThreadHandle. It is harder to mis-use.', 'More info: '
Arthur Sonzogni60348572e2023-04-07 10:22:521763 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1764 'Please contact platform-architecture-dev@ before adding new instances.'
Daniel Cheng566634ff2024-06-29 14:56:531765 ), False, []),
1766 BanRule(r'CrossThreadWeakPersistent<', (
Arthur Sonzogni60348572e2023-04-07 10:22:521767 'Do not use blink::CrossThreadWeakPersistent, but '
Daniel Cheng566634ff2024-06-29 14:56:531768 'blink::CrossThreadWeakHandle. It is harder to mis-use.', 'More info: '
Arthur Sonzogni60348572e2023-04-07 10:22:521769 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1770 'Please contact platform-architecture-dev@ before adding new instances.'
Daniel Cheng566634ff2024-06-29 14:56:531771 ), False, []),
1772 BanRule(r'objc/objc.h', (
Avi Drissman491617c2023-04-13 17:33:151773 'Do not include <objc/objc.h>. It defines away ARC lifetime '
1774 'annotations, and is thus dangerous.',
1775 'Please use the pimpl pattern; search for `ObjCStorage` for examples.',
1776 'For further reading on how to safely mix C++ and Obj-C, see',
1777 'https://chromium.googlesource.com/chromium/src/+/main/docs/mac/mixing_cpp_and_objc.md'
Daniel Cheng566634ff2024-06-29 14:56:531778 ), True, []),
1779 BanRule(
1780 r'/#include <filesystem>',
1781 ('libc++ <filesystem> is banned per the Google C++ styleguide.', ),
1782 True,
1783 # This fuzzing framework is a standalone open source project and
1784 # cannot rely on Chromium base.
1785 (r'third_party/centipede'),
Avi Drissman491617c2023-04-13 17:33:151786 ),
Grace Park8d59b54b2023-04-26 17:53:351787 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531788 r'TopDocument()',
1789 ('TopDocument() does not work correctly with out-of-process iframes. '
1790 'Please do not introduce new uses.', ),
1791 True,
1792 (
1793 # TODO(crbug.com/617677): Remove all remaining uses.
1794 r'^third_party/blink/renderer/core/dom/document\.cc',
1795 r'^third_party/blink/renderer/core/dom/document\.h',
1796 r'^third_party/blink/renderer/core/dom/element\.cc',
1797 r'^third_party/blink/renderer/core/exported/web_disallow_transition_scope_test\.cc',
1798 r'^third_party/blink/renderer/core/exported/web_document_test\.cc',
1799 r'^third_party/blink/renderer/core/html/html_anchor_element\.cc',
1800 r'^third_party/blink/renderer/core/html/html_dialog_element\.cc',
1801 r'^third_party/blink/renderer/core/html/html_element\.cc',
1802 r'^third_party/blink/renderer/core/html/html_frame_owner_element\.cc',
1803 r'^third_party/blink/renderer/core/html/media/video_wake_lock\.cc',
1804 r'^third_party/blink/renderer/core/loader/anchor_element_interaction_tracker\.cc',
1805 r'^third_party/blink/renderer/core/page/scrolling/root_scroller_controller\.cc',
1806 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.cc',
1807 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.h',
1808 r'^third_party/blink/renderer/core/script/classic_pending_script\.cc',
1809 r'^third_party/blink/renderer/core/script/script_loader\.cc',
1810 ),
Grace Park8d59b54b2023-04-26 17:53:351811 ),
Daniel Cheng72153e02023-05-18 21:18:141812 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531813 pattern=r'base::raw_ptr<',
1814 explanation=('Do not use base::raw_ptr, use raw_ptr.', ),
1815 treat_as_error=True,
1816 excluded_paths=(
1817 '^base/',
1818 '^tools/',
1819 ),
Daniel Cheng72153e02023-05-18 21:18:141820 ),
Arthur Sonzognif0eea302023-08-18 19:20:311821 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531822 pattern=r'base:raw_ref<',
1823 explanation=('Do not use base::raw_ref, use raw_ref.', ),
1824 treat_as_error=True,
1825 excluded_paths=(
1826 '^base/',
1827 '^tools/',
1828 ),
Arthur Sonzognif0eea302023-08-18 19:20:311829 ),
1830 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531831 pattern=r'/raw_ptr<[^;}]*\w{};',
1832 explanation=(
1833 'Do not use {} for raw_ptr initialization, use = nullptr instead.',
1834 ),
1835 treat_as_error=True,
1836 excluded_paths=(
1837 '^base/',
1838 '^tools/',
1839 ),
Arthur Sonzognif0eea302023-08-18 19:20:311840 ),
Anton Maliev66751812023-08-24 16:28:131841 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531842 pattern=r'/#include "base/allocator/.*/raw_'
1843 r'(ptr|ptr_cast|ptr_exclusion|ref).h"',
1844 explanation=(
1845 'Please include the corresponding facade headers:',
1846 '- #include "base/memory/raw_ptr.h"',
1847 '- #include "base/memory/raw_ptr_cast.h"',
1848 '- #include "base/memory/raw_ptr_exclusion.h"',
1849 '- #include "base/memory/raw_ref.h"',
1850 ),
1851 treat_as_error=True,
1852 excluded_paths=(
1853 '^base/',
1854 '^tools/',
1855 ),
Tom Sepez41eb158d2023-09-12 16:16:221856 ),
1857 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531858 pattern=r'ContentSettingsType::COOKIES',
1859 explanation=
1860 ('Do not use ContentSettingsType::COOKIES to check whether cookies are '
1861 'supported in the provided context. Instead rely on the '
1862 'content_settings::CookieSettings API. If you are using '
1863 'ContentSettingsType::COOKIES to check the user preference setting '
1864 'specifically, disregard this warning.', ),
1865 treat_as_error=False,
1866 excluded_paths=(
1867 '^chrome/browser/ui/content_settings/',
1868 '^components/content_settings/',
1869 '^services/network/cookie_settings.cc',
1870 '.*test.cc',
1871 ),
Arthur Sonzogni48c6aea22023-09-04 22:25:201872 ),
1873 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531874 pattern=r'ContentSettingsType::TRACKING_PROTECTION',
1875 explanation=
1876 ('Do not directly use ContentSettingsType::TRACKING_PROTECTION to check '
1877 'for tracking protection exceptions. Instead rely on the '
1878 'privacy_sandbox::TrackingProtectionSettings API.', ),
1879 treat_as_error=False,
1880 excluded_paths=(
1881 '^chrome/browser/ui/content_settings/',
1882 '^components/content_settings/',
1883 '^components/privacy_sandbox/tracking_protection_settings.cc',
1884 '.*test.cc',
1885 ),
Anton Maliev66751812023-08-24 16:28:131886 ),
Tom Andersoncd522072023-10-03 00:52:351887 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531888 pattern=r'/\bg_signal_connect',
1889 explanation=('Use ScopedGSignal instead of g_signal_connect*()', ),
1890 treat_as_error=True,
1891 excluded_paths=('^ui/base/glib/scoped_gsignal.h', ),
Michelle Abreo6b7437822024-04-26 17:29:041892 ),
1893 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531894 pattern=r'features::kIsolatedWebApps',
1895 explanation=(
1896 'Do not use `features::kIsolatedWebApps` directly to guard Isolated ',
1897 'Web App code. ',
1898 'Use `content::IsolatedWebAppsPolicy::AreIsolatedWebAppsEnabled()` in ',
1899 'the browser process or check the `kEnableIsolatedWebAppsInRenderer` ',
1900 'command line flag in the renderer process.',
1901 ),
1902 treat_as_error=True,
1903 excluded_paths=_TEST_CODE_EXCLUDED_PATHS +
1904 ('^chrome/browser/about_flags.cc',
1905 '^chrome/browser/web_applications/isolated_web_apps/chrome_content_browser_client_isolated_web_apps_part.cc',
1906 '^chrome/browser/ui/startup/bad_flags_prompt.cc',
1907 '^content/shell/browser/shell_content_browser_client.cc')),
1908 BanRule(
1909 pattern=r'features::kIsolatedWebAppDevMode',
1910 explanation=(
1911 'Do not use `features::kIsolatedWebAppDevMode` directly to guard code ',
1912 'related to Isolated Web App Developer Mode. ',
1913 'Use `web_app::IsIwaDevModeEnabled()` instead.',
1914 ),
1915 treat_as_error=True,
1916 excluded_paths=_TEST_CODE_EXCLUDED_PATHS + (
1917 '^chrome/browser/about_flags.cc',
1918 '^chrome/browser/web_applications/isolated_web_apps/isolated_web_app_features.cc',
1919 '^chrome/browser/ui/startup/bad_flags_prompt.cc',
1920 )),
1921 BanRule(
1922 pattern=r'features::kIsolatedWebAppUnmanagedInstall',
1923 explanation=(
1924 'Do not use `features::kIsolatedWebAppUnmanagedInstall` directly to ',
1925 'guard code related to unmanaged install flow for Isolated Web Apps. ',
1926 'Use `web_app::IsIwaUnmanagedInstallEnabled()` instead.',
1927 ),
1928 treat_as_error=True,
1929 excluded_paths=_TEST_CODE_EXCLUDED_PATHS + (
1930 '^chrome/browser/about_flags.cc',
1931 '^chrome/browser/web_applications/isolated_web_apps/isolated_web_app_features.cc',
1932 )),
1933 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531934 pattern='/(CUIAutomation|AccessibleObjectFromWindow)',
1935 explanation=
1936 ('Direct usage of UIAutomation or IAccessible2 in client code is '
1937 'discouraged in Chromium, as it is not an assistive technology and '
1938 'should not rely on accessibility APIs directly. These APIs can '
1939 'introduce significant performance overhead. However, if you believe '
1940 'your use case warrants an exception, please discuss it with an '
1941 'accessibility owner before proceeding. For more information on the '
1942 'performance implications, see https://docs.google.com/document/d/1jN4itpCe_bDXF0BhFaYwv4xVLsCWkL9eULdzjmLzkuk/edit#heading=h.pwth3nbwdub0.',
1943 ),
1944 treat_as_error=False,
Andrew Rayskiycdd45e732024-03-20 14:32:391945 ),
1946 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531947 pattern=r'/WIDGET_OWNS_NATIVE_WIDGET|'
1948 r'NATIVE_WIDGET_OWNS_WIDGET',
1949 explanation=
1950 ('WIDGET_OWNS_NATIVE_WIDGET and NATIVE_WIDGET_OWNS_WIDGET are in the '
1951 'process of being deprecated. Consider using the new '
1952 'CLIENT_OWNS_WIDGET ownership model. Eventually, this will be the only '
1953 'available ownership model available and the associated enumeration'
1954 'will be removed.', ),
1955 treat_as_error=False,
Andrew Rayskiycdd45e732024-03-20 14:32:391956 ),
1957 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531958 pattern='ProfileManager::GetLastUsedProfile',
1959 explanation=
1960 ('Most code should already be scoped to a Profile. Pass in a Profile* '
1961 'or retreive from an existing entity with a reference to the Profile '
1962 '(e.g. WebContents).', ),
1963 treat_as_error=False,
Arthur Sonzogni5cbd3e32024-02-08 17:51:321964 ),
Helmut Januschkab3f71ab52024-03-12 02:48:051965 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531966 pattern=(r'/FindBrowserWithUiElementContext|'
1967 r'FindBrowserWithTab|'
1968 r'FindBrowserWithGroup|'
1969 r'FindTabbedBrowser|'
1970 r'FindAnyBrowser|'
1971 r'FindBrowserWithProfile|'
Erik Chen5f02eb4c2024-08-23 06:30:441972 r'FindLastActive|'
Daniel Cheng566634ff2024-06-29 14:56:531973 r'FindBrowserWithActiveWindow'),
1974 explanation=
1975 ('Most code should already be scoped to a Browser. Pass in a Browser* '
1976 'or retreive from an existing entity with a reference to the Browser.',
1977 ),
1978 treat_as_error=False,
Helmut Januschkab3f71ab52024-03-12 02:48:051979 ),
1980 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531981 pattern='BrowserUserData',
1982 explanation=
1983 ('Do not use BrowserUserData to store state on a Browser instance. '
1984 'Instead use BrowserWindowFeatures. BrowserWindowFeatures is '
1985 'functionally identical but has two benefits: it does not force a '
1986 'dependency onto class Browser, and lifetime semantics are explicit '
1987 'rather than implicit. See BrowserUserData header file for more '
1988 'details.', ),
1989 treat_as_error=False,
Mike Doughertyab1bdec2024-08-06 16:39:011990 excluded_paths=(
1991 # Exclude iOS as the iOS implementation of BrowserUserData is separate
1992 # and still in use.
1993 '^ios/',
1994 ),
Erik Chen87358e82024-06-04 02:13:121995 ),
Tom Sepezea67b6e2024-08-08 18:17:271996 BanRule(
Tom Sepezd3272cd2025-02-21 19:11:311997 pattern=r'subspan(0u,',
1998 explanation=
1999 ('Prefer first(n) over subspan(0u, n) as it is shorter, and the '
2000 'compiler may have to emit a branch for the n == dynamic_extent '
2001 'case of subspan().',
2002 ),
2003 treat_as_error=False,
2004 ),
2005 BanRule(
Tom Sepezea67b6e2024-08-08 18:17:272006 pattern=r'UNSAFE_TODO(',
2007 explanation=
2008 ('Do not use UNSAFE_TODO() to write new unsafe code. Use only when '
Tom Sepeza90f92b2024-08-15 16:01:352009 'removing a pre-existing file-wide allow_unsafe_buffers pragma, or '
2010 'when incrementally converting code off of unsafe interfaces',
Tom Sepezea67b6e2024-08-08 18:17:272011 ),
2012 treat_as_error=False,
2013 ),
2014 BanRule(
2015 pattern=r'UNSAFE_BUFFERS(',
2016 explanation=
Tom Sepeza90f92b2024-08-15 16:01:352017 ('Try to avoid using UNSAFE_BUFFERS() if at all possible. Otherwise, '
2018 'be sure to justify in a // SAFETY comment why other options are not '
2019 'available, and why the code is safe.',
Tom Sepezea67b6e2024-08-08 18:17:272020 ),
2021 treat_as_error=False,
2022 ),
Erik Chend086ae02024-08-20 22:53:332023 BanRule(
2024 pattern='BrowserWithTestWindowTest',
2025 explanation=
2026 ('Do not use BrowserWithTestWindowTest. By instantiating an instance '
2027 'of class Browser, the test is no longer a unit test but is instead a '
2028 'browser test. The class BrowserWithTestWindowTest forces production '
2029 'logic to take on test-only conditionals, which is an anti-pattern. '
2030 'Features should be performing dependency injection rather than '
2031 'directly using class Browser. See '
mikt19226ff22024-08-27 05:28:212032 'docs/chrome_browser_design_principles.md for more details.',
Erik Chend086ae02024-08-20 22:53:332033 ),
2034 treat_as_error=False,
2035 ),
Erik Chen8cf3a652024-08-23 17:13:302036 BanRule(
Erik Chen959cdd72024-08-29 02:11:212037 pattern='TestWithBrowserView',
2038 explanation=
2039 ('Do not use TestWithBrowserView. See '
2040 'docs/chrome_browser_design_principles.md for details. If you want '
2041 'to write a test that has both a Browser and a BrowserView, create '
2042 'a browser_test. If you want to write a unit_test, your code must '
Erik Chendba23692024-09-26 06:43:362043 'not reference Browser*.',
Erik Chen959cdd72024-08-29 02:11:212044 ),
2045 treat_as_error=False,
2046 ),
2047 BanRule(
Erik Chene89ebe32025-02-22 02:46:492048 pattern='CreateBrowserWithTestWindow',
2049 explanation=
2050 ('Do not use CreateBrowserWithTestWindow. See '
2051 'docs/chrome_browser_design_principles.md for details. If you want '
2052 'to write a test that has a Browser, create a browser_test. If you '
2053 'want to write a unit_test, your code must not reference Browser*.',
2054 ),
2055 treat_as_error=False,
2056 ),
2057 BanRule(
Erik Chen8cf3a652024-08-23 17:13:302058 pattern='RunUntilIdle',
2059 explanation=
2060 ('Do not RunUntilIdle. If possible, explicitly quit the run loop using '
2061 'run_loop.Quit() or run_loop.QuitClosure() if completion can be '
2062 'observed using a lambda or callback. Otherwise, wait for the '
mikt19226ff22024-08-27 05:28:212063 'condition to be true via base::test::RunUntil().',
Erik Chen8cf3a652024-08-23 17:13:302064 ),
2065 treat_as_error=False,
2066 ),
Daniel Chengddde13a2024-09-05 21:39:282067 BanRule(
2068 pattern=r'/\bstd::(literals|string_literals|string_view_literals)\b',
2069 explanation = (
2070 'User-defined literals are banned by the Google C++ style guide. '
2071 'Exceptions are provided in Chrome for string and string_view '
2072 'literals that embed \\0.',
2073 ),
2074 treat_as_error=True,
2075 excluded_paths=(
2076 # Various tests or test helpers that embed NUL in strings or
2077 # string_views.
Daniel Chengddde13a2024-09-05 21:39:282078 r'^base/strings/string_util_unittest\.cc',
2079 r'^base/strings/utf_string_conversions_unittest\.cc',
2080 r'^chrome/browser/ash/crosapi/browser_data_back_migrator_unittest\.cc',
2081 r'^chrome/browser/ash/crosapi/browser_data_migrator_util_unittest\.cc',
2082 r'^chrome/browser/ash/crosapi/move_migrator_unittest\.cc',
Hidehiko Abe51601812025-01-12 16:17:352083 r'^chromeos/ash/experiences/arc/session/serial_number_util_unittest\.cc',
Daniel Chengddde13a2024-09-05 21:39:282084 r'^components/history/core/browser/visit_annotations_database\.cc',
2085 r'^components/history/core/browser/visit_annotations_database_unittest\.cc',
2086 r'^components/os_crypt/sync/os_crypt_unittest\.cc',
2087 r'^components/password_manager/core/browser/credentials_cleaner_unittest\.cc',
2088 r'^content/browser/file_system_access/file_system_access_file_writer_impl_unittest\.cc',
2089 r'^net/cookies/parsed_cookie_unittest\.cc',
2090 r'^third_party/blink/renderer/modules/webcodecs/test_helpers\.cc',
2091 r'^third_party/blink/renderer/modules/websockets/websocket_channel_impl_test\.cc',
2092 ),
Erik Chenba8b0cd32024-10-01 08:36:362093 ),
2094 BanRule(
2095 pattern='BUILDFLAG(GOOGLE_CHROME_BRANDING)',
2096 explanation=
2097 ('Code gated by GOOGLE_CHROME_BRANDING is effectively untested. This '
2098 'is typically wrong. Valid use cases are glue for private modules '
2099 'shipped alongside Chrome, and installation-related logic.',
2100 ),
2101 treat_as_error=False,
2102 ),
2103 BanRule(
2104 pattern='defined(OFFICIAL_BUILD)',
2105 explanation=
2106 ('Code gated by OFFICIAL_BUILD is effectively untested. This '
2107 'is typically wrong. One valid use case is low-level code that '
2108 'handles subtleties related to high-levels of optimizations that come '
2109 'with OFFICIAL_BUILD.',
2110 ),
2111 treat_as_error=False,
2112 ),
Erik Chen95b9c782024-11-08 03:26:272113 BanRule(
2114 pattern='WebContentsDestroyed',
2115 explanation=
2116 ('Do not use this method. It is invoked half-way through the '
2117 'destructor of WebContentsImpl and using it often results in crashes '
2118 'or surprising behavior. Conceptually, this is only necessary by '
2119 'objects that depend on, but outlive the WebContents. These objects '
2120 'should instead coordinate with the owner of the WebContents which is '
2121 'responsible for destroying the WebContents.',
2122 ),
2123 treat_as_error=False,
2124 ),
Maksim Sisovc98fdfa2024-11-16 20:12:272125 BanRule(
2126 pattern=(r'/IS_CHROMEOS_ASH|'
2127 r'IS_CHROMEOS_LACROS'),
2128 explanation=
2129 ('Lacros is deprecated. Please do not use IS_CHROMEOS_ASH and '
Maksim Sisov34bfc572025-01-14 07:03:122130 'IS_CHROMEOS_LACROS anymore. Instead, remove the code section under '
2131 'IS_CHROMEOS_LACROS and use IS_CHROMEOS for ChromeOS-only code.',
Maksim Sisovc98fdfa2024-11-16 20:12:272132 ),
2133 treat_as_error=False,
2134 ),
Erik Chen1396bbe2025-01-27 23:39:362135 BanRule(
2136 pattern=(r'namespace {'),
2137 explanation=
2138 ('Anonymous namespaces are disallowed in C++ header files. See '
2139 'https://google.github.io/styleguide/cppguide.html#Internal_Linkage '
2140 ' for details.',
2141 ),
2142 treat_as_error=False,
2143 excluded_paths=[
2144 _THIRD_PARTY_EXCEPT_BLINK, # Don't warn in third_party folders.
2145 r'^(?!.*\.h$).*$', # Exclude all files except those that end in .h
2146 ],
2147 ),
[email protected]127f18ec2012-06-16 05:05:592148)
2149
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152150_DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING = (
2151 'Used a predicate related to signin::ConsentLevel::kSync which will always '
2152 'return false in the future (crbug.com/40066949). Prefer using a predicate '
2153 'that also supports signin::ConsentLevel::kSignin when appropriate. It is '
2154 'safe to ignore this warning if you are just moving an existing call, or if '
2155 'you want special handling for users in the legacy state. In doubt, reach '
Victor Hugo Vianna Silvae2292972024-06-04 17:11:552156 'out to //components/sync/OWNERS.',
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152157)
2158
2159# C++ functions related to signin::ConsentLevel::kSync which are deprecated.
2160_DEPRECATED_SYNC_CONSENT_CPP_FUNCTIONS : Sequence[BanRule] = (
2161 BanRule(
2162 'HasSyncConsent',
2163 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2164 False,
2165 ),
2166 BanRule(
2167 'CanSyncFeatureStart',
2168 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2169 False,
2170 ),
2171 BanRule(
2172 'IsSyncFeatureEnabled',
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152173 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152174 False,
2175 ),
2176 BanRule(
2177 'IsSyncFeatureActive',
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152178 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152179 False,
2180 ),
2181)
2182
2183# Java functions related to signin::ConsentLevel::kSync which are deprecated.
2184_DEPRECATED_SYNC_CONSENT_JAVA_FUNCTIONS : Sequence[BanRule] = (
2185 BanRule(
2186 'hasSyncConsent',
2187 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2188 False,
2189 ),
2190 BanRule(
2191 'canSyncFeatureStart',
2192 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2193 False,
2194 ),
2195 BanRule(
2196 'isSyncFeatureEnabled',
2197 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2198 False,
2199 ),
2200 BanRule(
2201 'isSyncFeatureActive',
2202 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2203 False,
2204 ),
2205)
2206
Daniel Cheng92c15e32022-03-16 17:48:222207_BANNED_MOJOM_PATTERNS : Sequence[BanRule] = (
2208 BanRule(
2209 'handle<shared_buffer>',
2210 (
2211 'Please use one of the more specific shared memory types instead:',
2212 ' mojo_base.mojom.ReadOnlySharedMemoryRegion',
2213 ' mojo_base.mojom.WritableSharedMemoryRegion',
2214 ' mojo_base.mojom.UnsafeSharedMemoryRegion',
2215 ),
2216 True,
2217 ),
2218)
2219
mlamouria82272622014-09-16 18:45:042220_IPC_ENUM_TRAITS_DEPRECATED = (
2221 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:502222 'See http://www.chromium.org/Home/chromium-security/education/'
2223 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:042224
Stephen Martinis97a394142018-06-07 23:06:052225_LONG_PATH_ERROR = (
2226 'Some files included in this CL have file names that are too long (> 200'
2227 ' characters). If committed, these files will cause issues on Windows. See'
2228 ' https://crbug.com/612667 for more details.'
2229)
2230
Shenghua Zhangbfaa38b82017-11-16 21:58:022231_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Bruce Dawson40fece62022-09-16 19:58:312232 r".*/BuildHooksAndroidImpl\.java",
2233 r".*/LicenseContentProvider\.java",
2234 r".*/PlatformServiceBridgeImpl.java",
2235 r".*chrome/android/feed/dummy/.*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:022236]
[email protected]127f18ec2012-06-16 05:05:592237
Mohamed Heikald048240a2019-11-12 16:57:372238# List of image extensions that are used as resources in chromium.
2239_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
2240
Sean Kau46e29bc2017-08-28 16:31:162241# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:402242_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Bruce Dawson40fece62022-09-16 19:58:312243 r'test/data/',
2244 r'testing/buildbot/',
2245 r'^components/policy/resources/policy_templates\.json$',
2246 r'^third_party/protobuf/',
Camillo Bruni1411a352023-05-24 12:39:032247 r'^third_party/blink/perf_tests/speedometer.*/resources/todomvc/learn\.json',
Bruce Dawson40fece62022-09-16 19:58:312248 r'^third_party/blink/renderer/devtools/protocol\.json$',
2249 r'^third_party/blink/web_tests/external/wpt/',
2250 r'^tools/perf/',
2251 r'^tools/traceline/svgui/startup-release.json',
Daniel Cheng2d4c2d192022-07-01 01:38:312252 # vscode configuration files allow comments
Bruce Dawson40fece62022-09-16 19:58:312253 r'^tools/vscode/',
Sean Kau46e29bc2017-08-28 16:31:162254]
2255
Andrew Grieveb773bad2020-06-05 18:00:382256# These are not checked on the public chromium-presubmit trybot.
2257# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:042258# checkouts.
agrievef32bcc72016-04-04 14:57:402259_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:382260 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382261]
2262
2263
2264_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:042265 'android_webview/tools/run_cts.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:362266 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042267 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362268 'build/android/gyp/aar.pydeps',
2269 'build/android/gyp/aidl.pydeps',
2270 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:382271 'build/android/gyp/assert_static_initializers.pydeps',
Mohamed Heikal133e1f22023-04-18 20:04:372272 'build/android/gyp/binary_baseline_profile.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:022273 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:222274 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieveacac4242024-12-20 19:39:422275 'build/android/gyp/check_for_missing_direct_deps.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:112276 'build/android/gyp/compile_java.pydeps',
Peter Weneaa963f2023-01-20 19:40:302277 'build/android/gyp/compile_kt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362278 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362279 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362280 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:112281 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042282 'build/android/gyp/create_app_bundle_apks.pydeps',
2283 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362284 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:122285 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:092286 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:222287 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve2d972e5f2025-01-28 18:28:142288 'build/android/gyp/create_stub_manifest.pydeps',
Peter Wene6e017e2022-07-27 21:40:402289 'build/android/gyp/create_test_apk_wrapper_script.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002290 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362291 'build/android/gyp/dex.pydeps',
2292 'build/android/gyp/dist_aar.pydeps',
Andrew Grieve651ddb32025-01-23 03:27:342293 'build/android/gyp/errorprone.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362294 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:212295 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362296 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:362297 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362298 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:582299 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362300 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:142301 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:262302 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:472303 'build/android/gyp/java_google_api_keys.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042304 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362305 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362306 'build/android/gyp/merge_manifest.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:102307 'build/android/gyp/optimize_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362308 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:222309 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362310 'build/android/gyp/proguard.pydeps',
Mohamed Heikaldd52b452024-09-10 17:10:502311 'build/android/gyp/rename_java_classes.pydeps',
Andrew Grievee3a775ab2022-05-16 15:59:222312 'build/android/gyp/system_image_apks.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:102313 'build/android/gyp/trace_event_bytecode_rewriter.pydeps',
Andrew Grieve170b9782025-02-03 15:54:532314 'build/android/gyp/tracereferences.pydeps',
Peter Wen578730b2020-03-19 19:55:462315 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:302316 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:242317 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362318 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:462319 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:562320 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362321 'build/android/incremental_install/generate_android_manifest.pydeps',
2322 'build/android/incremental_install/write_installer_json.pydeps',
Stephanie Kim392913b452022-06-15 17:25:322323 'build/android/pylib/results/presentation/test_results_presentation.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042324 'build/android/resource_sizes.pydeps',
2325 'build/android/test_runner.pydeps',
2326 'build/android/test_wrapper/logdog_wrapper.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362327 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:322328 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:272329 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
2330 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:042331 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Mohannad Farrag19102742023-12-01 01:16:302332 'components/cronet/tools/check_combined_proguard_file.pydeps',
2333 'components/cronet/tools/generate_proguard_file.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002334 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382335 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002336 'content/public/android/generate_child_service.pydeps',
Hzj_jie77bdb802024-07-22 18:14:512337 'fuchsia_web/av_testing/av_sync_tests.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382338 'net/tools/testserver/testserver.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:182339 'testing/scripts/run_isolated_script_test.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:412340 'testing/merge_scripts/standard_isolated_script_merge.pydeps',
2341 'testing/merge_scripts/standard_gtest_merge.pydeps',
2342 'testing/merge_scripts/code_coverage/merge_results.pydeps',
2343 'testing/merge_scripts/code_coverage/merge_steps.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042344 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:422345 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
Yuki Shiino38eeaad12022-08-11 06:40:252346 'third_party/blink/renderer/bindings/scripts/check_generated_file_list.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:422347 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:132348 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Yuki Shiinoea477d32023-08-21 06:24:342349 'third_party/blink/renderer/bindings/scripts/generate_event_interface_names.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:502350 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:412351 'third_party/blink/tools/blinkpy/web_tests/merge_results.pydeps',
2352 'third_party/blink/tools/merge_web_test_results.pydeps',
John Budorickbc3571aa2019-04-25 02:20:062353 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:222354 'tools/binary_size/supersize.pydeps',
Ben Pastene028104a2022-08-10 19:17:452355 'tools/perf/process_perf_results.pydeps',
Peter Wence103e12024-10-09 19:23:512356 'tools/pgo/generate_profile.pydeps',
agrievef32bcc72016-04-04 14:57:402357]
2358
wnwenbdc444e2016-05-25 13:44:152359
agrievef32bcc72016-04-04 14:57:402360_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
2361
2362
Eric Boren6fd2b932018-01-25 15:05:082363# Bypass the AUTHORS check for these accounts.
2364_KNOWN_ROBOTS = set(
Shuai Xia0d99ebf2025-02-11 23:47:592365 ) | set('%[email protected]' % s for s in ('findit-for-me',
2366 'luci-bisection',
2367 'predator-for-me-staging',
2368 'predator-for-me')
Achuith Bhandarkar35905562018-07-25 19:28:452369 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:592370 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:522371 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:232372 'wpt-autoroller', 'chrome-weblayer-builder',
Georg Neise5817eb2025-02-06 03:47:312373 'skylab-test-cros-roller', 'infra-try-recipes-tester',
2374 'chrome-automated-expectation',
Stephanie Kimb49bdd242023-04-28 16:46:042375 'chromium-automated-expectation', 'chrome-branch-day',
2376 'chromium-autosharder')
Eric Boren835d71f2018-09-07 21:09:042377 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:272378 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:042379 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:162380 for s in ('chromium-internal-autoroll',)
Kyungjun Lee3b7c9352024-04-02 23:59:142381 ) | set('%[email protected]' % s
2382 for s in ('chrome-screen-ai-releaser',)
Yulan Lineb0cfba2021-04-09 18:43:162383 ) | set('%[email protected]' % s
Chong Gub277e342022-10-15 03:30:552384 for s in ('swarming-tasks',)
2385 ) | set('%[email protected]' % s
2386 for s in ('global-integration-try-builder',
Joey Scarr1103c5d2023-09-14 01:17:552387 'global-integration-ci-builder')
Suma Kasa3b9cf7a2023-09-21 22:05:542388 ) | set('%[email protected]' % s
2389 for s in ('chops-security-borg',
2390 'chops-security-cronjobs-cpesuggest'))
Eric Boren6fd2b932018-01-25 15:05:082391
Matt Stark6ef08872021-07-29 01:21:462392_INVALID_GRD_FILE_LINE = [
2393 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
2394]
Eric Boren6fd2b932018-01-25 15:05:082395
Daniel Bratell65b033262019-04-23 08:17:062396def _IsCPlusPlusFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502397 """Returns True if this file contains C++-like code (and not Python,
2398 Go, Java, MarkDown, ...)"""
Daniel Bratell65b033262019-04-23 08:17:062399
Sam Maiera6e76d72022-02-11 21:43:502400 ext = input_api.os_path.splitext(file_path)[1]
2401 # This list is compatible with CppChecker.IsCppFile but we should
2402 # consider adding ".c" to it. If we do that we can use this function
2403 # at more places in the code.
2404 return ext in (
2405 '.h',
2406 '.cc',
2407 '.cpp',
2408 '.m',
2409 '.mm',
2410 )
2411
Daniel Bratell65b033262019-04-23 08:17:062412
2413def _IsCPlusPlusHeaderFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502414 return input_api.os_path.splitext(file_path)[1] == ".h"
Daniel Bratell65b033262019-04-23 08:17:062415
2416
2417def _IsJavaFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502418 return input_api.os_path.splitext(file_path)[1] == ".java"
Daniel Bratell65b033262019-04-23 08:17:062419
2420
2421def _IsProtoFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502422 return input_api.os_path.splitext(file_path)[1] == ".proto"
Daniel Bratell65b033262019-04-23 08:17:062423
Mohamed Heikal5e5b7922020-10-29 18:57:592424
Erik Staabc734cd7a2021-11-23 03:11:522425def _IsXmlOrGrdFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502426 ext = input_api.os_path.splitext(file_path)[1]
2427 return ext in ('.grd', '.xml')
Erik Staabc734cd7a2021-11-23 03:11:522428
2429
Sven Zheng76a79ea2022-12-21 21:25:242430def _IsMojomFile(input_api, file_path):
2431 return input_api.os_path.splitext(file_path)[1] == ".mojom"
2432
2433
Mohamed Heikal5e5b7922020-10-29 18:57:592434def CheckNoUpstreamDepsOnClank(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502435 """Prevent additions of dependencies from the upstream repo on //clank."""
2436 # clank can depend on clank
2437 if input_api.change.RepositoryRoot().endswith('clank'):
2438 return []
2439 build_file_patterns = [
2440 r'(.+/)?BUILD\.gn',
2441 r'.+\.gni',
2442 ]
2443 excluded_files = [r'build[/\\]config[/\\]android[/\\]config\.gni']
2444 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
Mohamed Heikal5e5b7922020-10-29 18:57:592445
Sam Maiera6e76d72022-02-11 21:43:502446 error_message = 'Disallowed import on //clank in an upstream build file:'
Mohamed Heikal5e5b7922020-10-29 18:57:592447
Sam Maiera6e76d72022-02-11 21:43:502448 def FilterFile(affected_file):
2449 return input_api.FilterSourceFile(affected_file,
2450 files_to_check=build_file_patterns,
2451 files_to_skip=excluded_files)
Mohamed Heikal5e5b7922020-10-29 18:57:592452
Sam Maiera6e76d72022-02-11 21:43:502453 problems = []
2454 for f in input_api.AffectedSourceFiles(FilterFile):
2455 local_path = f.LocalPath()
2456 for line_number, line in f.ChangedContents():
2457 if (bad_pattern.search(line)):
2458 problems.append('%s:%d\n %s' %
2459 (local_path, line_number, line.strip()))
2460 if problems:
2461 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
2462 else:
2463 return []
Mohamed Heikal5e5b7922020-10-29 18:57:592464
2465
Saagar Sanghavifceeaae2020-08-12 16:40:362466def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502467 """Attempts to prevent use of functions intended only for testing in
2468 non-testing code. For now this is just a best-effort implementation
2469 that ignores header files and may have some false positives. A
2470 better implementation would probably need a proper C++ parser.
2471 """
2472 # We only scan .cc files and the like, as the declaration of
2473 # for-testing functions in header files are hard to distinguish from
2474 # calls to such functions without a proper C++ parser.
2475 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:192476
Sam Maiera6e76d72022-02-11 21:43:502477 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
2478 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' %
2479 base_function_pattern)
2480 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
2481 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
2482 exclusion_pattern = input_api.re.compile(
2483 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' %
2484 (base_function_pattern, base_function_pattern))
2485 # Avoid a false positive in this case, where the method name, the ::, and
2486 # the closing { are all on different lines due to line wrapping.
2487 # HelperClassForTesting::
2488 # HelperClassForTesting(
2489 # args)
2490 # : member(0) {}
2491 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:192492
Sam Maiera6e76d72022-02-11 21:43:502493 def FilterFile(affected_file):
2494 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2495 input_api.DEFAULT_FILES_TO_SKIP)
2496 return input_api.FilterSourceFile(
2497 affected_file,
2498 files_to_check=file_inclusion_pattern,
2499 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:192500
Sam Maiera6e76d72022-02-11 21:43:502501 problems = []
2502 for f in input_api.AffectedSourceFiles(FilterFile):
2503 local_path = f.LocalPath()
2504 in_method_defn = False
2505 for line_number, line in f.ChangedContents():
2506 if (inclusion_pattern.search(line)
2507 and not comment_pattern.search(line)
2508 and not exclusion_pattern.search(line)
2509 and not allowlist_pattern.search(line)
2510 and not in_method_defn):
2511 problems.append('%s:%d\n %s' %
2512 (local_path, line_number, line.strip()))
2513 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:192514
Sam Maiera6e76d72022-02-11 21:43:502515 if problems:
2516 return [
2517 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
2518 ]
2519 else:
2520 return []
[email protected]55459852011-08-10 15:17:192521
2522
Saagar Sanghavifceeaae2020-08-12 16:40:362523def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502524 """This is a simplified version of
2525 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
2526 """
2527 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
2528 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
2529 name_pattern = r'ForTest(s|ing)?'
2530 # Describes an occurrence of "ForTest*" inside a // comment.
2531 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
2532 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
2533 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
2534 # Catch calls.
2535 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
2536 # Ignore definitions. (Comments are ignored separately.)
2537 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
Andrew Grieve40f451d2023-07-06 19:46:512538 allowlist_re = input_api.re.compile(r'// IN-TEST$')
Vaclav Brozek7dbc28c2018-03-27 08:35:232539
Sam Maiera6e76d72022-02-11 21:43:502540 problems = []
2541 sources = lambda x: input_api.FilterSourceFile(
2542 x,
2543 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
2544 DEFAULT_FILES_TO_SKIP),
2545 files_to_check=[r'.*\.java$'])
2546 for f in input_api.AffectedFiles(include_deletes=False,
2547 file_filter=sources):
2548 local_path = f.LocalPath()
Vaclav Brozek7dbc28c2018-03-27 08:35:232549 is_inside_javadoc = False
Sam Maiera6e76d72022-02-11 21:43:502550 for line_number, line in f.ChangedContents():
2551 if is_inside_javadoc and javadoc_end_re.search(line):
2552 is_inside_javadoc = False
2553 if not is_inside_javadoc and javadoc_start_re.search(line):
2554 is_inside_javadoc = True
2555 if is_inside_javadoc:
2556 continue
2557 if (inclusion_re.search(line) and not comment_re.search(line)
2558 and not annotation_re.search(line)
Andrew Grieve40f451d2023-07-06 19:46:512559 and not allowlist_re.search(line)
Sam Maiera6e76d72022-02-11 21:43:502560 and not exclusion_re.search(line)):
2561 problems.append('%s:%d\n %s' %
2562 (local_path, line_number, line.strip()))
Vaclav Brozek7dbc28c2018-03-27 08:35:232563
Sam Maiera6e76d72022-02-11 21:43:502564 if problems:
2565 return [
2566 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
2567 ]
2568 else:
2569 return []
Vaclav Brozek7dbc28c2018-03-27 08:35:232570
2571
Saagar Sanghavifceeaae2020-08-12 16:40:362572def CheckNoIOStreamInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502573 """Checks to make sure no .h files include <iostream>."""
2574 files = []
2575 pattern = input_api.re.compile(r'^#include\s*<iostream>',
2576 input_api.re.MULTILINE)
2577 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2578 if not f.LocalPath().endswith('.h'):
2579 continue
2580 contents = input_api.ReadFile(f)
2581 if pattern.search(contents):
2582 files.append(f)
[email protected]10689ca2011-09-02 02:31:542583
Sam Maiera6e76d72022-02-11 21:43:502584 if len(files):
2585 return [
2586 output_api.PresubmitError(
2587 'Do not #include <iostream> in header files, since it inserts static '
2588 'initialization into every file including the header. Instead, '
2589 '#include <ostream>. See http://crbug.com/94794', files)
2590 ]
2591 return []
2592
[email protected]10689ca2011-09-02 02:31:542593
Aleksey Khoroshilov9b28c032022-06-03 16:35:322594def CheckNoStrCatRedefines(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502595 """Checks no windows headers with StrCat redefined are included directly."""
2596 files = []
Aleksey Khoroshilov9b28c032022-06-03 16:35:322597 files_to_check = (r'.+%s' % _HEADER_EXTENSIONS,
2598 r'.+%s' % _IMPLEMENTATION_EXTENSIONS)
2599 files_to_skip = (input_api.DEFAULT_FILES_TO_SKIP +
2600 _NON_BASE_DEPENDENT_PATHS)
2601 sources_filter = lambda f: input_api.FilterSourceFile(
2602 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
2603
Sam Maiera6e76d72022-02-11 21:43:502604 pattern_deny = input_api.re.compile(
2605 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
2606 input_api.re.MULTILINE)
2607 pattern_allow = input_api.re.compile(
2608 r'^#include\s"base/win/windows_defines.inc"', input_api.re.MULTILINE)
Aleksey Khoroshilov9b28c032022-06-03 16:35:322609 for f in input_api.AffectedSourceFiles(sources_filter):
Sam Maiera6e76d72022-02-11 21:43:502610 contents = input_api.ReadFile(f)
2611 if pattern_deny.search(
2612 contents) and not pattern_allow.search(contents):
2613 files.append(f.LocalPath())
Danil Chapovalov3518f362018-08-11 16:13:432614
Sam Maiera6e76d72022-02-11 21:43:502615 if len(files):
2616 return [
2617 output_api.PresubmitError(
2618 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
2619 'directly since they pollute code with StrCat macro. Instead, '
2620 'include matching header from base/win. See http://crbug.com/856536',
2621 files)
2622 ]
2623 return []
Danil Chapovalov3518f362018-08-11 16:13:432624
[email protected]10689ca2011-09-02 02:31:542625
Andrew Williamsc9f69b482023-07-10 16:07:362626def _CheckNoUNIT_TESTInSourceFiles(input_api, f):
2627 problems = []
2628
2629 unit_test_macro = input_api.re.compile(
2630 '^\s*#.*(?:ifn?def\s+UNIT_TEST|defined\s*\(?\s*UNIT_TEST\s*\)?)(?:$|\s+)')
2631 for line_num, line in f.ChangedContents():
2632 if unit_test_macro.match(line):
2633 problems.append(' %s:%d' % (f.LocalPath(), line_num))
2634
2635 return problems
2636
2637
Saagar Sanghavifceeaae2020-08-12 16:40:362638def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502639 """Checks to make sure no source files use UNIT_TEST."""
2640 problems = []
2641 for f in input_api.AffectedFiles():
2642 if (not f.LocalPath().endswith(('.cc', '.mm'))):
2643 continue
Andrew Williamsc9f69b482023-07-10 16:07:362644 problems.extend(
2645 _CheckNoUNIT_TESTInSourceFiles(input_api, f))
[email protected]72df4e782012-06-21 16:28:182646
Sam Maiera6e76d72022-02-11 21:43:502647 if not problems:
2648 return []
2649 return [
2650 output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
2651 '\n'.join(problems))
2652 ]
2653
[email protected]72df4e782012-06-21 16:28:182654
Saagar Sanghavifceeaae2020-08-12 16:40:362655def CheckNoDISABLETypoInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502656 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
Dominic Battre033531052018-09-24 15:45:342657
Sam Maiera6e76d72022-02-11 21:43:502658 This test warns if somebody tries to disable a test with the DISABLE_ prefix
2659 instead of DISABLED_. To filter false positives, reports are only generated
2660 if a corresponding MAYBE_ line exists.
2661 """
2662 problems = []
Dominic Battre033531052018-09-24 15:45:342663
Sam Maiera6e76d72022-02-11 21:43:502664 # The following two patterns are looked for in tandem - is a test labeled
2665 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
2666 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
2667 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
Dominic Battre033531052018-09-24 15:45:342668
Sam Maiera6e76d72022-02-11 21:43:502669 # This is for the case that a test is disabled on all platforms.
2670 full_disable_pattern = input_api.re.compile(
2671 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
2672 input_api.re.MULTILINE)
Dominic Battre033531052018-09-24 15:45:342673
Arthur Sonzognic66e9c82024-04-23 07:53:042674 for f in input_api.AffectedFiles(include_deletes=False):
Sam Maiera6e76d72022-02-11 21:43:502675 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2676 continue
Dominic Battre033531052018-09-24 15:45:342677
Arthur Sonzognic66e9c82024-04-23 07:53:042678 # Search for MAYBE_, DISABLE_ pairs.
Sam Maiera6e76d72022-02-11 21:43:502679 disable_lines = {} # Maps of test name to line number.
2680 maybe_lines = {}
2681 for line_num, line in f.ChangedContents():
2682 disable_match = disable_pattern.search(line)
2683 if disable_match:
2684 disable_lines[disable_match.group(1)] = line_num
2685 maybe_match = maybe_pattern.search(line)
2686 if maybe_match:
2687 maybe_lines[maybe_match.group(1)] = line_num
Dominic Battre033531052018-09-24 15:45:342688
Sam Maiera6e76d72022-02-11 21:43:502689 # Search for DISABLE_ occurrences within a TEST() macro.
2690 disable_tests = set(disable_lines.keys())
2691 maybe_tests = set(maybe_lines.keys())
2692 for test in disable_tests.intersection(maybe_tests):
2693 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
Dominic Battre033531052018-09-24 15:45:342694
Sam Maiera6e76d72022-02-11 21:43:502695 contents = input_api.ReadFile(f)
2696 full_disable_match = full_disable_pattern.search(contents)
2697 if full_disable_match:
2698 problems.append(' %s' % f.LocalPath())
Dominic Battre033531052018-09-24 15:45:342699
Sam Maiera6e76d72022-02-11 21:43:502700 if not problems:
2701 return []
2702 return [
2703 output_api.PresubmitPromptWarning(
2704 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
2705 '\n'.join(problems))
2706 ]
2707
Dominic Battre033531052018-09-24 15:45:342708
Nina Satragnof7660532021-09-20 18:03:352709def CheckForgettingMAYBEInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502710 """Checks to make sure tests disabled conditionally are not missing a
2711 corresponding MAYBE_ prefix.
2712 """
2713 # Expect at least a lowercase character in the test name. This helps rule out
2714 # false positives with macros wrapping the actual tests name.
2715 define_maybe_pattern = input_api.re.compile(
2716 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
Bruce Dawsonffc55292022-04-20 04:18:192717 # The test_maybe_pattern needs to handle all of these forms. The standard:
2718 # IN_PROC_TEST_F(SyncTest, MAYBE_Start) {
2719 # With a wrapper macro around the test name:
2720 # IN_PROC_TEST_F(SyncTest, E2E_ENABLED(MAYBE_Start)) {
2721 # And the odd-ball NACL_BROWSER_TEST_f format:
2722 # NACL_BROWSER_TEST_F(NaClBrowserTest, SimpleLoad, {
2723 # The optional E2E_ENABLED-style is handled with (\w*\()?
2724 # The NACL_BROWSER_TEST_F pattern is handled by allowing a trailing comma or
2725 # trailing ')'.
2726 test_maybe_pattern = (
2727 r'^\s*\w*TEST[^(]*\(\s*\w+,\s*(\w*\()?MAYBE_{test_name}[\),]')
Sam Maiera6e76d72022-02-11 21:43:502728 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
2729 warnings = []
Nina Satragnof7660532021-09-20 18:03:352730
Sam Maiera6e76d72022-02-11 21:43:502731 # Read the entire files. We can't just read the affected lines, forgetting to
2732 # add MAYBE_ on a change would not show up otherwise.
Arthur Sonzognic66e9c82024-04-23 07:53:042733 for f in input_api.AffectedFiles(include_deletes=False):
Sam Maiera6e76d72022-02-11 21:43:502734 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2735 continue
2736 contents = input_api.ReadFile(f)
2737 lines = contents.splitlines(True)
2738 current_position = 0
2739 warning_test_names = set()
2740 for line_num, line in enumerate(lines, start=1):
2741 current_position += len(line)
2742 maybe_match = define_maybe_pattern.search(line)
2743 if maybe_match:
2744 test_name = maybe_match.group('test_name')
2745 # Do not warn twice for the same test.
2746 if (test_name in warning_test_names):
2747 continue
2748 warning_test_names.add(test_name)
Nina Satragnof7660532021-09-20 18:03:352749
Sam Maiera6e76d72022-02-11 21:43:502750 # Attempt to find the corresponding MAYBE_ test or suite, starting from
2751 # the current position.
2752 test_match = input_api.re.compile(
2753 test_maybe_pattern.format(test_name=test_name),
2754 input_api.re.MULTILINE).search(contents, current_position)
2755 suite_match = input_api.re.compile(
2756 suite_maybe_pattern.format(test_name=test_name),
2757 input_api.re.MULTILINE).search(contents, current_position)
2758 if not test_match and not suite_match:
2759 warnings.append(
2760 output_api.PresubmitPromptWarning(
2761 '%s:%d found MAYBE_ defined without corresponding test %s'
2762 % (f.LocalPath(), line_num, test_name)))
2763 return warnings
2764
[email protected]72df4e782012-06-21 16:28:182765
Saagar Sanghavifceeaae2020-08-12 16:40:362766def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502767 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
2768 errors = []
Kalvin Lee4a3b79de2022-05-26 16:00:162769 pattern = input_api.re.compile(r'\bDCHECK_IS_ON\b(?!\(\))',
Sam Maiera6e76d72022-02-11 21:43:502770 input_api.re.MULTILINE)
2771 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2772 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
2773 continue
2774 for lnum, line in f.ChangedContents():
2775 if input_api.re.search(pattern, line):
2776 errors.append(
2777 output_api.PresubmitError((
2778 '%s:%d: Use of DCHECK_IS_ON() must be written as "#if '
2779 + 'DCHECK_IS_ON()", not forgetting the parentheses.') %
2780 (f.LocalPath(), lnum)))
2781 return errors
danakj61c1aa22015-10-26 19:55:522782
2783
Weilun Shia487fad2020-10-28 00:10:342784# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
2785# more reliable way. See
2786# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:192787
wnwenbdc444e2016-05-25 13:44:152788
Saagar Sanghavifceeaae2020-08-12 16:40:362789def CheckFlakyTestUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502790 """Check that FlakyTest annotation is our own instead of the android one"""
2791 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
2792 files = []
2793 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2794 if f.LocalPath().endswith('Test.java'):
2795 if pattern.search(input_api.ReadFile(f)):
2796 files.append(f)
2797 if len(files):
2798 return [
2799 output_api.PresubmitError(
2800 'Use org.chromium.base.test.util.FlakyTest instead of '
2801 'android.test.FlakyTest', files)
2802 ]
2803 return []
mcasasb7440c282015-02-04 14:52:192804
wnwenbdc444e2016-05-25 13:44:152805
Saagar Sanghavifceeaae2020-08-12 16:40:362806def CheckNoDEPSGIT(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502807 """Make sure .DEPS.git is never modified manually."""
2808 if any(f.LocalPath().endswith('.DEPS.git')
2809 for f in input_api.AffectedFiles()):
2810 return [
2811 output_api.PresubmitError(
2812 'Never commit changes to .DEPS.git. This file is maintained by an\n'
2813 'automated system based on what\'s in DEPS and your changes will be\n'
2814 'overwritten.\n'
2815 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
2816 'get-the-code#Rolling_DEPS\n'
2817 'for more information')
2818 ]
2819 return []
[email protected]2a8ac9c2011-10-19 17:20:442820
2821
Sven Zheng76a79ea2022-12-21 21:25:242822def CheckCrosApiNeedBrowserTest(input_api, output_api):
2823 """Check new crosapi should add browser test."""
2824 has_new_crosapi = False
2825 has_browser_test = False
2826 for f in input_api.AffectedFiles():
Anton Bershanskyi4253349482025-02-11 21:01:272827 path = f.UnixLocalPath()
Sven Zheng76a79ea2022-12-21 21:25:242828 if (path.startswith('chromeos/crosapi/mojom') and
2829 _IsMojomFile(input_api, path) and f.Action() == 'A'):
2830 has_new_crosapi = True
2831 if path.endswith('browsertest.cc') or path.endswith('browser_test.cc'):
2832 has_browser_test = True
2833 if has_new_crosapi and not has_browser_test:
2834 return [
2835 output_api.PresubmitPromptWarning(
2836 'You are adding a new crosapi, but there is no file ends with '
2837 'browsertest.cc file being added or modified. It is important '
2838 'to add crosapi browser test coverage to avoid version '
2839 ' skew issues.\n'
2840 'Check //docs/lacros/test_instructions.md for more information.'
2841 )
2842 ]
2843 return []
2844
2845
Saagar Sanghavifceeaae2020-08-12 16:40:362846def CheckValidHostsInDEPSOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502847 """Checks that DEPS file deps are from allowed_hosts."""
2848 # Run only if DEPS file has been modified to annoy fewer bystanders.
2849 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
2850 return []
2851 # Outsource work to gclient verify
2852 try:
2853 gclient_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
2854 'third_party', 'depot_tools',
2855 'gclient.py')
2856 input_api.subprocess.check_output(
Bruce Dawson8a43cf72022-05-13 17:10:322857 [input_api.python3_executable, gclient_path, 'verify'],
Sam Maiera6e76d72022-02-11 21:43:502858 stderr=input_api.subprocess.STDOUT)
2859 return []
2860 except input_api.subprocess.CalledProcessError as error:
2861 return [
2862 output_api.PresubmitError(
2863 'DEPS file must have only git dependencies.',
2864 long_text=error.output)
2865 ]
tandriief664692014-09-23 14:51:472866
2867
Mario Sanchez Prada2472cab2019-09-18 10:58:312868def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152869 ban_rule):
Allen Bauer84778682022-09-22 16:28:562870 """Helper method for checking for banned constructs.
Mario Sanchez Prada2472cab2019-09-18 10:58:312871
Sam Maiera6e76d72022-02-11 21:43:502872 Returns an string composed of the name of the file, the line number where the
2873 match has been found and the additional text passed as |message| in case the
2874 target type name matches the text inside the line passed as parameter.
2875 """
2876 result = []
Peng Huang9c5949a02020-06-11 19:20:542877
Daniel Chenga44a1bcd2022-03-15 20:00:152878 # Ignore comments about banned types.
2879 if input_api.re.search(r"^ *//", line):
Sam Maiera6e76d72022-02-11 21:43:502880 return result
Daniel Chenga44a1bcd2022-03-15 20:00:152881 # A // nocheck comment will bypass this error.
2882 if line.endswith(" nocheck"):
Sam Maiera6e76d72022-02-11 21:43:502883 return result
2884
2885 matched = False
Daniel Chenga44a1bcd2022-03-15 20:00:152886 if ban_rule.pattern[0:1] == '/':
2887 regex = ban_rule.pattern[1:]
Sam Maiera6e76d72022-02-11 21:43:502888 if input_api.re.search(regex, line):
2889 matched = True
Daniel Chenga44a1bcd2022-03-15 20:00:152890 elif ban_rule.pattern in line:
Sam Maiera6e76d72022-02-11 21:43:502891 matched = True
2892
2893 if matched:
2894 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
Daniel Chenga44a1bcd2022-03-15 20:00:152895 for line in ban_rule.explanation:
2896 result.append(' %s' % line)
Sam Maiera6e76d72022-02-11 21:43:502897
danakjd18e8892020-12-17 17:42:012898 return result
Mario Sanchez Prada2472cab2019-09-18 10:58:312899
2900
Saagar Sanghavifceeaae2020-08-12 16:40:362901def CheckNoBannedFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502902 """Make sure that banned functions are not used."""
2903 warnings = []
2904 errors = []
[email protected]127f18ec2012-06-16 05:05:592905
Sam Maiera6e76d72022-02-11 21:43:502906 def IsExcludedFile(affected_file, excluded_paths):
Daniel Chenga44a1bcd2022-03-15 20:00:152907 if not excluded_paths:
2908 return False
2909
Anton Bershanskyi4253349482025-02-11 21:01:272910 local_path = affected_file.UnixLocalPath()
Sam Maiera6e76d72022-02-11 21:43:502911 for item in excluded_paths:
2912 if input_api.re.match(item, local_path):
2913 return True
2914 return False
wnwenbdc444e2016-05-25 13:44:152915
Sam Maiera6e76d72022-02-11 21:43:502916 def IsIosObjcFile(affected_file):
2917 local_path = affected_file.LocalPath()
2918 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m',
2919 '.h'):
2920 return False
2921 basename = input_api.os_path.basename(local_path)
2922 if 'ios' in basename.split('_'):
2923 return True
2924 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
2925 if sep and 'ios' in local_path.split(sep):
2926 return True
2927 return False
Sylvain Defresnea8b73d252018-02-28 15:45:542928
Daniel Chenga44a1bcd2022-03-15 20:00:152929 def CheckForMatch(affected_file, line_num: int, line: str,
2930 ban_rule: BanRule):
2931 if IsExcludedFile(affected_file, ban_rule.excluded_paths):
2932 return
2933
Sam Maiera6e76d72022-02-11 21:43:502934 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152935 ban_rule)
Sam Maiera6e76d72022-02-11 21:43:502936 if problems:
Daniel Chenga44a1bcd2022-03-15 20:00:152937 if ban_rule.treat_as_error is not None and ban_rule.treat_as_error:
Sam Maiera6e76d72022-02-11 21:43:502938 errors.extend(problems)
2939 else:
2940 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:152941
Sam Maiera6e76d72022-02-11 21:43:502942 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2943 for f in input_api.AffectedFiles(file_filter=file_filter):
2944 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152945 for ban_rule in _BANNED_JAVA_FUNCTIONS:
2946 CheckForMatch(f, line_num, line, ban_rule)
Eric Stevensona9a980972017-09-23 00:04:412947
Clement Yan9b330cb2022-11-17 05:25:292948 file_filter = lambda f: f.LocalPath().endswith(('.js', '.ts'))
2949 for f in input_api.AffectedFiles(file_filter=file_filter):
2950 for line_num, line in f.ChangedContents():
2951 for ban_rule in _BANNED_JAVASCRIPT_FUNCTIONS:
2952 CheckForMatch(f, line_num, line, ban_rule)
2953
Sam Maiera6e76d72022-02-11 21:43:502954 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
2955 for f in input_api.AffectedFiles(file_filter=file_filter):
2956 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152957 for ban_rule in _BANNED_OBJC_FUNCTIONS:
2958 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:592959
Sam Maiera6e76d72022-02-11 21:43:502960 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
2961 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152962 for ban_rule in _BANNED_IOS_OBJC_FUNCTIONS:
2963 CheckForMatch(f, line_num, line, ban_rule)
Sylvain Defresnea8b73d252018-02-28 15:45:542964
Sam Maiera6e76d72022-02-11 21:43:502965 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
2966 for f in input_api.AffectedFiles(file_filter=egtest_filter):
2967 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152968 for ban_rule in _BANNED_IOS_EGTEST_FUNCTIONS:
2969 CheckForMatch(f, line_num, line, ban_rule)
Peter K. Lee6c03ccff2019-07-15 14:40:052970
Sam Maiera6e76d72022-02-11 21:43:502971 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
2972 for f in input_api.AffectedFiles(file_filter=file_filter):
2973 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152974 for ban_rule in _BANNED_CPP_FUNCTIONS:
2975 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:592976
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152977 # As of 05/2024, iOS fully migrated ConsentLevel::kSync to kSignin, and
2978 # Android is in the process of preventing new users from entering kSync.
2979 # So the warning is restricted to those platforms.
2980 ios_pattern = input_api.re.compile('(^|[\W_])ios[\W_]')
2981 file_filter = lambda f: (f.LocalPath().endswith(('.cc', '.mm', '.h')) and
2982 ('android' in f.LocalPath() or
2983 # Simply checking for an 'ios' substring would
2984 # catch unrelated cases, use a regex.
2985 ios_pattern.search(f.LocalPath())))
2986 for f in input_api.AffectedFiles(file_filter=file_filter):
2987 for line_num, line in f.ChangedContents():
2988 for ban_rule in _DEPRECATED_SYNC_CONSENT_CPP_FUNCTIONS:
2989 CheckForMatch(f, line_num, line, ban_rule)
2990
2991 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2992 for f in input_api.AffectedFiles(file_filter=file_filter):
2993 for line_num, line in f.ChangedContents():
2994 for ban_rule in _DEPRECATED_SYNC_CONSENT_JAVA_FUNCTIONS:
2995 CheckForMatch(f, line_num, line, ban_rule)
2996
Daniel Cheng92c15e32022-03-16 17:48:222997 file_filter = lambda f: f.LocalPath().endswith(('.mojom'))
2998 for f in input_api.AffectedFiles(file_filter=file_filter):
2999 for line_num, line in f.ChangedContents():
3000 for ban_rule in _BANNED_MOJOM_PATTERNS:
3001 CheckForMatch(f, line_num, line, ban_rule)
3002
3003
Sam Maiera6e76d72022-02-11 21:43:503004 result = []
3005 if (warnings):
3006 result.append(
3007 output_api.PresubmitPromptWarning('Banned functions were used.\n' +
3008 '\n'.join(warnings)))
3009 if (errors):
3010 result.append(
3011 output_api.PresubmitError('Banned functions were used.\n' +
3012 '\n'.join(errors)))
3013 return result
[email protected]127f18ec2012-06-16 05:05:593014
Michael Thiessen44457642020-02-06 00:24:153015def _CheckAndroidNoBannedImports(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503016 """Make sure that banned java imports are not used."""
3017 errors = []
Michael Thiessen44457642020-02-06 00:24:153018
Sam Maiera6e76d72022-02-11 21:43:503019 file_filter = lambda f: f.LocalPath().endswith(('.java'))
3020 for f in input_api.AffectedFiles(file_filter=file_filter):
3021 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:153022 for ban_rule in _BANNED_JAVA_IMPORTS:
3023 # Consider merging this into the above function. There is no
3024 # real difference anymore other than helping with a little
3025 # bit of boilerplate text. Doing so means things like
3026 # `treat_as_error` will also be uniformly handled.
Sam Maiera6e76d72022-02-11 21:43:503027 problems = _GetMessageForMatchingType(input_api, f, line_num,
Daniel Chenga44a1bcd2022-03-15 20:00:153028 line, ban_rule)
Sam Maiera6e76d72022-02-11 21:43:503029 if problems:
3030 errors.extend(problems)
3031 result = []
3032 if (errors):
3033 result.append(
3034 output_api.PresubmitError('Banned imports were used.\n' +
3035 '\n'.join(errors)))
3036 return result
Michael Thiessen44457642020-02-06 00:24:153037
3038
Saagar Sanghavifceeaae2020-08-12 16:40:363039def CheckNoPragmaOnce(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503040 """Make sure that banned functions are not used."""
3041 files = []
3042 pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
3043 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
3044 if not f.LocalPath().endswith('.h'):
3045 continue
Bruce Dawson4c4c2922022-05-02 18:07:333046 if f.LocalPath().endswith('com_imported_mstscax.h'):
3047 continue
Sam Maiera6e76d72022-02-11 21:43:503048 contents = input_api.ReadFile(f)
3049 if pattern.search(contents):
3050 files.append(f)
[email protected]6c063c62012-07-11 19:11:063051
Sam Maiera6e76d72022-02-11 21:43:503052 if files:
3053 return [
3054 output_api.PresubmitError(
3055 'Do not use #pragma once in header files.\n'
3056 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
3057 files)
3058 ]
3059 return []
[email protected]6c063c62012-07-11 19:11:063060
[email protected]127f18ec2012-06-16 05:05:593061
Saagar Sanghavifceeaae2020-08-12 16:40:363062def CheckNoTrinaryTrueFalse(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503063 """Checks to make sure we don't introduce use of foo ? true : false."""
3064 problems = []
3065 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
3066 for f in input_api.AffectedFiles():
3067 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
3068 continue
[email protected]e7479052012-09-19 00:26:123069
Sam Maiera6e76d72022-02-11 21:43:503070 for line_num, line in f.ChangedContents():
3071 if pattern.match(line):
3072 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]e7479052012-09-19 00:26:123073
Sam Maiera6e76d72022-02-11 21:43:503074 if not problems:
3075 return []
3076 return [
3077 output_api.PresubmitPromptWarning(
3078 'Please consider avoiding the "? true : false" pattern if possible.\n'
3079 + '\n'.join(problems))
3080 ]
[email protected]e7479052012-09-19 00:26:123081
3082
Saagar Sanghavifceeaae2020-08-12 16:40:363083def CheckUnwantedDependencies(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503084 """Runs checkdeps on #include and import statements added in this
3085 change. Breaking - rules is an error, breaking ! rules is a
3086 warning.
3087 """
3088 # Return early if no relevant file types were modified.
3089 for f in input_api.AffectedFiles():
3090 path = f.LocalPath()
3091 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path)
3092 or _IsJavaFile(input_api, path)):
3093 break
[email protected]55f9f382012-07-31 11:02:183094 else:
Sam Maiera6e76d72022-02-11 21:43:503095 return []
rhalavati08acd232017-04-03 07:23:283096
Sam Maiera6e76d72022-02-11 21:43:503097 import sys
3098 # We need to wait until we have an input_api object and use this
3099 # roundabout construct to import checkdeps because this file is
3100 # eval-ed and thus doesn't have __file__.
3101 original_sys_path = sys.path
3102 try:
3103 sys.path = sys.path + [
3104 input_api.os_path.join(input_api.PresubmitLocalPath(),
3105 'buildtools', 'checkdeps')
3106 ]
3107 import checkdeps
3108 from rules import Rule
3109 finally:
3110 # Restore sys.path to what it was before.
3111 sys.path = original_sys_path
[email protected]55f9f382012-07-31 11:02:183112
Sam Maiera6e76d72022-02-11 21:43:503113 added_includes = []
3114 added_imports = []
3115 added_java_imports = []
3116 for f in input_api.AffectedFiles():
3117 if _IsCPlusPlusFile(input_api, f.LocalPath()):
3118 changed_lines = [line for _, line in f.ChangedContents()]
3119 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
3120 elif _IsProtoFile(input_api, f.LocalPath()):
3121 changed_lines = [line for _, line in f.ChangedContents()]
3122 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
3123 elif _IsJavaFile(input_api, f.LocalPath()):
3124 changed_lines = [line for _, line in f.ChangedContents()]
3125 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:243126
Sam Maiera6e76d72022-02-11 21:43:503127 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
3128
3129 error_descriptions = []
3130 warning_descriptions = []
3131 error_subjects = set()
3132 warning_subjects = set()
3133
3134 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
3135 added_includes):
3136 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3137 description_with_path = '%s\n %s' % (path, rule_description)
3138 if rule_type == Rule.DISALLOW:
3139 error_descriptions.append(description_with_path)
3140 error_subjects.add("#includes")
3141 else:
3142 warning_descriptions.append(description_with_path)
3143 warning_subjects.add("#includes")
3144
3145 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
3146 added_imports):
3147 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3148 description_with_path = '%s\n %s' % (path, rule_description)
3149 if rule_type == Rule.DISALLOW:
3150 error_descriptions.append(description_with_path)
3151 error_subjects.add("imports")
3152 else:
3153 warning_descriptions.append(description_with_path)
3154 warning_subjects.add("imports")
3155
3156 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
3157 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
3158 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3159 description_with_path = '%s\n %s' % (path, rule_description)
3160 if rule_type == Rule.DISALLOW:
3161 error_descriptions.append(description_with_path)
3162 error_subjects.add("imports")
3163 else:
3164 warning_descriptions.append(description_with_path)
3165 warning_subjects.add("imports")
3166
3167 results = []
3168 if error_descriptions:
3169 results.append(
3170 output_api.PresubmitError(
3171 'You added one or more %s that violate checkdeps rules.' %
3172 " and ".join(error_subjects), error_descriptions))
3173 if warning_descriptions:
3174 results.append(
3175 output_api.PresubmitPromptOrNotify(
3176 'You added one or more %s of files that are temporarily\n'
3177 'allowed but being removed. Can you avoid introducing the\n'
3178 '%s? See relevant DEPS file(s) for details and contacts.' %
3179 (" and ".join(warning_subjects), "/".join(warning_subjects)),
3180 warning_descriptions))
3181 return results
[email protected]55f9f382012-07-31 11:02:183182
3183
Saagar Sanghavifceeaae2020-08-12 16:40:363184def CheckFilePermissions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503185 """Check that all files have their permissions properly set."""
3186 if input_api.platform == 'win32':
3187 return []
3188 checkperms_tool = input_api.os_path.join(input_api.PresubmitLocalPath(),
3189 'tools', 'checkperms',
3190 'checkperms.py')
3191 args = [
Bruce Dawson8a43cf72022-05-13 17:10:323192 input_api.python3_executable, checkperms_tool, '--root',
Sam Maiera6e76d72022-02-11 21:43:503193 input_api.change.RepositoryRoot()
3194 ]
3195 with input_api.CreateTemporaryFile() as file_list:
3196 for f in input_api.AffectedFiles():
3197 # checkperms.py file/directory arguments must be relative to the
3198 # repository.
3199 file_list.write((f.LocalPath() + '\n').encode('utf8'))
3200 file_list.close()
3201 args += ['--file-list', file_list.name]
3202 try:
3203 input_api.subprocess.check_output(args)
3204 return []
3205 except input_api.subprocess.CalledProcessError as error:
3206 return [
3207 output_api.PresubmitError('checkperms.py failed:',
3208 long_text=error.output.decode(
3209 'utf-8', 'ignore'))
3210 ]
[email protected]fbcafe5a2012-08-08 15:31:223211
3212
Saagar Sanghavifceeaae2020-08-12 16:40:363213def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503214 """Makes sure we don't include ui/aura/window_property.h
3215 in header files.
3216 """
3217 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
3218 errors = []
3219 for f in input_api.AffectedFiles():
3220 if not f.LocalPath().endswith('.h'):
3221 continue
3222 for line_num, line in f.ChangedContents():
3223 if pattern.match(line):
3224 errors.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]c8278b32012-10-30 20:35:493225
Sam Maiera6e76d72022-02-11 21:43:503226 results = []
3227 if errors:
3228 results.append(
3229 output_api.PresubmitError(
3230 'Header files should not include ui/aura/window_property.h',
3231 errors))
3232 return results
[email protected]c8278b32012-10-30 20:35:493233
3234
Omer Katzcc77ea92021-04-26 10:23:283235def CheckNoInternalHeapIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503236 """Makes sure we don't include any headers from
3237 third_party/blink/renderer/platform/heap/impl or
3238 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
3239 third_party/blink/renderer/platform/heap
3240 """
3241 impl_pattern = input_api.re.compile(
3242 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
3243 v8_wrapper_pattern = input_api.re.compile(
3244 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"'
3245 )
3246 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:313247 r"^third_party/blink/renderer/platform/heap/.*",
Anton Bershanskyi4253349482025-02-11 21:01:273248 f.UnixLocalPath())
Sam Maiera6e76d72022-02-11 21:43:503249 errors = []
Omer Katzcc77ea92021-04-26 10:23:283250
Sam Maiera6e76d72022-02-11 21:43:503251 for f in input_api.AffectedFiles(file_filter=file_filter):
3252 for line_num, line in f.ChangedContents():
3253 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
3254 errors.append(' %s:%d' % (f.LocalPath(), line_num))
Omer Katzcc77ea92021-04-26 10:23:283255
Sam Maiera6e76d72022-02-11 21:43:503256 results = []
3257 if errors:
3258 results.append(
3259 output_api.PresubmitError(
3260 'Do not include files from third_party/blink/renderer/platform/heap/impl'
3261 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
3262 'relevant counterparts from third_party/blink/renderer/platform/heap',
3263 errors))
3264 return results
Omer Katzcc77ea92021-04-26 10:23:283265
3266
[email protected]70ca77752012-11-20 03:45:033267def _CheckForVersionControlConflictsInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:503268 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
3269 errors = []
3270 for line_num, line in f.ChangedContents():
3271 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
3272 # First-level headers in markdown look a lot like version control
3273 # conflict markers. http://daringfireball.net/projects/markdown/basics
3274 continue
3275 if pattern.match(line):
3276 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
3277 return errors
[email protected]70ca77752012-11-20 03:45:033278
3279
Saagar Sanghavifceeaae2020-08-12 16:40:363280def CheckForVersionControlConflicts(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503281 """Usually this is not intentional and will cause a compile failure."""
3282 errors = []
3283 for f in input_api.AffectedFiles():
3284 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
[email protected]70ca77752012-11-20 03:45:033285
Sam Maiera6e76d72022-02-11 21:43:503286 results = []
3287 if errors:
3288 results.append(
3289 output_api.PresubmitError(
3290 'Version control conflict markers found, please resolve.',
3291 errors))
3292 return results
[email protected]70ca77752012-11-20 03:45:033293
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203294
Saagar Sanghavifceeaae2020-08-12 16:40:363295def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503296 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
3297 errors = []
3298 for f in input_api.AffectedFiles():
3299 for line_num, line in f.ChangedContents():
3300 if pattern.search(line):
3301 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
estadee17314a02017-01-12 16:22:163302
Sam Maiera6e76d72022-02-11 21:43:503303 results = []
3304 if errors:
3305 results.append(
3306 output_api.PresubmitPromptWarning(
3307 'Found Google support URL addressed by answer number. Please replace '
3308 'with a p= identifier instead. See crbug.com/679462\n',
3309 errors))
3310 return results
estadee17314a02017-01-12 16:22:163311
[email protected]70ca77752012-11-20 03:45:033312
Saagar Sanghavifceeaae2020-08-12 16:40:363313def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503314 def FilterFile(affected_file):
3315 """Filter function for use with input_api.AffectedSourceFiles,
3316 below. This filters out everything except non-test files from
3317 top-level directories that generally speaking should not hard-code
3318 service URLs (e.g. src/android_webview/, src/content/ and others).
3319 """
3320 return input_api.FilterSourceFile(
3321 affected_file,
Bruce Dawson40fece62022-09-16 19:58:313322 files_to_check=[r'^(android_webview|base|content|net)/.*'],
Sam Maiera6e76d72022-02-11 21:43:503323 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3324 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:443325
Sam Maiera6e76d72022-02-11 21:43:503326 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
3327 '\.(com|net)[^"]*"')
3328 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
3329 pattern = input_api.re.compile(base_pattern)
3330 problems = [] # items are (filename, line_number, line)
3331 for f in input_api.AffectedSourceFiles(FilterFile):
3332 for line_num, line in f.ChangedContents():
3333 if not comment_pattern.search(line) and pattern.search(line):
3334 problems.append((f.LocalPath(), line_num, line))
[email protected]06e6d0ff2012-12-11 01:36:443335
Sam Maiera6e76d72022-02-11 21:43:503336 if problems:
3337 return [
3338 output_api.PresubmitPromptOrNotify(
3339 'Most layers below src/chrome/ should not hardcode service URLs.\n'
3340 'Are you sure this is correct?', [
3341 ' %s:%d: %s' % (problem[0], problem[1], problem[2])
3342 for problem in problems
3343 ])
3344 ]
3345 else:
3346 return []
[email protected]06e6d0ff2012-12-11 01:36:443347
3348
Saagar Sanghavifceeaae2020-08-12 16:40:363349def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503350 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
James Cook6b6597c2019-11-06 22:05:293351
Sam Maiera6e76d72022-02-11 21:43:503352 def FileFilter(affected_file):
3353 """Includes directories known to be Chrome OS only."""
3354 return input_api.FilterSourceFile(
3355 affected_file,
3356 files_to_check=(
3357 '^ash/',
3358 '^chromeos/', # Top-level src/chromeos.
3359 '.*/chromeos/', # Any path component.
3360 '^components/arc',
3361 '^components/exo'),
3362 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:293363
Sam Maiera6e76d72022-02-11 21:43:503364 prefs = []
3365 priority_prefs = []
3366 for f in input_api.AffectedFiles(file_filter=FileFilter):
3367 for line_num, line in f.ChangedContents():
3368 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF',
3369 line):
3370 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
3371 prefs.append(' %s' % line)
3372 if input_api.re.search(
3373 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
3374 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
3375 priority_prefs.append(' %s' % line)
3376
3377 results = []
3378 if (prefs):
3379 results.append(
3380 output_api.PresubmitPromptWarning(
3381 'Preferences were registered as SYNCABLE_PREF and will be controlled '
3382 'by browser sync settings. If these prefs should be controlled by OS '
3383 'sync settings use SYNCABLE_OS_PREF instead.\n' +
3384 '\n'.join(prefs)))
3385 if (priority_prefs):
3386 results.append(
3387 output_api.PresubmitPromptWarning(
3388 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
3389 'controlled by browser sync settings. If these prefs should be '
3390 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
3391 'instead.\n' + '\n'.join(prefs)))
3392 return results
James Cook6b6597c2019-11-06 22:05:293393
3394
Saagar Sanghavifceeaae2020-08-12 16:40:363395def CheckNoAbbreviationInPngFileName(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503396 """Makes sure there are no abbreviations in the name of PNG files.
3397 The native_client_sdk directory is excluded because it has auto-generated PNG
3398 files for documentation.
3399 """
3400 errors = []
Yuanqing Zhu9eef02832022-12-04 14:42:173401 files_to_check = [r'.*\.png$']
Bruce Dawson40fece62022-09-16 19:58:313402 files_to_skip = [r'^native_client_sdk/',
3403 r'^services/test/',
3404 r'^third_party/blink/web_tests/',
Bruce Dawson3db456212022-05-02 05:34:183405 ]
Sam Maiera6e76d72022-02-11 21:43:503406 file_filter = lambda f: input_api.FilterSourceFile(
3407 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Yuanqing Zhu9eef02832022-12-04 14:42:173408 abbreviation = input_api.re.compile('.+_[a-z]\.png|.+_[a-z]_.*\.png')
Sam Maiera6e76d72022-02-11 21:43:503409 for f in input_api.AffectedFiles(include_deletes=False,
3410 file_filter=file_filter):
Yuanqing Zhu9eef02832022-12-04 14:42:173411 file_name = input_api.os_path.split(f.LocalPath())[1]
3412 if abbreviation.search(file_name):
3413 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:273414
Sam Maiera6e76d72022-02-11 21:43:503415 results = []
3416 if errors:
3417 results.append(
3418 output_api.PresubmitError(
3419 'The name of PNG files should not have abbreviations. \n'
3420 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
3421 'Contact [email protected] if you have questions.', errors))
3422 return results
[email protected]d2530012013-01-25 16:39:273423
Evan Stade7cd4a2c2022-08-04 23:37:253424def CheckNoProductIconsAddedToPublicRepo(input_api, output_api):
3425 """Heuristically identifies product icons based on their file name and reminds
3426 contributors not to add them to the Chromium repository.
3427 """
3428 errors = []
3429 files_to_check = [r'.*google.*\.png$|.*google.*\.svg$|.*google.*\.icon$']
3430 file_filter = lambda f: input_api.FilterSourceFile(
3431 f, files_to_check=files_to_check)
3432 for f in input_api.AffectedFiles(include_deletes=False,
3433 file_filter=file_filter):
3434 errors.append(' %s' % f.LocalPath())
3435
3436 results = []
3437 if errors:
Bruce Dawson3bcf0c92022-08-12 00:03:083438 # Give warnings instead of errors on presubmit --all and presubmit
3439 # --files.
3440 message_type = (output_api.PresubmitNotifyResult if input_api.no_diffs
3441 else output_api.PresubmitError)
Evan Stade7cd4a2c2022-08-04 23:37:253442 results.append(
Bruce Dawson3bcf0c92022-08-12 00:03:083443 message_type(
Evan Stade7cd4a2c2022-08-04 23:37:253444 'Trademarked images should not be added to the public repo. '
3445 'See crbug.com/944754', errors))
3446 return results
3447
[email protected]d2530012013-01-25 16:39:273448
Daniel Cheng4dcdb6b2017-04-13 08:30:173449def _ExtractAddRulesFromParsedDeps(parsed_deps):
Sam Maiera6e76d72022-02-11 21:43:503450 """Extract the rules that add dependencies from a parsed DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:173451
Sam Maiera6e76d72022-02-11 21:43:503452 Args:
3453 parsed_deps: the locals dictionary from evaluating the DEPS file."""
3454 add_rules = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:173455 add_rules.update([
Sam Maiera6e76d72022-02-11 21:43:503456 rule[1:] for rule in parsed_deps.get('include_rules', [])
Daniel Cheng4dcdb6b2017-04-13 08:30:173457 if rule.startswith('+') or rule.startswith('!')
3458 ])
Sam Maiera6e76d72022-02-11 21:43:503459 for _, rules in parsed_deps.get('specific_include_rules', {}).items():
3460 add_rules.update([
3461 rule[1:] for rule in rules
3462 if rule.startswith('+') or rule.startswith('!')
3463 ])
3464 return add_rules
Daniel Cheng4dcdb6b2017-04-13 08:30:173465
3466
3467def _ParseDeps(contents):
Sam Maiera6e76d72022-02-11 21:43:503468 """Simple helper for parsing DEPS files."""
Daniel Cheng4dcdb6b2017-04-13 08:30:173469
Sam Maiera6e76d72022-02-11 21:43:503470 # Stubs for handling special syntax in the root DEPS file.
3471 class _VarImpl:
3472 def __init__(self, local_scope):
3473 self._local_scope = local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:173474
Sam Maiera6e76d72022-02-11 21:43:503475 def Lookup(self, var_name):
3476 """Implements the Var syntax."""
3477 try:
3478 return self._local_scope['vars'][var_name]
3479 except KeyError:
3480 raise Exception('Var is not defined: %s' % var_name)
Daniel Cheng4dcdb6b2017-04-13 08:30:173481
Sam Maiera6e76d72022-02-11 21:43:503482 local_scope = {}
3483 global_scope = {
3484 'Var': _VarImpl(local_scope).Lookup,
3485 'Str': str,
3486 }
Dirk Pranke1b9e06382021-05-14 01:16:223487
Sam Maiera6e76d72022-02-11 21:43:503488 exec(contents, global_scope, local_scope)
3489 return local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:173490
3491
Andrew Grieveb77ac762024-11-29 15:01:483492def _FindAllDepsFilesForSubpath(input_api, subpath):
3493 ret = []
3494 while subpath:
3495 cur = input_api.os_path.join(input_api.change.RepositoryRoot(), subpath, 'DEPS')
Joanna Wang130e7bdd2024-12-10 17:39:033496 if input_api.os_path.isfile(cur):
Andrew Grieveb77ac762024-11-29 15:01:483497 ret.append(cur)
3498 subpath = input_api.os_path.dirname(subpath)
3499 return ret
3500
3501
3502def _FindAddedDepsThatRequireReview(input_api, depended_on_paths):
3503 """Filters to those whose DEPS set new_usages_require_review=True"""
3504 ret = set()
3505 cache = {}
3506 for target_path in depended_on_paths:
3507 for subpath in _FindAllDepsFilesForSubpath(input_api, target_path):
3508 config = cache.get(subpath)
3509 if config is None:
3510 config = _ParseDeps(input_api.ReadFile(subpath))
3511 cache[subpath] = config
3512 if config.get('new_usages_require_review'):
3513 ret.add(target_path)
3514 break
3515 return ret
3516
3517
Daniel Cheng4dcdb6b2017-04-13 08:30:173518def _CalculateAddedDeps(os_path, old_contents, new_contents):
Sam Maiera6e76d72022-02-11 21:43:503519 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
3520 a set of DEPS entries that we should look up.
[email protected]14a6131c2014-01-08 01:15:413521
Sam Maiera6e76d72022-02-11 21:43:503522 For a directory (rather than a specific filename) we fake a path to
3523 a specific filename by adding /DEPS. This is chosen as a file that
3524 will seldom or never be subject to per-file include_rules.
3525 """
3526 # We ignore deps entries on auto-generated directories.
3527 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:083528
Sam Maiera6e76d72022-02-11 21:43:503529 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
3530 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
Daniel Cheng4dcdb6b2017-04-13 08:30:173531
Sam Maiera6e76d72022-02-11 21:43:503532 added_deps = new_deps.difference(old_deps)
Daniel Cheng4dcdb6b2017-04-13 08:30:173533
Sam Maiera6e76d72022-02-11 21:43:503534 results = set()
3535 for added_dep in added_deps:
3536 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
3537 continue
3538 # Assume that a rule that ends in .h is a rule for a specific file.
3539 if added_dep.endswith('.h'):
3540 results.add(added_dep)
3541 else:
3542 results.add(os_path.join(added_dep, 'DEPS'))
3543 return results
[email protected]f32e2d1e2013-07-26 21:39:083544
Stephanie Kimec4f55a2024-04-24 16:54:023545def CheckForNewDEPSDownloadFromGoogleStorageHooks(input_api, output_api):
3546 """Checks that there are no new download_from_google_storage hooks"""
3547 for f in input_api.AffectedFiles(include_deletes=False):
3548 if f.LocalPath() == 'DEPS':
3549 old_hooks = _ParseDeps('\n'.join(f.OldContents()))['hooks']
3550 new_hooks = _ParseDeps('\n'.join(f.NewContents()))['hooks']
3551 old_name_to_hook = {hook['name']: hook for hook in old_hooks}
3552 new_name_to_hook = {hook['name']: hook for hook in new_hooks}
3553 added_hook_names = set(new_name_to_hook.keys()) - set(
3554 old_name_to_hook.keys())
3555 if not added_hook_names:
3556 return []
3557 new_download_from_google_storage_hooks = []
3558 for new_hook in added_hook_names:
3559 hook = new_name_to_hook[new_hook]
3560 action_cmd = hook['action']
3561 if any('download_from_google_storage' in arg
3562 for arg in action_cmd):
3563 new_download_from_google_storage_hooks.append(new_hook)
3564 if new_download_from_google_storage_hooks:
3565 return [
3566 output_api.PresubmitError(
3567 'Please do not add new download_from_google_storage '
3568 'hooks. Instead, add a `gcs` dep_type entry to `deps`. '
3569 'See https://chromium.googlesource.com/chromium/src.git'
3570 '/+/refs/heads/main/docs/gcs_dependencies.md for more '
3571 'info. Added hooks:',
3572 items=new_download_from_google_storage_hooks)
3573 ]
3574 return []
3575
[email protected]f32e2d1e2013-07-26 21:39:083576
Rasika Navarangec2d33d22024-05-23 15:19:023577def CheckEachPerfettoTestDataFileHasDepsEntry(input_api, output_api):
3578 test_data_filter = lambda f: input_api.FilterSourceFile(
Rasika Navarange08e542162024-05-31 13:31:263579 f, files_to_check=[r'^base/tracing/test/data_sha256/.*\.sha256'])
Rasika Navarangec2d33d22024-05-23 15:19:023580 if not any(input_api.AffectedFiles(file_filter=test_data_filter)):
3581 return []
3582
3583 # Find DEPS entry
3584 deps_entry = []
Rasika Navarange277cd662024-06-04 10:14:593585 old_deps_entry = []
Rasika Navarangec2d33d22024-05-23 15:19:023586 for f in input_api.AffectedFiles(include_deletes=False):
3587 if f.LocalPath() == 'DEPS':
3588 new_deps = _ParseDeps('\n'.join(f.NewContents()))['deps']
3589 deps_entry = new_deps['src/base/tracing/test/data']
Rasika Navarange277cd662024-06-04 10:14:593590 old_deps = _ParseDeps('\n'.join(f.OldContents()))['deps']
3591 old_deps_entry = old_deps['src/base/tracing/test/data']
Rasika Navarangec2d33d22024-05-23 15:19:023592 if not deps_entry:
Rasika Navarange08e542162024-05-31 13:31:263593 # TODO(312895063):Add back error when .sha256 files have been moved.
Rasika Navaranged977df342024-06-05 10:01:273594 return [output_api.PresubmitError(
Rasika Navarangec2d33d22024-05-23 15:19:023595 'You must update the DEPS file when you update a '
Rasika Navarange08e542162024-05-31 13:31:263596 '.sha256 file in base/tracing/test/data_sha256'
Rasika Navarangec2d33d22024-05-23 15:19:023597 )]
3598
3599 output = []
3600 for f in input_api.AffectedFiles(file_filter=test_data_filter):
3601 objects = deps_entry['objects']
3602 if not f.NewContents():
3603 # Deleted file so check that DEPS entry removed
3604 sha256_from_file = f.OldContents()[0]
3605 object_entry = next(
3606 (item for item in objects if item["sha256sum"] == sha256_from_file),
3607 None)
Rasika Navarange277cd662024-06-04 10:14:593608 old_entry = next(
3609 (item for item in old_deps_entry['objects'] if item["sha256sum"] == sha256_from_file),
3610 None)
Rasika Navarangec2d33d22024-05-23 15:19:023611 if object_entry:
Rasika Navarange277cd662024-06-04 10:14:593612 # Allow renaming of objects with the same hash
3613 if object_entry['object_name'] != old_entry['object_name']:
3614 continue
Rasika Navarangec2d33d22024-05-23 15:19:023615 output.append(output_api.PresubmitError(
3616 'You deleted %s so you must also remove the corresponding DEPS entry.'
3617 % f.LocalPath()
3618 ))
3619 continue
3620
3621 sha256_from_file = f.NewContents()[0]
3622 object_entry = next(
3623 (item for item in objects if item["sha256sum"] == sha256_from_file),
3624 None)
3625 if not object_entry:
3626 output.append(output_api.PresubmitError(
3627 'No corresponding DEPS entry found for %s. '
3628 'Run `base/tracing/test/test_data.py get_deps --filepath %s` '
3629 'to generate the DEPS entry.'
3630 % (f.LocalPath(), f.LocalPath())
3631 ))
3632
3633 if output:
3634 output.append(output_api.PresubmitError(
3635 'The DEPS entry for `src/base/tracing/test/data` in the DEPS file has not been '
3636 'updated properly. Run `base/tracing/test/test_data.py get_all_deps` to see what '
3637 'the DEPS entry should look like.'
3638 ))
3639 return output
3640
3641
Saagar Sanghavifceeaae2020-08-12 16:40:363642def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503643 """When a dependency prefixed with + is added to a DEPS file, we
3644 want to make sure that the change is reviewed by an OWNER of the
3645 target file or directory, to avoid layering violations from being
3646 introduced. This check verifies that this happens.
3647 """
3648 # We rely on Gerrit's code-owners to check approvals.
3649 # input_api.gerrit is always set for Chromium, but other projects
3650 # might not use Gerrit.
Bruce Dawson344ab262022-06-04 11:35:103651 if not input_api.gerrit or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:503652 return []
Bruce Dawsonb357aeb2022-08-09 15:38:303653 if 'PRESUBMIT_SKIP_NETWORK' in input_api.environ:
Sam Maiera6e76d72022-02-11 21:43:503654 return []
Bruce Dawsonb357aeb2022-08-09 15:38:303655 try:
3656 if (input_api.change.issue and
3657 input_api.gerrit.IsOwnersOverrideApproved(
3658 input_api.change.issue)):
3659 # Skip OWNERS check when Owners-Override label is approved. This is
3660 # intended for global owners, trusted bots, and on-call sheriffs.
3661 # Review is still required for these changes.
3662 return []
3663 except Exception as e:
Sam Maier4cef9242022-10-03 14:21:243664 return [output_api.PresubmitPromptWarning(
3665 'Failed to retrieve owner override status - %s' % str(e))]
Edward Lesmes6fba51082021-01-20 04:20:233666
Andrew Grieveb77ac762024-11-29 15:01:483667 # A set of paths (that might not exist) that are being added as DEPS
3668 # (via lines like "+foo/bar/baz").
3669 depended_on_paths = set()
jochen53efcdd2016-01-29 05:09:243670
Sam Maiera6e76d72022-02-11 21:43:503671 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:313672 r"^third_party/blink/.*",
Anton Bershanskyi4253349482025-02-11 21:01:273673 f.UnixLocalPath())
Sam Maiera6e76d72022-02-11 21:43:503674 for f in input_api.AffectedFiles(include_deletes=False,
3675 file_filter=file_filter):
3676 filename = input_api.os_path.basename(f.LocalPath())
3677 if filename == 'DEPS':
Andrew Grieveb77ac762024-11-29 15:01:483678 depended_on_paths.update(
Sam Maiera6e76d72022-02-11 21:43:503679 _CalculateAddedDeps(input_api.os_path,
3680 '\n'.join(f.OldContents()),
3681 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:553682
Andrew Grieveb77ac762024-11-29 15:01:483683 # Requiring reviews is opt-in as of https://crbug.com/365797506
3684 depended_on_paths = _FindAddedDepsThatRequireReview(input_api, depended_on_paths)
3685 if not depended_on_paths:
Sam Maiera6e76d72022-02-11 21:43:503686 return []
[email protected]e871964c2013-05-13 14:14:553687
Sam Maiera6e76d72022-02-11 21:43:503688 if input_api.is_committing:
3689 if input_api.tbr:
3690 return [
3691 output_api.PresubmitNotifyResult(
3692 '--tbr was specified, skipping OWNERS check for DEPS additions'
3693 )
3694 ]
Daniel Cheng3008dc12022-05-13 04:02:113695 # TODO(dcheng): Make this generate an error on dry runs if the reviewer
3696 # is not added, to prevent review serialization.
Sam Maiera6e76d72022-02-11 21:43:503697 if input_api.dry_run:
3698 return [
3699 output_api.PresubmitNotifyResult(
3700 'This is a dry run, skipping OWNERS check for DEPS additions'
3701 )
3702 ]
3703 if not input_api.change.issue:
3704 return [
3705 output_api.PresubmitError(
3706 "DEPS approval by OWNERS check failed: this change has "
3707 "no change number, so we can't check it for approvals.")
3708 ]
3709 output = output_api.PresubmitError
[email protected]14a6131c2014-01-08 01:15:413710 else:
Sam Maiera6e76d72022-02-11 21:43:503711 output = output_api.PresubmitNotifyResult
[email protected]e871964c2013-05-13 14:14:553712
Sam Maiera6e76d72022-02-11 21:43:503713 owner_email, reviewers = (
3714 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3715 input_api, None, approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:553716
Sam Maiera6e76d72022-02-11 21:43:503717 owner_email = owner_email or input_api.change.author_email
3718
3719 approval_status = input_api.owners_client.GetFilesApprovalStatus(
Andrew Grieveb77ac762024-11-29 15:01:483720 depended_on_paths, reviewers.union([owner_email]), [])
Sam Maiera6e76d72022-02-11 21:43:503721 missing_files = [
Andrew Grieveb77ac762024-11-29 15:01:483722 p for p in depended_on_paths
3723 if approval_status[p] != input_api.owners_client.APPROVED
Sam Maiera6e76d72022-02-11 21:43:503724 ]
3725
3726 # We strip the /DEPS part that was added by
3727 # _FilesToCheckForIncomingDeps to fake a path to a file in a
3728 # directory.
3729 def StripDeps(path):
3730 start_deps = path.rfind('/DEPS')
3731 if start_deps != -1:
3732 return path[:start_deps]
3733 else:
3734 return path
3735
Scott Leebf6a0942024-06-26 22:59:393736 submodule_paths = set(input_api.ListSubmodules())
3737 def is_from_submodules(path, submodule_paths):
3738 path = input_api.os_path.normpath(path)
3739 while path:
3740 if path in submodule_paths:
3741 return True
3742
3743 # All deps should be a relative path from the checkout.
3744 # i.e., shouldn't start with "/" or "c:\", for example.
3745 #
3746 # That said, this is to prevent an infinite loop, just in case
3747 # an input dep path starts with "/", because
3748 # os.path.dirname("/") => "/"
3749 parent = input_api.os_path.dirname(path)
3750 if parent == path:
3751 break
3752 path = parent
3753
3754 return False
3755
Sam Maiera6e76d72022-02-11 21:43:503756 unapproved_dependencies = [
3757 "'+%s'," % StripDeps(path) for path in missing_files
Scott Leebf6a0942024-06-26 22:59:393758 # if a newly added dep is from a submodule, it becomes trickier
3759 # to get suggested owners, especially it is from a different host.
3760 #
3761 # skip the review enforcement for cross-repo deps.
3762 if not is_from_submodules(path, submodule_paths)
Sam Maiera6e76d72022-02-11 21:43:503763 ]
3764
3765 if unapproved_dependencies:
3766 output_list = [
3767 output(
3768 'You need LGTM from owners of depends-on paths in DEPS that were '
3769 'modified in this CL:\n %s' %
3770 '\n '.join(sorted(unapproved_dependencies)))
3771 ]
3772 suggested_owners = input_api.owners_client.SuggestOwners(
3773 missing_files, exclude=[owner_email])
3774 output_list.append(
3775 output('Suggested missing target path OWNERS:\n %s' %
3776 '\n '.join(suggested_owners or [])))
3777 return output_list
3778
3779 return []
[email protected]e871964c2013-05-13 14:14:553780
3781
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493782# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:363783def CheckSpamLogging(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503784 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3785 files_to_skip = (
3786 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3787 input_api.DEFAULT_FILES_TO_SKIP + (
Jaewon Jung2f323bb2022-12-07 23:55:013788 r"^base/fuchsia/scoped_fx_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313789 r"^base/logging\.h$",
3790 r"^base/logging\.cc$",
3791 r"^base/task/thread_pool/task_tracker\.cc$",
3792 r"^chrome/app/chrome_main_delegate\.cc$",
Yao Li359937b2023-02-15 23:43:033793 r"^chrome/browser/ash/arc/enterprise/cert_store/arc_cert_installer\.cc$",
3794 r"^chrome/browser/ash/policy/remote_commands/user_command_arc_job\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313795 r"^chrome/browser/chrome_browser_main\.cc$",
3796 r"^chrome/browser/ui/startup/startup_browser_creator\.cc$",
3797 r"^chrome/browser/browser_switcher/bho/.*",
3798 r"^chrome/browser/diagnostics/diagnostics_writer\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313799 r"^chrome/chrome_elf/dll_hash/dll_hash_main\.cc$",
3800 r"^chrome/installer/setup/.*",
Daniel Ruberyad36eea2024-08-01 01:38:323801 # crdmg runs as a separate binary which intentionally does
3802 # not depend on base logging.
3803 r"^chrome/utility/safe_browsing/mac/crdmg\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313804 r"^chromecast/",
Vigen Issahhanjane2d93822023-06-30 15:57:203805 r"^components/cast",
Bruce Dawson40fece62022-09-16 19:58:313806 r"^components/media_control/renderer/media_playback_options\.cc$",
Salma Elmahallawy52976452023-01-27 17:04:493807 r"^components/policy/core/common/policy_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313808 r"^components/viz/service/display/"
Sam Maiera6e76d72022-02-11 21:43:503809 r"overlay_strategy_underlay_cast\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313810 r"^components/zucchini/.*",
Sam Maiera6e76d72022-02-11 21:43:503811 # TODO(peter): Remove exception. https://crbug.com/534537
Bruce Dawson40fece62022-09-16 19:58:313812 r"^content/browser/notifications/"
Sam Maiera6e76d72022-02-11 21:43:503813 r"notification_event_dispatcher_impl\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313814 r"^content/common/gpu/client/gl_helper_benchmark\.cc$",
3815 r"^courgette/courgette_minimal_tool\.cc$",
3816 r"^courgette/courgette_tool\.cc$",
3817 r"^extensions/renderer/logging_native_handler\.cc$",
3818 r"^fuchsia_web/common/init_logging\.cc$",
3819 r"^fuchsia_web/runners/common/web_component\.cc$",
Caroline Liua7050132023-02-13 22:23:153820 r"^fuchsia_web/shell/.*\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313821 r"^headless/app/headless_shell\.cc$",
3822 r"^ipc/ipc_logging\.cc$",
3823 r"^native_client_sdk/",
3824 r"^remoting/base/logging\.h$",
3825 r"^remoting/host/.*",
3826 r"^sandbox/linux/.*",
Austin Sullivana6054e02024-05-20 16:31:293827 r"^services/webnn/tflite/graph_impl_tflite\.cc$",
3828 r"^services/webnn/coreml/graph_impl_coreml\.mm$",
Bruce Dawson40fece62022-09-16 19:58:313829 r"^storage/browser/file_system/dump_file_system\.cc$",
Steinar H. Gundersone5689e42024-08-07 18:17:193830 r"^testing/perf/",
Bruce Dawson40fece62022-09-16 19:58:313831 r"^tools/",
3832 r"^ui/base/resource/data_pack\.cc$",
3833 r"^ui/aura/bench/bench_main\.cc$",
3834 r"^ui/ozone/platform/cast/",
3835 r"^ui/base/x/xwmstartupcheck/"
Sam Maiera6e76d72022-02-11 21:43:503836 r"xwmstartupcheck\.cc$"))
3837 source_file_filter = lambda x: input_api.FilterSourceFile(
3838 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:403839
Sam Maiera6e76d72022-02-11 21:43:503840 log_info = set([])
3841 printf = set([])
[email protected]85218562013-11-22 07:41:403842
Sam Maiera6e76d72022-02-11 21:43:503843 for f in input_api.AffectedSourceFiles(source_file_filter):
3844 for _, line in f.ChangedContents():
3845 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
3846 log_info.add(f.LocalPath())
3847 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
3848 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:373849
Sam Maiera6e76d72022-02-11 21:43:503850 if input_api.re.search(r"\bprintf\(", line):
3851 printf.add(f.LocalPath())
3852 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
3853 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:403854
Sam Maiera6e76d72022-02-11 21:43:503855 if log_info:
3856 return [
3857 output_api.PresubmitError(
3858 'These files spam the console log with LOG(INFO):',
3859 items=log_info)
3860 ]
3861 if printf:
3862 return [
3863 output_api.PresubmitError(
3864 'These files spam the console log with printf/fprintf:',
3865 items=printf)
3866 ]
3867 return []
[email protected]85218562013-11-22 07:41:403868
3869
Saagar Sanghavifceeaae2020-08-12 16:40:363870def CheckForAnonymousVariables(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503871 """These types are all expected to hold locks while in scope and
3872 so should never be anonymous (which causes them to be immediately
3873 destroyed)."""
3874 they_who_must_be_named = [
3875 'base::AutoLock',
3876 'base::AutoReset',
3877 'base::AutoUnlock',
3878 'SkAutoAlphaRestore',
3879 'SkAutoBitmapShaderInstall',
3880 'SkAutoBlitterChoose',
3881 'SkAutoBounderCommit',
3882 'SkAutoCallProc',
3883 'SkAutoCanvasRestore',
3884 'SkAutoCommentBlock',
3885 'SkAutoDescriptor',
3886 'SkAutoDisableDirectionCheck',
3887 'SkAutoDisableOvalCheck',
3888 'SkAutoFree',
3889 'SkAutoGlyphCache',
3890 'SkAutoHDC',
3891 'SkAutoLockColors',
3892 'SkAutoLockPixels',
3893 'SkAutoMalloc',
3894 'SkAutoMaskFreeImage',
3895 'SkAutoMutexAcquire',
3896 'SkAutoPathBoundsUpdate',
3897 'SkAutoPDFRelease',
3898 'SkAutoRasterClipValidate',
3899 'SkAutoRef',
3900 'SkAutoTime',
3901 'SkAutoTrace',
3902 'SkAutoUnref',
3903 ]
3904 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
3905 # bad: base::AutoLock(lock.get());
3906 # not bad: base::AutoLock lock(lock.get());
3907 bad_pattern = input_api.re.compile(anonymous)
3908 # good: new base::AutoLock(lock.get())
3909 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
3910 errors = []
[email protected]49aa76a2013-12-04 06:59:163911
Sam Maiera6e76d72022-02-11 21:43:503912 for f in input_api.AffectedFiles():
3913 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
3914 continue
3915 for linenum, line in f.ChangedContents():
3916 if bad_pattern.search(line) and not good_pattern.search(line):
3917 errors.append('%s:%d' % (f.LocalPath(), linenum))
[email protected]49aa76a2013-12-04 06:59:163918
Sam Maiera6e76d72022-02-11 21:43:503919 if errors:
3920 return [
3921 output_api.PresubmitError(
3922 'These lines create anonymous variables that need to be named:',
3923 items=errors)
3924 ]
3925 return []
[email protected]49aa76a2013-12-04 06:59:163926
3927
Saagar Sanghavifceeaae2020-08-12 16:40:363928def CheckUniquePtrOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503929 # Returns whether |template_str| is of the form <T, U...> for some types T
Glen Robertson9142ffd72024-05-16 01:37:473930 # and U, or is invalid due to mismatched angle bracket pairs. Assumes that
3931 # |template_str| is already in the form <...>.
3932 def HasMoreThanOneArgOrInvalid(template_str):
Sam Maiera6e76d72022-02-11 21:43:503933 # Level of <...> nesting.
3934 nesting = 0
3935 for c in template_str:
3936 if c == '<':
3937 nesting += 1
3938 elif c == '>':
3939 nesting -= 1
3940 elif c == ',' and nesting == 1:
3941 return True
Glen Robertson9142ffd72024-05-16 01:37:473942 if nesting != 0:
Daniel Cheng566634ff2024-06-29 14:56:533943 # Invalid.
3944 return True
Sam Maiera6e76d72022-02-11 21:43:503945 return False
Vaclav Brozekb7fadb692018-08-30 06:39:533946
Sam Maiera6e76d72022-02-11 21:43:503947 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3948 sources = lambda affected_file: input_api.FilterSourceFile(
3949 affected_file,
3950 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3951 DEFAULT_FILES_TO_SKIP),
3952 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:553953
Sam Maiera6e76d72022-02-11 21:43:503954 # Pattern to capture a single "<...>" block of template arguments. It can
3955 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
3956 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
3957 # latter would likely require counting that < and > match, which is not
3958 # expressible in regular languages. Should the need arise, one can introduce
3959 # limited counting (matching up to a total number of nesting depth), which
3960 # should cover all practical cases for already a low nesting limit.
3961 template_arg_pattern = (
3962 r'<[^>]*' # Opening block of <.
3963 r'>([^<]*>)?') # Closing block of >.
3964 # Prefix expressing that whatever follows is not already inside a <...>
3965 # block.
3966 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
3967 null_construct_pattern = input_api.re.compile(
3968 not_inside_template_arg_pattern + r'\bstd::unique_ptr' +
3969 template_arg_pattern + r'\(\)')
Vaclav Brozeka54c528b2018-04-06 19:23:553970
Sam Maiera6e76d72022-02-11 21:43:503971 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
3972 template_arg_no_array_pattern = (
3973 r'<[^>]*[^]]' # Opening block of <.
3974 r'>([^(<]*[^]]>)?') # Closing block of >.
3975 # Prefix saying that what follows is the start of an expression.
3976 start_of_expr_pattern = r'(=|\breturn|^)\s*'
3977 # Suffix saying that what follows are call parentheses with a non-empty list
3978 # of arguments.
3979 nonempty_arg_list_pattern = r'\(([^)]|$)'
3980 # Put the template argument into a capture group for deeper examination later.
3981 return_construct_pattern = input_api.re.compile(
3982 start_of_expr_pattern + r'std::unique_ptr' + '(?P<template_arg>' +
3983 template_arg_no_array_pattern + ')' + nonempty_arg_list_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:553984
Sam Maiera6e76d72022-02-11 21:43:503985 problems_constructor = []
3986 problems_nullptr = []
3987 for f in input_api.AffectedSourceFiles(sources):
3988 for line_number, line in f.ChangedContents():
3989 # Disallow:
3990 # return std::unique_ptr<T>(foo);
3991 # bar = std::unique_ptr<T>(foo);
3992 # But allow:
3993 # return std::unique_ptr<T[]>(foo);
3994 # bar = std::unique_ptr<T[]>(foo);
3995 # And also allow cases when the second template argument is present. Those
3996 # cases cannot be handled by std::make_unique:
3997 # return std::unique_ptr<T, U>(foo);
3998 # bar = std::unique_ptr<T, U>(foo);
3999 local_path = f.LocalPath()
4000 return_construct_result = return_construct_pattern.search(line)
Glen Robertson9142ffd72024-05-16 01:37:474001 if return_construct_result and not HasMoreThanOneArgOrInvalid(
Sam Maiera6e76d72022-02-11 21:43:504002 return_construct_result.group('template_arg')):
4003 problems_constructor.append(
4004 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4005 # Disallow:
4006 # std::unique_ptr<T>()
4007 if null_construct_pattern.search(line):
4008 problems_nullptr.append(
4009 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Vaclav Brozek851d9602018-04-04 16:13:054010
Sam Maiera6e76d72022-02-11 21:43:504011 errors = []
4012 if problems_nullptr:
4013 errors.append(
4014 output_api.PresubmitPromptWarning(
4015 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
4016 problems_nullptr))
4017 if problems_constructor:
4018 errors.append(
4019 output_api.PresubmitError(
4020 'The following files use explicit std::unique_ptr constructor. '
4021 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
4022 'std::make_unique is not an option.', problems_constructor))
4023 return errors
Peter Kasting4844e46e2018-02-23 07:27:104024
4025
Saagar Sanghavifceeaae2020-08-12 16:40:364026def CheckUserActionUpdate(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504027 """Checks if any new user action has been added."""
4028 if any('actions.xml' == input_api.os_path.basename(f)
4029 for f in input_api.LocalPaths()):
4030 # If actions.xml is already included in the changelist, the PRESUBMIT
4031 # for actions.xml will do a more complete presubmit check.
4032 return []
4033
4034 file_inclusion_pattern = [r'.*\.(cc|mm)$']
4035 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
4036 input_api.DEFAULT_FILES_TO_SKIP)
4037 file_filter = lambda f: input_api.FilterSourceFile(
4038 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
4039
4040 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
4041 current_actions = None
4042 for f in input_api.AffectedFiles(file_filter=file_filter):
4043 for line_num, line in f.ChangedContents():
4044 match = input_api.re.search(action_re, line)
4045 if match:
4046 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
4047 # loaded only once.
4048 if not current_actions:
Bruce Dawson6cb2d4d2023-03-01 21:35:094049 with open('tools/metrics/actions/actions.xml',
4050 encoding='utf-8') as actions_f:
Sam Maiera6e76d72022-02-11 21:43:504051 current_actions = actions_f.read()
4052 # Search for the matched user action name in |current_actions|.
4053 for action_name in match.groups():
4054 action = 'name="{0}"'.format(action_name)
4055 if action not in current_actions:
4056 return [
4057 output_api.PresubmitPromptWarning(
4058 'File %s line %d: %s is missing in '
4059 'tools/metrics/actions/actions.xml. Please run '
4060 'tools/metrics/actions/extract_actions.py to update.'
4061 % (f.LocalPath(), line_num, action_name))
4062 ]
[email protected]999261d2014-03-03 20:08:084063 return []
4064
[email protected]999261d2014-03-03 20:08:084065
Daniel Cheng13ca61a882017-08-25 15:11:254066def _ImportJSONCommentEater(input_api):
Sam Maiera6e76d72022-02-11 21:43:504067 import sys
4068 sys.path = sys.path + [
4069 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4070 'json_comment_eater')
4071 ]
4072 import json_comment_eater
4073 return json_comment_eater
Daniel Cheng13ca61a882017-08-25 15:11:254074
4075
[email protected]99171a92014-06-03 08:44:474076def _GetJSONParseError(input_api, filename, eat_comments=True):
dchenge07de812016-06-20 19:27:174077 try:
Sam Maiera6e76d72022-02-11 21:43:504078 contents = input_api.ReadFile(filename)
4079 if eat_comments:
4080 json_comment_eater = _ImportJSONCommentEater(input_api)
4081 contents = json_comment_eater.Nom(contents)
dchenge07de812016-06-20 19:27:174082
Sam Maiera6e76d72022-02-11 21:43:504083 input_api.json.loads(contents)
4084 except ValueError as e:
4085 return e
Andrew Grieve4deedb12022-02-03 21:34:504086 return None
4087
4088
Sam Maiera6e76d72022-02-11 21:43:504089def _GetIDLParseError(input_api, filename):
4090 try:
4091 contents = input_api.ReadFile(filename)
Devlin Croninf7582a12022-04-21 21:14:284092 for i, char in enumerate(contents):
Daniel Chenga37c03db2022-05-12 17:20:344093 if not char.isascii():
4094 return (
4095 'Non-ascii character "%s" (ord %d) found at offset %d.' %
4096 (char, ord(char), i))
Sam Maiera6e76d72022-02-11 21:43:504097 idl_schema = input_api.os_path.join(input_api.PresubmitLocalPath(),
4098 'tools', 'json_schema_compiler',
4099 'idl_schema.py')
4100 process = input_api.subprocess.Popen(
Bruce Dawson679fb082022-04-14 00:47:284101 [input_api.python3_executable, idl_schema],
Sam Maiera6e76d72022-02-11 21:43:504102 stdin=input_api.subprocess.PIPE,
4103 stdout=input_api.subprocess.PIPE,
4104 stderr=input_api.subprocess.PIPE,
4105 universal_newlines=True)
4106 (_, error) = process.communicate(input=contents)
4107 return error or None
4108 except ValueError as e:
4109 return e
agrievef32bcc72016-04-04 14:57:404110
agrievef32bcc72016-04-04 14:57:404111
Sam Maiera6e76d72022-02-11 21:43:504112def CheckParseErrors(input_api, output_api):
4113 """Check that IDL and JSON files do not contain syntax errors."""
4114 actions = {
4115 '.idl': _GetIDLParseError,
4116 '.json': _GetJSONParseError,
4117 }
4118 # Most JSON files are preprocessed and support comments, but these do not.
4119 json_no_comments_patterns = [
Bruce Dawson40fece62022-09-16 19:58:314120 r'^testing/',
Sam Maiera6e76d72022-02-11 21:43:504121 ]
4122 # Only run IDL checker on files in these directories.
4123 idl_included_patterns = [
Bruce Dawson40fece62022-09-16 19:58:314124 r'^chrome/common/extensions/api/',
4125 r'^extensions/common/api/',
Sam Maiera6e76d72022-02-11 21:43:504126 ]
agrievef32bcc72016-04-04 14:57:404127
Sam Maiera6e76d72022-02-11 21:43:504128 def get_action(affected_file):
4129 filename = affected_file.LocalPath()
4130 return actions.get(input_api.os_path.splitext(filename)[1])
agrievef32bcc72016-04-04 14:57:404131
Sam Maiera6e76d72022-02-11 21:43:504132 def FilterFile(affected_file):
4133 action = get_action(affected_file)
4134 if not action:
4135 return False
Anton Bershanskyi4253349482025-02-11 21:01:274136 path = affected_file.UnixLocalPath()
agrievef32bcc72016-04-04 14:57:404137
Sam Maiera6e76d72022-02-11 21:43:504138 if _MatchesFile(input_api,
4139 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS, path):
4140 return False
4141
4142 if (action == _GetIDLParseError
4143 and not _MatchesFile(input_api, idl_included_patterns, path)):
4144 return False
4145 return True
4146
4147 results = []
4148 for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
4149 include_deletes=False):
4150 action = get_action(affected_file)
4151 kwargs = {}
4152 if (action == _GetJSONParseError
4153 and _MatchesFile(input_api, json_no_comments_patterns,
Anton Bershanskyi4253349482025-02-11 21:01:274154 affected_file.UnixLocalPath())):
Sam Maiera6e76d72022-02-11 21:43:504155 kwargs['eat_comments'] = False
4156 parse_error = action(input_api, affected_file.AbsoluteLocalPath(),
4157 **kwargs)
4158 if parse_error:
4159 results.append(
4160 output_api.PresubmitError(
4161 '%s could not be parsed: %s' %
4162 (affected_file.LocalPath(), parse_error)))
4163 return results
4164
4165
4166def CheckJavaStyle(input_api, output_api):
4167 """Runs checkstyle on changed java files and returns errors if any exist."""
4168
4169 # Return early if no java files were modified.
4170 if not any(
4171 _IsJavaFile(input_api, f.LocalPath())
4172 for f in input_api.AffectedFiles()):
4173 return []
4174
4175 import sys
4176 original_sys_path = sys.path
4177 try:
4178 sys.path = sys.path + [
4179 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4180 'android', 'checkstyle')
4181 ]
4182 import checkstyle
4183 finally:
4184 # Restore sys.path to what it was before.
4185 sys.path = original_sys_path
4186
Andrew Grieve4f88e3ca2022-11-22 19:09:204187 return checkstyle.run_presubmit(
Sam Maiera6e76d72022-02-11 21:43:504188 input_api,
4189 output_api,
Sam Maiera6e76d72022-02-11 21:43:504190 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
4191
4192
4193def CheckPythonDevilInit(input_api, output_api):
4194 """Checks to make sure devil is initialized correctly in python scripts."""
4195 script_common_initialize_pattern = input_api.re.compile(
4196 r'script_common\.InitializeEnvironment\(')
4197 devil_env_config_initialize = input_api.re.compile(
4198 r'devil_env\.config\.Initialize\(')
4199
4200 errors = []
4201
4202 sources = lambda affected_file: input_api.FilterSourceFile(
4203 affected_file,
4204 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314205 r'^build/android/devil_chromium\.py',
Sven Zheng8e079562024-05-10 20:11:064206 r'^tools/bisect-builds\.py',
Bruce Dawson40fece62022-09-16 19:58:314207 r'^third_party/.*',
Sam Maiera6e76d72022-02-11 21:43:504208 )),
4209 files_to_check=[r'.*\.py$'])
4210
4211 for f in input_api.AffectedSourceFiles(sources):
4212 for line_num, line in f.ChangedContents():
4213 if (script_common_initialize_pattern.search(line)
4214 or devil_env_config_initialize.search(line)):
4215 errors.append("%s:%d" % (f.LocalPath(), line_num))
4216
4217 results = []
4218
4219 if errors:
4220 results.append(
4221 output_api.PresubmitError(
4222 'Devil initialization should always be done using '
4223 'devil_chromium.Initialize() in the chromium project, to use better '
4224 'defaults for dependencies (ex. up-to-date version of adb).',
4225 errors))
4226
4227 return results
4228
4229
4230def _MatchesFile(input_api, patterns, path):
4231 for pattern in patterns:
4232 if input_api.re.search(pattern, path):
4233 return True
4234 return False
4235
4236
Daniel Chenga37c03db2022-05-12 17:20:344237def _ChangeHasSecurityReviewer(input_api, owners_file):
4238 """Returns True iff the CL has a reviewer from SECURITY_OWNERS.
Sam Maiera6e76d72022-02-11 21:43:504239
Daniel Chenga37c03db2022-05-12 17:20:344240 Args:
4241 input_api: The presubmit input API.
4242 owners_file: OWNERS file with required reviewers. Typically, this is
4243 something like ipc/SECURITY_OWNERS.
4244
4245 Note: if the presubmit is running for commit rather than for upload, this
4246 only returns True if a security reviewer has also approved the CL.
Sam Maiera6e76d72022-02-11 21:43:504247 """
Daniel Chengd88244472022-05-16 09:08:474248 # Owners-Override should bypass all additional OWNERS enforcement checks.
4249 # A CR+1 vote will still be required to land this change.
4250 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
4251 input_api.change.issue)):
4252 return True
4253
Daniel Chenga37c03db2022-05-12 17:20:344254 owner_email, reviewers = (
4255 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
Daniel Cheng3008dc12022-05-13 04:02:114256 input_api,
4257 None,
4258 approval_needed=input_api.is_committing and not input_api.dry_run))
Sam Maiera6e76d72022-02-11 21:43:504259
Daniel Chenga37c03db2022-05-12 17:20:344260 security_owners = input_api.owners_client.ListOwners(owners_file)
4261 return any(owner in reviewers for owner in security_owners)
Sam Maiera6e76d72022-02-11 21:43:504262
Daniel Chenga37c03db2022-05-12 17:20:344263
4264@dataclass
Daniel Cheng171dad8d2022-05-21 00:40:254265class _SecurityProblemWithItems:
4266 problem: str
4267 items: Sequence[str]
4268
4269
4270@dataclass
Daniel Chenga37c03db2022-05-12 17:20:344271class _MissingSecurityOwnersResult:
Daniel Cheng171dad8d2022-05-21 00:40:254272 owners_file_problems: Sequence[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:344273 has_security_sensitive_files: bool
Daniel Cheng171dad8d2022-05-21 00:40:254274 missing_reviewer_problem: Optional[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:344275
4276
4277def _FindMissingSecurityOwners(input_api,
4278 output_api,
4279 file_patterns: Sequence[str],
4280 excluded_patterns: Sequence[str],
4281 required_owners_file: str,
4282 custom_rule_function: Optional[Callable] = None
4283 ) -> _MissingSecurityOwnersResult:
4284 """Find OWNERS files missing per-file rules for security-sensitive files.
4285
4286 Args:
4287 input_api: the PRESUBMIT input API object.
4288 output_api: the PRESUBMIT output API object.
4289 file_patterns: basename patterns that require a corresponding per-file
4290 security restriction.
4291 excluded_patterns: path patterns that should be exempted from
4292 requiring a security restriction.
4293 required_owners_file: path to the required OWNERS file, e.g.
4294 ipc/SECURITY_OWNERS
4295 cc_alias: If not None, email that will be CCed automatically if the
4296 change contains security-sensitive files, as determined by
4297 `file_patterns` and `excluded_patterns`.
4298 custom_rule_function: If not None, will be called with `input_api` and
4299 the current file under consideration. Returning True will add an
4300 exact match per-file rule check for the current file.
4301 """
4302
4303 # `to_check` is a mapping of an OWNERS file path to Patterns.
4304 #
4305 # Patterns is a dictionary mapping glob patterns (suitable for use in
4306 # per-file rules) to a PatternEntry.
4307 #
Sam Maiera6e76d72022-02-11 21:43:504308 # PatternEntry is a dictionary with two keys:
4309 # - 'files': the files that are matched by this pattern
4310 # - 'rules': the per-file rules needed for this pattern
Daniel Chenga37c03db2022-05-12 17:20:344311 #
Sam Maiera6e76d72022-02-11 21:43:504312 # For example, if we expect OWNERS file to contain rules for *.mojom and
4313 # *_struct_traits*.*, Patterns might look like this:
4314 # {
4315 # '*.mojom': {
4316 # 'files': ...,
4317 # 'rules': [
4318 # 'per-file *.mojom=set noparent',
4319 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
4320 # ],
4321 # },
4322 # '*_struct_traits*.*': {
4323 # 'files': ...,
4324 # 'rules': [
4325 # 'per-file *_struct_traits*.*=set noparent',
4326 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
4327 # ],
4328 # },
4329 # }
4330 to_check = {}
Daniel Chenga37c03db2022-05-12 17:20:344331 files_to_review = []
Sam Maiera6e76d72022-02-11 21:43:504332
Daniel Chenga37c03db2022-05-12 17:20:344333 def AddPatternToCheck(file, pattern):
Sam Maiera6e76d72022-02-11 21:43:504334 owners_file = input_api.os_path.join(
Daniel Chengd88244472022-05-16 09:08:474335 input_api.os_path.dirname(file.LocalPath()), 'OWNERS')
Sam Maiera6e76d72022-02-11 21:43:504336 if owners_file not in to_check:
4337 to_check[owners_file] = {}
4338 if pattern not in to_check[owners_file]:
4339 to_check[owners_file][pattern] = {
4340 'files': [],
4341 'rules': [
Daniel Chenga37c03db2022-05-12 17:20:344342 f'per-file {pattern}=set noparent',
4343 f'per-file {pattern}=file://{required_owners_file}',
Sam Maiera6e76d72022-02-11 21:43:504344 ]
4345 }
Daniel Chenged57a162022-05-25 02:56:344346 to_check[owners_file][pattern]['files'].append(file.LocalPath())
Daniel Chenga37c03db2022-05-12 17:20:344347 files_to_review.append(file.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:504348
Daniel Chenga37c03db2022-05-12 17:20:344349 # Only enforce security OWNERS rules for a directory if that directory has a
4350 # file that matches `file_patterns`. For example, if a directory only
4351 # contains *.mojom files and no *_messages*.h files, the check should only
4352 # ensure that rules for *.mojom files are present.
4353 for file in input_api.AffectedFiles(include_deletes=False):
4354 file_basename = input_api.os_path.basename(file.LocalPath())
4355 if custom_rule_function is not None and custom_rule_function(
4356 input_api, file):
4357 AddPatternToCheck(file, file_basename)
4358 continue
Sam Maiera6e76d72022-02-11 21:43:504359
Daniel Chenga37c03db2022-05-12 17:20:344360 if any(
4361 input_api.fnmatch.fnmatch(file.LocalPath(), pattern)
4362 for pattern in excluded_patterns):
Sam Maiera6e76d72022-02-11 21:43:504363 continue
4364
4365 for pattern in file_patterns:
Daniel Chenga37c03db2022-05-12 17:20:344366 # Unlike `excluded_patterns`, `file_patterns` is checked only against the
4367 # file's basename.
4368 if input_api.fnmatch.fnmatch(file_basename, pattern):
4369 AddPatternToCheck(file, pattern)
Sam Maiera6e76d72022-02-11 21:43:504370 break
4371
Daniel Chenga37c03db2022-05-12 17:20:344372 has_security_sensitive_files = bool(to_check)
Daniel Cheng171dad8d2022-05-21 00:40:254373
4374 # Check if any newly added lines in OWNERS files intersect with required
4375 # per-file OWNERS lines. If so, ensure that a security reviewer is included.
4376 # This is a hack, but is needed because the OWNERS check (by design) ignores
4377 # new OWNERS entries; otherwise, a non-owner could add someone as a new
4378 # OWNER and have that newly-added OWNER self-approve their own addition.
4379 newly_covered_files = []
4380 for file in input_api.AffectedFiles(include_deletes=False):
4381 if not file.LocalPath() in to_check:
4382 continue
4383 for _, line in file.ChangedContents():
4384 for _, entry in to_check[file.LocalPath()].items():
4385 if line in entry['rules']:
4386 newly_covered_files.extend(entry['files'])
4387
4388 missing_reviewer_problems = None
4389 if newly_covered_files and not _ChangeHasSecurityReviewer(
Daniel Chenga37c03db2022-05-12 17:20:344390 input_api, required_owners_file):
Daniel Cheng171dad8d2022-05-21 00:40:254391 missing_reviewer_problems = _SecurityProblemWithItems(
4392 f'Review from an owner in {required_owners_file} is required for '
4393 'the following newly-added files:',
4394 [f'{file}' for file in sorted(set(newly_covered_files))])
Sam Maiera6e76d72022-02-11 21:43:504395
4396 # Go through the OWNERS files to check, filtering out rules that are already
4397 # present in that OWNERS file.
4398 for owners_file, patterns in to_check.items():
4399 try:
Daniel Cheng171dad8d2022-05-21 00:40:254400 lines = set(
4401 input_api.ReadFile(
4402 input_api.os_path.join(input_api.change.RepositoryRoot(),
4403 owners_file)).splitlines())
4404 for entry in patterns.values():
4405 entry['rules'] = [
4406 rule for rule in entry['rules'] if rule not in lines
4407 ]
Sam Maiera6e76d72022-02-11 21:43:504408 except IOError:
4409 # No OWNERS file, so all the rules are definitely missing.
4410 continue
4411
4412 # All the remaining lines weren't found in OWNERS files, so emit an error.
Daniel Cheng171dad8d2022-05-21 00:40:254413 owners_file_problems = []
Daniel Chenga37c03db2022-05-12 17:20:344414
Sam Maiera6e76d72022-02-11 21:43:504415 for owners_file, patterns in to_check.items():
4416 missing_lines = []
4417 files = []
4418 for _, entry in patterns.items():
Daniel Chenged57a162022-05-25 02:56:344419 files.extend(entry['files'])
Sam Maiera6e76d72022-02-11 21:43:504420 missing_lines.extend(entry['rules'])
Sam Maiera6e76d72022-02-11 21:43:504421 if missing_lines:
Daniel Cheng171dad8d2022-05-21 00:40:254422 joined_missing_lines = '\n'.join(line for line in missing_lines)
4423 owners_file_problems.append(
4424 _SecurityProblemWithItems(
4425 'Found missing OWNERS lines for security-sensitive files. '
4426 f'Please add the following lines to {owners_file}:\n'
4427 f'{joined_missing_lines}\n\nTo ensure security review for:',
4428 files))
Daniel Chenga37c03db2022-05-12 17:20:344429
Daniel Cheng171dad8d2022-05-21 00:40:254430 return _MissingSecurityOwnersResult(owners_file_problems,
Daniel Chenga37c03db2022-05-12 17:20:344431 has_security_sensitive_files,
Daniel Cheng171dad8d2022-05-21 00:40:254432 missing_reviewer_problems)
Daniel Chenga37c03db2022-05-12 17:20:344433
4434
4435def _CheckChangeForIpcSecurityOwners(input_api, output_api):
4436 # Whether or not a file affects IPC is (mostly) determined by a simple list
4437 # of filename patterns.
4438 file_patterns = [
4439 # Legacy IPC:
4440 '*_messages.cc',
4441 '*_messages*.h',
4442 '*_param_traits*.*',
4443 # Mojo IPC:
4444 '*.mojom',
4445 '*_mojom_traits*.*',
4446 '*_type_converter*.*',
4447 # Android native IPC:
4448 '*.aidl',
4449 ]
4450
Daniel Chenga37c03db2022-05-12 17:20:344451 excluded_patterns = [
Daniel Cheng518943f2022-05-12 22:15:464452 # These third_party directories do not contain IPCs, but contain files
4453 # matching the above patterns, which trigger false positives.
Daniel Chenga37c03db2022-05-12 17:20:344454 'third_party/crashpad/*',
4455 'third_party/blink/renderer/platform/bindings/*',
Evan Stade23a77da2025-02-06 21:15:314456 'third_party/protobuf/*',
Daniel Chenga37c03db2022-05-12 17:20:344457 'third_party/win_build_output/*',
Daniel Chengd88244472022-05-16 09:08:474458 # Enum-only mojoms used for web metrics, so no security review needed.
4459 'third_party/blink/public/mojom/use_counter/metrics/*',
Daniel Chenga37c03db2022-05-12 17:20:344460 # These files are just used to communicate between class loaders running
4461 # in the same process.
4462 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
4463 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
4464 ]
4465
4466 def IsMojoServiceManifestFile(input_api, file):
4467 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
4468 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
4469 if not manifest_pattern.search(file.LocalPath()):
4470 return False
4471
4472 if test_manifest_pattern.search(file.LocalPath()):
4473 return False
4474
4475 # All actual service manifest files should contain at least one
4476 # qualified reference to service_manager::Manifest.
4477 return any('service_manager::Manifest' in line
4478 for line in file.NewContents())
4479
4480 return _FindMissingSecurityOwners(
4481 input_api,
4482 output_api,
4483 file_patterns,
4484 excluded_patterns,
4485 'ipc/SECURITY_OWNERS',
4486 custom_rule_function=IsMojoServiceManifestFile)
4487
4488
4489def _CheckChangeForFuchsiaSecurityOwners(input_api, output_api):
4490 file_patterns = [
4491 # Component specifications.
4492 '*.cml', # Component Framework v2.
4493 '*.cmx', # Component Framework v1.
4494
4495 # Fuchsia IDL protocol specifications.
4496 '*.fidl',
4497 ]
4498
4499 # Don't check for owners files for changes in these directories.
4500 excluded_patterns = [
4501 'third_party/crashpad/*',
4502 ]
4503
4504 return _FindMissingSecurityOwners(input_api, output_api, file_patterns,
4505 excluded_patterns,
4506 'build/fuchsia/SECURITY_OWNERS')
4507
4508
4509def CheckSecurityOwners(input_api, output_api):
4510 """Checks that various security-sensitive files have an IPC OWNERS rule."""
4511 ipc_results = _CheckChangeForIpcSecurityOwners(input_api, output_api)
4512 fuchsia_results = _CheckChangeForFuchsiaSecurityOwners(
4513 input_api, output_api)
4514
4515 if ipc_results.has_security_sensitive_files:
4516 output_api.AppendCC('[email protected]')
Sam Maiera6e76d72022-02-11 21:43:504517
4518 results = []
Daniel Chenga37c03db2022-05-12 17:20:344519
Daniel Cheng171dad8d2022-05-21 00:40:254520 missing_reviewer_problems = []
4521 if ipc_results.missing_reviewer_problem:
4522 missing_reviewer_problems.append(ipc_results.missing_reviewer_problem)
4523 if fuchsia_results.missing_reviewer_problem:
4524 missing_reviewer_problems.append(
4525 fuchsia_results.missing_reviewer_problem)
Daniel Chenga37c03db2022-05-12 17:20:344526
Daniel Cheng171dad8d2022-05-21 00:40:254527 # Missing reviewers are an error unless there's no issue number
4528 # associated with this branch; in that case, the presubmit is being run
4529 # with --all or --files.
4530 #
4531 # Note that upload should never be an error; otherwise, it would be
4532 # impossible to upload changes at all.
4533 if input_api.is_committing and input_api.change.issue:
4534 make_presubmit_message = output_api.PresubmitError
4535 else:
4536 make_presubmit_message = output_api.PresubmitNotifyResult
4537 for problem in missing_reviewer_problems:
Sam Maiera6e76d72022-02-11 21:43:504538 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:254539 make_presubmit_message(problem.problem, items=problem.items))
Daniel Chenga37c03db2022-05-12 17:20:344540
Daniel Cheng171dad8d2022-05-21 00:40:254541 owners_file_problems = []
4542 owners_file_problems.extend(ipc_results.owners_file_problems)
4543 owners_file_problems.extend(fuchsia_results.owners_file_problems)
Daniel Chenga37c03db2022-05-12 17:20:344544
Daniel Cheng171dad8d2022-05-21 00:40:254545 for problem in owners_file_problems:
Daniel Cheng3008dc12022-05-13 04:02:114546 # Missing per-file rules are always an error. While swarming and caching
4547 # means that uploading a patchset with updated OWNERS files and sending
4548 # it to the CQ again should not have a large incremental cost, it is
4549 # still frustrating to discover the error only after the change has
4550 # already been uploaded.
Daniel Chenga37c03db2022-05-12 17:20:344551 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:254552 output_api.PresubmitError(problem.problem, items=problem.items))
Sam Maiera6e76d72022-02-11 21:43:504553
4554 return results
4555
4556
4557def _GetFilesUsingSecurityCriticalFunctions(input_api):
4558 """Checks affected files for changes to security-critical calls. This
4559 function checks the full change diff, to catch both additions/changes
4560 and removals.
4561
4562 Returns a dict keyed by file name, and the value is a set of detected
4563 functions.
4564 """
4565 # Map of function pretty name (displayed in an error) to the pattern to
4566 # match it with.
4567 _PATTERNS_TO_CHECK = {
4568 'content::GetServiceSandboxType<>()': 'GetServiceSandboxType\\<'
4569 }
4570 _PATTERNS_TO_CHECK = {
4571 k: input_api.re.compile(v)
4572 for k, v in _PATTERNS_TO_CHECK.items()
4573 }
4574
Sam Maiera6e76d72022-02-11 21:43:504575 # We don't want to trigger on strings within this file.
4576 def presubmit_file_filter(f):
Daniel Chenga37c03db2022-05-12 17:20:344577 return 'PRESUBMIT.py' != input_api.os_path.split(f.LocalPath())[1]
Sam Maiera6e76d72022-02-11 21:43:504578
4579 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
4580 files_to_functions = {}
4581 for f in input_api.AffectedFiles(file_filter=presubmit_file_filter):
4582 diff = f.GenerateScmDiff()
4583 for line in diff.split('\n'):
4584 # Not using just RightHandSideLines() because removing a
4585 # call to a security-critical function can be just as important
4586 # as adding or changing the arguments.
4587 if line.startswith('-') or (line.startswith('+')
4588 and not line.startswith('++')):
4589 for name, pattern in _PATTERNS_TO_CHECK.items():
4590 if pattern.search(line):
4591 path = f.LocalPath()
4592 if not path in files_to_functions:
4593 files_to_functions[path] = set()
4594 files_to_functions[path].add(name)
4595 return files_to_functions
4596
4597
4598def CheckSecurityChanges(input_api, output_api):
4599 """Checks that changes involving security-critical functions are reviewed
4600 by the security team.
4601 """
4602 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
4603 if not len(files_to_functions):
4604 return []
4605
Sam Maiera6e76d72022-02-11 21:43:504606 owners_file = 'ipc/SECURITY_OWNERS'
Daniel Chenga37c03db2022-05-12 17:20:344607 if _ChangeHasSecurityReviewer(input_api, owners_file):
Sam Maiera6e76d72022-02-11 21:43:504608 return []
4609
Daniel Chenga37c03db2022-05-12 17:20:344610 msg = 'The following files change calls to security-sensitive functions\n' \
Sam Maiera6e76d72022-02-11 21:43:504611 'that need to be reviewed by {}.\n'.format(owners_file)
4612 for path, names in files_to_functions.items():
4613 msg += ' {}\n'.format(path)
4614 for name in names:
4615 msg += ' {}\n'.format(name)
4616 msg += '\n'
4617
4618 if input_api.is_committing:
4619 output = output_api.PresubmitError
Mohamed Heikale217fc852020-07-06 19:44:034620 else:
Sam Maiera6e76d72022-02-11 21:43:504621 output = output_api.PresubmitNotifyResult
4622 return [output(msg)]
4623
4624
4625def CheckSetNoParent(input_api, output_api):
4626 """Checks that set noparent is only used together with an OWNERS file in
4627 //build/OWNERS.setnoparent (see also
4628 //docs/code_reviews.md#owners-files-details)
4629 """
4630 # Return early if no OWNERS files were modified.
4631 if not any(f.LocalPath().endswith('OWNERS')
4632 for f in input_api.AffectedFiles(include_deletes=False)):
4633 return []
4634
4635 errors = []
4636
4637 allowed_owners_files_file = 'build/OWNERS.setnoparent'
4638 allowed_owners_files = set()
Bruce Dawson58a45d22023-02-27 11:24:164639 with open(allowed_owners_files_file, 'r', encoding='utf-8') as f:
Sam Maiera6e76d72022-02-11 21:43:504640 for line in f:
4641 line = line.strip()
4642 if not line or line.startswith('#'):
4643 continue
4644 allowed_owners_files.add(line)
4645
4646 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
4647
4648 for f in input_api.AffectedFiles(include_deletes=False):
4649 if not f.LocalPath().endswith('OWNERS'):
4650 continue
4651
4652 found_owners_files = set()
4653 found_set_noparent_lines = dict()
4654
4655 # Parse the OWNERS file.
4656 for lineno, line in enumerate(f.NewContents(), 1):
4657 line = line.strip()
4658 if line.startswith('set noparent'):
4659 found_set_noparent_lines[''] = lineno
4660 if line.startswith('file://'):
4661 if line in allowed_owners_files:
4662 found_owners_files.add('')
4663 if line.startswith('per-file'):
4664 match = per_file_pattern.match(line)
4665 if match:
4666 glob = match.group(1).strip()
4667 directive = match.group(2).strip()
4668 if directive == 'set noparent':
4669 found_set_noparent_lines[glob] = lineno
4670 if directive.startswith('file://'):
4671 if directive in allowed_owners_files:
4672 found_owners_files.add(glob)
4673
4674 # Check that every set noparent line has a corresponding file:// line
4675 # listed in build/OWNERS.setnoparent. An exception is made for top level
4676 # directories since src/OWNERS shouldn't review them.
Anton Bershanskyi4253349482025-02-11 21:01:274677 linux_path = f.UnixLocalPath()
Bruce Dawson6bb0d672022-04-06 15:13:494678 if (linux_path.count('/') != 1
4679 and (not linux_path in _EXCLUDED_SET_NO_PARENT_PATHS)):
Sam Maiera6e76d72022-02-11 21:43:504680 for set_noparent_line in found_set_noparent_lines:
4681 if set_noparent_line in found_owners_files:
4682 continue
4683 errors.append(' %s:%d' %
Bruce Dawson6bb0d672022-04-06 15:13:494684 (linux_path,
Sam Maiera6e76d72022-02-11 21:43:504685 found_set_noparent_lines[set_noparent_line]))
4686
4687 results = []
4688 if errors:
4689 if input_api.is_committing:
4690 output = output_api.PresubmitError
4691 else:
4692 output = output_api.PresubmitPromptWarning
4693 results.append(
4694 output(
4695 'Found the following "set noparent" restrictions in OWNERS files that '
4696 'do not include owners from build/OWNERS.setnoparent:',
4697 long_text='\n\n'.join(errors)))
4698 return results
4699
4700
4701def CheckUselessForwardDeclarations(input_api, output_api):
4702 """Checks that added or removed lines in non third party affected
4703 header files do not lead to new useless class or struct forward
4704 declaration.
4705 """
4706 results = []
4707 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
4708 input_api.re.MULTILINE)
4709 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
4710 input_api.re.MULTILINE)
4711 for f in input_api.AffectedFiles(include_deletes=False):
Anton Bershanskyi4253349482025-02-11 21:01:274712 local_path = f.UnixLocalPath()
4713 if (local_path.startswith('third_party')
4714 and not local_path.startswith('third_party/blink')):
Sam Maiera6e76d72022-02-11 21:43:504715 continue
4716
Anton Bershanskyi4253349482025-02-11 21:01:274717 if not local_path.endswith('.h'):
Sam Maiera6e76d72022-02-11 21:43:504718 continue
4719
4720 contents = input_api.ReadFile(f)
4721 fwd_decls = input_api.re.findall(class_pattern, contents)
4722 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
4723
4724 useless_fwd_decls = []
4725 for decl in fwd_decls:
4726 count = sum(1 for _ in input_api.re.finditer(
4727 r'\b%s\b' % input_api.re.escape(decl), contents))
4728 if count == 1:
4729 useless_fwd_decls.append(decl)
4730
4731 if not useless_fwd_decls:
4732 continue
4733
4734 for line in f.GenerateScmDiff().splitlines():
4735 if (line.startswith('-') and not line.startswith('--')
4736 or line.startswith('+') and not line.startswith('++')):
4737 for decl in useless_fwd_decls:
4738 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
4739 results.append(
4740 output_api.PresubmitPromptWarning(
4741 '%s: %s forward declaration is no longer needed'
4742 % (f.LocalPath(), decl)))
4743 useless_fwd_decls.remove(decl)
4744
4745 return results
4746
4747
4748def _CheckAndroidDebuggableBuild(input_api, output_api):
4749 """Checks that code uses BuildInfo.isDebugAndroid() instead of
4750 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
4751 this is a debuggable build of Android.
4752 """
4753 build_type_check_pattern = input_api.re.compile(
4754 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
4755
4756 errors = []
4757
4758 sources = lambda affected_file: input_api.FilterSourceFile(
4759 affected_file,
4760 files_to_skip=(
4761 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4762 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314763 r"^android_webview/support_library/boundary_interfaces/",
4764 r"^chrome/android/webapk/.*",
4765 r'^third_party/.*',
4766 r"tools/android/customtabs_benchmark/.*",
4767 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504768 )),
4769 files_to_check=[r'.*\.java$'])
4770
4771 for f in input_api.AffectedSourceFiles(sources):
4772 for line_num, line in f.ChangedContents():
4773 if build_type_check_pattern.search(line):
4774 errors.append("%s:%d" % (f.LocalPath(), line_num))
4775
4776 results = []
4777
4778 if errors:
4779 results.append(
4780 output_api.PresubmitPromptWarning(
4781 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
4782 ' Please use BuildInfo.isDebugAndroid() instead.', errors))
4783
4784 return results
4785
4786# TODO: add unit tests
4787def _CheckAndroidToastUsage(input_api, output_api):
4788 """Checks that code uses org.chromium.ui.widget.Toast instead of
4789 android.widget.Toast (Chromium Toast doesn't force hardware
4790 acceleration on low-end devices, saving memory).
4791 """
4792 toast_import_pattern = input_api.re.compile(
4793 r'^import android\.widget\.Toast;$')
4794
4795 errors = []
4796
4797 sources = lambda affected_file: input_api.FilterSourceFile(
4798 affected_file,
4799 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
Bruce Dawson40fece62022-09-16 19:58:314800 DEFAULT_FILES_TO_SKIP + (r'^chromecast/.*',
4801 r'^remoting/.*')),
Sam Maiera6e76d72022-02-11 21:43:504802 files_to_check=[r'.*\.java$'])
4803
4804 for f in input_api.AffectedSourceFiles(sources):
4805 for line_num, line in f.ChangedContents():
4806 if toast_import_pattern.search(line):
4807 errors.append("%s:%d" % (f.LocalPath(), line_num))
4808
4809 results = []
4810
4811 if errors:
4812 results.append(
4813 output_api.PresubmitError(
4814 'android.widget.Toast usage is detected. Android toasts use hardware'
4815 ' acceleration, and can be\ncostly on low-end devices. Please use'
4816 ' org.chromium.ui.widget.Toast instead.\n'
4817 'Contact [email protected] if you have any questions.',
4818 errors))
4819
4820 return results
4821
4822
4823def _CheckAndroidCrLogUsage(input_api, output_api):
4824 """Checks that new logs using org.chromium.base.Log:
4825 - Are using 'TAG' as variable name for the tags (warn)
4826 - Are using a tag that is shorter than 20 characters (error)
4827 """
4828
4829 # Do not check format of logs in the given files
4830 cr_log_check_excluded_paths = [
4831 # //chrome/android/webapk cannot depend on //base
Bruce Dawson40fece62022-09-16 19:58:314832 r"^chrome/android/webapk/.*",
Sam Maiera6e76d72022-02-11 21:43:504833 # WebView license viewer code cannot depend on //base; used in stub APK.
Bruce Dawson40fece62022-09-16 19:58:314834 r"^android_webview/glue/java/src/com/android/"
4835 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504836 # The customtabs_benchmark is a small app that does not depend on Chromium
4837 # java pieces.
Bruce Dawson40fece62022-09-16 19:58:314838 r"tools/android/customtabs_benchmark/.*",
Sam Maiera6e76d72022-02-11 21:43:504839 ]
4840
4841 cr_log_import_pattern = input_api.re.compile(
4842 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
4843 class_in_base_pattern = input_api.re.compile(
4844 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
4845 has_some_log_import_pattern = input_api.re.compile(r'^import .*\.Log;$',
4846 input_api.re.MULTILINE)
4847 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
4848 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
4849 log_decl_pattern = input_api.re.compile(
4850 r'static final String TAG = "(?P<name>(.*))"')
4851 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
4852
4853 REF_MSG = ('See docs/android_logging.md for more info.')
4854 sources = lambda x: input_api.FilterSourceFile(
4855 x,
4856 files_to_check=[r'.*\.java$'],
4857 files_to_skip=cr_log_check_excluded_paths)
4858
4859 tag_decl_errors = []
Andrew Grieved3a35d82024-01-02 21:24:384860 tag_length_errors = []
Sam Maiera6e76d72022-02-11 21:43:504861 tag_errors = []
4862 tag_with_dot_errors = []
4863 util_log_errors = []
4864
4865 for f in input_api.AffectedSourceFiles(sources):
4866 file_content = input_api.ReadFile(f)
4867 has_modified_logs = False
4868 # Per line checks
4869 if (cr_log_import_pattern.search(file_content)
4870 or (class_in_base_pattern.search(file_content)
4871 and not has_some_log_import_pattern.search(file_content))):
4872 # Checks to run for files using cr log
4873 for line_num, line in f.ChangedContents():
4874 if rough_log_decl_pattern.search(line):
4875 has_modified_logs = True
4876
4877 # Check if the new line is doing some logging
4878 match = log_call_pattern.search(line)
4879 if match:
4880 has_modified_logs = True
4881
4882 # Make sure it uses "TAG"
4883 if not match.group('tag') == 'TAG':
4884 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
4885 else:
4886 # Report non cr Log function calls in changed lines
4887 for line_num, line in f.ChangedContents():
4888 if log_call_pattern.search(line):
4889 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
4890
4891 # Per file checks
4892 if has_modified_logs:
4893 # Make sure the tag is using the "cr" prefix and is not too long
4894 match = log_decl_pattern.search(file_content)
4895 tag_name = match.group('name') if match else None
4896 if not tag_name:
4897 tag_decl_errors.append(f.LocalPath())
Andrew Grieved3a35d82024-01-02 21:24:384898 elif len(tag_name) > 20:
4899 tag_length_errors.append(f.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:504900 elif '.' in tag_name:
4901 tag_with_dot_errors.append(f.LocalPath())
4902
4903 results = []
4904 if tag_decl_errors:
4905 results.append(
4906 output_api.PresubmitPromptWarning(
4907 'Please define your tags using the suggested format: .\n'
4908 '"private static final String TAG = "<package tag>".\n'
4909 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
4910 tag_decl_errors))
4911
Andrew Grieved3a35d82024-01-02 21:24:384912 if tag_length_errors:
4913 results.append(
4914 output_api.PresubmitError(
4915 'The tag length is restricted by the system to be at most '
4916 '20 characters.\n' + REF_MSG, tag_length_errors))
4917
Sam Maiera6e76d72022-02-11 21:43:504918 if tag_errors:
4919 results.append(
4920 output_api.PresubmitPromptWarning(
4921 'Please use a variable named "TAG" for your log tags.\n' +
4922 REF_MSG, tag_errors))
4923
4924 if util_log_errors:
4925 results.append(
4926 output_api.PresubmitPromptWarning(
4927 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
4928 util_log_errors))
4929
4930 if tag_with_dot_errors:
4931 results.append(
4932 output_api.PresubmitPromptWarning(
4933 'Dot in log tags cause them to be elided in crash reports.\n' +
4934 REF_MSG, tag_with_dot_errors))
4935
4936 return results
4937
4938
Sam Maiera6e76d72022-02-11 21:43:504939def _CheckAndroidTestAnnotationUsage(input_api, output_api):
4940 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
4941 deprecated_annotation_import_pattern = input_api.re.compile(
4942 r'^import android\.test\.suitebuilder\.annotation\..*;',
4943 input_api.re.MULTILINE)
4944 sources = lambda x: input_api.FilterSourceFile(
4945 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
4946 errors = []
4947 for f in input_api.AffectedFiles(file_filter=sources):
4948 for line_num, line in f.ChangedContents():
4949 if deprecated_annotation_import_pattern.search(line):
4950 errors.append("%s:%d" % (f.LocalPath(), line_num))
4951
4952 results = []
4953 if errors:
4954 results.append(
4955 output_api.PresubmitError(
4956 'Annotations in android.test.suitebuilder.annotation have been'
Mohamed Heikal3d7a94c2023-03-28 16:55:244957 ' deprecated since API level 24. Please use androidx.test.filters'
4958 ' from //third_party/androidx:androidx_test_runner_java instead.'
Sam Maiera6e76d72022-02-11 21:43:504959 ' Contact [email protected] if you have any questions.',
4960 errors))
4961 return results
4962
4963
4964def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
4965 """Checks if MDPI assets are placed in a correct directory."""
Anton Bershanskyi4253349482025-02-11 21:01:274966 file_filter = lambda f: (f.UnixLocalPath().endswith(
4967 '.png') and ('/res/drawable/' in f.
4968 UnixLocalPath() or '/res/drawable-ldrtl/' in f.UnixLocalPath()))
Sam Maiera6e76d72022-02-11 21:43:504969 errors = []
4970 for f in input_api.AffectedFiles(include_deletes=False,
4971 file_filter=file_filter):
4972 errors.append(' %s' % f.LocalPath())
4973
4974 results = []
4975 if errors:
4976 results.append(
4977 output_api.PresubmitError(
4978 'MDPI assets should be placed in /res/drawable-mdpi/ or '
4979 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
4980 '/res/drawable-ldrtl/.\n'
4981 'Contact [email protected] if you have questions.', errors))
4982 return results
4983
4984
4985def _CheckAndroidWebkitImports(input_api, output_api):
4986 """Checks that code uses org.chromium.base.Callback instead of
4987 android.webview.ValueCallback except in the WebView glue layer
4988 and WebLayer.
4989 """
4990 valuecallback_import_pattern = input_api.re.compile(
4991 r'^import android\.webkit\.ValueCallback;$')
4992
4993 errors = []
4994
4995 sources = lambda affected_file: input_api.FilterSourceFile(
4996 affected_file,
4997 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4998 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314999 r'^android_webview/glue/.*',
elabadysayedcbbaea72024-08-01 16:10:425000 r'^android_webview/support_library/.*',
Bruce Dawson40fece62022-09-16 19:58:315001 r'^weblayer/.*',
Sam Maiera6e76d72022-02-11 21:43:505002 )),
5003 files_to_check=[r'.*\.java$'])
5004
5005 for f in input_api.AffectedSourceFiles(sources):
5006 for line_num, line in f.ChangedContents():
5007 if valuecallback_import_pattern.search(line):
5008 errors.append("%s:%d" % (f.LocalPath(), line_num))
5009
5010 results = []
5011
5012 if errors:
5013 results.append(
5014 output_api.PresubmitError(
5015 'android.webkit.ValueCallback usage is detected outside of the glue'
5016 ' layer. To stay compatible with the support library, android.webkit.*'
5017 ' classes should only be used inside the glue layer and'
5018 ' org.chromium.base.Callback should be used instead.', errors))
5019
5020 return results
5021
5022
5023def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
5024 """Checks Android XML styles """
5025
5026 # Return early if no relevant files were modified.
5027 if not any(
5028 _IsXmlOrGrdFile(input_api, f.LocalPath())
5029 for f in input_api.AffectedFiles(include_deletes=False)):
5030 return []
5031
5032 import sys
5033 original_sys_path = sys.path
5034 try:
5035 sys.path = sys.path + [
5036 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5037 'android', 'checkxmlstyle')
5038 ]
5039 import checkxmlstyle
5040 finally:
5041 # Restore sys.path to what it was before.
5042 sys.path = original_sys_path
5043
5044 if is_check_on_upload:
5045 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
5046 else:
5047 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
5048
5049
5050def _CheckAndroidInfoBarDeprecation(input_api, output_api):
5051 """Checks Android Infobar Deprecation """
5052
5053 import sys
5054 original_sys_path = sys.path
5055 try:
5056 sys.path = sys.path + [
5057 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5058 'android', 'infobar_deprecation')
5059 ]
5060 import infobar_deprecation
5061 finally:
5062 # Restore sys.path to what it was before.
5063 sys.path = original_sys_path
5064
5065 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
5066
5067
5068class _PydepsCheckerResult:
5069 def __init__(self, cmd, pydeps_path, process, old_contents):
5070 self._cmd = cmd
5071 self._pydeps_path = pydeps_path
5072 self._process = process
5073 self._old_contents = old_contents
5074
5075 def GetError(self):
5076 """Returns an error message, or None."""
5077 import difflib
Andrew Grieved27620b62023-07-13 16:35:075078 new_contents = self._process.stdout.read().splitlines()[2:]
Sam Maiera6e76d72022-02-11 21:43:505079 if self._process.wait() != 0:
5080 # STDERR should already be printed.
5081 return 'Command failed: ' + self._cmd
Sam Maiera6e76d72022-02-11 21:43:505082 if self._old_contents != new_contents:
5083 diff = '\n'.join(
5084 difflib.context_diff(self._old_contents, new_contents))
5085 return ('File is stale: {}\n'
5086 'Diff (apply to fix):\n'
5087 '{}\n'
5088 'To regenerate, run:\n\n'
5089 ' {}').format(self._pydeps_path, diff, self._cmd)
5090 return None
5091
5092
5093class PydepsChecker:
5094 def __init__(self, input_api, pydeps_files):
5095 self._file_cache = {}
5096 self._input_api = input_api
5097 self._pydeps_files = pydeps_files
5098
5099 def _LoadFile(self, path):
5100 """Returns the list of paths within a .pydeps file relative to //."""
5101 if path not in self._file_cache:
5102 with open(path, encoding='utf-8') as f:
5103 self._file_cache[path] = f.read()
5104 return self._file_cache[path]
5105
5106 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
Gao Shenga79ebd42022-08-08 17:25:595107 """Returns an iterable of paths within the .pydep, relativized to //."""
Sam Maiera6e76d72022-02-11 21:43:505108 pydeps_data = self._LoadFile(pydeps_path)
5109 uses_gn_paths = '--gn-paths' in pydeps_data
5110 entries = (l for l in pydeps_data.splitlines()
5111 if not l.startswith('#'))
5112 if uses_gn_paths:
5113 # Paths look like: //foo/bar/baz
5114 return (e[2:] for e in entries)
5115 else:
5116 # Paths look like: path/relative/to/file.pydeps
5117 os_path = self._input_api.os_path
5118 pydeps_dir = os_path.dirname(pydeps_path)
5119 return (os_path.normpath(os_path.join(pydeps_dir, e))
5120 for e in entries)
5121
5122 def _CreateFilesToPydepsMap(self):
5123 """Returns a map of local_path -> list_of_pydeps."""
5124 ret = {}
5125 for pydep_local_path in self._pydeps_files:
5126 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
5127 ret.setdefault(path, []).append(pydep_local_path)
5128 return ret
5129
5130 def ComputeAffectedPydeps(self):
5131 """Returns an iterable of .pydeps files that might need regenerating."""
5132 affected_pydeps = set()
5133 file_to_pydeps_map = None
5134 for f in self._input_api.AffectedFiles(include_deletes=True):
5135 local_path = f.LocalPath()
5136 # Changes to DEPS can lead to .pydeps changes if any .py files are in
5137 # subrepositories. We can't figure out which files change, so re-check
5138 # all files.
5139 # Changes to print_python_deps.py affect all .pydeps.
5140 if local_path in ('DEPS', 'PRESUBMIT.py'
5141 ) or local_path.endswith('print_python_deps.py'):
5142 return self._pydeps_files
5143 elif local_path.endswith('.pydeps'):
5144 if local_path in self._pydeps_files:
5145 affected_pydeps.add(local_path)
5146 elif local_path.endswith('.py'):
5147 if file_to_pydeps_map is None:
5148 file_to_pydeps_map = self._CreateFilesToPydepsMap()
5149 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
5150 return affected_pydeps
5151
5152 def DetermineIfStaleAsync(self, pydeps_path):
5153 """Runs print_python_deps.py to see if the files is stale."""
5154 import os
5155
5156 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
5157 if old_pydeps_data:
5158 cmd = old_pydeps_data[1][1:].strip()
5159 if '--output' not in cmd:
5160 cmd += ' --output ' + pydeps_path
5161 old_contents = old_pydeps_data[2:]
5162 else:
5163 # A default cmd that should work in most cases (as long as pydeps filename
5164 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
5165 # file is empty/new.
5166 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
5167 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
5168 old_contents = []
5169 env = dict(os.environ)
5170 env['PYTHONDONTWRITEBYTECODE'] = '1'
5171 process = self._input_api.subprocess.Popen(
5172 cmd + ' --output ""',
5173 shell=True,
5174 env=env,
5175 stdout=self._input_api.subprocess.PIPE,
5176 encoding='utf-8')
5177 return _PydepsCheckerResult(cmd, pydeps_path, process, old_contents)
agrievef32bcc72016-04-04 14:57:405178
5179
Tibor Goldschwendt360793f72019-06-25 18:23:495180def _ParseGclientArgs():
Sam Maiera6e76d72022-02-11 21:43:505181 args = {}
5182 with open('build/config/gclient_args.gni', 'r') as f:
5183 for line in f:
5184 line = line.strip()
5185 if not line or line.startswith('#'):
5186 continue
5187 attribute, value = line.split('=')
5188 args[attribute.strip()] = value.strip()
5189 return args
Tibor Goldschwendt360793f72019-06-25 18:23:495190
5191
Saagar Sanghavifceeaae2020-08-12 16:40:365192def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
Sam Maiera6e76d72022-02-11 21:43:505193 """Checks if a .pydeps file needs to be regenerated."""
5194 # This check is for Python dependency lists (.pydeps files), and involves
5195 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
5196 # doesn't work on Windows and Mac, so skip it on other platforms.
5197 if not input_api.platform.startswith('linux'):
5198 return []
Erik Staabc734cd7a2021-11-23 03:11:525199
Sam Maiera6e76d72022-02-11 21:43:505200 results = []
5201 # First, check for new / deleted .pydeps.
5202 for f in input_api.AffectedFiles(include_deletes=True):
5203 # Check whether we are running the presubmit check for a file in src.
Sam Maiera6e76d72022-02-11 21:43:505204 if f.LocalPath().endswith('.pydeps'):
Andrew Grieve713b89b2024-10-15 20:20:085205 # f.LocalPath is relative to repo (src, or internal repo).
5206 # os_path.exists is relative to src repo.
5207 # Therefore if os_path.exists is true, it means f.LocalPath is relative
5208 # to src and we can conclude that the pydeps is in src.
5209 exists = input_api.os_path.exists(f.LocalPath())
5210 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
5211 results.append(
5212 output_api.PresubmitError(
5213 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
5214 'remove %s' % f.LocalPath()))
5215 elif (f.Action() != 'D' and exists
5216 and f.LocalPath() not in _ALL_PYDEPS_FILES):
5217 results.append(
5218 output_api.PresubmitError(
5219 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
5220 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:405221
Sam Maiera6e76d72022-02-11 21:43:505222 if results:
5223 return results
5224
Gavin Mak23884402024-07-25 20:39:265225 try:
5226 parsed_args = _ParseGclientArgs()
5227 except FileNotFoundError:
5228 message = (
5229 'build/config/gclient_args.gni not found. Please make sure your '
5230 'workspace has been initialized with gclient sync.'
5231 )
5232 import sys
5233 original_sys_path = sys.path
5234 try:
5235 sys.path = sys.path + [
5236 input_api.os_path.join(input_api.PresubmitLocalPath(),
5237 'third_party', 'depot_tools')
5238 ]
5239 import gclient_utils
5240 if gclient_utils.IsEnvCog():
5241 # Users will always hit this when they run presubmits before cog
5242 # workspace initialization finishes. The check shouldn't fail in
5243 # this case. This is an unavoidable workaround that's needed for
5244 # good presubmit UX for cog.
5245 results.append(output_api.PresubmitPromptWarning(message))
5246 else:
5247 results.append(output_api.PresubmitError(message))
5248 return results
5249 finally:
5250 # Restore sys.path to what it was before.
5251 sys.path = original_sys_path
5252
5253 is_android = parsed_args.get('checkout_android', 'false') == 'true'
Sam Maiera6e76d72022-02-11 21:43:505254 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
5255 affected_pydeps = set(checker.ComputeAffectedPydeps())
5256 affected_android_pydeps = affected_pydeps.intersection(
5257 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
5258 if affected_android_pydeps and not is_android:
5259 results.append(
5260 output_api.PresubmitPromptOrNotify(
5261 'You have changed python files that may affect pydeps for android\n'
Gao Shenga79ebd42022-08-08 17:25:595262 'specific scripts. However, the relevant presubmit check cannot be\n'
Sam Maiera6e76d72022-02-11 21:43:505263 'run because you are not using an Android checkout. To validate that\n'
5264 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
5265 'use the android-internal-presubmit optional trybot.\n'
5266 'Possibly stale pydeps files:\n{}'.format(
5267 '\n'.join(affected_android_pydeps))))
5268
5269 all_pydeps = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
5270 pydeps_to_check = affected_pydeps.intersection(all_pydeps)
5271 # Process these concurrently, as each one takes 1-2 seconds.
5272 pydep_results = [checker.DetermineIfStaleAsync(p) for p in pydeps_to_check]
5273 for result in pydep_results:
5274 error_msg = result.GetError()
5275 if error_msg:
5276 results.append(output_api.PresubmitError(error_msg))
5277
agrievef32bcc72016-04-04 14:57:405278 return results
5279
agrievef32bcc72016-04-04 14:57:405280
Saagar Sanghavifceeaae2020-08-12 16:40:365281def CheckSingletonInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505282 """Checks to make sure no header files have |Singleton<|."""
5283
5284 def FileFilter(affected_file):
5285 # It's ok for base/memory/singleton.h to have |Singleton<|.
5286 files_to_skip = (_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
Bruce Dawson40fece62022-09-16 19:58:315287 (r"^base/memory/singleton\.h$",
5288 r"^net/quic/platform/impl/quic_singleton_impl\.h$"))
Sam Maiera6e76d72022-02-11 21:43:505289 return input_api.FilterSourceFile(affected_file,
5290 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:435291
Sam Maiera6e76d72022-02-11 21:43:505292 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
5293 files = []
5294 for f in input_api.AffectedSourceFiles(FileFilter):
5295 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx')
5296 or f.LocalPath().endswith('.hpp')
5297 or f.LocalPath().endswith('.inl')):
5298 contents = input_api.ReadFile(f)
5299 for line in contents.splitlines(False):
5300 if (not line.lstrip().startswith('//')
5301 and # Strip C++ comment.
5302 pattern.search(line)):
5303 files.append(f)
5304 break
glidere61efad2015-02-18 17:39:435305
Sam Maiera6e76d72022-02-11 21:43:505306 if files:
5307 return [
5308 output_api.PresubmitError(
5309 'Found base::Singleton<T> in the following header files.\n' +
5310 'Please move them to an appropriate source file so that the ' +
5311 'template gets instantiated in a single compilation unit.',
5312 files)
5313 ]
5314 return []
glidere61efad2015-02-18 17:39:435315
5316
[email protected]fd20b902014-05-09 02:14:535317_DEPRECATED_CSS = [
5318 # Values
5319 ( "-webkit-box", "flex" ),
5320 ( "-webkit-inline-box", "inline-flex" ),
5321 ( "-webkit-flex", "flex" ),
5322 ( "-webkit-inline-flex", "inline-flex" ),
5323 ( "-webkit-min-content", "min-content" ),
5324 ( "-webkit-max-content", "max-content" ),
5325
5326 # Properties
5327 ( "-webkit-background-clip", "background-clip" ),
5328 ( "-webkit-background-origin", "background-origin" ),
5329 ( "-webkit-background-size", "background-size" ),
5330 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:445331 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:535332
5333 # Functions
5334 ( "-webkit-gradient", "gradient" ),
5335 ( "-webkit-repeating-gradient", "repeating-gradient" ),
5336 ( "-webkit-linear-gradient", "linear-gradient" ),
5337 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
5338 ( "-webkit-radial-gradient", "radial-gradient" ),
5339 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
5340]
5341
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:205342
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:495343# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:365344def CheckNoDeprecatedCss(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505345 """ Make sure that we don't use deprecated CSS
5346 properties, functions or values. Our external
5347 documentation and iOS CSS for dom distiller
5348 (reader mode) are ignored by the hooks as it
5349 needs to be consumed by WebKit. """
5350 results = []
5351 file_inclusion_pattern = [r".+\.css$"]
5352 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
5353 input_api.DEFAULT_FILES_TO_SKIP +
dpapad7fcdfc42024-12-06 01:21:385354 (# Legacy CSS file using deprecated CSS.
5355 r"^chrome/browser/resources/chromeos/arc_support/cr_overlay.css$",
5356 r"^chrome/common/extensions/docs", r"^chrome/docs",
Teresa Mao1d910882024-04-26 21:06:255357 r"^native_client_sdk",
5358 # The NTP team prefers reserving -webkit-line-clamp for
5359 # ellipsis effect which can only be used with -webkit-box.
5360 r"ui/webui/resources/cr_components/most_visited/.*\.css$"))
Sam Maiera6e76d72022-02-11 21:43:505361 file_filter = lambda f: input_api.FilterSourceFile(
5362 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
5363 for fpath in input_api.AffectedFiles(file_filter=file_filter):
5364 for line_num, line in fpath.ChangedContents():
5365 for (deprecated_value, value) in _DEPRECATED_CSS:
5366 if deprecated_value in line:
5367 results.append(
5368 output_api.PresubmitError(
5369 "%s:%d: Use of deprecated CSS %s, use %s instead" %
5370 (fpath.LocalPath(), line_num, deprecated_value,
5371 value)))
5372 return results
[email protected]fd20b902014-05-09 02:14:535373
mohan.reddyf21db962014-10-16 12:26:475374
Saagar Sanghavifceeaae2020-08-12 16:40:365375def CheckForRelativeIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505376 bad_files = {}
5377 for f in input_api.AffectedFiles(include_deletes=False):
Anton Bershanskyi4253349482025-02-11 21:01:275378 if (f.UnixLocalPath().startswith('third_party')
5379 and not f.LocalPath().startswith('third_party/blink')):
Sam Maiera6e76d72022-02-11 21:43:505380 continue
rlanday6802cf632017-05-30 17:48:365381
Sam Maiera6e76d72022-02-11 21:43:505382 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
5383 continue
rlanday6802cf632017-05-30 17:48:365384
Sam Maiera6e76d72022-02-11 21:43:505385 relative_includes = [
5386 line for _, line in f.ChangedContents()
5387 if "#include" in line and "../" in line
5388 ]
5389 if not relative_includes:
5390 continue
5391 bad_files[f.LocalPath()] = relative_includes
rlanday6802cf632017-05-30 17:48:365392
Sam Maiera6e76d72022-02-11 21:43:505393 if not bad_files:
5394 return []
rlanday6802cf632017-05-30 17:48:365395
Sam Maiera6e76d72022-02-11 21:43:505396 error_descriptions = []
5397 for file_path, bad_lines in bad_files.items():
5398 error_description = file_path
5399 for line in bad_lines:
5400 error_description += '\n ' + line
5401 error_descriptions.append(error_description)
rlanday6802cf632017-05-30 17:48:365402
Sam Maiera6e76d72022-02-11 21:43:505403 results = []
5404 results.append(
5405 output_api.PresubmitError(
5406 'You added one or more relative #include paths (including "../").\n'
5407 'These shouldn\'t be used because they can be used to include headers\n'
5408 'from code that\'s not correctly specified as a dependency in the\n'
5409 'relevant BUILD.gn file(s).', error_descriptions))
rlanday6802cf632017-05-30 17:48:365410
Sam Maiera6e76d72022-02-11 21:43:505411 return results
rlanday6802cf632017-05-30 17:48:365412
Takeshi Yoshinoe387aa32017-08-02 13:16:135413
Saagar Sanghavifceeaae2020-08-12 16:40:365414def CheckForCcIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505415 """Check that nobody tries to include a cc file. It's a relatively
5416 common error which results in duplicate symbols in object
5417 files. This may not always break the build until someone later gets
5418 very confusing linking errors."""
5419 results = []
5420 for f in input_api.AffectedFiles(include_deletes=False):
5421 # We let third_party code do whatever it wants
Anton Bershanskyi4253349482025-02-11 21:01:275422 if (f.UnixLocalPath().startswith('third_party')
5423 and not f.LocalPath().startswith('third_party/blink')):
Sam Maiera6e76d72022-02-11 21:43:505424 continue
Daniel Bratell65b033262019-04-23 08:17:065425
Sam Maiera6e76d72022-02-11 21:43:505426 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
5427 continue
Daniel Bratell65b033262019-04-23 08:17:065428
Sam Maiera6e76d72022-02-11 21:43:505429 for _, line in f.ChangedContents():
5430 if line.startswith('#include "'):
5431 included_file = line.split('"')[1]
5432 if _IsCPlusPlusFile(input_api, included_file):
5433 # The most common naming for external files with C++ code,
5434 # apart from standard headers, is to call them foo.inc, but
5435 # Chromium sometimes uses foo-inc.cc so allow that as well.
5436 if not included_file.endswith(('.h', '-inc.cc')):
5437 results.append(
5438 output_api.PresubmitError(
5439 'Only header files or .inc files should be included in other\n'
5440 'C++ files. Compiling the contents of a cc file more than once\n'
5441 'will cause duplicate information in the build which may later\n'
5442 'result in strange link_errors.\n' +
5443 f.LocalPath() + ':\n ' + line))
Daniel Bratell65b033262019-04-23 08:17:065444
Sam Maiera6e76d72022-02-11 21:43:505445 return results
Daniel Bratell65b033262019-04-23 08:17:065446
5447
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205448def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
Sam Maiera6e76d72022-02-11 21:43:505449 if not isinstance(key, ast.Str):
5450 return 'Key at line %d must be a string literal' % key.lineno
5451 if not isinstance(value, ast.Dict):
5452 return 'Value at line %d must be a dict' % value.lineno
5453 if len(value.keys) != 1:
5454 return 'Dict at line %d must have single entry' % value.lineno
5455 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
5456 return (
5457 'Entry at line %d must have a string literal \'filepath\' as key' %
5458 value.lineno)
5459 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:135460
Takeshi Yoshinoe387aa32017-08-02 13:16:135461
Sergey Ulanov4af16052018-11-08 02:41:465462def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Sam Maiera6e76d72022-02-11 21:43:505463 if not isinstance(key, ast.Str):
5464 return 'Key at line %d must be a string literal' % key.lineno
5465 if not isinstance(value, ast.List):
5466 return 'Value at line %d must be a list' % value.lineno
5467 for element in value.elts:
5468 if not isinstance(element, ast.Str):
5469 return 'Watchlist elements on line %d is not a string' % key.lineno
5470 if not email_regex.match(element.s):
5471 return ('Watchlist element on line %d doesn\'t look like a valid '
5472 + 'email: %s') % (key.lineno, element.s)
5473 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:135474
Takeshi Yoshinoe387aa32017-08-02 13:16:135475
Sergey Ulanov4af16052018-11-08 02:41:465476def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Sam Maiera6e76d72022-02-11 21:43:505477 mismatch_template = (
5478 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
5479 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:135480
Sam Maiera6e76d72022-02-11 21:43:505481 email_regex = input_api.re.compile(
5482 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
Sergey Ulanov4af16052018-11-08 02:41:465483
Sam Maiera6e76d72022-02-11 21:43:505484 ast = input_api.ast
5485 i = 0
5486 last_key = ''
5487 while True:
5488 if i >= len(wd_dict.keys):
5489 if i >= len(w_dict.keys):
5490 return None
5491 return mismatch_template % ('missing',
5492 'line %d' % w_dict.keys[i].lineno)
5493 elif i >= len(w_dict.keys):
5494 return (mismatch_template %
5495 ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:135496
Sam Maiera6e76d72022-02-11 21:43:505497 wd_key = wd_dict.keys[i]
5498 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:135499
Sam Maiera6e76d72022-02-11 21:43:505500 result = _CheckWatchlistDefinitionsEntrySyntax(wd_key,
5501 wd_dict.values[i], ast)
5502 if result is not None:
5503 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:135504
Sam Maiera6e76d72022-02-11 21:43:505505 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast,
5506 email_regex)
5507 if result is not None:
5508 return 'Bad entry in WATCHLISTS dict: %s' % result
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205509
Sam Maiera6e76d72022-02-11 21:43:505510 if wd_key.s != w_key.s:
5511 return mismatch_template % ('%s at line %d' %
5512 (wd_key.s, wd_key.lineno),
5513 '%s at line %d' %
5514 (w_key.s, w_key.lineno))
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205515
Sam Maiera6e76d72022-02-11 21:43:505516 if wd_key.s < last_key:
5517 return (
5518 'WATCHLISTS dict is not sorted lexicographically at line %d and %d'
5519 % (wd_key.lineno, w_key.lineno))
5520 last_key = wd_key.s
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205521
Sam Maiera6e76d72022-02-11 21:43:505522 i = i + 1
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205523
5524
Sergey Ulanov4af16052018-11-08 02:41:465525def _CheckWATCHLISTSSyntax(expression, input_api):
Sam Maiera6e76d72022-02-11 21:43:505526 ast = input_api.ast
5527 if not isinstance(expression, ast.Expression):
5528 return 'WATCHLISTS file must contain a valid expression'
5529 dictionary = expression.body
5530 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
5531 return 'WATCHLISTS file must have single dict with exactly two entries'
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205532
Sam Maiera6e76d72022-02-11 21:43:505533 first_key = dictionary.keys[0]
5534 first_value = dictionary.values[0]
5535 second_key = dictionary.keys[1]
5536 second_value = dictionary.values[1]
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205537
Sam Maiera6e76d72022-02-11 21:43:505538 if (not isinstance(first_key, ast.Str)
5539 or first_key.s != 'WATCHLIST_DEFINITIONS'
5540 or not isinstance(first_value, ast.Dict)):
5541 return ('The first entry of the dict in WATCHLISTS file must be '
5542 'WATCHLIST_DEFINITIONS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205543
Sam Maiera6e76d72022-02-11 21:43:505544 if (not isinstance(second_key, ast.Str) or second_key.s != 'WATCHLISTS'
5545 or not isinstance(second_value, ast.Dict)):
5546 return ('The second entry of the dict in WATCHLISTS file must be '
5547 'WATCHLISTS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205548
Sam Maiera6e76d72022-02-11 21:43:505549 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:135550
5551
Saagar Sanghavifceeaae2020-08-12 16:40:365552def CheckWATCHLISTS(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505553 for f in input_api.AffectedFiles(include_deletes=False):
5554 if f.LocalPath() == 'WATCHLISTS':
5555 contents = input_api.ReadFile(f, 'r')
Takeshi Yoshinoe387aa32017-08-02 13:16:135556
Sam Maiera6e76d72022-02-11 21:43:505557 try:
5558 # First, make sure that it can be evaluated.
5559 input_api.ast.literal_eval(contents)
5560 # Get an AST tree for it and scan the tree for detailed style checking.
5561 expression = input_api.ast.parse(contents,
5562 filename='WATCHLISTS',
5563 mode='eval')
5564 except ValueError as e:
5565 return [
5566 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5567 long_text=repr(e))
5568 ]
5569 except SyntaxError as e:
5570 return [
5571 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5572 long_text=repr(e))
5573 ]
5574 except TypeError as e:
5575 return [
5576 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5577 long_text=repr(e))
5578 ]
Takeshi Yoshinoe387aa32017-08-02 13:16:135579
Sam Maiera6e76d72022-02-11 21:43:505580 result = _CheckWATCHLISTSSyntax(expression, input_api)
5581 if result is not None:
5582 return [output_api.PresubmitError(result)]
5583 break
Takeshi Yoshinoe387aa32017-08-02 13:16:135584
Sam Maiera6e76d72022-02-11 21:43:505585 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:135586
Sean Kaucb7c9b32022-10-25 21:25:525587def CheckGnRebasePath(input_api, output_api):
Terrence Reilly313f44ff2025-01-22 15:10:145588 """Checks that target_gen_dir is not used with "//" in rebase_path().
Sean Kaucb7c9b32022-10-25 21:25:525589
5590 Developers should use root_build_dir instead of "//" when using target_gen_dir because
5591 Chromium is sometimes built outside of the source tree.
5592 """
5593
5594 def gn_files(f):
5595 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
5596
5597 rebase_path_regex = input_api.re.compile(r'rebase_path\(("\$target_gen_dir"|target_gen_dir), ("/"|"//")\)')
5598 problems = []
5599 for f in input_api.AffectedSourceFiles(gn_files):
5600 for line_num, line in f.ChangedContents():
5601 if rebase_path_regex.search(line):
5602 problems.append(
5603 'Absolute path in rebase_path() in %s:%d' %
5604 (f.LocalPath(), line_num))
5605
5606 if problems:
5607 return [
5608 output_api.PresubmitPromptWarning(
5609 'Using an absolute path in rebase_path()',
5610 items=sorted(problems),
5611 long_text=(
5612 'rebase_path() should use root_build_dir instead of "/" ',
5613 'since builds can be initiated from outside of the source ',
5614 'root.'))
5615 ]
5616 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:135617
Andrew Grieve1b290e4a22020-11-24 20:07:015618def CheckGnGlobForward(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505619 """Checks that forward_variables_from(invoker, "*") follows best practices.
Andrew Grieve1b290e4a22020-11-24 20:07:015620
Sam Maiera6e76d72022-02-11 21:43:505621 As documented at //build/docs/writing_gn_templates.md
5622 """
Andrew Grieve1b290e4a22020-11-24 20:07:015623
Sam Maiera6e76d72022-02-11 21:43:505624 def gn_files(f):
5625 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
Andrew Grieve1b290e4a22020-11-24 20:07:015626
Sam Maiera6e76d72022-02-11 21:43:505627 problems = []
5628 for f in input_api.AffectedSourceFiles(gn_files):
5629 for line_num, line in f.ChangedContents():
5630 if 'forward_variables_from(invoker, "*")' in line:
5631 problems.append(
5632 'Bare forward_variables_from(invoker, "*") in %s:%d' %
5633 (f.LocalPath(), line_num))
5634
5635 if problems:
5636 return [
5637 output_api.PresubmitPromptWarning(
5638 'forward_variables_from("*") without exclusions',
5639 items=sorted(problems),
5640 long_text=(
Gao Shenga79ebd42022-08-08 17:25:595641 'The variables "visibility" and "test_only" should be '
Sam Maiera6e76d72022-02-11 21:43:505642 'explicitly listed in forward_variables_from(). For more '
5643 'details, see:\n'
5644 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
5645 'build/docs/writing_gn_templates.md'
5646 '#Using-forward_variables_from'))
5647 ]
5648 return []
Andrew Grieve1b290e4a22020-11-24 20:07:015649
Saagar Sanghavifceeaae2020-08-12 16:40:365650def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505651 """Checks that newly added header files have corresponding GN changes.
5652 Note that this is only a heuristic. To be precise, run script:
5653 build/check_gn_headers.py.
5654 """
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195655
Sam Maiera6e76d72022-02-11 21:43:505656 def headers(f):
5657 return input_api.FilterSourceFile(
5658 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195659
Sam Maiera6e76d72022-02-11 21:43:505660 new_headers = []
5661 for f in input_api.AffectedSourceFiles(headers):
5662 if f.Action() != 'A':
5663 continue
5664 new_headers.append(f.LocalPath())
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195665
Sam Maiera6e76d72022-02-11 21:43:505666 def gn_files(f):
5667 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195668
Sam Maiera6e76d72022-02-11 21:43:505669 all_gn_changed_contents = ''
5670 for f in input_api.AffectedSourceFiles(gn_files):
5671 for _, line in f.ChangedContents():
5672 all_gn_changed_contents += line
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195673
Sam Maiera6e76d72022-02-11 21:43:505674 problems = []
5675 for header in new_headers:
5676 basename = input_api.os_path.basename(header)
5677 if basename not in all_gn_changed_contents:
5678 problems.append(header)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195679
Sam Maiera6e76d72022-02-11 21:43:505680 if problems:
5681 return [
5682 output_api.PresubmitPromptWarning(
5683 'Missing GN changes for new header files',
5684 items=sorted(problems),
5685 long_text=
5686 'Please double check whether newly added header files need '
5687 'corresponding changes in gn or gni files.\nThis checking is only a '
5688 'heuristic. Run build/check_gn_headers.py to be precise.\n'
5689 'Read https://crbug.com/661774 for more info.')
5690 ]
5691 return []
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195692
5693
Saagar Sanghavifceeaae2020-08-12 16:40:365694def CheckCorrectProductNameInMessages(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505695 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
Michael Giuffridad3bc8672018-10-25 22:48:025696
Sam Maiera6e76d72022-02-11 21:43:505697 This assumes we won't intentionally reference one product from the other
5698 product.
5699 """
5700 all_problems = []
5701 test_cases = [{
5702 "filename_postfix": "google_chrome_strings.grd",
5703 "correct_name": "Chrome",
5704 "incorrect_name": "Chromium",
5705 }, {
Thiago Perrotta099034f2023-06-05 18:10:205706 "filename_postfix": "google_chrome_strings.grd",
5707 "correct_name": "Chrome",
5708 "incorrect_name": "Chrome for Testing",
5709 }, {
Sam Maiera6e76d72022-02-11 21:43:505710 "filename_postfix": "chromium_strings.grd",
5711 "correct_name": "Chromium",
5712 "incorrect_name": "Chrome",
5713 }]
Michael Giuffridad3bc8672018-10-25 22:48:025714
Sam Maiera6e76d72022-02-11 21:43:505715 for test_case in test_cases:
5716 problems = []
5717 filename_filter = lambda x: x.LocalPath().endswith(test_case[
5718 "filename_postfix"])
Michael Giuffridad3bc8672018-10-25 22:48:025719
Sam Maiera6e76d72022-02-11 21:43:505720 # Check each new line. Can yield false positives in multiline comments, but
5721 # easier than trying to parse the XML because messages can have nested
5722 # children, and associating message elements with affected lines is hard.
5723 for f in input_api.AffectedSourceFiles(filename_filter):
5724 for line_num, line in f.ChangedContents():
5725 if "<message" in line or "<!--" in line or "-->" in line:
5726 continue
5727 if test_case["incorrect_name"] in line:
Thiago Perrotta099034f2023-06-05 18:10:205728 # Chrome for Testing is a special edge case: https://goo.gle/chrome-for-testing#bookmark=id.n1rat320av91
5729 if (test_case["correct_name"] == "Chromium" and line.count("Chrome") == line.count("Chrome for Testing")):
5730 continue
Sam Maiera6e76d72022-02-11 21:43:505731 problems.append("Incorrect product name in %s:%d" %
5732 (f.LocalPath(), line_num))
Michael Giuffridad3bc8672018-10-25 22:48:025733
Sam Maiera6e76d72022-02-11 21:43:505734 if problems:
5735 message = (
5736 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
5737 % (test_case["correct_name"], test_case["correct_name"],
5738 test_case["incorrect_name"]))
5739 all_problems.append(
5740 output_api.PresubmitPromptWarning(message, items=problems))
Michael Giuffridad3bc8672018-10-25 22:48:025741
Sam Maiera6e76d72022-02-11 21:43:505742 return all_problems
Michael Giuffridad3bc8672018-10-25 22:48:025743
5744
Saagar Sanghavifceeaae2020-08-12 16:40:365745def CheckForTooLargeFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505746 """Avoid large files, especially binary files, in the repository since
5747 git doesn't scale well for those. They will be in everyone's repo
5748 clones forever, forever making Chromium slower to clone and work
5749 with."""
Daniel Bratell93eb6c62019-04-29 20:13:365750
Sam Maiera6e76d72022-02-11 21:43:505751 # Uploading files to cloud storage is not trivial so we don't want
5752 # to set the limit too low, but the upper limit for "normal" large
5753 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
5754 # anything over 20 MB is exceptional.
Bruce Dawsonbb414db2022-12-27 20:21:255755 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024
Daniel Bratell93eb6c62019-04-29 20:13:365756
Sam Maiera6e76d72022-02-11 21:43:505757 too_large_files = []
5758 for f in input_api.AffectedFiles():
5759 # Check both added and modified files (but not deleted files).
5760 if f.Action() in ('A', 'M'):
5761 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Joe DeBlasio10a832f2023-04-21 20:20:185762 if size > TOO_LARGE_FILE_SIZE_LIMIT:
Sam Maiera6e76d72022-02-11 21:43:505763 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
Daniel Bratell93eb6c62019-04-29 20:13:365764
Sam Maiera6e76d72022-02-11 21:43:505765 if too_large_files:
5766 message = (
5767 'Do not commit large files to git since git scales badly for those.\n'
5768 +
5769 'Instead put the large files in cloud storage and use DEPS to\n' +
5770 'fetch them.\n' + '\n'.join(too_large_files))
5771 return [
5772 output_api.PresubmitError('Too large files found in commit',
5773 long_text=message + '\n')
5774 ]
5775 else:
5776 return []
Daniel Bratell93eb6c62019-04-29 20:13:365777
Max Morozb47503b2019-08-08 21:03:275778
Saagar Sanghavifceeaae2020-08-12 16:40:365779def CheckFuzzTargetsOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505780 """Checks specific for fuzz target sources."""
5781 EXPORTED_SYMBOLS = [
5782 'LLVMFuzzerInitialize',
5783 'LLVMFuzzerCustomMutator',
5784 'LLVMFuzzerCustomCrossOver',
5785 'LLVMFuzzerMutate',
5786 ]
Max Morozb47503b2019-08-08 21:03:275787
Sam Maiera6e76d72022-02-11 21:43:505788 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
Max Morozb47503b2019-08-08 21:03:275789
Sam Maiera6e76d72022-02-11 21:43:505790 def FilterFile(affected_file):
5791 """Ignore libFuzzer source code."""
5792 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
Bruce Dawson40fece62022-09-16 19:58:315793 files_to_skip = r"^third_party/libFuzzer"
Max Morozb47503b2019-08-08 21:03:275794
Sam Maiera6e76d72022-02-11 21:43:505795 return input_api.FilterSourceFile(affected_file,
5796 files_to_check=[files_to_check],
5797 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:275798
Sam Maiera6e76d72022-02-11 21:43:505799 files_with_missing_header = []
5800 for f in input_api.AffectedSourceFiles(FilterFile):
5801 contents = input_api.ReadFile(f, 'r')
5802 if REQUIRED_HEADER in contents:
5803 continue
Max Morozb47503b2019-08-08 21:03:275804
Sam Maiera6e76d72022-02-11 21:43:505805 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
5806 files_with_missing_header.append(f.LocalPath())
Max Morozb47503b2019-08-08 21:03:275807
Sam Maiera6e76d72022-02-11 21:43:505808 if not files_with_missing_header:
5809 return []
Max Morozb47503b2019-08-08 21:03:275810
Sam Maiera6e76d72022-02-11 21:43:505811 long_text = (
5812 'If you define any of the libFuzzer optional functions (%s), it is '
5813 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
5814 'work incorrectly on Mac (crbug.com/687076).\nNote that '
5815 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
5816 'to access command line arguments passed to the fuzzer. Instead, prefer '
5817 'static initialization and shared resources as documented in '
5818 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
5819 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n'
5820 % (', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER))
Max Morozb47503b2019-08-08 21:03:275821
Sam Maiera6e76d72022-02-11 21:43:505822 return [
5823 output_api.PresubmitPromptWarning(message="Missing '%s' in:" %
5824 REQUIRED_HEADER,
5825 items=files_with_missing_header,
5826 long_text=long_text)
5827 ]
Max Morozb47503b2019-08-08 21:03:275828
5829
Mohamed Heikald048240a2019-11-12 16:57:375830def _CheckNewImagesWarning(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505831 """
5832 Warns authors who add images into the repo to make sure their images are
5833 optimized before committing.
5834 """
5835 images_added = False
5836 image_paths = []
5837 errors = []
5838 filter_lambda = lambda x: input_api.FilterSourceFile(
5839 x,
5840 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
5841 DEFAULT_FILES_TO_SKIP),
5842 files_to_check=[r'.*\/(drawable|mipmap)'])
5843 for f in input_api.AffectedFiles(include_deletes=False,
5844 file_filter=filter_lambda):
5845 local_path = f.LocalPath().lower()
5846 if any(
5847 local_path.endswith(extension)
5848 for extension in _IMAGE_EXTENSIONS):
5849 images_added = True
5850 image_paths.append(f)
5851 if images_added:
5852 errors.append(
5853 output_api.PresubmitPromptWarning(
5854 'It looks like you are trying to commit some images. If these are '
5855 'non-test-only images, please make sure to read and apply the tips in '
5856 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
5857 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
5858 'FYI only and will not block your CL on the CQ.', image_paths))
5859 return errors
Mohamed Heikald048240a2019-11-12 16:57:375860
5861
Saagar Sanghavifceeaae2020-08-12 16:40:365862def ChecksAndroidSpecificOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505863 """Groups upload checks that target android code."""
5864 results = []
5865 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
5866 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
5867 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
5868 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505869 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
5870 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
5871 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
5872 results.extend(_CheckNewImagesWarning(input_api, output_api))
5873 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
5874 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
5875 return results
5876
Becky Zhou7c69b50992018-12-10 19:37:575877
Saagar Sanghavifceeaae2020-08-12 16:40:365878def ChecksAndroidSpecificOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505879 """Groups commit checks that target android code."""
5880 results = []
5881 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
5882 return results
dgnaa68d5e2015-06-10 10:08:225883
Chris Hall59f8d0c72020-05-01 07:31:195884# TODO(chrishall): could we additionally match on any path owned by
5885# ui/accessibility/OWNERS ?
5886_ACCESSIBILITY_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:315887 r"^chrome/browser.*/accessibility/",
5888 r"^chrome/browser/extensions/api/automation.*/",
5889 r"^chrome/renderer/extensions/accessibility_.*",
5890 r"^chrome/tests/data/accessibility/",
5891 r"^content/browser/accessibility/",
5892 r"^content/renderer/accessibility/",
5893 r"^content/tests/data/accessibility/",
5894 r"^extensions/renderer/api/automation/",
Katie Dektar58ef07b2022-09-27 13:19:175895 r"^services/accessibility/",
Abigail Klein7a63c572024-02-28 20:45:095896 r"^services/screen_ai/",
Bruce Dawson40fece62022-09-16 19:58:315897 r"^ui/accessibility/",
5898 r"^ui/views/accessibility/",
Chris Hall59f8d0c72020-05-01 07:31:195899)
5900
Saagar Sanghavifceeaae2020-08-12 16:40:365901def CheckAccessibilityRelnotesField(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505902 """Checks that commits to accessibility code contain an AX-Relnotes field in
5903 their commit message."""
Chris Hall59f8d0c72020-05-01 07:31:195904
Sam Maiera6e76d72022-02-11 21:43:505905 def FileFilter(affected_file):
5906 paths = _ACCESSIBILITY_PATHS
5907 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:195908
Sam Maiera6e76d72022-02-11 21:43:505909 # Only consider changes affecting accessibility paths.
5910 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
5911 return []
Akihiro Ota08108e542020-05-20 15:30:535912
Sam Maiera6e76d72022-02-11 21:43:505913 # AX-Relnotes can appear in either the description or the footer.
5914 # When searching the description, require 'AX-Relnotes:' to appear at the
5915 # beginning of a line.
5916 ax_regex = input_api.re.compile('ax-relnotes[:=]')
5917 description_has_relnotes = any(
5918 ax_regex.match(line)
5919 for line in input_api.change.DescriptionText().lower().splitlines())
Chris Hall59f8d0c72020-05-01 07:31:195920
Sam Maiera6e76d72022-02-11 21:43:505921 footer_relnotes = input_api.change.GitFootersFromDescription().get(
5922 'AX-Relnotes', [])
5923 if description_has_relnotes or footer_relnotes:
5924 return []
Chris Hall59f8d0c72020-05-01 07:31:195925
Sam Maiera6e76d72022-02-11 21:43:505926 # TODO(chrishall): link to Relnotes documentation in message.
5927 message = (
5928 "Missing 'AX-Relnotes:' field required for accessibility changes"
5929 "\n please add 'AX-Relnotes: [release notes].' to describe any "
5930 "user-facing changes"
5931 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
5932 "user-facing effects"
5933 "\n if this is confusing or annoying then please contact members "
5934 "of ui/accessibility/OWNERS.")
5935
5936 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:225937
Mark Schillaci44c90b42024-11-22 20:44:385938
5939_ACCESSIBILITY_ARIA_METHOD_CANDIDATES_PATTERNS = r'(\-\>|\.)(get|has|FastGet|FastHas)Attribute\('
5940
5941_ACCESSIBILITY_ARIA_BAD_PARAMS_PATTERNS = (
5942 r"\(html_names::kAria(.*)Attr\)",
5943 r"\(html_names::kRoleAttr\)"
5944)
5945
5946_ACCESSIBILITY_ARIA_FILE_CANDIDATES_PATTERNS = (
5947 r".*/accessibility/.*.(cc|h)",
5948 r".*/ax_.*.(cc|h)"
5949)
5950
5951def CheckAccessibilityAriaElementAttributeGetters(input_api, output_api):
5952 """Checks that the blink accessibility code follows the defined patterns
5953 for checking aria attributes, so that ElementInternals is not bypassed."""
5954
5955 # Limit to accessibility-related files.
5956 def FileFilter(affected_file):
5957 paths = _ACCESSIBILITY_ARIA_FILE_CANDIDATES_PATTERNS
5958 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
5959
5960 aria_method_regex = input_api.re.compile(_ACCESSIBILITY_ARIA_METHOD_CANDIDATES_PATTERNS)
5961 aria_bad_params_regex = input_api.re.compile(
5962 "|".join(_ACCESSIBILITY_ARIA_BAD_PARAMS_PATTERNS)
5963 )
5964 problems = []
5965
5966 for f in input_api.AffectedSourceFiles(FileFilter):
5967 for line_num, line in f.ChangedContents():
5968 if aria_method_regex.search(line) and aria_bad_params_regex.search(line):
5969 problems.append(f"{f.LocalPath()}:{line_num}\n {line.strip()}")
5970
5971 if problems:
5972 return [
5973 output_api.PresubmitPromptWarning(
5974 "Accessibility code should not use element methods to get or check"
5975 "\nthe presence of aria attributes"
5976 "\nPlease use ARIA-specific attribute access, e.g. HasAriaAttribute(),"
5977 "\nAriaTokenAttribute(), AriaBoolAttribute(), AriaBooleanAttribute(),"
5978 "\nAriaFloatAttribute().",
5979 problems,
5980 )
5981 ]
5982 return []
5983
seanmccullough4a9356252021-04-08 19:54:095984# string pattern, sequence of strings to show when pattern matches,
5985# error flag. True if match is a presubmit error, otherwise it's a warning.
5986_NON_INCLUSIVE_TERMS = (
5987 (
5988 # Note that \b pattern in python re is pretty particular. In this
5989 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
5990 # ...' will not. This may require some tweaking to catch these cases
5991 # without triggering a lot of false positives. Leaving it naive and
5992 # less matchy for now.
Josip Sokcevic9d2806a02023-12-13 03:04:025993 r'/(?i)\b((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:095994 (
5995 'Please don\'t use blacklist, whitelist, ' # nocheck
5996 'or slave in your', # nocheck
5997 'code and make every effort to use other terms. Using "// nocheck"',
5998 '"# nocheck" or "<!-- nocheck -->"',
5999 'at the end of the offending line will bypass this PRESUBMIT error',
6000 'but avoid using this whenever possible. Reach out to',
6001 '[email protected] if you have questions'),
6002 True),)
6003
Saagar Sanghavifceeaae2020-08-12 16:40:366004def ChecksCommon(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506005 """Checks common to both upload and commit."""
6006 results = []
Eric Boren6fd2b932018-01-25 15:05:086007 results.extend(
Sam Maiera6e76d72022-02-11 21:43:506008 input_api.canned_checks.PanProjectChecks(
6009 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:086010
Sam Maiera6e76d72022-02-11 21:43:506011 author = input_api.change.author_email
6012 if author and author not in _KNOWN_ROBOTS:
6013 results.extend(
6014 input_api.canned_checks.CheckAuthorizedAuthor(
6015 input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:246016
Sam Maiera6e76d72022-02-11 21:43:506017 results.extend(
6018 input_api.canned_checks.CheckChangeHasNoTabs(
6019 input_api,
6020 output_api,
6021 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
6022 results.extend(
6023 input_api.RunTests(
6024 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Edward Lesmesce51df52020-08-04 22:10:176025
Bruce Dawsonc8054482022-03-28 15:33:376026 dirmd = 'dirmd.bat' if input_api.is_windows else 'dirmd'
Sam Maiera6e76d72022-02-11 21:43:506027 dirmd_bin = input_api.os_path.join(input_api.PresubmitLocalPath(),
Bruce Dawsonc8054482022-03-28 15:33:376028 'third_party', 'depot_tools', dirmd)
Sam Maiera6e76d72022-02-11 21:43:506029 results.extend(
6030 input_api.RunTests(
6031 input_api.canned_checks.CheckDirMetadataFormat(
6032 input_api, output_api, dirmd_bin)))
6033 results.extend(
6034 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
6035 input_api, output_api))
6036 results.extend(
6037 input_api.canned_checks.CheckNoNewMetadataInOwners(
6038 input_api, output_api))
6039 results.extend(
6040 input_api.canned_checks.CheckInclusiveLanguage(
6041 input_api,
6042 output_api,
6043 excluded_directories_relative_path=[
6044 'infra', 'inclusive_language_presubmit_exempt_dirs.txt'
6045 ],
6046 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Dirk Prankee3c9c62d2021-05-18 18:35:596047
Aleksey Khoroshilov2978c942022-06-13 16:14:126048 presubmit_py_filter = lambda f: input_api.FilterSourceFile(
Bruce Dawson696963f2022-09-13 01:15:476049 f, files_to_check=[r'.*PRESUBMIT\.py$'])
Aleksey Khoroshilov2978c942022-06-13 16:14:126050 for f in input_api.AffectedFiles(include_deletes=False,
6051 file_filter=presubmit_py_filter):
6052 full_path = input_api.os_path.dirname(f.AbsoluteLocalPath())
6053 test_file = input_api.os_path.join(full_path, 'PRESUBMIT_test.py')
6054 # The PRESUBMIT.py file (and the directory containing it) might have
6055 # been affected by being moved or removed, so only try to run the tests
6056 # if they still exist.
6057 if not input_api.os_path.exists(test_file):
6058 continue
Sam Maiera6e76d72022-02-11 21:43:506059
Aleksey Khoroshilov2978c942022-06-13 16:14:126060 results.extend(
6061 input_api.canned_checks.RunUnitTestsInDirectory(
6062 input_api,
6063 output_api,
6064 full_path,
Takuto Ikuta40def482023-06-02 02:23:496065 files_to_check=[r'^PRESUBMIT_test\.py$']))
Sam Maiera6e76d72022-02-11 21:43:506066 return results
[email protected]1f7b4172010-01-28 01:17:346067
[email protected]b337cb5b2011-01-23 21:24:056068
Saagar Sanghavifceeaae2020-08-12 16:40:366069def CheckPatchFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506070 problems = [
6071 f.LocalPath() for f in input_api.AffectedFiles()
6072 if f.LocalPath().endswith(('.orig', '.rej'))
6073 ]
6074 # Cargo.toml.orig files are part of third-party crates downloaded from
6075 # crates.io and should be included.
6076 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
6077 if problems:
6078 return [
6079 output_api.PresubmitError("Don't commit .rej and .orig files.",
6080 problems)
6081 ]
6082 else:
6083 return []
[email protected]b8079ae4a2012-12-05 19:56:496084
6085
Saagar Sanghavifceeaae2020-08-12 16:40:366086def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506087 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
6088 macro_re = input_api.re.compile(
6089 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
6090 include_re = input_api.re.compile(r'^#include\s+"build/build_config.h"',
6091 input_api.re.MULTILINE)
6092 extension_re = input_api.re.compile(r'\.[a-z]+$')
6093 errors = []
Bruce Dawsonf7679202022-08-09 20:24:006094 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:506095 for f in input_api.AffectedFiles(include_deletes=False):
Bruce Dawsonf7679202022-08-09 20:24:006096 # The build-config macros are allowed to be used in build_config.h
6097 # without including itself.
6098 if f.LocalPath() == config_h_file:
6099 continue
Sam Maiera6e76d72022-02-11 21:43:506100 if not f.LocalPath().endswith(
6101 ('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
6102 continue
Arthur Sonzognia3dec412024-04-29 12:05:376103
Sam Maiera6e76d72022-02-11 21:43:506104 found_line_number = None
6105 found_macro = None
6106 all_lines = input_api.ReadFile(f, 'r').splitlines()
6107 for line_num, line in enumerate(all_lines):
6108 match = macro_re.search(line)
6109 if match:
6110 found_line_number = line_num
6111 found_macro = match.group(2)
6112 break
6113 if not found_line_number:
6114 continue
Kent Tamura5a8755d2017-06-29 23:37:076115
Sam Maiera6e76d72022-02-11 21:43:506116 found_include_line = -1
6117 for line_num, line in enumerate(all_lines):
6118 if include_re.search(line):
6119 found_include_line = line_num
6120 break
6121 if found_include_line >= 0 and found_include_line < found_line_number:
6122 continue
Kent Tamura5a8755d2017-06-29 23:37:076123
Sam Maiera6e76d72022-02-11 21:43:506124 if not f.LocalPath().endswith('.h'):
6125 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
6126 try:
6127 content = input_api.ReadFile(primary_header_path, 'r')
6128 if include_re.search(content):
6129 continue
6130 except IOError:
6131 pass
6132 errors.append('%s:%d %s macro is used without first including build/'
6133 'build_config.h.' %
6134 (f.LocalPath(), found_line_number, found_macro))
6135 if errors:
6136 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
6137 return []
Kent Tamura5a8755d2017-06-29 23:37:076138
6139
Lei Zhang1c12a22f2021-05-12 11:28:456140def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506141 stl_include_re = input_api.re.compile(r'^#include\s+<('
6142 r'algorithm|'
6143 r'array|'
6144 r'limits|'
6145 r'list|'
6146 r'map|'
6147 r'memory|'
6148 r'queue|'
6149 r'set|'
6150 r'string|'
6151 r'unordered_map|'
6152 r'unordered_set|'
6153 r'utility|'
6154 r'vector)>')
6155 std_namespace_re = input_api.re.compile(r'std::')
6156 errors = []
6157 for f in input_api.AffectedFiles():
6158 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
6159 continue
Lei Zhang1c12a22f2021-05-12 11:28:456160
Sam Maiera6e76d72022-02-11 21:43:506161 uses_std_namespace = False
6162 has_stl_include = False
6163 for line in f.NewContents():
6164 if has_stl_include and uses_std_namespace:
6165 break
Lei Zhang1c12a22f2021-05-12 11:28:456166
Sam Maiera6e76d72022-02-11 21:43:506167 if not has_stl_include and stl_include_re.search(line):
6168 has_stl_include = True
6169 continue
Lei Zhang1c12a22f2021-05-12 11:28:456170
Bruce Dawson4a5579a2022-04-08 17:11:366171 if not uses_std_namespace and (std_namespace_re.search(line)
6172 or 'no-std-usage-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:506173 uses_std_namespace = True
6174 continue
Lei Zhang1c12a22f2021-05-12 11:28:456175
Sam Maiera6e76d72022-02-11 21:43:506176 if has_stl_include and not uses_std_namespace:
6177 errors.append(
6178 '%s: Includes STL header(s) but does not reference std::' %
6179 f.LocalPath())
6180 if errors:
6181 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
6182 return []
Lei Zhang1c12a22f2021-05-12 11:28:456183
6184
Xiaohan Wang42d96c22022-01-20 17:23:116185def _CheckForDeprecatedOSMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:506186 """Check for sensible looking, totally invalid OS macros."""
6187 preprocessor_statement = input_api.re.compile(r'^\s*#')
6188 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
6189 results = []
6190 for lnum, line in f.ChangedContents():
6191 if preprocessor_statement.search(line):
6192 for match in os_macro.finditer(line):
6193 results.append(
6194 ' %s:%d: %s' %
6195 (f.LocalPath(), lnum, 'defined(OS_' + match.group(1) +
6196 ') -> BUILDFLAG(IS_' + match.group(1) + ')'))
6197 return results
[email protected]b00342e7f2013-03-26 16:21:546198
6199
Xiaohan Wang42d96c22022-01-20 17:23:116200def CheckForDeprecatedOSMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506201 """Check all affected files for invalid OS macros."""
6202 bad_macros = []
Bruce Dawsonf7679202022-08-09 20:24:006203 # The OS_ macros are allowed to be used in build/build_config.h.
6204 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:506205 for f in input_api.AffectedSourceFiles(None):
Bruce Dawsonf7679202022-08-09 20:24:006206 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')) \
6207 and f.LocalPath() != config_h_file:
Sam Maiera6e76d72022-02-11 21:43:506208 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
[email protected]b00342e7f2013-03-26 16:21:546209
Sam Maiera6e76d72022-02-11 21:43:506210 if not bad_macros:
6211 return []
[email protected]b00342e7f2013-03-26 16:21:546212
Sam Maiera6e76d72022-02-11 21:43:506213 return [
6214 output_api.PresubmitError(
6215 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
6216 'defined in build_config.h):', bad_macros)
6217 ]
[email protected]b00342e7f2013-03-26 16:21:546218
lliabraa35bab3932014-10-01 12:16:446219
6220def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:506221 """Check all affected files for invalid "if defined" macros."""
6222 ALWAYS_DEFINED_MACROS = (
6223 "TARGET_CPU_PPC",
6224 "TARGET_CPU_PPC64",
6225 "TARGET_CPU_68K",
6226 "TARGET_CPU_X86",
6227 "TARGET_CPU_ARM",
6228 "TARGET_CPU_MIPS",
6229 "TARGET_CPU_SPARC",
6230 "TARGET_CPU_ALPHA",
6231 "TARGET_IPHONE_SIMULATOR",
6232 "TARGET_OS_EMBEDDED",
6233 "TARGET_OS_IPHONE",
6234 "TARGET_OS_MAC",
6235 "TARGET_OS_UNIX",
6236 "TARGET_OS_WIN32",
6237 )
6238 ifdef_macro = input_api.re.compile(
6239 r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
6240 results = []
6241 for lnum, line in f.ChangedContents():
6242 for match in ifdef_macro.finditer(line):
6243 if match.group(1) in ALWAYS_DEFINED_MACROS:
6244 always_defined = ' %s is always defined. ' % match.group(1)
6245 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
6246 results.append(
6247 ' %s:%d %s\n\t%s' %
6248 (f.LocalPath(), lnum, always_defined, did_you_mean))
6249 return results
lliabraa35bab3932014-10-01 12:16:446250
6251
Saagar Sanghavifceeaae2020-08-12 16:40:366252def CheckForInvalidIfDefinedMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506253 """Check all affected files for invalid "if defined" macros."""
Arthur Sonzogni4fd14fd2024-06-02 18:42:526254 SKIPPED_PATHS = [
6255 'base/allocator/partition_allocator/src/partition_alloc/build_config.h',
6256 'build/build_config.h',
6257 'third_party/abseil-cpp/',
6258 'third_party/sqlite/',
6259 ]
6260 def affected_files_filter(f):
6261 # Normalize the local path to Linux-style path separators so that the
6262 # path comparisons work on Windows as well.
Anton Bershanskyi4253349482025-02-11 21:01:276263 path = f.UnixLocalPath()
Arthur Sonzogni4fd14fd2024-06-02 18:42:526264
6265 for skipped_path in SKIPPED_PATHS:
6266 if path.startswith(skipped_path):
6267 return False
6268
6269 return path.endswith(('.h', '.c', '.cc', '.m', '.mm'))
6270
Sam Maiera6e76d72022-02-11 21:43:506271 bad_macros = []
Arthur Sonzogni4fd14fd2024-06-02 18:42:526272 for f in input_api.AffectedSourceFiles(affected_files_filter):
6273 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
lliabraa35bab3932014-10-01 12:16:446274
Sam Maiera6e76d72022-02-11 21:43:506275 if not bad_macros:
6276 return []
lliabraa35bab3932014-10-01 12:16:446277
Sam Maiera6e76d72022-02-11 21:43:506278 return [
6279 output_api.PresubmitError(
6280 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
6281 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
6282 bad_macros)
6283 ]
lliabraa35bab3932014-10-01 12:16:446284
Saagar Sanghavifceeaae2020-08-12 16:40:366285def CheckForIPCRules(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506286 """Check for same IPC rules described in
6287 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
6288 """
6289 base_pattern = r'IPC_ENUM_TRAITS\('
6290 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
6291 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
mlamouria82272622014-09-16 18:45:046292
Sam Maiera6e76d72022-02-11 21:43:506293 problems = []
6294 for f in input_api.AffectedSourceFiles(None):
6295 local_path = f.LocalPath()
6296 if not local_path.endswith('.h'):
6297 continue
6298 for line_number, line in f.ChangedContents():
6299 if inclusion_pattern.search(
6300 line) and not comment_pattern.search(line):
6301 problems.append('%s:%d\n %s' %
6302 (local_path, line_number, line.strip()))
mlamouria82272622014-09-16 18:45:046303
Sam Maiera6e76d72022-02-11 21:43:506304 if problems:
6305 return [
6306 output_api.PresubmitPromptWarning(_IPC_ENUM_TRAITS_DEPRECATED,
6307 problems)
6308 ]
6309 else:
6310 return []
mlamouria82272622014-09-16 18:45:046311
[email protected]b00342e7f2013-03-26 16:21:546312
Saagar Sanghavifceeaae2020-08-12 16:40:366313def CheckForLongPathnames(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506314 """Check to make sure no files being submitted have long paths.
6315 This causes issues on Windows.
6316 """
6317 problems = []
6318 for f in input_api.AffectedTestableFiles():
6319 local_path = f.LocalPath()
6320 # Windows has a path limit of 260 characters. Limit path length to 200 so
6321 # that we have some extra for the prefix on dev machines and the bots.
Weizhong Xia8b461f12024-06-21 21:46:336322 if (local_path.startswith('third_party/blink/web_tests/platform/') and
6323 not local_path.startswith('third_party/blink/web_tests/platform/win')):
6324 # Do not check length of the path for files not used by Windows
6325 continue
Sam Maiera6e76d72022-02-11 21:43:506326 if len(local_path) > 200:
6327 problems.append(local_path)
Stephen Martinis97a394142018-06-07 23:06:056328
Sam Maiera6e76d72022-02-11 21:43:506329 if problems:
6330 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
6331 else:
6332 return []
Stephen Martinis97a394142018-06-07 23:06:056333
6334
Saagar Sanghavifceeaae2020-08-12 16:40:366335def CheckForIncludeGuards(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506336 """Check that header files have proper guards against multiple inclusion.
6337 If a file should not have such guards (and it probably should) then it
Bruce Dawson4a5579a2022-04-08 17:11:366338 should include the string "no-include-guard-because-multiply-included" or
6339 "no-include-guard-because-pch-file".
Sam Maiera6e76d72022-02-11 21:43:506340 """
Daniel Bratell8ba52722018-03-02 16:06:146341
Sam Maiera6e76d72022-02-11 21:43:506342 def is_chromium_header_file(f):
6343 # We only check header files under the control of the Chromium
mikt84d6c712024-03-27 13:29:036344 # project. This excludes:
6345 # - third_party/*, except blink.
6346 # - base/allocator/partition_allocator/: PartitionAlloc is a standalone
6347 # library used outside of Chrome. Includes are referenced from its
6348 # own base directory. It has its own `CheckForIncludeGuards`
6349 # PRESUBMIT.py check.
6350 # - *_message_generator.h: They use include guards in a special,
6351 # non-typical way.
Sam Maiera6e76d72022-02-11 21:43:506352 file_with_path = input_api.os_path.normpath(f.LocalPath())
6353 return (file_with_path.endswith('.h')
6354 and not file_with_path.endswith('_message_generator.h')
Bruce Dawson4c4c2922022-05-02 18:07:336355 and not file_with_path.endswith('com_imported_mstscax.h')
Peter Kasting66c1f752024-12-02 15:28:376356 and not file_with_path.startswith(
6357 input_api.os_path.join('base', 'allocator',
6358 'partition_allocator'))
Sam Maiera6e76d72022-02-11 21:43:506359 and (not file_with_path.startswith('third_party')
6360 or file_with_path.startswith(
6361 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:146362
Sam Maiera6e76d72022-02-11 21:43:506363 def replace_special_with_underscore(string):
6364 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:146365
Sam Maiera6e76d72022-02-11 21:43:506366 errors = []
Daniel Bratell8ba52722018-03-02 16:06:146367
Sam Maiera6e76d72022-02-11 21:43:506368 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
6369 guard_name = None
6370 guard_line_number = None
6371 seen_guard_end = False
Lei Zhangd84f9512024-05-28 19:43:306372 bypass_checks_at_end_of_file = False
Daniel Bratell8ba52722018-03-02 16:06:146373
Sam Maiera6e76d72022-02-11 21:43:506374 file_with_path = input_api.os_path.normpath(f.LocalPath())
6375 base_file_name = input_api.os_path.splitext(
6376 input_api.os_path.basename(file_with_path))[0]
6377 upper_base_file_name = base_file_name.upper()
Daniel Bratell8ba52722018-03-02 16:06:146378
Sam Maiera6e76d72022-02-11 21:43:506379 expected_guard = replace_special_with_underscore(
6380 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:146381
Sam Maiera6e76d72022-02-11 21:43:506382 # For "path/elem/file_name.h" we should really only accept
6383 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
6384 # are too many (1000+) files with slight deviations from the
6385 # coding style. The most important part is that the include guard
6386 # is there, and that it's unique, not the name so this check is
6387 # forgiving for existing files.
6388 #
6389 # As code becomes more uniform, this could be made stricter.
Daniel Bratell8ba52722018-03-02 16:06:146390
Sam Maiera6e76d72022-02-11 21:43:506391 guard_name_pattern_list = [
6392 # Anything with the right suffix (maybe with an extra _).
6393 r'\w+_H__?',
Daniel Bratell8ba52722018-03-02 16:06:146394
Sam Maiera6e76d72022-02-11 21:43:506395 # To cover include guards with old Blink style.
6396 r'\w+_h',
Daniel Bratell8ba52722018-03-02 16:06:146397
Sam Maiera6e76d72022-02-11 21:43:506398 # Anything including the uppercase name of the file.
6399 r'\w*' + input_api.re.escape(
6400 replace_special_with_underscore(upper_base_file_name)) +
6401 r'\w*',
6402 ]
6403 guard_name_pattern = '|'.join(guard_name_pattern_list)
6404 guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
6405 guard_name_pattern + ')')
Daniel Bratell8ba52722018-03-02 16:06:146406
Sam Maiera6e76d72022-02-11 21:43:506407 for line_number, line in enumerate(f.NewContents()):
Bruce Dawson4a5579a2022-04-08 17:11:366408 if ('no-include-guard-because-multiply-included' in line
6409 or 'no-include-guard-because-pch-file' in line):
Lei Zhangd84f9512024-05-28 19:43:306410 bypass_checks_at_end_of_file = True
Sam Maiera6e76d72022-02-11 21:43:506411 break
Daniel Bratell8ba52722018-03-02 16:06:146412
Sam Maiera6e76d72022-02-11 21:43:506413 if guard_name is None:
6414 match = guard_pattern.match(line)
6415 if match:
6416 guard_name = match.group(1)
6417 guard_line_number = line_number
Daniel Bratell8ba52722018-03-02 16:06:146418
Sam Maiera6e76d72022-02-11 21:43:506419 # We allow existing files to use include guards whose names
6420 # don't match the chromium style guide, but new files should
6421 # get it right.
Bruce Dawson6cc154e2022-04-12 20:39:496422 if guard_name != expected_guard:
Bruce Dawson95eb7562022-09-14 15:27:166423 if f.Action() == 'A': # If file was just 'A'dded
Sam Maiera6e76d72022-02-11 21:43:506424 errors.append(
6425 output_api.PresubmitPromptWarning(
6426 'Header using the wrong include guard name %s'
6427 % guard_name, [
6428 '%s:%d' %
6429 (f.LocalPath(), line_number + 1)
6430 ], 'Expected: %r\nFound: %r' %
6431 (expected_guard, guard_name)))
6432 else:
6433 # The line after #ifndef should have a #define of the same name.
6434 if line_number == guard_line_number + 1:
6435 expected_line = '#define %s' % guard_name
6436 if line != expected_line:
6437 errors.append(
6438 output_api.PresubmitPromptWarning(
6439 'Missing "%s" for include guard' %
6440 expected_line,
6441 ['%s:%d' % (f.LocalPath(), line_number + 1)],
6442 'Expected: %r\nGot: %r' %
6443 (expected_line, line)))
Daniel Bratell8ba52722018-03-02 16:06:146444
Sam Maiera6e76d72022-02-11 21:43:506445 if not seen_guard_end and line == '#endif // %s' % guard_name:
6446 seen_guard_end = True
6447 elif seen_guard_end:
6448 if line.strip() != '':
6449 errors.append(
6450 output_api.PresubmitPromptWarning(
6451 'Include guard %s not covering the whole file'
6452 % (guard_name), [f.LocalPath()]))
6453 break # Nothing else to check and enough to warn once.
Daniel Bratell8ba52722018-03-02 16:06:146454
Lei Zhangd84f9512024-05-28 19:43:306455 if bypass_checks_at_end_of_file:
6456 continue
6457
Sam Maiera6e76d72022-02-11 21:43:506458 if guard_name is None:
6459 errors.append(
6460 output_api.PresubmitPromptWarning(
Bruce Dawson32114b62022-04-11 16:45:496461 'Missing include guard in %s\n'
Sam Maiera6e76d72022-02-11 21:43:506462 'Recommended name: %s\n'
6463 'This check can be disabled by having the string\n'
Bruce Dawson4a5579a2022-04-08 17:11:366464 '"no-include-guard-because-multiply-included" or\n'
6465 '"no-include-guard-because-pch-file" in the header.'
Sam Maiera6e76d72022-02-11 21:43:506466 % (f.LocalPath(), expected_guard)))
Lei Zhangd84f9512024-05-28 19:43:306467 elif not seen_guard_end:
6468 errors.append(
6469 output_api.PresubmitPromptWarning(
6470 'Incorrect or missing include guard #endif in %s\n'
6471 'Recommended #endif comment: // %s'
6472 % (f.LocalPath(), expected_guard)))
Sam Maiera6e76d72022-02-11 21:43:506473
6474 return errors
Daniel Bratell8ba52722018-03-02 16:06:146475
6476
Saagar Sanghavifceeaae2020-08-12 16:40:366477def CheckForWindowsLineEndings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506478 """Check source code and known ascii text files for Windows style line
6479 endings.
6480 """
Bruce Dawson5efbdc652022-04-11 19:29:516481 known_text_files = r'.*\.(txt|html|htm|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:236482
dpapadfd421fb2025-02-13 00:47:326483 _WEBUI_FILES_EXTENSIONS = r'\.(css|html|js|ts|svg)$'
6484
Sam Maiera6e76d72022-02-11 21:43:506485 file_inclusion_pattern = (known_text_files,
6486 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
dpapadfd421fb2025-02-13 00:47:326487 r'.+%s' % _HEADER_EXTENSIONS,
6488 r'.+%s' % _WEBUI_FILES_EXTENSIONS)
6489
6490 # Exclude folder that contains .ts files that are actually binary video
6491 # format and not TypeScript.
6492 file_exclusion_pattern = (r'media/test/data/')
mostynbb639aca52015-01-07 20:31:236493
Sam Maiera6e76d72022-02-11 21:43:506494 problems = []
6495 source_file_filter = lambda f: input_api.FilterSourceFile(
dpapadfd421fb2025-02-13 00:47:326496 f, files_to_check=file_inclusion_pattern,
6497 files_to_skip=file_exclusion_pattern)
Sam Maiera6e76d72022-02-11 21:43:506498 for f in input_api.AffectedSourceFiles(source_file_filter):
Bruce Dawson5efbdc652022-04-11 19:29:516499 # Ignore test files that contain crlf intentionally.
6500 if f.LocalPath().endswith('crlf.txt'):
Daniel Chenga37c03db2022-05-12 17:20:346501 continue
Sam Maiera6e76d72022-02-11 21:43:506502 include_file = False
6503 for line in input_api.ReadFile(f, 'r').splitlines(True):
6504 if line.endswith('\r\n'):
6505 include_file = True
6506 if include_file:
6507 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:236508
Sam Maiera6e76d72022-02-11 21:43:506509 if problems:
6510 return [
6511 output_api.PresubmitPromptWarning(
6512 'Are you sure that you want '
6513 'these files to contain Windows style line endings?\n' +
6514 '\n'.join(problems))
6515 ]
mostynbb639aca52015-01-07 20:31:236516
Sam Maiera6e76d72022-02-11 21:43:506517 return []
6518
mostynbb639aca52015-01-07 20:31:236519
Evan Stade6cfc964c12021-05-18 20:21:166520def CheckIconFilesForLicenseHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506521 """Check that .icon files (which are fragments of C++) have license headers.
6522 """
Evan Stade6cfc964c12021-05-18 20:21:166523
Sam Maiera6e76d72022-02-11 21:43:506524 icon_files = (r'.*\.icon$', )
Evan Stade6cfc964c12021-05-18 20:21:166525
Sam Maiera6e76d72022-02-11 21:43:506526 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
6527 return input_api.canned_checks.CheckLicense(input_api,
6528 output_api,
6529 source_file_filter=icons)
6530
Evan Stade6cfc964c12021-05-18 20:21:166531
Jose Magana2b456f22021-03-09 23:26:406532def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506533 """Check source code for use of Chrome App technologies being
6534 deprecated.
6535 """
Jose Magana2b456f22021-03-09 23:26:406536
Sam Maiera6e76d72022-02-11 21:43:506537 def _CheckForDeprecatedTech(input_api,
6538 output_api,
6539 detection_list,
6540 files_to_check=None,
6541 files_to_skip=None):
Jose Magana2b456f22021-03-09 23:26:406542
Sam Maiera6e76d72022-02-11 21:43:506543 if (files_to_check or files_to_skip):
6544 source_file_filter = lambda f: input_api.FilterSourceFile(
6545 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
6546 else:
6547 source_file_filter = None
6548
6549 problems = []
6550
6551 for f in input_api.AffectedSourceFiles(source_file_filter):
6552 if f.Action() == 'D':
6553 continue
6554 for _, line in f.ChangedContents():
6555 if any(detect in line for detect in detection_list):
6556 problems.append(f.LocalPath())
6557
6558 return problems
6559
6560 # to avoid this presubmit script triggering warnings
6561 files_to_skip = ['PRESUBMIT.py', 'PRESUBMIT_test.py']
Jose Magana2b456f22021-03-09 23:26:406562
6563 problems = []
6564
Sam Maiera6e76d72022-02-11 21:43:506565 # NMF: any files with extensions .nmf or NMF
6566 _NMF_FILES = r'\.(nmf|NMF)$'
6567 problems += _CheckForDeprecatedTech(
6568 input_api,
6569 output_api,
6570 detection_list=[''], # any change to the file will trigger warning
6571 files_to_check=[r'.+%s' % _NMF_FILES])
Jose Magana2b456f22021-03-09 23:26:406572
Sam Maiera6e76d72022-02-11 21:43:506573 # MANIFEST: any manifest.json that in its diff includes "app":
6574 _MANIFEST_FILES = r'(manifest\.json)$'
6575 problems += _CheckForDeprecatedTech(
6576 input_api,
6577 output_api,
6578 detection_list=['"app":'],
6579 files_to_check=[r'.*%s' % _MANIFEST_FILES])
Jose Magana2b456f22021-03-09 23:26:406580
Sam Maiera6e76d72022-02-11 21:43:506581 # NaCl / PNaCl: any file that in its diff contains the strings in the list
6582 problems += _CheckForDeprecatedTech(
6583 input_api,
6584 output_api,
6585 detection_list=['config=nacl', 'enable-nacl', 'cpu=pnacl', 'nacl_io'],
Bruce Dawson40fece62022-09-16 19:58:316586 files_to_skip=files_to_skip + [r"^native_client_sdk/"])
Jose Magana2b456f22021-03-09 23:26:406587
Gao Shenga79ebd42022-08-08 17:25:596588 # PPAPI: any C/C++ file that in its diff includes a ppapi library
Sam Maiera6e76d72022-02-11 21:43:506589 problems += _CheckForDeprecatedTech(
6590 input_api,
6591 output_api,
6592 detection_list=['#include "ppapi', '#include <ppapi'],
6593 files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,
6594 r'.+%s' % _IMPLEMENTATION_EXTENSIONS),
Bruce Dawson40fece62022-09-16 19:58:316595 files_to_skip=[r"^ppapi/"])
Jose Magana2b456f22021-03-09 23:26:406596
Sam Maiera6e76d72022-02-11 21:43:506597 if problems:
6598 return [
6599 output_api.PresubmitPromptWarning(
6600 'You are adding/modifying code'
6601 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
6602 ' PNaCl, PPAPI). See this blog post for more details:\n'
6603 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
6604 'and this documentation for options to replace these technologies:\n'
6605 'https://developer.chrome.com/docs/apps/migration/\n' +
6606 '\n'.join(problems))
6607 ]
Jose Magana2b456f22021-03-09 23:26:406608
Sam Maiera6e76d72022-02-11 21:43:506609 return []
Jose Magana2b456f22021-03-09 23:26:406610
mostynbb639aca52015-01-07 20:31:236611
Saagar Sanghavifceeaae2020-08-12 16:40:366612def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
Sam Maiera6e76d72022-02-11 21:43:506613 """Checks that all source files use SYSLOG properly."""
6614 syslog_files = []
6615 for f in input_api.AffectedSourceFiles(src_file_filter):
6616 for line_number, line in f.ChangedContents():
6617 if 'SYSLOG' in line:
6618 syslog_files.append(f.LocalPath() + ':' + str(line_number))
pastarmovj032ba5bc2017-01-12 10:41:566619
Sam Maiera6e76d72022-02-11 21:43:506620 if syslog_files:
6621 return [
6622 output_api.PresubmitPromptWarning(
6623 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
6624 ' calls.\nFiles to check:\n',
6625 items=syslog_files)
6626 ]
6627 return []
pastarmovj89f7ee12016-09-20 14:58:136628
6629
[email protected]1f7b4172010-01-28 01:17:346630def CheckChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506631 if input_api.version < [2, 0, 0]:
6632 return [
6633 output_api.PresubmitError(
6634 "Your depot_tools is out of date. "
6635 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
6636 "but your version is %d.%d.%d" % tuple(input_api.version))
6637 ]
6638 results = []
6639 results.extend(
6640 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
6641 return results
[email protected]ca8d1982009-02-19 16:33:126642
6643
6644def CheckChangeOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506645 if input_api.version < [2, 0, 0]:
6646 return [
6647 output_api.PresubmitError(
6648 "Your depot_tools is out of date. "
6649 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
6650 "but your version is %d.%d.%d" % tuple(input_api.version))
6651 ]
Saagar Sanghavifceeaae2020-08-12 16:40:366652
Sam Maiera6e76d72022-02-11 21:43:506653 results = []
6654 # Make sure the tree is 'open'.
6655 results.extend(
6656 input_api.canned_checks.CheckTreeIsOpen(
6657 input_api,
6658 output_api,
6659 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:276660
Sam Maiera6e76d72022-02-11 21:43:506661 results.extend(
6662 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
6663 results.extend(
6664 input_api.canned_checks.CheckChangeHasBugField(input_api, output_api))
6665 results.extend(
6666 input_api.canned_checks.CheckChangeHasNoUnwantedTags(
6667 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:506668 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146669
6670
Saagar Sanghavifceeaae2020-08-12 16:40:366671def CheckStrings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506672 """Check string ICU syntax validity and if translation screenshots exist."""
6673 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
6674 # footer is set to true.
6675 git_footers = input_api.change.GitFootersFromDescription()
6676 skip_screenshot_check_footer = [
6677 footer.lower() for footer in git_footers.get(
6678 u'Skip-Translation-Screenshots-Check', [])
6679 ]
6680 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:026681
Sam Maiera6e76d72022-02-11 21:43:506682 import os
6683 import re
6684 import sys
6685 from io import StringIO
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146686
Sam Maiera6e76d72022-02-11 21:43:506687 new_or_added_paths = set(f.LocalPath() for f in input_api.AffectedFiles()
6688 if (f.Action() == 'A' or f.Action() == 'M'))
6689 removed_paths = set(f.LocalPath()
6690 for f in input_api.AffectedFiles(include_deletes=True)
6691 if f.Action() == 'D')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146692
Sam Maiera6e76d72022-02-11 21:43:506693 affected_grds = [
6694 f for f in input_api.AffectedFiles()
6695 if f.LocalPath().endswith(('.grd', '.grdp'))
6696 ]
6697 affected_grds = [
6698 f for f in affected_grds if not 'testdata' in f.LocalPath()
6699 ]
6700 if not affected_grds:
6701 return []
meacer8c0d3832019-12-26 21:46:166702
Sam Maiera6e76d72022-02-11 21:43:506703 affected_png_paths = [
Andrew Grieve713b89b2024-10-15 20:20:086704 f.LocalPath() for f in input_api.AffectedFiles()
6705 if f.LocalPath().endswith('.png')
Sam Maiera6e76d72022-02-11 21:43:506706 ]
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146707
Sam Maiera6e76d72022-02-11 21:43:506708 # Check for screenshots. Developers can upload screenshots using
6709 # tools/translation/upload_screenshots.py which finds and uploads
6710 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
6711 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
6712 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
6713 #
6714 # The logic here is as follows:
6715 #
6716 # - If the CL has a .png file under the screenshots directory for a grd
6717 # file, warn the developer. Actual images should never be checked into the
6718 # Chrome repo.
6719 #
6720 # - If the CL contains modified or new messages in grd files and doesn't
6721 # contain the corresponding .sha1 files, warn the developer to add images
6722 # and upload them via tools/translation/upload_screenshots.py.
6723 #
6724 # - If the CL contains modified or new messages in grd files and the
6725 # corresponding .sha1 files, everything looks good.
6726 #
6727 # - If the CL contains removed messages in grd files but the corresponding
6728 # .sha1 files aren't removed, warn the developer to remove them.
6729 unnecessary_screenshots = []
Jens Mueller054652c2023-05-10 15:12:306730 invalid_sha1 = []
Sam Maiera6e76d72022-02-11 21:43:506731 missing_sha1 = []
Bruce Dawson55776c42022-12-09 17:23:476732 missing_sha1_modified = []
Sam Maiera6e76d72022-02-11 21:43:506733 unnecessary_sha1_files = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146734
Sam Maiera6e76d72022-02-11 21:43:506735 # This checks verifies that the ICU syntax of messages this CL touched is
6736 # valid, and reports any found syntax errors.
6737 # Without this presubmit check, ICU syntax errors in Chromium strings can land
6738 # without developers being aware of them. Later on, such ICU syntax errors
6739 # break message extraction for translation, hence would block Chromium
6740 # translations until they are fixed.
6741 icu_syntax_errors = []
Jens Mueller054652c2023-05-10 15:12:306742 sha1_pattern = input_api.re.compile(r'^[a-fA-F0-9]{40}$',
6743 input_api.re.MULTILINE)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146744
Sam Maiera6e76d72022-02-11 21:43:506745 def _CheckScreenshotAdded(screenshots_dir, message_id):
6746 sha1_path = input_api.os_path.join(screenshots_dir,
6747 message_id + '.png.sha1')
6748 if sha1_path not in new_or_added_paths:
6749 missing_sha1.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306750 elif not _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256751 invalid_sha1.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146752
Bruce Dawson55776c42022-12-09 17:23:476753 def _CheckScreenshotModified(screenshots_dir, message_id):
6754 sha1_path = input_api.os_path.join(screenshots_dir,
6755 message_id + '.png.sha1')
6756 if sha1_path not in new_or_added_paths:
6757 missing_sha1_modified.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306758 elif not _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256759 invalid_sha1.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306760
6761 def _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256762 return sha1_pattern.search(
6763 next("\n".join(f.NewContents()) for f in input_api.AffectedFiles()
6764 if f.LocalPath() == sha1_path))
Bruce Dawson55776c42022-12-09 17:23:476765
Sam Maiera6e76d72022-02-11 21:43:506766 def _CheckScreenshotRemoved(screenshots_dir, message_id):
6767 sha1_path = input_api.os_path.join(screenshots_dir,
6768 message_id + '.png.sha1')
6769 if input_api.os_path.exists(
6770 sha1_path) and sha1_path not in removed_paths:
6771 unnecessary_sha1_files.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146772
Sam Maiera6e76d72022-02-11 21:43:506773 def _ValidateIcuSyntax(text, level, signatures):
6774 """Validates ICU syntax of a text string.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146775
Sam Maiera6e76d72022-02-11 21:43:506776 Check if text looks similar to ICU and checks for ICU syntax correctness
6777 in this case. Reports various issues with ICU syntax and values of
6778 variants. Supports checking of nested messages. Accumulate information of
6779 each ICU messages found in the text for further checking.
Rainhard Findlingfc31844c52020-05-15 09:58:266780
Sam Maiera6e76d72022-02-11 21:43:506781 Args:
6782 text: a string to check.
6783 level: a number of current nesting level.
6784 signatures: an accumulator, a list of tuple of (level, variable,
6785 kind, variants).
Rainhard Findlingfc31844c52020-05-15 09:58:266786
Sam Maiera6e76d72022-02-11 21:43:506787 Returns:
6788 None if a string is not ICU or no issue detected.
6789 A tuple of (message, start index, end index) if an issue detected.
6790 """
6791 valid_types = {
6792 'plural': (frozenset(
Rainhard Findling3cde3ef02024-02-05 18:40:326793 ['=0', '=1', '=2', '=3', 'zero', 'one', 'two', 'few', 'many',
Sam Maiera6e76d72022-02-11 21:43:506794 'other']), frozenset(['=1', 'other'])),
6795 'selectordinal': (frozenset(
Rainhard Findling3cde3ef02024-02-05 18:40:326796 ['=0', '=1', '=2', '=3', 'zero', 'one', 'two', 'few', 'many',
Sam Maiera6e76d72022-02-11 21:43:506797 'other']), frozenset(['one', 'other'])),
6798 'select': (frozenset(), frozenset(['other'])),
6799 }
Rainhard Findlingfc31844c52020-05-15 09:58:266800
Sam Maiera6e76d72022-02-11 21:43:506801 # Check if the message looks like an attempt to use ICU
6802 # plural. If yes - check if its syntax strictly matches ICU format.
6803 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b',
6804 text)
6805 if not like:
6806 signatures.append((level, None, None, None))
6807 return
Rainhard Findlingfc31844c52020-05-15 09:58:266808
Sam Maiera6e76d72022-02-11 21:43:506809 # Check for valid prefix and suffix
6810 m = re.match(
6811 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
6812 r'(plural|selectordinal|select),\s*'
6813 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
6814 if not m:
6815 return (('This message looks like an ICU plural, '
6816 'but does not follow ICU syntax.'), like.start(),
6817 like.end())
6818 starting, variable, kind, variant_pairs = m.groups()
6819 variants, depth, last_pos = _ParseIcuVariants(variant_pairs,
6820 m.start(4))
6821 if depth:
6822 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
6823 len(text))
6824 first = text[0]
6825 ending = text[last_pos:]
6826 if not starting:
6827 return ('Invalid ICU format. No initial opening bracket',
6828 last_pos - 1, last_pos)
6829 if not ending or '}' not in ending:
6830 return ('Invalid ICU format. No final closing bracket',
6831 last_pos - 1, last_pos)
6832 elif first != '{':
6833 return ((
6834 'Invalid ICU format. Extra characters at the start of a complex '
6835 'message (go/icu-message-migration): "%s"') % starting, 0,
6836 len(starting))
6837 elif ending != '}':
6838 return ((
6839 'Invalid ICU format. Extra characters at the end of a complex '
6840 'message (go/icu-message-migration): "%s"') % ending,
6841 last_pos - 1, len(text) - 1)
6842 if kind not in valid_types:
6843 return (('Unknown ICU message type %s. '
6844 'Valid types are: plural, select, selectordinal') % kind,
6845 0, 0)
6846 known, required = valid_types[kind]
6847 defined_variants = set()
6848 for variant, variant_range, value, value_range in variants:
6849 start, end = variant_range
6850 if variant in defined_variants:
6851 return ('Variant "%s" is defined more than once' % variant,
6852 start, end)
6853 elif known and variant not in known:
6854 return ('Variant "%s" is not valid for %s message' %
6855 (variant, kind), start, end)
6856 defined_variants.add(variant)
6857 # Check for nested structure
6858 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
6859 if res:
6860 return (res[0], res[1] + value_range[0] + 1,
6861 res[2] + value_range[0] + 1)
6862 missing = required - defined_variants
6863 if missing:
6864 return ('Required variants missing: %s' % ', '.join(missing), 0,
6865 len(text))
6866 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:266867
Sam Maiera6e76d72022-02-11 21:43:506868 def _ParseIcuVariants(text, offset=0):
6869 """Parse variants part of ICU complex message.
Rainhard Findlingfc31844c52020-05-15 09:58:266870
Sam Maiera6e76d72022-02-11 21:43:506871 Builds a tuple of variant names and values, as well as
6872 their offsets in the input string.
Rainhard Findlingfc31844c52020-05-15 09:58:266873
Sam Maiera6e76d72022-02-11 21:43:506874 Args:
6875 text: a string to parse
6876 offset: additional offset to add to positions in the text to get correct
6877 position in the complete ICU string.
Rainhard Findlingfc31844c52020-05-15 09:58:266878
Sam Maiera6e76d72022-02-11 21:43:506879 Returns:
6880 List of tuples, each tuple consist of four fields: variant name,
6881 variant name span (tuple of two integers), variant value, value
6882 span (tuple of two integers).
6883 """
6884 depth, start, end = 0, -1, -1
6885 variants = []
6886 key = None
6887 for idx, char in enumerate(text):
6888 if char == '{':
6889 if not depth:
6890 start = idx
6891 chunk = text[end + 1:start]
6892 key = chunk.strip()
6893 pos = offset + end + 1 + chunk.find(key)
6894 span = (pos, pos + len(key))
6895 depth += 1
6896 elif char == '}':
6897 if not depth:
6898 return variants, depth, offset + idx
6899 depth -= 1
6900 if not depth:
6901 end = idx
6902 variants.append((key, span, text[start:end + 1],
6903 (offset + start, offset + end + 1)))
6904 return variants, depth, offset + end + 1
Rainhard Findlingfc31844c52020-05-15 09:58:266905
Terrence Reilly313f44ff2025-01-22 15:10:146906 old_sys_path = sys.path
Sam Maiera6e76d72022-02-11 21:43:506907 try:
Sam Maiera6e76d72022-02-11 21:43:506908 sys.path = sys.path + [
6909 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
6910 'translation')
6911 ]
6912 from helper import grd_helper
6913 finally:
6914 sys.path = old_sys_path
Rainhard Findlingfc31844c52020-05-15 09:58:266915
Sam Maiera6e76d72022-02-11 21:43:506916 for f in affected_grds:
6917 file_path = f.LocalPath()
6918 old_id_to_msg_map = {}
6919 new_id_to_msg_map = {}
6920 # Note that this code doesn't check if the file has been deleted. This is
6921 # OK because it only uses the old and new file contents and doesn't load
6922 # the file via its path.
6923 # It's also possible that a file's content refers to a renamed or deleted
6924 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
6925 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
6926 # .grdp files.
6927 if file_path.endswith('.grdp'):
6928 if f.OldContents():
6929 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6930 '\n'.join(f.OldContents()))
6931 if f.NewContents():
6932 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6933 '\n'.join(f.NewContents()))
6934 else:
6935 file_dir = input_api.os_path.dirname(file_path) or '.'
6936 if f.OldContents():
6937 old_id_to_msg_map = grd_helper.GetGrdMessages(
6938 StringIO('\n'.join(f.OldContents())), file_dir)
6939 if f.NewContents():
6940 new_id_to_msg_map = grd_helper.GetGrdMessages(
6941 StringIO('\n'.join(f.NewContents())), file_dir)
Rainhard Findlingfc31844c52020-05-15 09:58:266942
Sam Maiera6e76d72022-02-11 21:43:506943 grd_name, ext = input_api.os_path.splitext(
6944 input_api.os_path.basename(file_path))
6945 screenshots_dir = input_api.os_path.join(
6946 input_api.os_path.dirname(file_path),
6947 grd_name + ext.replace('.', '_'))
Rainhard Findlingfc31844c52020-05-15 09:58:266948
Sam Maiera6e76d72022-02-11 21:43:506949 # Compute added, removed and modified message IDs.
6950 old_ids = set(old_id_to_msg_map)
6951 new_ids = set(new_id_to_msg_map)
6952 added_ids = new_ids - old_ids
6953 removed_ids = old_ids - new_ids
6954 modified_ids = set([])
6955 for key in old_ids.intersection(new_ids):
6956 if (old_id_to_msg_map[key].ContentsAsXml('', True) !=
6957 new_id_to_msg_map[key].ContentsAsXml('', True)):
6958 # The message content itself changed. Require an updated screenshot.
6959 modified_ids.add(key)
6960 elif old_id_to_msg_map[key].attrs['meaning'] != \
6961 new_id_to_msg_map[key].attrs['meaning']:
Jens Mueller054652c2023-05-10 15:12:306962 # The message meaning changed. We later check for a screenshot.
6963 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146964
Sam Maiera6e76d72022-02-11 21:43:506965 if run_screenshot_check:
6966 # Check the screenshot directory for .png files. Warn if there is any.
6967 for png_path in affected_png_paths:
6968 if png_path.startswith(screenshots_dir):
6969 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146970
Sam Maiera6e76d72022-02-11 21:43:506971 for added_id in added_ids:
6972 _CheckScreenshotAdded(screenshots_dir, added_id)
Rainhard Findlingd8d04372020-08-13 13:30:096973
Sam Maiera6e76d72022-02-11 21:43:506974 for modified_id in modified_ids:
Bruce Dawson55776c42022-12-09 17:23:476975 _CheckScreenshotModified(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146976
Sam Maiera6e76d72022-02-11 21:43:506977 for removed_id in removed_ids:
6978 _CheckScreenshotRemoved(screenshots_dir, removed_id)
6979
6980 # Check new and changed strings for ICU syntax errors.
6981 for key in added_ids.union(modified_ids):
6982 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
6983 err = _ValidateIcuSyntax(msg, 0, [])
6984 if err is not None:
6985 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
6986
6987 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:266988 if run_screenshot_check:
Sam Maiera6e76d72022-02-11 21:43:506989 if unnecessary_screenshots:
6990 results.append(
6991 output_api.PresubmitError(
6992 'Do not include actual screenshots in the changelist. Run '
6993 'tools/translate/upload_screenshots.py to upload them instead:',
6994 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146995
Sam Maiera6e76d72022-02-11 21:43:506996 if missing_sha1:
6997 results.append(
6998 output_api.PresubmitError(
Bruce Dawson55776c42022-12-09 17:23:476999 'You are adding UI strings.\n'
Sam Maiera6e76d72022-02-11 21:43:507000 'To ensure the best translations, take screenshots of the relevant UI '
7001 '(https://g.co/chrome/translation) and add these files to your '
7002 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147003
Jens Mueller054652c2023-05-10 15:12:307004 if invalid_sha1:
7005 results.append(
7006 output_api.PresubmitError(
7007 'The following files do not seem to contain valid sha1 hashes. '
7008 'Make sure they contain hashes created by '
7009 'tools/translate/upload_screenshots.py:', sorted(invalid_sha1)))
7010
Bruce Dawson55776c42022-12-09 17:23:477011 if missing_sha1_modified:
7012 results.append(
7013 output_api.PresubmitError(
7014 'You are modifying UI strings or their meanings.\n'
7015 'To ensure the best translations, take screenshots of the relevant UI '
7016 '(https://g.co/chrome/translation) and add these files to your '
7017 'changelist:', sorted(missing_sha1_modified)))
7018
Sam Maiera6e76d72022-02-11 21:43:507019 if unnecessary_sha1_files:
7020 results.append(
7021 output_api.PresubmitError(
7022 'You removed strings associated with these files. Remove:',
7023 sorted(unnecessary_sha1_files)))
7024 else:
7025 results.append(
7026 output_api.PresubmitPromptOrNotify('Skipping translation '
7027 'screenshots check.'))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147028
Sam Maiera6e76d72022-02-11 21:43:507029 if icu_syntax_errors:
7030 results.append(
7031 output_api.PresubmitPromptWarning(
7032 'ICU syntax errors were found in the following strings (problems or '
7033 'feedback? Contact [email protected]):',
7034 items=icu_syntax_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:267035
Sam Maiera6e76d72022-02-11 21:43:507036 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:127037
7038
Saagar Sanghavifceeaae2020-08-12 16:40:367039def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:127040 repo_root=None,
7041 translation_expectations_path=None,
7042 grd_files=None):
Sam Maiera6e76d72022-02-11 21:43:507043 import sys
7044 affected_grds = [
7045 f for f in input_api.AffectedFiles()
7046 if (f.LocalPath().endswith('.grd') or f.LocalPath().endswith('.grdp'))
7047 ]
7048 if not affected_grds:
7049 return []
7050
Terrence Reilly313f44ff2025-01-22 15:10:147051 old_sys_path = sys.path
Sam Maiera6e76d72022-02-11 21:43:507052 try:
Sam Maiera6e76d72022-02-11 21:43:507053 sys.path = sys.path + [
7054 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
7055 'translation')
7056 ]
Terrence Reilly313f44ff2025-01-22 15:10:147057 sys.path = sys.path + [
7058 input_api.os_path.join(input_api.PresubmitLocalPath(),
7059 'third_party', 'depot_tools')
7060 ]
Sam Maiera6e76d72022-02-11 21:43:507061 from helper import git_helper
7062 from helper import translation_helper
Terrence Reilly313f44ff2025-01-22 15:10:147063 import gclient_utils
Sam Maiera6e76d72022-02-11 21:43:507064 finally:
7065 sys.path = old_sys_path
7066
7067 # Check that translation expectations can be parsed and we can get a list of
7068 # translatable grd files. |repo_root| and |translation_expectations_path| are
7069 # only passed by tests.
7070 if not repo_root:
7071 repo_root = input_api.PresubmitLocalPath()
7072 if not translation_expectations_path:
7073 translation_expectations_path = input_api.os_path.join(
7074 repo_root, 'tools', 'gritsettings', 'translation_expectations.pyl')
Terrence Reilly313f44ff2025-01-22 15:10:147075 is_cog = gclient_utils.IsEnvCog()
7076 # Git is not available in cog workspaces.
7077 if not grd_files and not is_cog:
Sam Maiera6e76d72022-02-11 21:43:507078 grd_files = git_helper.list_grds_in_repository(repo_root)
Terrence Reilly313f44ff2025-01-22 15:10:147079 if not grd_files:
7080 grd_files = []
Sam Maiera6e76d72022-02-11 21:43:507081
7082 # Ignore bogus grd files used only for testing
Gao Shenga79ebd42022-08-08 17:25:597083 # ui/webui/resources/tools/generate_grd.py.
Sam Maiera6e76d72022-02-11 21:43:507084 ignore_path = input_api.os_path.join('ui', 'webui', 'resources', 'tools',
7085 'tests')
7086 grd_files = [p for p in grd_files if ignore_path not in p]
7087
7088 try:
7089 translation_helper.get_translatable_grds(
Terrence Reilly313f44ff2025-01-22 15:10:147090 repo_root, grd_files, translation_expectations_path, is_cog)
Sam Maiera6e76d72022-02-11 21:43:507091 except Exception as e:
7092 return [
7093 output_api.PresubmitNotifyResult(
7094 'Failed to get a list of translatable grd files. This happens when:\n'
7095 ' - One of the modified grd or grdp files cannot be parsed or\n'
7096 ' - %s is not updated.\n'
7097 'Stack:\n%s' % (translation_expectations_path, str(e)))
7098 ]
Mustafa Emre Acer51f2f742020-03-09 19:41:127099 return []
7100
Ken Rockotc31f4832020-05-29 18:58:517101
Saagar Sanghavifceeaae2020-08-12 16:40:367102def CheckStableMojomChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507103 """Changes to [Stable] mojom types must preserve backward-compatibility."""
7104 changed_mojoms = input_api.AffectedFiles(
7105 include_deletes=True,
7106 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:527107
Bruce Dawson344ab262022-06-04 11:35:107108 if not changed_mojoms or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:507109 return []
7110
7111 delta = []
7112 for mojom in changed_mojoms:
Sam Maiera6e76d72022-02-11 21:43:507113 delta.append({
7114 'filename': mojom.LocalPath(),
7115 'old': '\n'.join(mojom.OldContents()) or None,
7116 'new': '\n'.join(mojom.NewContents()) or None,
7117 })
7118
7119 process = input_api.subprocess.Popen([
Takuto Ikutadca10222022-04-13 02:51:217120 input_api.python3_executable,
Sam Maiera6e76d72022-02-11 21:43:507121 input_api.os_path.join(
7122 input_api.PresubmitLocalPath(), 'mojo', 'public', 'tools', 'mojom',
7123 'check_stable_mojom_compatibility.py'), '--src-root',
7124 input_api.PresubmitLocalPath()
7125 ],
7126 stdin=input_api.subprocess.PIPE,
7127 stdout=input_api.subprocess.PIPE,
7128 stderr=input_api.subprocess.PIPE,
7129 universal_newlines=True)
7130 (x, error) = process.communicate(input=input_api.json.dumps(delta))
7131 if process.returncode:
7132 return [
7133 output_api.PresubmitError(
7134 'One or more [Stable] mojom definitions appears to have been changed '
Alex Goughc99921652024-02-15 22:59:127135 'in a way that is not backward-compatible. See '
7136 'https://chromium.googlesource.com/chromium/src/+/HEAD/mojo/public/tools/bindings/README.md#versioning'
7137 ' for details.',
Sam Maiera6e76d72022-02-11 21:43:507138 long_text=error)
7139 ]
Erik Staabc734cd7a2021-11-23 03:11:527140 return []
7141
Dominic Battre645d42342020-12-04 16:14:107142def CheckDeprecationOfPreferences(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507143 """Removing a preference should come with a deprecation."""
Dominic Battre645d42342020-12-04 16:14:107144
Sam Maiera6e76d72022-02-11 21:43:507145 def FilterFile(affected_file):
7146 """Accept only .cc files and the like."""
7147 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
7148 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
7149 input_api.DEFAULT_FILES_TO_SKIP)
7150 return input_api.FilterSourceFile(
7151 affected_file,
7152 files_to_check=file_inclusion_pattern,
7153 files_to_skip=files_to_skip)
Dominic Battre645d42342020-12-04 16:14:107154
Sam Maiera6e76d72022-02-11 21:43:507155 def ModifiedLines(affected_file):
7156 """Returns a list of tuples (line number, line text) of added and removed
7157 lines.
Dominic Battre645d42342020-12-04 16:14:107158
Sam Maiera6e76d72022-02-11 21:43:507159 Deleted lines share the same line number as the previous line.
Dominic Battre645d42342020-12-04 16:14:107160
Sam Maiera6e76d72022-02-11 21:43:507161 This relies on the scm diff output describing each changed code section
7162 with a line of the form
Dominic Battre645d42342020-12-04 16:14:107163
Sam Maiera6e76d72022-02-11 21:43:507164 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
7165 """
7166 line_num = 0
7167 modified_lines = []
7168 for line in affected_file.GenerateScmDiff().splitlines():
7169 # Extract <new line num> of the patch fragment (see format above).
7170 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@',
7171 line)
7172 if m:
7173 line_num = int(m.groups(1)[0])
7174 continue
7175 if ((line.startswith('+') and not line.startswith('++'))
7176 or (line.startswith('-') and not line.startswith('--'))):
7177 modified_lines.append((line_num, line))
Dominic Battre645d42342020-12-04 16:14:107178
Sam Maiera6e76d72022-02-11 21:43:507179 if not line.startswith('-'):
7180 line_num += 1
7181 return modified_lines
Dominic Battre645d42342020-12-04 16:14:107182
Sam Maiera6e76d72022-02-11 21:43:507183 def FindLineWith(lines, needle):
7184 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
Dominic Battre645d42342020-12-04 16:14:107185
Sam Maiera6e76d72022-02-11 21:43:507186 If 0 or >1 lines contain `needle`, -1 is returned.
7187 """
7188 matching_line_numbers = [
7189 # + 1 for 1-based counting of line numbers.
7190 i + 1 for i, line in enumerate(lines) if needle in line
7191 ]
7192 return matching_line_numbers[0] if len(
7193 matching_line_numbers) == 1 else -1
Dominic Battre645d42342020-12-04 16:14:107194
Sam Maiera6e76d72022-02-11 21:43:507195 def ModifiedPrefMigration(affected_file):
7196 """Returns whether the MigrateObsolete.*Pref functions were modified."""
7197 # Determine first and last lines of MigrateObsolete.*Pref functions.
7198 new_contents = affected_file.NewContents()
7199 range_1 = (FindLineWith(new_contents,
7200 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
7201 FindLineWith(new_contents,
7202 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
7203 range_2 = (FindLineWith(new_contents,
7204 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
7205 FindLineWith(new_contents,
7206 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
7207 if (-1 in range_1 + range_2):
7208 raise Exception(
7209 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.'
7210 )
Dominic Battre645d42342020-12-04 16:14:107211
Sam Maiera6e76d72022-02-11 21:43:507212 # Check whether any of the modified lines are part of the
7213 # MigrateObsolete.*Pref functions.
7214 for line_nr, line in ModifiedLines(affected_file):
7215 if (range_1[0] <= line_nr <= range_1[1]
7216 or range_2[0] <= line_nr <= range_2[1]):
7217 return True
7218 return False
Dominic Battre645d42342020-12-04 16:14:107219
Sam Maiera6e76d72022-02-11 21:43:507220 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
7221 browser_prefs_file_pattern = input_api.re.compile(
7222 r'chrome/browser/prefs/browser_prefs.cc')
Dominic Battre645d42342020-12-04 16:14:107223
Sam Maiera6e76d72022-02-11 21:43:507224 changes = input_api.AffectedFiles(include_deletes=True,
7225 file_filter=FilterFile)
7226 potential_problems = []
7227 for f in changes:
7228 for line in f.GenerateScmDiff().splitlines():
7229 # Check deleted lines for pref registrations.
7230 if (line.startswith('-') and not line.startswith('--')
7231 and register_pref_pattern.search(line)):
7232 potential_problems.append('%s: %s' % (f.LocalPath(), line))
Dominic Battre645d42342020-12-04 16:14:107233
Sam Maiera6e76d72022-02-11 21:43:507234 if browser_prefs_file_pattern.search(f.LocalPath()):
7235 # If the developer modified the MigrateObsolete.*Prefs() functions, we
7236 # assume that they knew that they have to deprecate preferences and don't
7237 # warn.
7238 try:
7239 if ModifiedPrefMigration(f):
7240 return []
7241 except Exception as e:
7242 return [output_api.PresubmitError(str(e))]
Dominic Battre645d42342020-12-04 16:14:107243
Sam Maiera6e76d72022-02-11 21:43:507244 if potential_problems:
7245 return [
7246 output_api.PresubmitPromptWarning(
7247 'Discovered possible removal of preference registrations.\n\n'
7248 'Please make sure to properly deprecate preferences by clearing their\n'
7249 'value for a couple of milestones before finally removing the code.\n'
7250 'Otherwise data may stay in the preferences files forever. See\n'
7251 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
7252 'chrome/browser/prefs/README.md for examples.\n'
7253 'This may be a false positive warning (e.g. if you move preference\n'
7254 'registrations to a different place).\n', potential_problems)
7255 ]
7256 return []
7257
Matt Stark6ef08872021-07-29 01:21:467258
7259def CheckConsistentGrdChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507260 """Changes to GRD files must be consistent for tools to read them."""
7261 changed_grds = input_api.AffectedFiles(
7262 include_deletes=False,
7263 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
7264 errors = []
7265 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
7266 for matcher, msg in _INVALID_GRD_FILE_LINE]
7267 for grd in changed_grds:
7268 for i, line in enumerate(grd.NewContents()):
7269 for matcher, msg in invalid_file_regexes:
7270 if matcher.search(line):
7271 errors.append(
7272 output_api.PresubmitError(
7273 'Problem on {grd}:{i} - {msg}'.format(
7274 grd=grd.LocalPath(), i=i + 1, msg=msg)))
7275 return errors
7276
Kevin McNee967dd2d22021-11-15 16:09:297277
Henrique Ferreiro2a4b55942021-11-29 23:45:367278def CheckAssertAshOnlyCode(input_api, output_api):
7279 """Errors if a BUILD.gn file in an ash/ directory doesn't include
Georg Neis94f87f02024-10-22 08:20:137280 assert(is_chromeos).
7281 For a transition period, assert(is_chromeos_ash) is also accepted.
Henrique Ferreiro2a4b55942021-11-29 23:45:367282 """
7283
7284 def FileFilter(affected_file):
7285 """Includes directories known to be Ash only."""
7286 return input_api.FilterSourceFile(
7287 affected_file,
7288 files_to_check=(
7289 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
7290 r'.*/ash/.*BUILD\.gn'), # Any path component.
7291 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
7292
7293 errors = []
Georg Neis94f87f02024-10-22 08:20:137294 pattern = input_api.re.compile(r'assert\(is_chromeos(_ash)?\b')
Jameson Thies0ce669f2021-12-09 15:56:567295 for f in input_api.AffectedFiles(include_deletes=False,
7296 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:367297 if (not pattern.search(input_api.ReadFile(f))):
7298 errors.append(
7299 output_api.PresubmitError(
Georg Neis94f87f02024-10-22 08:20:137300 'Please add assert(is_chromeos) to %s. If that\'s not '
7301 'possible, please create an issue and add a comment such '
Alison Galed6b25fe2024-04-17 13:59:047302 'as:\n # TODO(crbug.com/XXX): add '
Georg Neis94f87f02024-10-22 08:20:137303 'assert(is_chromeos) when ...' % f.LocalPath()))
Henrique Ferreiro2a4b55942021-11-29 23:45:367304 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:277305
7306
Kalvin Lee84ad17a2023-09-25 11:14:417307def _IsMiraclePtrDisallowed(input_api, affected_file):
Anton Bershanskyi4253349482025-02-11 21:01:277308 path = affected_file.UnixLocalPath()
Sam Maiera6e76d72022-02-11 21:43:507309 if not _IsCPlusPlusFile(input_api, path):
7310 return False
7311
Bartek Nowierski49b1a452024-06-08 00:24:357312 # Renderer-only code is generally allowed to use MiraclePtr. These
7313 # directories, however, are specifically disallowed, for perf reasons.
Kalvin Lee84ad17a2023-09-25 11:14:417314 if ("third_party/blink/renderer/core/" in path
7315 or "third_party/blink/renderer/platform/heap/" in path
Bartek Nowierski49b1a452024-06-08 00:24:357316 or "third_party/blink/renderer/platform/wtf/" in path
7317 or "third_party/blink/renderer/platform/fonts/" in path):
7318 return True
7319
7320 # The below paths are an explicitly listed subset of Renderer-only code,
7321 # because the plan is to Oilpanize it.
7322 # TODO(crbug.com/330759291): Remove once Oilpanization is completed or
7323 # abandoned.
7324 if ("third_party/blink/renderer/core/paint/" in path
7325 or "third_party/blink/renderer/platform/graphics/compositing/" in path
7326 or "third_party/blink/renderer/platform/graphics/paint/" in path):
Sam Maiera6e76d72022-02-11 21:43:507327 return True
7328
Sam Maiera6e76d72022-02-11 21:43:507329 # We assume that everything else may be used outside of Renderer processes.
Lukasz Anforowicz7016d05e2021-11-30 03:56:277330 return False
7331
Alison Galed6b25fe2024-04-17 13:59:047332# TODO(crbug.com/40206238): Remove these checks, once they are replaced
Lukasz Anforowicz7016d05e2021-11-30 03:56:277333# by the Chromium Clang Plugin (which will be preferable because it will
7334# 1) report errors earlier - at compile-time and 2) cover more rules).
7335def CheckRawPtrUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507336 """Rough checks that raw_ptr<T> usage guidelines are followed."""
7337 errors = []
7338 # The regex below matches "raw_ptr<" following a word boundary, but not in a
7339 # C++ comment.
7340 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
Kalvin Lee84ad17a2023-09-25 11:14:417341 file_filter = lambda f: _IsMiraclePtrDisallowed(input_api, f)
Sam Maiera6e76d72022-02-11 21:43:507342 for f, line_num, line in input_api.RightHandSideLines(file_filter):
7343 if raw_ptr_matcher.search(line):
7344 errors.append(
7345 output_api.PresubmitError(
7346 'Problem on {path}:{line} - '\
Kalvin Lee84ad17a2023-09-25 11:14:417347 'raw_ptr<T> should not be used in this renderer code '\
Sam Maiera6e76d72022-02-11 21:43:507348 '(as documented in the "Pointers to unprotected memory" '\
7349 'section in //base/memory/raw_ptr.md)'.format(
7350 path=f.LocalPath(), line=line_num)))
7351 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:567352
mikt9337567c2023-09-08 18:38:177353def CheckAdvancedMemorySafetyChecksUsage(input_api, output_api):
7354 """Checks that ADVANCED_MEMORY_SAFETY_CHECKS() macro is neither added nor
7355 removed as it is managed by the memory safety team internally.
7356 Do not add / remove it manually."""
7357 paths = set([])
7358 # The regex below matches "ADVANCED_MEMORY_SAFETY_CHECKS(" following a word
7359 # boundary, but not in a C++ comment.
7360 macro_matcher = input_api.re.compile(
7361 r'^((?!//).)*\bADVANCED_MEMORY_SAFETY_CHECKS\(', input_api.re.MULTILINE)
7362 for f in input_api.AffectedFiles():
7363 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
7364 continue
7365 if macro_matcher.search(f.GenerateScmDiff()):
7366 paths.add(f.LocalPath())
7367 if not paths:
7368 return []
7369 return [output_api.PresubmitPromptWarning(
7370 'ADVANCED_MEMORY_SAFETY_CHECKS() macro is managed by ' \
7371 'the memory safety team (chrome-memory-safety@). ' \
7372 'Please contact us to add/delete the uses of the macro.',
7373 paths)]
Henrique Ferreirof9819f2e32021-11-30 13:31:567374
7375def CheckPythonShebang(input_api, output_api):
7376 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
7377 system-wide python.
7378 """
7379 errors = []
7380 sources = lambda affected_file: input_api.FilterSourceFile(
7381 affected_file,
7382 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
7383 r'third_party/blink/web_tests/external/') + input_api.
7384 DEFAULT_FILES_TO_SKIP),
7385 files_to_check=[r'.*\.py$'])
7386 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:277387 for line_num, line in f.ChangedContents():
7388 if line_num == 1 and line.startswith('#!/usr/bin/python'):
7389 errors.append(f.LocalPath())
7390 break
Henrique Ferreirof9819f2e32021-11-30 13:31:567391
7392 result = []
7393 for file in errors:
7394 result.append(
7395 output_api.PresubmitError(
7396 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
7397 file))
7398 return result
James Shen81cc0e22022-06-15 21:10:457399
7400
Andrew Grieve5a66ae72024-12-13 15:21:537401def CheckAndroidTestAnnotations(input_api, output_api):
James Shen81cc0e22022-06-15 21:10:457402 """Checks that tests have either @Batch or @DoNotBatch annotation. If this
7403 is not an instrumentation test, disregard."""
7404
7405 batch_annotation = input_api.re.compile(r'^\s*@Batch')
7406 do_not_batch_annotation = input_api.re.compile(r'^\s*@DoNotBatch')
Andrew Grieve5a66ae72024-12-13 15:21:537407 robolectric_test = input_api.re.compile(r'@RunWith\((.*?)RobolectricTestRunner')
James Shen81cc0e22022-06-15 21:10:457408 test_class_declaration = input_api.re.compile(r'^\s*public\sclass.*Test')
7409 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
Mark Schillaci8ef0d872023-07-18 22:07:597410 test_annotation_declaration = input_api.re.compile(r'^\s*public\s@interface\s.*{')
James Shen81cc0e22022-06-15 21:10:457411
ckitagawae8fd23b2022-06-17 15:29:387412 missing_annotation_errors = []
7413 extra_annotation_errors = []
Andrew Grieve5a66ae72024-12-13 15:21:537414 wrong_robolectric_test_runner_errors = []
James Shen81cc0e22022-06-15 21:10:457415
7416 def _FilterFile(affected_file):
7417 return input_api.FilterSourceFile(
7418 affected_file,
7419 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
7420 files_to_check=[r'.*Test\.java$'])
7421
7422 for f in input_api.AffectedSourceFiles(_FilterFile):
7423 batch_matched = None
7424 do_not_batch_matched = None
7425 is_instrumentation_test = True
Mark Schillaci8ef0d872023-07-18 22:07:597426 test_annotation_declaration_matched = None
Andrew Grieve5a66ae72024-12-13 15:21:537427 has_base_robolectric_rule = False
James Shen81cc0e22022-06-15 21:10:457428 for line in f.NewContents():
Andrew Grieve5a66ae72024-12-13 15:21:537429 if 'BaseRobolectricTestRule' in line:
7430 has_base_robolectric_rule = True
7431 continue
7432 if m := robolectric_test.search(line):
7433 is_instrumentation_test = False
7434 if m.group(1) == '' and not has_base_robolectric_rule:
7435 path = str(f.LocalPath())
7436 # These two spots cannot use it.
7437 if 'webapk' not in path and 'build' not in path:
7438 wrong_robolectric_test_runner_errors.append(path)
7439 break
7440 if uiautomator_test.search(line):
James Shen81cc0e22022-06-15 21:10:457441 is_instrumentation_test = False
7442 break
7443 if not batch_matched:
7444 batch_matched = batch_annotation.search(line)
7445 if not do_not_batch_matched:
7446 do_not_batch_matched = do_not_batch_annotation.search(line)
7447 test_class_declaration_matched = test_class_declaration.search(
7448 line)
Mark Schillaci8ef0d872023-07-18 22:07:597449 test_annotation_declaration_matched = test_annotation_declaration.search(line)
7450 if test_class_declaration_matched or test_annotation_declaration_matched:
James Shen81cc0e22022-06-15 21:10:457451 break
Mark Schillaci8ef0d872023-07-18 22:07:597452 if test_annotation_declaration_matched:
7453 continue
James Shen81cc0e22022-06-15 21:10:457454 if (is_instrumentation_test and
7455 not batch_matched and
7456 not do_not_batch_matched):
Sam Maier4cef9242022-10-03 14:21:247457 missing_annotation_errors.append(str(f.LocalPath()))
ckitagawae8fd23b2022-06-17 15:29:387458 if (not is_instrumentation_test and
7459 (batch_matched or
7460 do_not_batch_matched)):
Sam Maier4cef9242022-10-03 14:21:247461 extra_annotation_errors.append(str(f.LocalPath()))
James Shen81cc0e22022-06-15 21:10:457462
7463 results = []
7464
ckitagawae8fd23b2022-06-17 15:29:387465 if missing_annotation_errors:
James Shen81cc0e22022-06-15 21:10:457466 results.append(
7467 output_api.PresubmitPromptWarning(
7468 """
Andrew Grieve43a5cf82023-09-08 15:09:467469A change was made to an on-device test that has neither been annotated with
7470@Batch nor @DoNotBatch. If this is a new test, please add the annotation. If
7471this is an existing test, please consider adding it if you are sufficiently
7472familiar with the test (but do so as a separate change).
7473
Jens Mueller2085ff82023-02-27 11:54:497474See https://source.chromium.org/chromium/chromium/src/+/main:docs/testing/batching_instrumentation_tests.md
ckitagawae8fd23b2022-06-17 15:29:387475""", missing_annotation_errors))
7476 if extra_annotation_errors:
7477 results.append(
7478 output_api.PresubmitPromptWarning(
7479 """
7480Robolectric tests do not need a @Batch or @DoNotBatch annotations.
7481""", extra_annotation_errors))
Andrew Grieve5a66ae72024-12-13 15:21:537482 if wrong_robolectric_test_runner_errors:
7483 results.append(
7484 output_api.PresubmitPromptWarning(
7485 """
Wenyu Fu0005ab82025-01-03 18:13:267486Robolectric tests should use either @RunWith(BaseRobolectricTestRunner.class) (or
Andrew Grieve5a66ae72024-12-13 15:21:537487a subclass of it), or use "@Rule BaseRobolectricTestRule".
7488""", wrong_robolectric_test_runner_errors))
James Shen81cc0e22022-06-15 21:10:457489
7490 return results
Sam Maier4cef9242022-10-03 14:21:247491
7492
Mike Dougherty1b8be712022-10-20 00:15:137493def CheckNoJsInIos(input_api, output_api):
7494 """Checks to make sure that JavaScript files are not used on iOS."""
7495
7496 def _FilterFile(affected_file):
7497 return input_api.FilterSourceFile(
7498 affected_file,
7499 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP +
Daniel White44b8bd02023-08-22 16:20:367500 (r'^ios/third_party/*', r'^ios/tools/*', r'^third_party/*',
7501 r'^components/autofill/ios/form_util/resources/*'),
Mike Dougherty1b8be712022-10-20 00:15:137502 files_to_check=[r'^ios/.*\.js$', r'.*/ios/.*\.js$'])
7503
Mike Dougherty4d1050b2023-03-14 15:59:537504 deleted_files = []
7505
7506 # Collect filenames of all removed JS files.
Arthur Sonzognic66e9c82024-04-23 07:53:047507 for f in input_api.AffectedFiles(file_filter=_FilterFile):
Mike Dougherty4d1050b2023-03-14 15:59:537508 local_path = f.LocalPath()
7509
7510 if input_api.os_path.splitext(local_path)[1] == '.js' and f.Action() == 'D':
7511 deleted_files.append(input_api.os_path.basename(local_path))
7512
Mike Dougherty1b8be712022-10-20 00:15:137513 error_paths = []
Mike Dougherty4d1050b2023-03-14 15:59:537514 moved_paths = []
Mike Dougherty1b8be712022-10-20 00:15:137515 warning_paths = []
7516
7517 for f in input_api.AffectedSourceFiles(_FilterFile):
7518 local_path = f.LocalPath()
7519
7520 if input_api.os_path.splitext(local_path)[1] == '.js':
7521 if f.Action() == 'A':
Mike Dougherty4d1050b2023-03-14 15:59:537522 if input_api.os_path.basename(local_path) in deleted_files:
7523 # This script was probably moved rather than newly created.
7524 # Present a warning instead of an error for these cases.
7525 moved_paths.append(local_path)
7526 else:
7527 error_paths.append(local_path)
Mike Dougherty1b8be712022-10-20 00:15:137528 elif f.Action() != 'D':
7529 warning_paths.append(local_path)
7530
7531 results = []
7532
7533 if warning_paths:
7534 results.append(output_api.PresubmitPromptWarning(
7535 'TypeScript is now fully supported for iOS feature scripts. '
7536 'Consider converting JavaScript files to TypeScript. See '
7537 '//ios/web/public/js_messaging/README.md for more details.',
7538 warning_paths))
7539
Mike Dougherty4d1050b2023-03-14 15:59:537540 if moved_paths:
7541 results.append(output_api.PresubmitPromptWarning(
7542 'Do not use JavaScript on iOS for new files as TypeScript is '
7543 'fully supported. (If this is a moved file, you may leave the '
7544 'script unconverted.) See //ios/web/public/js_messaging/README.md '
7545 'for help using scripts on iOS.', moved_paths))
7546
Mike Dougherty1b8be712022-10-20 00:15:137547 if error_paths:
7548 results.append(output_api.PresubmitError(
7549 'Do not use JavaScript on iOS as TypeScript is fully supported. '
7550 'See //ios/web/public/js_messaging/README.md for help using '
7551 'scripts on iOS.', error_paths))
7552
7553 return results
Hans Wennborg23a81d52023-03-24 16:38:137554
7555def CheckLibcxxRevisionsMatch(input_api, output_api):
7556 """Check to make sure the libc++ version matches across deps files."""
Andrew Grieve21bb6792023-03-27 19:06:487557 # Disable check for changes to sub-repositories.
7558 if input_api.PresubmitLocalPath() != input_api.change.RepositoryRoot():
Sam Maierb926c58c2023-08-08 19:58:257559 return []
Hans Wennborg23a81d52023-03-24 16:38:137560
7561 DEPS_FILES = [ 'DEPS', 'buildtools/deps_revisions.gni' ]
7562
Anton Bershanskyi4253349482025-02-11 21:01:277563 file_filter = lambda f: f.UnixLocalPath() in DEPS_FILES
Hans Wennborg23a81d52023-03-24 16:38:137564 changed_deps_files = input_api.AffectedFiles(file_filter=file_filter)
7565 if not changed_deps_files:
7566 return []
7567
7568 def LibcxxRevision(file):
7569 file = input_api.os_path.join(input_api.PresubmitLocalPath(),
7570 *file.split('/'))
7571 return input_api.re.search(
7572 r'libcxx_revision.*[:=].*[\'"](\w+)[\'"]',
7573 input_api.ReadFile(file)).group(1)
7574
7575 if len(set([LibcxxRevision(f) for f in DEPS_FILES])) == 1:
7576 return []
7577
7578 return [output_api.PresubmitError(
7579 'libcxx_revision not equal across %s' % ', '.join(DEPS_FILES),
7580 changed_deps_files)]
Arthur Sonzogni7109bd32023-10-03 10:34:427581
7582
7583def CheckDanglingUntriaged(input_api, output_api):
7584 """Warn developers adding DanglingUntriaged raw_ptr."""
7585
7586 # Ignore during git presubmit --all.
7587 #
7588 # This would be too costly, because this would check every lines of every
7589 # C++ files. Check from _BANNED_CPP_FUNCTIONS are also reading the whole
7590 # source code, but only once to apply every checks. It seems the bots like
7591 # `win-presubmit` are particularly sensitive to reading the files. Adding
7592 # this check caused the bot to run 2x longer. See https://crbug.com/1486612.
7593 if input_api.no_diffs:
Arthur Sonzogni9eafd222023-11-10 08:50:397594 return []
Arthur Sonzogni7109bd32023-10-03 10:34:427595
7596 def FilterFile(file):
7597 return input_api.FilterSourceFile(
7598 file,
7599 files_to_check=[r".*\.(h|cc|cpp|cxx|m|mm)$"],
7600 files_to_skip=[r"^base/allocator.*"],
7601 )
7602
7603 count = 0
Arthur Sonzognic66e9c82024-04-23 07:53:047604 for f in input_api.AffectedFiles(file_filter=FilterFile):
Arthur Sonzogni9eafd222023-11-10 08:50:397605 count -= sum([l.count("DanglingUntriaged") for l in f.OldContents()])
7606 count += sum([l.count("DanglingUntriaged") for l in f.NewContents()])
Arthur Sonzogni7109bd32023-10-03 10:34:427607
7608 # Most likely, nothing changed:
7609 if count == 0:
7610 return []
7611
7612 # Congrats developers for improving it:
7613 if count < 0:
Arthur Sonzogni9eafd222023-11-10 08:50:397614 message = f"DanglingUntriaged pointers removed: {-count}\nThank you!"
Arthur Sonzogni7109bd32023-10-03 10:34:427615 return [output_api.PresubmitNotifyResult(message)]
7616
7617 # Check for 'DanglingUntriaged-notes' in the description:
7618 notes_regex = input_api.re.compile("DanglingUntriaged-notes[:=]")
7619 if any(
7620 notes_regex.match(line)
7621 for line in input_api.change.DescriptionText().splitlines()):
7622 return []
7623
7624 # Check for DanglingUntriaged-notes in the git footer:
7625 if input_api.change.GitFootersFromDescription().get(
7626 "DanglingUntriaged-notes", []):
7627 return []
7628
7629 message = (
Arthur Sonzogni9eafd222023-11-10 08:50:397630 "Unexpected new occurrences of `DanglingUntriaged` detected. Please\n" +
7631 "avoid adding new ones\n" +
7632 "\n" +
7633 "See documentation:\n" +
7634 "https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr.md\n" +
7635 "\n" +
7636 "See also the guide to fix dangling pointers:\n" +
7637 "https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr_guide.md\n" +
7638 "\n" +
7639 "To disable this warning, please add in the commit description:\n" +
Alex Gough26dcd852023-12-22 16:47:197640 "DanglingUntriaged-notes: <rationale for new untriaged dangling " +
Arthur Sonzogni9eafd222023-11-10 08:50:397641 "pointers>"
Arthur Sonzogni7109bd32023-10-03 10:34:427642 )
7643 return [output_api.PresubmitPromptWarning(message)]
Jan Keitel77be7522023-10-12 20:40:497644
7645def CheckInlineConstexprDefinitionsInHeaders(input_api, output_api):
7646 """Checks that non-static constexpr definitions in headers are inline."""
7647 # In a properly formatted file, constexpr definitions inside classes or
7648 # structs will have additional whitespace at the beginning of the line.
7649 # The pattern looks for variables initialized as constexpr kVar = ...; or
7650 # constexpr kVar{...};
7651 # The pattern does not match expressions that have braces in kVar to avoid
7652 # matching constexpr functions.
7653 pattern = input_api.re.compile(r'^constexpr (?!inline )[^\(\)]*[={]')
7654 attribute_pattern = input_api.re.compile(r'(\[\[[a-zA-Z_:]+\]\]|[A-Z]+[A-Z_]+) ')
7655 problems = []
7656 for f in input_api.AffectedFiles():
7657 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
7658 continue
7659
7660 for line_number, line in f.ChangedContents():
7661 line = attribute_pattern.sub('', line)
7662 if pattern.search(line):
7663 problems.append(
7664 f"{f.LocalPath()}: {line_number}\n {line}")
7665
7666 if problems:
7667 return [
7668 output_api.PresubmitPromptWarning(
7669 'Consider inlining constexpr variable definitions in headers '
7670 'outside of classes to avoid unnecessary copies of the '
7671 'constant. See https://abseil.io/tips/168 for more details.',
7672 problems)
7673 ]
7674 else:
7675 return []
Alison Galed6b25fe2024-04-17 13:59:047676
7677def CheckTodoBugReferences(input_api, output_api):
7678 """Checks that bugs in TODOs use updated issue tracker IDs."""
7679
Manish Goregaokardc9e3512025-02-03 15:30:587680 files_to_skip = ['PRESUBMIT_test.py', r"^third_party/rust/chromium_crates_io/vendor/.*"]
Alison Galed6b25fe2024-04-17 13:59:047681
7682 def _FilterFile(affected_file):
7683 return input_api.FilterSourceFile(
7684 affected_file,
7685 files_to_skip=files_to_skip)
7686
7687 # Monorail bug IDs are all less than or equal to 1524553 so check that all
7688 # bugs in TODOs are greater than that value.
Tom Sepez8e628582025-02-14 02:18:557689 pattern = input_api.re.compile(r'.*\bTODO\([^\)0-9]*([0-9]+)\).*')
Alison Galed6b25fe2024-04-17 13:59:047690 problems = []
7691 for f in input_api.AffectedSourceFiles(_FilterFile):
7692 for line_number, line in f.ChangedContents():
7693 match = pattern.match(line)
7694 if match and int(match.group(1)) <= 1524553:
7695 problems.append(
7696 f"{f.LocalPath()}: {line_number}\n {line}")
7697
7698 if problems:
7699 return [
7700 output_api.PresubmitPromptWarning(
Alison Galecb598de52024-04-26 17:03:257701 'TODOs should use the new Chromium Issue Tracker IDs which can '
7702 'be found by navigating to the bug. See '
7703 'https://crbug.com/336778624 for more details.',
Alison Galed6b25fe2024-04-17 13:59:047704 problems)
7705 ]
7706 else:
7707 return []