blob: 0f9d94236718d3b08a05591d0bf3e4479cd31a0b [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
Ben Pastenee79d66112025-04-23 19:46:15147 # If True, surfaces any violation as a Gerrit comment on the CL after
148 # running the CQ.
149 surface_as_gerrit_lint: Optional[bool] = None
[email protected]cf9b78f2012-11-14 11:40:28150
Daniel Chenga44a1bcd2022-03-15 20:00:15151
Daniel Cheng917ce542022-03-15 20:46:57152_BANNED_JAVA_IMPORTS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15153 BanRule(
154 'import java.net.URI;',
155 (
156 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
157 ),
158 excluded_paths=(
159 (r'net/android/javatests/src/org/chromium/net/'
Dirk Prankee4df27972025-02-26 18:39:35160 r'AndroidProxySelectorTest\.java'),
Daniel Chenga44a1bcd2022-03-15 20:00:15161 r'components/cronet/',
162 r'third_party/robolectric/local/',
163 ),
Michael Thiessen44457642020-02-06 00:24:15164 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15165 BanRule(
166 'import android.annotation.TargetApi;',
167 (
168 'Do not use TargetApi, use @androidx.annotation.RequiresApi instead. '
169 'RequiresApi ensures that any calls are guarded by the appropriate '
170 'SDK_INT check. See https://crbug.com/1116486.',
171 ),
172 ),
173 BanRule(
Mohamed Heikal3d7a94c2023-03-28 16:55:24174 'import androidx.test.rule.ActivityTestRule;',
Daniel Chenga44a1bcd2022-03-15 20:00:15175 (
176 'Do not use ActivityTestRule, use '
177 'org.chromium.base.test.BaseActivityTestRule instead.',
178 ),
179 excluded_paths=(
180 'components/cronet/',
181 ),
182 ),
Min Qinbc44383c2023-02-22 17:25:26183 BanRule(
184 'import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;',
185 (
186 'Do not use VectorDrawableCompat, use getResources().getDrawable() to '
187 'avoid extra indirections. Please also add trace event as the call '
188 'might take more than 20 ms to complete.',
189 ),
190 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15191)
wnwenbdc444e2016-05-25 13:44:15192
Daniel Cheng917ce542022-03-15 20:46:57193_BANNED_JAVA_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15194 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41195 'StrictMode.allowThreadDiskReads()',
196 (
197 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
198 'directly.',
199 ),
200 False,
201 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15202 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41203 'StrictMode.allowThreadDiskWrites()',
204 (
205 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
206 'directly.',
207 ),
208 False,
209 ),
Daniel Cheng917ce542022-03-15 20:46:57210 BanRule(
Michael Thiessen0f2547e2020-07-27 21:55:36211 '.waitForIdleSync()',
212 (
213 'Do not use waitForIdleSync as it masks underlying issues. There is '
214 'almost always something else you should wait on instead.',
215 ),
216 False,
217 ),
Ashley Newson09cbd602022-10-26 11:40:14218 BanRule(
Ashley Newsoneb6f5ce2022-10-26 14:45:42219 r'/(?<!\bsuper\.)(?<!\bIntent )\bregisterReceiver\(',
Ashley Newson09cbd602022-10-26 11:40:14220 (
221 'Do not call android.content.Context.registerReceiver (or an override) '
222 'directly. Use one of the wrapper methods defined in '
223 'org.chromium.base.ContextUtils, such as '
224 'registerProtectedBroadcastReceiver, '
225 'registerExportedBroadcastReceiver, or '
226 'registerNonExportedBroadcastReceiver. See their documentation for '
227 'which one to use.',
228 ),
229 True,
230 excluded_paths=(
Ashley Newson22bc26d2022-11-01 20:30:57231 r'.*Test[^a-z]',
232 r'third_party/',
Ashley Newson09cbd602022-10-26 11:40:14233 'base/android/java/src/org/chromium/base/ContextUtils.java',
Brandon Mousseau7e76a9c2022-12-08 22:08:38234 'chromecast/browser/android/apk/src/org/chromium/chromecast/shell/BroadcastReceiverScope.java',
Ashley Newson09cbd602022-10-26 11:40:14235 ),
236 ),
Ted Chocd5b327b12022-11-05 02:13:22237 BanRule(
238 r'/(?:extends|new)\s*(?:android.util.)?Property<[A-Za-z.]+,\s*(?:Integer|Float)>',
239 (
240 'Do not use Property<..., Integer|Float>, but use FloatProperty or '
241 'IntProperty because it will avoid unnecessary autoboxing of '
242 'primitives.',
243 ),
244 ),
Peilin Wangbba4a8652022-11-10 16:33:57245 BanRule(
246 'requestLayout()',
247 (
248 'Layouts can be expensive. Prefer using ViewUtils.requestLayout(), '
249 'which emits a trace event with additional information to help with '
250 'scroll jank investigations. See http://crbug.com/1354176.',
251 ),
252 False,
253 excluded_paths=(
254 'ui/android/java/src/org/chromium/ui/base/ViewUtils.java',
255 ),
256 ),
Ted Chocf40ea9152023-02-14 19:02:39257 BanRule(
Ted Chocf486e3f2024-02-17 05:37:03258 'ProfileManager.getLastUsedRegularProfile()',
Ted Chocf40ea9152023-02-14 19:02:39259 (
260 'Prefer passing in the Profile reference instead of relying on the '
261 'static getLastUsedRegularProfile() call. Only top level entry points '
262 '(e.g. Activities) should call this method. Otherwise, the Profile '
263 'should either be passed in explicitly or retreived from an existing '
264 'entity with a reference to the Profile (e.g. WebContents).',
265 ),
266 False,
267 excluded_paths=(
268 r'.*Test[A-Z]?.*\.java',
269 ),
270 ),
Min Qinbc44383c2023-02-22 17:25:26271 BanRule(
272 r'/(ResourcesCompat|getResources\(\))\.getDrawable\(\)',
273 (
274 'getDrawable() can be expensive. If you have a lot of calls to '
275 'GetDrawable() or your code may introduce janks, please put your calls '
276 'inside a trace().',
277 ),
278 False,
279 excluded_paths=(
280 r'.*Test[A-Z]?.*\.java',
281 ),
282 ),
Henrique Nakashimabbf2b262023-03-10 17:21:39283 BanRule(
284 r'/RecordHistogram\.getHistogram(ValueCount|TotalCount|Samples)ForTesting\(',
285 (
286 'Raw histogram counts are easy to misuse; for example they don\'t reset '
Thiago Perrotta099034f2023-06-05 18:10:20287 'between batched tests. Use HistogramWatcher to check histogram records '
288 'instead.',
Henrique Nakashimabbf2b262023-03-10 17:21:39289 ),
290 False,
291 excluded_paths=(
292 'base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java',
293 'base/test/android/javatests/src/org/chromium/base/test/util/HistogramWatcher.java',
294 ),
295 ),
Jenna Himawan859865d2025-02-25 22:22:31296 BanRule(
297 r'/((announceForAccessibility\()|TYPE_ANNOUNCEMENT)',
298 ('Android 16 deprecates accessibility announcements, characterized by '
299 'the use of announceForAccessibility or the dispatch of '
300 'TYPE_ANNOUNCEMENT accessibility events. See '
301 'https://developer.android.com/about/versions/16/behavior-changes-all#disruptive-a11y'
302 ' for more details and suggested replacements.', ),
303 False,
304 ),
Nate Fischerd541ff82025-03-11 21:34:19305 BanRule(
306 pattern=(r'IS_DESKTOP_ANDROID'),
307 explanation=(
308 'Features which depend on IS_DESKTOP_ANDROID should only exist in '
309 'chrome/ layer and similar layers. Lower layers such as content/ '
310 'should not have features which are only designed for '
311 'desktop-android builds. See https://crbug.com/401628399.', ),
312 treat_as_error=False,
313 excluded_paths=[
314 _THIRD_PARTY_EXCEPT_BLINK, # Don't warn in third_party folders.
315 r'^build/', # This is permitted in build/ folder.
316 r'^chrome/', # This is permitted in chrome/ folder.
317 r'^components/', # This is permitted only for components/ that are not shared by WebView.
318 r'^extensions/', # This is permitted in chrome/ folder.
319 r'^infra/', # This is permitted in infra/ folder.
320 r'^tools/', # This is permitted in tools/ folder.
321 ],
Ben Pastenee79d66112025-04-23 19:46:15322 surface_as_gerrit_lint=True,
Nate Fischerd541ff82025-03-11 21:34:19323 ),
Eric Stevensona9a980972017-09-23 00:04:41324)
325
Clement Yan9b330cb2022-11-17 05:25:29326_BANNED_JAVASCRIPT_FUNCTIONS : Sequence [BanRule] = (
327 BanRule(
328 r'/\bchrome\.send\b',
329 (
330 '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).',
331 'Please use mojo instead for new webuis. https://docs.google.com/document/d/1RF-GSUoveYa37eoyZ9EhwMtaIwoW7Z88pIgNZ9YzQi4/edit#heading=h.gkk22wgk6wff',
332 ),
333 True,
334 (
335 r'^(?!ash\/webui).+',
336 # TODO(crbug.com/1385601): pre-existing violations still need to be
337 # cleaned up.
Rebekah Potter57aa94df2022-12-13 20:30:58338 'ash/webui/common/resources/cr.m.js',
Clement Yan9b330cb2022-11-17 05:25:29339 'ash/webui/common/resources/multidevice_setup/multidevice_setup_browser_proxy.js',
Martin Bidlingmaiera921fee72023-06-03 07:52:22340 'ash/webui/common/resources/quick_unlock/lock_screen_constants.ts',
Clement Yan9b330cb2022-11-17 05:25:29341 'ash/webui/common/resources/smb_shares/smb_browser_proxy.js',
Chad Duffin06e47de2023-12-14 18:04:13342 'ash/webui/connectivity_diagnostics/resources/connectivity_diagnostics.ts',
Clement Yan9b330cb2022-11-17 05:25:29343 'ash/webui/diagnostics_ui/resources/diagnostics_browser_proxy.ts',
344 'ash/webui/multidevice_debug/resources/logs.js',
345 'ash/webui/multidevice_debug/resources/webui.js',
346 'ash/webui/projector_app/resources/annotator/trusted/annotator_browser_proxy.js',
347 'ash/webui/projector_app/resources/app/trusted/projector_browser_proxy.js',
Ashley Prasad71f9024e2023-09-25 22:33:55348 # TODO(b/301634378): Remove violation exception once Scanning App
349 # migrated off usage of `chrome.send`.
350 'ash/webui/scanning/resources/scanning_browser_proxy.ts',
Clement Yan9b330cb2022-11-17 05:25:29351 ),
352 ),
353)
354
Daniel Cheng917ce542022-03-15 20:46:57355_BANNED_OBJC_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15356 BanRule(
[email protected]127f18ec2012-06-16 05:05:59357 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20358 (
359 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59360 'prohibited. Please use CrTrackingArea instead.',
361 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
362 ),
363 False,
364 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15365 BanRule(
[email protected]eaae1972014-04-16 04:17:26366 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20367 (
368 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59369 'instead.',
370 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
371 ),
372 False,
373 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15374 BanRule(
[email protected]127f18ec2012-06-16 05:05:59375 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20376 (
377 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59378 'Please use |convertPoint:(point) fromView:nil| instead.',
379 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
380 ),
381 True,
382 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15383 BanRule(
[email protected]127f18ec2012-06-16 05:05:59384 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20385 (
386 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59387 'Please use |convertPoint:(point) toView:nil| instead.',
388 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
389 ),
390 True,
391 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15392 BanRule(
[email protected]127f18ec2012-06-16 05:05:59393 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20394 (
395 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59396 'Please use |convertRect:(point) fromView:nil| instead.',
397 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
398 ),
399 True,
400 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15401 BanRule(
[email protected]127f18ec2012-06-16 05:05:59402 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20403 (
404 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59405 'Please use |convertRect:(point) toView:nil| instead.',
406 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
407 ),
408 True,
409 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15410 BanRule(
[email protected]127f18ec2012-06-16 05:05:59411 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20412 (
413 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59414 'Please use |convertSize:(point) fromView:nil| instead.',
415 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
416 ),
417 True,
418 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15419 BanRule(
[email protected]127f18ec2012-06-16 05:05:59420 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20421 (
422 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59423 'Please use |convertSize:(point) toView:nil| instead.',
424 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
425 ),
426 True,
427 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15428 BanRule(
jif65398702016-10-27 10:19:48429 r"/\s+UTF8String\s*]",
430 (
431 'The use of -[NSString UTF8String] is dangerous as it can return null',
432 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
433 'Please use |SysNSStringToUTF8| instead.',
434 ),
435 True,
Marijn Kruisselbrink1b7c48952023-08-31 16:58:34436 excluded_paths = (
437 '^third_party/ocmock/OCMock/',
438 ),
jif65398702016-10-27 10:19:48439 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15440 BanRule(
Sylvain Defresne4cf1d182017-09-18 14:16:34441 r'__unsafe_unretained',
442 (
443 'The use of __unsafe_unretained is almost certainly wrong, unless',
444 'when interacting with NSFastEnumeration or NSInvocation.',
445 'Please use __weak in files build with ARC, nothing otherwise.',
446 ),
447 False,
448 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15449 BanRule(
Avi Drissman7382afa02019-04-29 23:27:13450 'freeWhenDone:NO',
451 (
452 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
453 'Foundation types is prohibited.',
454 ),
455 True,
456 ),
Avi Drissman3d243a42023-08-01 16:53:59457 BanRule(
458 'This file requires ARC support.',
459 (
460 'ARC compilation is default in Chromium; do not add boilerplate to ',
461 'files that require ARC.',
462 ),
463 True,
464 ),
[email protected]127f18ec2012-06-16 05:05:59465)
466
Sylvain Defresnea8b73d252018-02-28 15:45:54467_BANNED_IOS_OBJC_FUNCTIONS = (
Daniel Chenga44a1bcd2022-03-15 20:00:15468 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54469 r'/\bTEST[(]',
470 (
471 'TEST() macro should not be used in Objective-C++ code as it does not ',
472 'drain the autorelease pool at the end of the test. Use TEST_F() ',
473 'macro instead with a fixture inheriting from PlatformTest (or a ',
474 'typedef).'
475 ),
476 True,
477 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15478 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54479 r'/\btesting::Test\b',
480 (
481 'testing::Test should not be used in Objective-C++ code as it does ',
482 'not drain the autorelease pool at the end of the test. Use ',
483 'PlatformTest instead.'
484 ),
485 True,
486 ),
Ewann2ecc8d72022-07-18 07:41:23487 BanRule(
488 ' systemImageNamed:',
489 (
490 '+[UIImage systemImageNamed:] should not be used to create symbols.',
491 'Instead use a wrapper defined in:',
Slobodan Pejic8ef56c702024-07-12 18:21:26492 'ios/chrome/browser/shared/ui/symbols/symbol_helpers.h'
Ewann2ecc8d72022-07-18 07:41:23493 ),
494 True,
Ewann450a2ef2022-07-19 14:38:23495 excluded_paths=(
Gauthier Ambard4d8756b2023-04-07 17:26:41496 'ios/chrome/browser/shared/ui/symbols/symbol_helpers.mm',
Slobodan Pejic8ef56c702024-07-12 18:21:26497 'ios/chrome/common',
Tommy Martino2a1182dc2024-11-20 19:34:42498 # App extensions have restricted dependencies and thus can't use the
499 # wrappers.
Riley Wong49be8a882025-02-27 00:38:23500 r'^ios/chrome/\w+_extension/',
Ewann450a2ef2022-07-19 14:38:23501 ),
Ewann2ecc8d72022-07-18 07:41:23502 ),
Sylvain Defresne781b9f92024-12-11 09:36:18503 BanRule(
504 r'public (RefCounted)?BrowserStateKeyedServiceFactory',
505 (
506 'KeyedService factories in //ios/chrome/browser should inherit from',
507 '(Refcounted)?ProfileKeyedServieFactoryIOS, not directory from',
508 '(Refcounted)?BrowserStateKeyedServiceFactory.'
509 ),
510 treat_as_error=True,
511 excluded_paths=(
512 'ios/components',
513 'ios/web_view',
514 ),
515 ),
Sylvain Defresnea8b73d252018-02-28 15:45:54516)
517
Daniel Cheng917ce542022-03-15 20:46:57518_BANNED_IOS_EGTEST_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15519 BanRule(
Peter K. Lee6c03ccff2019-07-15 14:40:05520 r'/\bEXPECT_OCMOCK_VERIFY\b',
521 (
522 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
523 'it is meant for GTests. Use [mock verify] instead.'
524 ),
525 True,
526 ),
527)
528
Daniel Cheng566634ff2024-06-29 14:56:53529_BANNED_CPP_FUNCTIONS: Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15530 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53531 '%#0',
532 (
533 'Zero-padded values that use "#" to add prefixes don\'t exhibit ',
534 'consistent behavior, since the prefix is not prepended for zero ',
535 'values. Use "0x%0..." instead.',
536 ),
537 False,
538 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting7c0d98a2023-10-06 15:42:39539 ),
540 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53541 r'/\busing namespace ',
542 (
543 'Using directives ("using namespace x") are banned by the Google Style',
544 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
545 'Explicitly qualify symbols or use using declarations ("using x::foo").',
546 ),
547 True,
548 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting94a56c42019-10-25 21:54:04549 ),
Antonio Gomes07300d02019-03-13 20:59:57550 # Make sure that gtest's FRIEND_TEST() macro is not used; the
551 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
552 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
Daniel Chenga44a1bcd2022-03-15 20:00:15553 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53554 'FRIEND_TEST(',
555 (
556 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
557 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
558 ),
559 False,
560 excluded_paths=(
561 "base/gtest_prod_util.h",
562 "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/gtest_prod_util.h",
563 ),
[email protected]23e6cbc2012-06-16 18:51:20564 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15565 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53566 'setMatrixClip',
567 (
568 'Overriding setMatrixClip() is prohibited; ',
569 'the base function is deprecated. ',
570 ),
571 True,
572 (),
tomhudsone2c14d552016-05-26 17:07:46573 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15574 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53575 'SkRefPtr',
576 ('The use of SkRefPtr is prohibited. ', 'Please use sk_sp<> instead.'),
577 True,
578 (),
[email protected]52657f62013-05-20 05:30:31579 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15580 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53581 'SkAutoRef',
582 ('The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
583 'Please use sk_sp<> instead.'),
584 True,
585 (),
[email protected]52657f62013-05-20 05:30:31586 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15587 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53588 'SkAutoTUnref',
589 ('The use of SkAutoTUnref is dangerous because it implicitly ',
590 'converts to a raw pointer. Please use sk_sp<> instead.'),
591 True,
592 (),
[email protected]52657f62013-05-20 05:30:31593 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15594 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53595 'SkAutoUnref',
596 ('The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
597 'because it implicitly converts to a raw pointer. ',
598 'Please use sk_sp<> instead.'),
599 True,
600 (),
[email protected]52657f62013-05-20 05:30:31601 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15602 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53603 r'/HANDLE_EINTR\(.*close',
604 ('HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
605 'descriptor will be closed, and it is incorrect to retry the close.',
606 'Either call close directly and ignore its return value, or wrap close',
607 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
608 ),
609 True,
610 (),
[email protected]d89eec82013-12-03 14:10:59611 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15612 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53613 r'/IGNORE_EINTR\((?!.*close)',
614 (
615 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
616 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
617 ),
618 True,
619 (
620 # Files that #define IGNORE_EINTR.
621 r'^base/posix/eintr_wrapper\.h$',
622 r'^ppapi/tests/test_broker\.cc$',
623 ),
[email protected]d89eec82013-12-03 14:10:59624 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15625 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53626 r'/v8::Extension\(',
627 (
628 'Do not introduce new v8::Extensions into the code base, use',
629 'gin::Wrappable instead. See http://crbug.com/334679',
630 ),
631 True,
632 (r'extensions/renderer/safe_builtins\.*', ),
[email protected]ec5b3f02014-04-04 18:43:43633 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15634 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53635 '#pragma comment(lib,',
636 ('Specify libraries to link with in build files and not in the source.',
637 ),
638 True,
639 (
640 r'^base/third_party/symbolize/.*',
641 r'^third_party/abseil-cpp/.*',
Victor Hugo Vianna Silvac86846c02025-03-07 06:56:37642 r'^third_party/grpc/source/.*',
Daniel Cheng566634ff2024-06-29 14:56:53643 ),
jame2d1a952016-04-02 00:27:10644 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15645 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53646 r'/base::SequenceChecker\b',
647 ('Consider using SEQUENCE_CHECKER macros instead of the class directly.',
648 ),
649 False,
650 (),
gabd52c912a2017-05-11 04:15:59651 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15652 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53653 r'/base::ThreadChecker\b',
654 ('Consider using THREAD_CHECKER macros instead of the class directly.',
655 ),
656 False,
657 (),
gabd52c912a2017-05-11 04:15:59658 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15659 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53660 r'/\b(?!(Sequenced|SingleThread))\w*TaskRunner::(GetCurrentDefault|CurrentDefaultHandle)',
661 (
662 'It is not allowed to call these methods from the subclasses ',
663 'of Sequenced or SingleThread task runners.',
664 ),
665 True,
666 (),
Sean Maher03efef12022-09-23 22:43:13667 ),
668 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53669 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
670 (
671 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
672 'deprecated (http://crbug.com/634507). Please avoid converting away',
673 'from the Time types in Chromium code, especially if any math is',
674 'being done on time values. For interfacing with platform/library',
675 'APIs, use base::Time::(From,To)DeltaSinceWindowsEpoch() or',
676 'base::{TimeDelta::In}Microseconds(), or one of the other type',
677 'converter methods instead. For faking TimeXXX values (for unit',
678 'testing only), use TimeXXX() + Microseconds(N). For',
679 'other use cases, please contact base/time/OWNERS.',
680 ),
681 False,
682 excluded_paths=(
683 "base/time/time.h",
684 "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/time/time.h",
685 ),
Yuri Wiitala2f8de5c2017-07-21 00:11:06686 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15687 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53688 'CallJavascriptFunctionUnsafe',
689 (
690 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
691 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
692 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
693 ),
694 False,
695 (
696 r'^content/browser/webui/web_ui_impl\.(cc|h)$',
697 r'^content/public/browser/web_ui\.h$',
698 r'^content/public/test/test_web_ui\.(cc|h)$',
699 ),
dbeamb6f4fde2017-06-15 04:03:06700 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15701 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53702 'leveldb::DB::Open',
703 (
704 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
705 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
706 "Chrome's tracing, making their memory usage visible.",
707 ),
708 True,
709 (r'^third_party/leveldatabase/.*\.(cc|h)$', ),
Gabriel Charette0592c3a2017-07-26 12:02:04710 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15711 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53712 'leveldb::NewMemEnv',
713 (
714 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
715 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
716 "to Chrome's tracing, making their memory usage visible.",
717 ),
718 True,
719 (r'^third_party/leveldatabase/.*\.(cc|h)$', ),
Chris Mumfordc38afb62017-10-09 17:55:08720 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15721 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53722 'base::ScopedMockTimeMessageLoopTaskRunner',
723 (
724 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
725 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
726 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
727 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
728 'with gab@ first if you think you need it)',
729 ),
730 False,
731 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57732 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15733 BanRule(
Peter Kasting5fdcd782025-01-13 14:57:07734 '\bstd::aligned_(storage|union)\b',
735 (
736 'std::aligned_storage and std::aligned_union are deprecated in',
737 'C++23. Use an aligned char array instead.'
738 ),
739 True,
740 (),
741 ),
742 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53743 'std::regex',
744 (
745 'Using std::regex adds unnecessary binary size to Chrome. Please use',
746 're2::RE2 instead (crbug.com/755321)',
747 ),
748 True,
749 [
750 # Abseil's benchmarks never linked into chrome.
751 'third_party/abseil-cpp/.*_benchmark.cc',
752 ],
Francois Doray43670e32017-09-27 12:40:38753 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15754 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53755 r'/\bstd::sto(i|l|ul|ll|ull)\b',
756 (
757 'std::sto{i,l,ul,ll,ull}() use exceptions to communicate results. ',
758 'Use base::StringTo[U]Int[64]() instead.',
759 ),
760 True,
761 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting991618a62019-06-17 22:00:09762 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15763 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53764 r'/\bstd::sto(f|d|ld)\b',
765 (
766 'std::sto{f,d,ld}() use exceptions to communicate results. ',
767 'For locale-independent values, e.g. reading numbers from disk',
768 'profiles, use base::StringToDouble().',
769 'For user-visible values, parse using ICU.',
770 ),
771 True,
772 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting991618a62019-06-17 22:00:09773 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15774 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53775 r'/\bstd::to_string\b',
776 (
777 'std::to_string() is locale dependent and slower than alternatives.',
778 'For locale-independent strings, e.g. writing numbers to disk',
779 'profiles, use base::NumberToString().',
780 'For user-visible strings, use base::FormatNumber() and',
781 'the related functions in base/i18n/number_formatting.h.',
782 ),
783 True,
784 [
785 # TODO(crbug.com/335672557): Please do not add to this list. Existing
786 # uses should removed.
Daniel Cheng566634ff2024-06-29 14:56:53787 "third_party/blink/renderer/core/css/parser/css_proto_converter.cc",
788 "third_party/blink/renderer/core/editing/ime/edit_context.cc",
789 "third_party/blink/renderer/platform/graphics/bitmap_image_test.cc",
Daniel Cheng566634ff2024-06-29 14:56:53790 _THIRD_PARTY_EXCEPT_BLINK
791 ],
Daniel Bratell69334cc2019-03-26 11:07:45792 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15793 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53794 r'/#include <(cctype|ctype\.h|cwctype|wctype.h)>',
795 (
796 '<cctype>/<ctype.h>/<cwctype>/<wctype.h> are banned. Use',
797 '"third_party/abseil-cpp/absl/strings/ascii.h" instead.',
798 ),
799 True,
800 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting6f79b202023-08-09 21:25:41801 ),
802 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53803 r'/\bstd::shared_ptr\b',
804 ('std::shared_ptr is banned. Use scoped_refptr instead.', ),
805 True,
806 [
807 # Needed for interop with third-party library.
Dirk Prankee4df27972025-02-26 18:39:35808 r'^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
809 r'array_buffer_contents\.(cc|h)',
810 r'^third_party/blink/renderer/core/typed_arrays/dom_array_buffer\.cc',
Daniel Cheng566634ff2024-06-29 14:56:53811 '^third_party/blink/renderer/bindings/core/v8/' +
812 'v8_wasm_response_extensions.cc',
Dirk Prankee4df27972025-02-26 18:39:35813 r'^gin/array_buffer\.(cc|h)',
814 r'^gin/per_isolate_data\.(cc|h)',
Daniel Cheng566634ff2024-06-29 14:56:53815 '^chrome/services/sharing/nearby/',
816 # Needed for interop with third-party library libunwindstack.
Dirk Prankee4df27972025-02-26 18:39:35817 r'^base/profiler/libunwindstack_unwinder_android\.(cc|h)',
818 r'^base/profiler/native_unwinder_android_memory_regions_map_impl.(cc|h)',
Daniel Cheng566634ff2024-06-29 14:56:53819 # Needed for interop with third-party boringssl cert verifier
820 '^third_party/boringssl/',
821 '^net/cert/',
822 '^net/tools/cert_verify_tool/',
823 '^services/cert_verifier/',
824 '^components/certificate_transparency/',
825 '^components/media_router/common/providers/cast/certificate/',
826 # gRPC provides some C++ libraries that use std::shared_ptr<>.
827 '^chromeos/ash/services/libassistant/grpc/',
828 '^chromecast/cast_core/grpc',
829 '^chromecast/cast_core/runtime/browser',
Dirk Prankee4df27972025-02-26 18:39:35830 r'^ios/chrome/test/earl_grey/chrome_egtest_plugin_client\.(mm|h)',
Daniel Cheng566634ff2024-06-29 14:56:53831 # Fuchsia provides C++ libraries that use std::shared_ptr<>.
Dirk Prankee4df27972025-02-26 18:39:35832 r'^base/fuchsia/.*\.(cc|h)',
833 r'.*fuchsia.*test\.(cc|h)',
Daniel Cheng566634ff2024-06-29 14:56:53834 # Clang plugins have different build config.
835 '^tools/clang/plugins/',
836 _THIRD_PARTY_EXCEPT_BLINK
837 ], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21838 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15839 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53840 r'/\bstd::weak_ptr\b',
841 ('std::weak_ptr is banned. Use base::WeakPtr instead.', ),
842 True,
843 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting991618a62019-06-17 22:00:09844 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15845 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53846 r'/\blong long\b',
847 ('long long is banned. Use [u]int64_t instead.', ),
848 False, # Only a warning since it is already used.
849 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21850 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15851 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53852 r'/\b(absl|std)::any\b',
853 (
854 '{absl,std}::any are banned due to incompatibility with the component ',
855 'build.',
856 ),
857 True,
858 # Not an error in third party folders, though it probably should be :)
859 [_THIRD_PARTY_EXCEPT_BLINK],
Daniel Chengc05fcc62022-01-12 16:54:29860 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15861 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53862 r'/\bstd::bind\b',
863 (
864 'std::bind() is banned because of lifetime risks. Use ',
865 'base::Bind{Once,Repeating}() instead.',
866 ),
867 True,
868 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21869 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15870 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53871 (r'/\bstd::(?:'
872 r'linear_congruential_engine|mersenne_twister_engine|'
873 r'subtract_with_carry_engine|discard_block_engine|'
874 r'independent_bits_engine|shuffle_order_engine|'
875 r'minstd_rand0?|mt19937(_64)?|ranlux(24|48)(_base)?|knuth_b|'
876 r'default_random_engine|'
877 r'random_device|'
878 r'seed_seq'
879 r')\b'),
880 (
881 'STL random number engines and generators are banned. Use the ',
882 'helpers in base/rand_util.h instead, e.g. base::RandBytes() or ',
883 'base::RandomBitGenerator.'
884 '',
885 'Please reach out to [email protected] if the base APIs are ',
886 'insufficient for your needs.',
887 ),
888 True,
889 [
890 # Not an error in third_party folders.
891 _THIRD_PARTY_EXCEPT_BLINK,
892 # Various tools which build outside of Chrome.
893 r'testing/libfuzzer',
Steinar H. Gundersone5689e42024-08-07 18:17:19894 r'testing/perf/confidence',
Daniel Cheng566634ff2024-06-29 14:56:53895 r'tools/android/io_benchmark/',
896 # Fuzzers are allowed to use standard library random number generators
897 # since fuzzing speed + reproducibility is important.
898 r'tools/ipc_fuzzer/',
899 r'.+_fuzzer\.cc$',
900 r'.+_fuzzertest\.cc$',
901 # TODO(https://crbug.com/1380528): These are all unsanctioned uses of
902 # the standard library's random number generators, and should be
903 # migrated to the //base equivalent.
904 r'ash/ambient/model/ambient_topic_queue\.cc',
905 r'base/allocator/partition_allocator/src/partition_alloc/partition_alloc_unittest\.cc',
Daniel Cheng566634ff2024-06-29 14:56:53906 r'base/test/launcher/test_launcher\.cc',
907 r'cc/metrics/video_playback_roughness_reporter_unittest\.cc',
908 r'chrome/browser/apps/app_service/metrics/website_metrics\.cc',
909 r'chrome/browser/ash/power/auto_screen_brightness/monotone_cubic_spline_unittest\.cc',
910 r'chrome/browser/ash/printing/zeroconf_printer_detector_unittest\.cc',
911 r'chrome/browser/nearby_sharing/contacts/nearby_share_contact_manager_impl_unittest\.cc',
912 r'chrome/browser/nearby_sharing/contacts/nearby_share_contacts_sorter_unittest\.cc',
913 r'chrome/browser/privacy_budget/mesa_distribution_unittest\.cc',
914 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
915 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
916 r'chrome/browser/win/conflicts/module_blocklist_cache_util_unittest\.cc',
917 r'chromeos/ash/components/memory/userspace_swap/swap_storage_unittest\.cc',
918 r'chromeos/ash/components/memory/userspace_swap/userspace_swap\.cc',
919 r'components/metrics/metrics_state_manager\.cc',
920 r'components/omnibox/browser/history_quick_provider_performance_unittest\.cc',
921 r'components/zucchini/disassembler_elf_unittest\.cc',
922 r'content/browser/webid/federated_auth_request_impl\.cc',
923 r'content/browser/webid/federated_auth_request_impl\.cc',
924 r'media/cast/test/utility/udp_proxy\.h',
925 r'sql/recover_module/module_unittest\.cc',
Nicolas Dossou-Gbeteaf9023d2025-04-07 17:44:38926 r'components/regional_capabilities/regional_capabilities_utils.cc',
Daniel Cheng566634ff2024-06-29 14:56:53927 # Do not add new entries to this list. If you have a use case which is
928 # not satisfied by the current APIs (i.e. you need an explicitly-seeded
929 # sequence, or stability of some sort is required), please contact
930 # [email protected].
931 ],
Daniel Cheng192683f2022-11-01 20:52:44932 ),
933 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53934 r'/\b(absl,std)::bind_front\b',
935 ('{absl,std}::bind_front() are banned. Use base::Bind{Once,Repeating}() '
936 'instead.', ),
937 True,
938 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12939 ),
940 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53941 r'/\bABSL_FLAG\b',
942 ('ABSL_FLAG is banned. Use base::CommandLine instead.', ),
943 True,
944 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12945 ),
946 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53947 r'/\babsl::c_',
948 (
Peter Kasting3b811ffd2025-01-29 22:20:16949 'Abseil container utilities are banned. Use std::ranges:: instead.',
Daniel Cheng566634ff2024-06-29 14:56:53950 ),
951 True,
952 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12953 ),
954 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53955 r'/\babsl::FixedArray\b',
956 ('absl::FixedArray is banned. Use base::FixedArray instead.', ),
957 True,
958 [
959 # base::FixedArray provides canonical access.
960 r'^base/types/fixed_array.h',
961 # Not an error in third_party folders.
962 _THIRD_PARTY_EXCEPT_BLINK,
963 ],
Peter Kasting431239a2023-09-29 03:11:44964 ),
965 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53966 r'/\babsl::FunctionRef\b',
967 ('absl::FunctionRef is banned. Use base::FunctionRef instead.', ),
968 True,
969 [
970 # base::Bind{Once,Repeating} references absl::FunctionRef to disallow
971 # interoperability.
972 r'^base/functional/bind_internal\.h',
973 # base::FunctionRef is implemented on top of absl::FunctionRef.
974 r'^base/functional/function_ref.*\..+',
975 # Not an error in third_party folders.
976 _THIRD_PARTY_EXCEPT_BLINK,
977 ],
Peter Kasting4f35bfc2022-10-18 18:39:12978 ),
979 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53980 r'/\babsl::(Insecure)?BitGen\b',
981 ('absl random number generators are banned. Use the helpers in '
982 'base/rand_util.h instead, e.g. base::RandBytes() or ',
983 'base::RandomBitGenerator.'),
984 True,
985 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12986 ),
987 BanRule(
Peter Kasting3b77a0c2024-08-22 00:22:26988 pattern=
989 r'/\babsl::(optional|nullopt|make_optional)\b',
990 explanation=('absl::optional is banned. Use std::optional instead.', ),
991 treat_as_error=True,
992 excluded_paths=[
993 _THIRD_PARTY_EXCEPT_BLINK,
994 ]),
995 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53996 r'/(\babsl::Span\b|#include <span>|\bstd::span\b)',
997 (
Peter Kastinge73b89d2024-11-26 19:35:52998 'absl::Span and std::span are banned. Use base::span instead.',
Daniel Cheng566634ff2024-06-29 14:56:53999 ),
1000 True,
1001 [
1002 # Included for conversions between base and std.
1003 r'base/containers/span.h',
1004 # Test base::span<> compatibility against std::span<>.
1005 r'base/containers/span_unittest.cc',
1006 # //base/numerics can't use base or absl. So it uses std.
1007 r'base/numerics/.*'
Lei Zhang1f9d9ec42024-06-20 18:42:271008
Daniel Cheng566634ff2024-06-29 14:56:531009 # Needed to use QUICHE API.
Ciara McMullinc029c8e2024-08-21 14:22:321010 r'android_webview/browser/ip_protection/.*',
Daniel Cheng566634ff2024-06-29 14:56:531011 r'chrome/browser/ip_protection/.*',
1012 r'components/ip_protection/.*',
1013 r'net/third_party/quiche/overrides/quiche_platform_impl/quiche_stack_trace_impl\.*',
1014 r'services/network/web_transport\.cc',
Lei Zhang1f9d9ec42024-06-20 18:42:271015
Daniel Cheng566634ff2024-06-29 14:56:531016 # Not an error in third_party folders.
1017 _THIRD_PARTY_EXCEPT_BLINK,
1018 ],
Peter Kasting4f35bfc2022-10-18 18:39:121019 ),
1020 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531021 r'/\babsl::StatusOr\b',
1022 ('absl::StatusOr is banned. Use base::expected instead.', ),
1023 True,
1024 [
1025 # Needed to use liburlpattern API.
1026 r'components/url_pattern/.*',
1027 r'services/network/shared_dictionary/simple_url_pattern_matcher\.cc',
1028 r'third_party/blink/renderer/core/url_pattern/.*',
1029 r'third_party/blink/renderer/modules/manifest/manifest_parser\.cc',
Lei Zhang1f9d9ec42024-06-20 18:42:271030
Daniel Cheng566634ff2024-06-29 14:56:531031 # Needed to use QUICHE API.
Ciara McMullinc029c8e2024-08-21 14:22:321032 r'android_webview/browser/ip_protection/.*',
Daniel Cheng566634ff2024-06-29 14:56:531033 r'chrome/browser/ip_protection/.*',
1034 r'components/ip_protection/.*',
Lei Zhang1f9d9ec42024-06-20 18:42:271035
Daniel Cheng566634ff2024-06-29 14:56:531036 # Needed to use MediaPipe API.
1037 r'components/media_effects/.*\.cc',
1038 # Not an error in third_party folders.
1039 _THIRD_PARTY_EXCEPT_BLINK
1040 ],
Peter Kasting4f35bfc2022-10-18 18:39:121041 ),
1042 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531043 r'/\babsl::(StrSplit|StrJoin|StrCat|StrAppend|Substitute|StrContains)\b',
1044 ('Abseil string utilities are banned. Use base/strings instead.', ),
1045 True,
1046 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:121047 ),
1048 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531049 r'/\babsl::(Mutex|CondVar|Notification|Barrier|BlockingCounter)\b',
1050 (
1051 'Abseil synchronization primitives are banned. Use',
1052 'base/synchronization instead.',
1053 ),
1054 True,
1055 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:121056 ),
1057 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531058 r'/\babsl::(Duration|Time|TimeZone|CivilDay)\b',
1059 ('Abseil\'s time library is banned. Use base/time instead.', ),
1060 True,
1061 [
1062 # Needed to use QUICHE API.
Ciara McMullinc029c8e2024-08-21 14:22:321063 r'android_webview/browser/ip_protection/.*',
Daniel Cheng566634ff2024-06-29 14:56:531064 r'chrome/browser/ip_protection/.*',
1065 r'components/ip_protection/.*',
Lei Zhang1f9d9ec42024-06-20 18:42:271066
Daniel Cheng566634ff2024-06-29 14:56:531067 # Needed to integrate with //third_party/nearby
1068 r'components/cross_device/nearby/system_clock.cc',
1069 _THIRD_PARTY_EXCEPT_BLINK # Not an error in third_party folders.
1070 ],
1071 ),
1072 BanRule(
Victor Hugo Vianna Silva6e84e8d42025-03-19 00:32:001073 r'/absl::(bad_variant_access|get|holds_alternative|monostate|variant|'
1074 r'visit)',
1075 ('Abseil\'s variant library is banned, use std.', ),
Victor Hugo Vianna Silvad9139fbe2025-03-19 20:59:081076 True,
Victor Hugo Vianna Silva6e84e8d42025-03-19 00:32:001077 [
1078 _THIRD_PARTY_EXCEPT_BLINK
1079 ],
1080 ),
1081 BanRule(
1082 r'/absl::(apply|exchange|forward|in_place|index_sequence|'
1083 r'integer_sequence|make_from_tuple|make_index_sequence|'
1084 r'make_integer_sequence|move)',
1085 ('Abseil\'s util library is banned, use std.', ),
Victor Hugo Vianna Silvad9139fbe2025-03-19 20:59:081086 True,
Victor Hugo Vianna Silva6e84e8d42025-03-19 00:32:001087 [
1088 _THIRD_PARTY_EXCEPT_BLINK
1089 ],
1090 ),
1091 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531092 r'/#include <chrono>',
1093 ('<chrono> is banned. Use base/time instead.', ),
1094 True,
1095 [
1096 # Not an error in third_party folders:
1097 _THIRD_PARTY_EXCEPT_BLINK,
Daniel Cheng566634ff2024-06-29 14:56:531098 # This uses openscreen API depending on std::chrono.
1099 "components/openscreen_platform/task_runner.cc",
1100 ]),
1101 BanRule(
1102 r'/#include <exception>',
1103 ('Exceptions are banned and disabled in Chromium.', ),
1104 True,
1105 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1106 ),
1107 BanRule(
1108 r'/\bstd::function\b',
1109 ('std::function is banned. Use base::{Once,Repeating}Callback instead.',
1110 ),
1111 True,
1112 [
1113 # Has tests that template trait helpers don't unintentionally match
1114 # std::function.
1115 r'base/functional/callback_helpers_unittest\.cc',
1116 # Required to implement interfaces from the third-party perfetto
1117 # library.
1118 r'base/tracing/perfetto_task_runner\.cc',
1119 r'base/tracing/perfetto_task_runner\.h',
1120 # Needed for interop with the third-party nearby library type
1121 # location::nearby::connections::ResultCallback.
Dirk Prankee4df27972025-02-26 18:39:351122 r'chrome/services/sharing/nearby/nearby_connections_conversions\.cc'
Daniel Cheng566634ff2024-06-29 14:56:531123 # Needed for interop with the internal libassistant library.
Dirk Prankee4df27972025-02-26 18:39:351124 r'chromeos/ash/services/libassistant/callback_utils\.h',
Daniel Cheng566634ff2024-06-29 14:56:531125 # Needed for interop with Fuchsia fidl APIs.
Dirk Prankee4df27972025-02-26 18:39:351126 r'fuchsia_web/webengine/browser/context_impl_browsertest\.cc',
1127 r'fuchsia_web/webengine/browser/cookie_manager_impl_unittest\.cc',
1128 r'fuchsia_web/webengine/browser/media_player_impl_unittest\.cc',
Daniel Cheng566634ff2024-06-29 14:56:531129 # Required to interop with interfaces from the third-party ChromeML
1130 # library API.
Dirk Prankee4df27972025-02-26 18:39:351131 r'services/on_device_model/ml/chrome_ml_api\.h',
1132 r'services/on_device_model/ml/on_device_model_executor\.cc',
1133 r'services/on_device_model/ml/on_device_model_executor\.h',
Daniel Cheng566634ff2024-06-29 14:56:531134 # Required to interop with interfaces from the third-party perfetto
1135 # library.
Dirk Prankee4df27972025-02-26 18:39:351136 r'components/tracing/common/etw_consumer_win_unittest\.cc',
1137 r'services/tracing/public/cpp/perfetto/custom_event_recorder\.cc',
1138 r'services/tracing/public/cpp/perfetto/perfetto_traced_process\.cc',
1139 r'services/tracing/public/cpp/perfetto/perfetto_traced_process\.h',
1140 r'services/tracing/public/cpp/perfetto/perfetto_tracing_backend\.cc',
1141 r'services/tracing/public/cpp/perfetto/producer_client\.cc',
1142 r'services/tracing/public/cpp/perfetto/producer_client\.h',
1143 r'services/tracing/public/cpp/perfetto/producer_test_utils\.cc',
1144 r'services/tracing/public/cpp/perfetto/producer_test_utils\.h',
Daniel Cheng566634ff2024-06-29 14:56:531145 # Required for interop with the third-party webrtc library.
Dirk Prankee4df27972025-02-26 18:39:351146 r'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.cc',
1147 r'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.h',
Daniel Cheng566634ff2024-06-29 14:56:531148 # TODO(https://crbug.com/1364577): Various uses that should be
1149 # migrated to something else.
1150 # Should use base::OnceCallback or base::RepeatingCallback.
Dirk Prankee4df27972025-02-26 18:39:351151 r'base/allocator/dispatcher/initializer_unittest\.cc',
1152 r'chrome/browser/ash/accessibility/speech_monitor\.cc',
1153 r'chrome/browser/ash/accessibility/speech_monitor\.h',
1154 r'chrome/browser/ash/login/ash_hud_login_browsertest\.cc',
1155 r'chromecast/base/observer_unittest\.cc',
1156 r'chromecast/browser/cast_web_view\.h',
1157 r'chromecast/public/cast_media_shlib\.h',
1158 r'device/bluetooth/floss/exported_callback_manager\.h',
1159 r'device/bluetooth/floss/floss_dbus_client\.h',
1160 r'device/fido/cable/v2_handshake_unittest\.cc',
1161 r'device/fido/pin\.cc',
1162 r'services/tracing/perfetto/test_utils\.h',
Daniel Cheng566634ff2024-06-29 14:56:531163 # Should use base::FunctionRef.
Dirk Prankee4df27972025-02-26 18:39:351164 r'chrome/browser/media/webrtc/test_stats_dictionary\.cc',
1165 r'chrome/browser/media/webrtc/test_stats_dictionary\.h',
1166 r'chromeos/ash/services/libassistant/device_settings_controller\.cc',
1167 r'components/browser_ui/client_certificate/android/ssl_client_certificate_request\.cc',
1168 r'components/gwp_asan/client/sampling_malloc_shims_unittest\.cc',
1169 r'content/browser/font_unique_name_lookup/font_unique_name_lookup_unittest\.cc',
Daniel Cheng566634ff2024-06-29 14:56:531170 # Does not need std::function at all.
Dirk Prankee4df27972025-02-26 18:39:351171 r'components/omnibox/browser/autocomplete_result\.cc',
1172 r'device/fido/win/webauthn_api\.cc',
1173 r'media/audio/alsa/alsa_util\.cc',
1174 r'media/remoting/stream_provider\.h',
1175 r'sql/vfs_wrapper\.cc',
Daniel Cheng566634ff2024-06-29 14:56:531176 # TODO(https://crbug.com/1364585): Remove usage and exception list
1177 # entries.
Dirk Prankee4df27972025-02-26 18:39:351178 r'extensions/renderer/api/automation/automation_internal_custom_bindings\.cc',
1179 r'extensions/renderer/api/automation/automation_internal_custom_bindings\.h',
Daniel Cheng566634ff2024-06-29 14:56:531180 # TODO(https://crbug.com/1364579): Remove usage and exception list
1181 # entry.
Dirk Prankee4df27972025-02-26 18:39:351182 r'ui/views/controls/focus_ring\.h',
Lei Zhang1f9d9ec42024-06-20 18:42:271183
Daniel Cheng566634ff2024-06-29 14:56:531184 # Various pre-existing uses in //tools that is low-priority to fix.
Dirk Prankee4df27972025-02-26 18:39:351185 r'tools/binary_size/libsupersize/viewer/caspian/diff\.cc',
1186 r'tools/binary_size/libsupersize/viewer/caspian/model\.cc',
1187 r'tools/binary_size/libsupersize/viewer/caspian/model\.h',
1188 r'tools/binary_size/libsupersize/viewer/caspian/tree_builder\.h',
1189 r'tools/clang/base_bind_rewriters/BaseBindRewriters\.cpp',
Daniel Chenge5583e3c2022-09-22 00:19:411190
Daniel Cheng566634ff2024-06-29 14:56:531191 # Not an error in third_party folders.
1192 _THIRD_PARTY_EXCEPT_BLINK
1193 ],
Daniel Bratell609102be2019-03-27 20:53:211194 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151195 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531196 r'/#include <X11/',
1197 ('Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.', ),
1198 True,
1199 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Tom Andersona95e12042020-09-09 23:08:001200 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151201 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531202 r'/\bstd::ratio\b',
1203 ('std::ratio is banned by the Google Style Guide.', ),
1204 True,
1205 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:451206 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151207 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531208 r'/\bstd::aligned_alloc\b',
1209 (
1210 'std::aligned_alloc() is not yet allowed (crbug.com/1412818). Use ',
1211 'base::AlignedAlloc() instead.',
1212 ),
1213 True,
1214 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181215 ),
1216 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531217 r'/#include <(barrier|latch|semaphore|stop_token)>',
1218 ('The thread support library is banned. Use base/synchronization '
1219 'instead.', ),
1220 True,
1221 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181222 ),
1223 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531224 r'/\bstd::execution::(par|seq)\b',
1225 ('std::execution::(par|seq) is banned; they do not fit into '
1226 ' Chrome\'s threading model, and libc++ doesn\'t have full '
mikt19226ff22024-08-27 05:28:211227 'support.', ),
Daniel Cheng566634ff2024-06-29 14:56:531228 True,
1229 [_THIRD_PARTY_EXCEPT_BLINK],
Helmut Januschka7cc8a84f2024-02-07 22:50:411230 ),
1231 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531232 r'/\bstd::bit_cast\b',
1233 ('std::bit_cast is banned; use base::bit_cast instead for values and '
1234 'standard C++ casting when pointers are involved.', ),
1235 True,
1236 [
1237 # Don't warn in third_party folders.
1238 _THIRD_PARTY_EXCEPT_BLINK,
1239 # //base/numerics can't use base or absl.
1240 r'base/numerics/.*'
1241 ],
Avi Drissman70cb7f72023-12-12 17:44:371242 ),
1243 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531244 r'/\bstd::(c8rtomb|mbrtoc8)\b',
1245 ('std::c8rtomb() and std::mbrtoc8() are banned.', ),
1246 True,
1247 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181248 ),
1249 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531250 r'/\bchar8_t|std::u8string\b',
1251 (
1252 'char8_t and std::u8string are not yet allowed. Can you use [unsigned]',
1253 ' char and std::string instead?',
1254 ),
1255 True,
1256 [
1257 # The demangler does not use this type but needs to know about it.
Dirk Prankee4df27972025-02-26 18:39:351258 r'base/third_party/symbolize/demangle\.cc',
Daniel Cheng566634ff2024-06-29 14:56:531259 # Don't warn in third_party folders.
1260 _THIRD_PARTY_EXCEPT_BLINK
1261 ],
Peter Kastinge2c5ee82023-02-15 17:23:081262 ),
1263 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531264 r'/(\b(co_await|co_return|co_yield)\b|#include <coroutine>)',
1265 ('Coroutines are not yet allowed (https://crbug.com/1403840).', ),
1266 True,
1267 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081268 ),
1269 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531270 r'/^\s*(export\s|import\s+["<:\w]|module(;|\s+[:\w]))',
1271 ('Modules are disallowed for now due to lack of toolchain support.', ),
1272 True,
1273 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting69357dc2023-03-14 01:34:291274 ),
1275 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531276 r'/\[\[(\w*::)?no_unique_address\]\]',
1277 (
1278 '[[no_unique_address]] does not work as expected on Windows ',
1279 '(https://crbug.com/1414621). Use NO_UNIQUE_ADDRESS instead.',
1280 ),
1281 True,
1282 [
1283 # NO_UNIQUE_ADDRESS / PA_NO_UNIQUE_ADDRESS provide canonical access.
1284 r'^base/compiler_specific\.h',
1285 r'^base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/compiler_specific\.h',
1286 # Not an error in third_party folders.
1287 _THIRD_PARTY_EXCEPT_BLINK,
1288 ],
Peter Kasting8bc046d22023-11-14 00:38:031289 ),
1290 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531291 r'/#include <format>',
1292 ('<format> is not yet allowed. Use base::StringPrintf() instead.', ),
1293 True,
1294 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081295 ),
1296 BanRule(
Daniel Cheng89719222024-07-04 04:59:291297 pattern='std::views',
1298 explanation=(
1299 'Use of std::views is banned in Chrome. If you need this '
1300 'functionality, please contact [email protected].',
1301 ),
1302 treat_as_error=True,
1303 excluded_paths=[
1304 # Don't warn in third_party folders.
1305 _THIRD_PARTY_EXCEPT_BLINK
1306 ],
1307 ),
1308 BanRule(
1309 # Ban everything except specifically allowlisted constructs.
1310 pattern=r'/std::ranges::(?!' + '|'.join((
1311 # From https://en.cppreference.com/w/cpp/ranges:
1312 # Range access
1313 'begin',
1314 'end',
1315 'cbegin',
1316 'cend',
1317 'rbegin',
1318 'rend',
1319 'crbegin',
1320 'crend',
1321 'size',
1322 'ssize',
1323 'empty',
1324 'data',
1325 'cdata',
1326 # Range primitives
1327 'iterator_t',
1328 'const_iterator_t',
1329 'sentinel_t',
1330 'const_sentinel_t',
1331 'range_difference_t',
1332 'range_size_t',
1333 'range_value_t',
1334 'range_reference_t',
1335 'range_const_reference_t',
1336 'range_rvalue_reference_t',
1337 'range_common_reference_t',
1338 # Dangling iterator handling
1339 'dangling',
1340 'borrowed_iterator_t',
1341 # Banned: borrowed_subrange_t
1342 # Range concepts
1343 'range',
1344 'borrowed_range',
1345 'sized_range',
1346 'view',
1347 'input_range',
1348 'output_range',
1349 'forward_range',
1350 'bidirectional_range',
1351 'random_access_range',
1352 'contiguous_range',
1353 'common_range',
1354 'viewable_range',
1355 'constant_range',
1356 # Banned: Views
1357 # Banned: Range factories
1358 # Banned: Range adaptors
Peter Kastinga7f93752024-10-24 22:15:401359 # Incidentally listed on
1360 # https://en.cppreference.com/w/cpp/header/ranges:
1361 'enable_borrowed_range',
1362 'enable_view',
Daniel Cheng89719222024-07-04 04:59:291363 # From https://en.cppreference.com/w/cpp/algorithm/ranges:
1364 # Constrained algorithms: non-modifying sequence operations
1365 'all_of',
1366 'any_of',
1367 'none_of',
1368 'for_each',
1369 'for_each_n',
1370 'count',
1371 'count_if',
1372 'mismatch',
1373 'equal',
1374 'lexicographical_compare',
1375 'find',
1376 'find_if',
1377 'find_if_not',
1378 'find_end',
1379 'find_first_of',
1380 'adjacent_find',
1381 'search',
1382 'search_n',
1383 # Constrained algorithms: modifying sequence operations
1384 'copy',
1385 'copy_if',
1386 'copy_n',
1387 'copy_backward',
1388 'move',
1389 'move_backward',
1390 'fill',
1391 'fill_n',
1392 'transform',
1393 'generate',
1394 'generate_n',
1395 'remove',
1396 'remove_if',
1397 'remove_copy',
1398 'remove_copy_if',
1399 'replace',
1400 'replace_if',
1401 'replace_copy',
1402 'replace_copy_if',
1403 'swap_ranges',
1404 'reverse',
1405 'reverse_copy',
1406 'rotate',
1407 'rotate_copy',
1408 'shuffle',
1409 'sample',
1410 'unique',
1411 'unique_copy',
1412 # Constrained algorithms: partitioning operations
1413 'is_partitioned',
1414 'partition',
1415 'partition_copy',
1416 'stable_partition',
1417 'partition_point',
1418 # Constrained algorithms: sorting operations
1419 'is_sorted',
1420 'is_sorted_until',
1421 'sort',
1422 'partial_sort',
1423 'partial_sort_copy',
1424 'stable_sort',
1425 'nth_element',
1426 # Constrained algorithms: binary search operations (on sorted ranges)
1427 'lower_bound',
1428 'upper_bound',
1429 'binary_search',
1430 'equal_range',
1431 # Constrained algorithms: set operations (on sorted ranges)
1432 'merge',
1433 'inplace_merge',
1434 'includes',
1435 'set_difference',
1436 'set_intersection',
1437 'set_symmetric_difference',
1438 'set_union',
1439 # Constrained algorithms: heap operations
1440 'is_heap',
1441 'is_heap_until',
1442 'make_heap',
1443 'push_heap',
1444 'pop_heap',
1445 'sort_heap',
1446 # Constrained algorithms: minimum/maximum operations
1447 'max',
1448 'max_element',
1449 'min',
1450 'min_element',
1451 'minmax',
1452 'minmax_element',
1453 'clamp',
1454 # Constrained algorithms: permutation operations
1455 'is_permutation',
1456 'next_permutation',
1457 'prev_premutation',
1458 # Constrained uninitialized memory algorithms
1459 'uninitialized_copy',
1460 'uninitialized_copy_n',
1461 'uninitialized_fill',
1462 'uninitialized_fill_n',
1463 'uninitialized_move',
1464 'uninitialized_move_n',
1465 'uninitialized_default_construct',
1466 'uninitialized_default_construct_n',
1467 'uninitialized_value_construct',
1468 'uninitialized_value_construct_n',
1469 'destroy',
1470 'destroy_n',
1471 'destroy_at',
1472 'construct_at',
1473 # Return types
1474 'in_fun_result',
1475 'in_in_result',
1476 'in_out_result',
1477 'in_in_out_result',
1478 'in_out_out_result',
1479 'min_max_result',
1480 'in_found_result',
Peter Kastingf379c022025-01-13 14:01:001481 # From https://en.cppreference.com/w/cpp/header/functional
1482 'equal_to',
1483 'not_equal_to',
1484 'greater',
1485 'less',
1486 'greater_equal',
1487 'less_equal',
danakj91c715b2024-07-10 13:24:261488 # From https://en.cppreference.com/w/cpp/iterator
1489 'advance',
1490 'distance',
1491 'next',
1492 'prev',
Daniel Cheng89719222024-07-04 04:59:291493 )) + r')\w+',
1494 explanation=(
1495 'Use of range views and associated helpers is banned in Chrome. '
1496 'If you need this functionality, please contact [email protected].',
1497 ),
1498 treat_as_error=True,
1499 excluded_paths=[
1500 # Don't warn in third_party folders.
1501 _THIRD_PARTY_EXCEPT_BLINK
1502 ],
Peter Kastinge2c5ee82023-02-15 17:23:081503 ),
1504 BanRule(
Peter Kasting31879d82024-10-07 20:18:391505 r'/#include <regex>',
1506 ('<regex> is not allowed. Use third_party/re2 instead.',
1507 ),
1508 True,
1509 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1510 ),
1511 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531512 r'/#include <source_location>',
1513 ('<source_location> is not yet allowed. Use base/location.h instead.',
1514 ),
1515 True,
1516 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081517 ),
1518 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531519 r'/\bstd::to_address\b',
1520 (
1521 'std::to_address is banned because it is not guaranteed to be',
1522 'SFINAE-compatible. Use base::to_address from base/types/to_address.h',
1523 'instead.',
1524 ),
1525 True,
1526 [
1527 # Needed in base::to_address implementation.
1528 r'base/types/to_address.h',
1529 _THIRD_PARTY_EXCEPT_BLINK
1530 ], # Not an error in third_party folders.
Nick Diego Yamanee522ae82024-02-27 04:23:221531 ),
1532 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531533 r'/#include <syncstream>',
1534 ('<syncstream> is banned.', ),
1535 True,
1536 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181537 ),
1538 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531539 r'/\bRunMessageLoop\b',
1540 ('RunMessageLoop is deprecated, use RunLoop instead.', ),
1541 False,
1542 (),
Gabriel Charette147335ea2018-03-22 15:59:191543 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151544 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531545 'RunAllPendingInMessageLoop()',
1546 (
1547 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
1548 "if you're convinced you need this.",
1549 ),
1550 False,
1551 (),
Gabriel Charette147335ea2018-03-22 15:59:191552 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151553 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531554 'RunAllPendingInMessageLoop(BrowserThread',
1555 (
1556 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
1557 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
1558 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
1559 'async events instead of flushing threads.',
1560 ),
1561 False,
1562 (),
Gabriel Charette147335ea2018-03-22 15:59:191563 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151564 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531565 r'MessageLoopRunner',
1566 ('MessageLoopRunner is deprecated, use RunLoop instead.', ),
1567 False,
1568 (),
Gabriel Charette147335ea2018-03-22 15:59:191569 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151570 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531571 'GetDeferredQuitTaskForRunLoop',
1572 (
1573 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
1574 "gab@ if you found a use case where this is the only solution.",
1575 ),
1576 False,
1577 (),
Gabriel Charette147335ea2018-03-22 15:59:191578 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151579 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531580 'sqlite3_initialize(',
1581 (
1582 'Instead of calling sqlite3_initialize(), depend on //sql, ',
1583 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
1584 ),
1585 True,
1586 (
1587 r'^sql/initialization\.(cc|h)$',
1588 r'^third_party/sqlite/.*\.(c|cc|h)$',
1589 ),
Victor Costan3653df62018-02-08 21:38:161590 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151591 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531592 'CREATE VIEW',
1593 (
1594 'SQL views are disabled in Chromium feature code',
1595 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-views',
1596 ),
1597 True,
1598 (
1599 _THIRD_PARTY_EXCEPT_BLINK,
1600 # sql/ itself uses views when using memory-mapped IO.
1601 r'^sql/.*',
1602 # Various performance tools that do not build as part of Chrome.
1603 r'^infra/.*',
1604 r'^tools/perf.*',
1605 r'.*perfetto.*',
1606 ),
Austin Sullivand661ab52022-11-16 08:55:151607 ),
1608 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531609 'CREATE VIRTUAL TABLE',
1610 (
1611 'SQL virtual tables are disabled in Chromium feature code',
1612 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-virtual-tables',
1613 ),
1614 True,
1615 (
1616 _THIRD_PARTY_EXCEPT_BLINK,
1617 # sql/ itself uses virtual tables in the recovery module and tests.
1618 r'^sql/.*',
1619 # TODO(https://crbug.com/695592): Remove once WebSQL is deprecated.
1620 r'third_party/blink/web_tests/storage/websql/.*'
1621 # Various performance tools that do not build as part of Chrome.
1622 r'^tools/perf.*',
1623 r'.*perfetto.*',
1624 ),
Austin Sullivand661ab52022-11-16 08:55:151625 ),
1626 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531627 'std::random_shuffle',
1628 ('std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
1629 'base::RandomShuffle instead.'),
1630 True,
1631 (),
tzik5de2157f2018-05-08 03:42:471632 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151633 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531634 'ios/web/public/test/http_server',
1635 ('web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
1636 ),
1637 False,
1638 (),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:241639 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151640 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531641 'GetAddressOf',
1642 ('Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
1643 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
1644 'operator& is generally recommended. So always use operator& instead. ',
1645 'See http://crbug.com/914910 for more conversion guidance.'),
1646 True,
1647 (),
Robert Liao764c9492019-01-24 18:46:281648 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151649 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531650 'SHFileOperation',
1651 ('SHFileOperation was deprecated in Windows Vista, and there are less ',
1652 'complex functions to achieve the same goals. Use IFileOperation for ',
1653 'any esoteric actions instead.'),
1654 True,
1655 (),
Ben Lewisa9514602019-04-29 17:53:051656 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151657 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531658 'StringFromGUID2',
1659 ('StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
1660 'Use base::win::WStringFromGUID instead.'),
1661 True,
1662 (r'/base/win/win_util_unittest.cc', ),
Cliff Smolinsky81951642019-04-30 21:39:511663 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151664 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531665 'StringFromCLSID',
1666 ('StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
1667 'Use base::win::WStringFromGUID instead.'),
1668 True,
1669 (r'/base/win/win_util_unittest.cc', ),
Cliff Smolinsky81951642019-04-30 21:39:511670 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151671 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531672 'kCFAllocatorNull',
1673 (
1674 'The use of kCFAllocatorNull with the NoCopy creation of ',
1675 'CoreFoundation types is prohibited.',
1676 ),
1677 True,
1678 (),
Avi Drissman7382afa02019-04-29 23:27:131679 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151680 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531681 'mojo::ConvertTo',
1682 ('mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1683 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1684 'StringTraits if you would like to convert between custom types and',
1685 'the wire format of mojom types.'),
1686 False,
1687 (
1688 r'^fuchsia_web/webengine/browser/url_request_rewrite_rules_manager\.cc$',
1689 r'^fuchsia_web/webengine/url_request_rewrite_type_converters\.cc$',
1690 r'^third_party/blink/.*\.(cc|h)$',
1691 r'^content/renderer/.*\.(cc|h)$',
1692 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291693 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151694 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531695 'GetInterfaceProvider',
1696 ('InterfaceProvider is deprecated.',
1697 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1698 'or Platform::GetBrowserInterfaceBroker.'),
1699 False,
1700 (),
Oksana Zhuravlovac8222d22019-12-19 19:21:161701 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151702 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531703 'CComPtr',
1704 ('New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1705 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1706 'details.'),
1707 False,
1708 (),
Robert Liao1d78df52019-11-11 20:02:011709 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151710 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531711 r'/\b(IFACE|STD)METHOD_?\(',
1712 ('IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1713 'Instead, always use IFACEMETHODIMP in the declaration.'),
1714 False,
1715 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Xiaohan Wang72bd2ba2020-02-18 21:38:201716 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151717 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531718 'RemoveAllChildViewsWithoutDeleting',
1719 ('RemoveAllChildViewsWithoutDeleting is deprecated.',
1720 'This method is deemed dangerous as, unless raw pointers are re-added,',
1721 'calls to this method introduce memory leaks.'),
1722 False,
1723 (),
Peter Boström7ff41522021-07-29 03:43:271724 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151725 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531726 r'/\bTRACE_EVENT_ASYNC_',
1727 (
1728 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1729 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1730 ),
1731 False,
1732 (
1733 r'^base/trace_event/.*',
1734 r'^base/tracing/.*',
1735 ),
Eric Secklerbe6f48d2020-05-06 18:09:121736 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151737 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531738 'RoInitialize',
1739 ('Improper use of [base::win]::RoInitialize() has been implicated in a ',
1740 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
1741 'instead. See http://crbug.com/1197722 for more information.'),
1742 True,
1743 (
1744 r'^base/win/scoped_winrt_initializer\.cc$',
1745 r'^third_party/abseil-cpp/absl/.*',
1746 ),
Robert Liao22f66a52021-04-10 00:57:521747 ),
Patrick Monettec343bb982022-06-01 17:18:451748 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531749 r'base::Watchdog',
1750 (
1751 'base::Watchdog is deprecated because it creates its own thread.',
1752 'Instead, manually start a timer on a SequencedTaskRunner.',
1753 ),
1754 False,
1755 (),
Patrick Monettec343bb982022-06-01 17:18:451756 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091757 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531758 'base::Passed',
1759 ('Do not use base::Passed. It is a legacy helper for capturing ',
1760 'move-only types with base::BindRepeating, but invoking the ',
1761 'resulting RepeatingCallback moves the captured value out of ',
1762 'the callback storage, and subsequent invocations may pass the ',
1763 'value in a valid but undefined state. Prefer base::BindOnce().',
1764 'See http://crbug.com/1326449 for context.'),
1765 False,
1766 (
1767 # False positive, but it is also fine to let bind internals reference
1768 # base::Passed.
1769 r'^base[\\/]functional[\\/]bind\.h',
1770 r'^base[\\/]functional[\\/]bind_internal\.h',
1771 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091772 ),
Daniel Cheng2248b332022-07-27 06:16:591773 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531774 r'base::Feature k',
1775 ('Please use BASE_DECLARE_FEATURE() or BASE_FEATURE() instead of ',
1776 'directly declaring/defining features.'),
1777 True,
1778 [
1779 # Implements BASE_DECLARE_FEATURE().
1780 r'^base/feature_list\.h',
1781 ],
Daniel Chengba3bc2e2022-10-03 02:45:431782 ),
Robert Ogden92101dcb2022-10-19 23:49:361783 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531784 r'/\bchartorune\b',
1785 ('chartorune is not memory-safe, unless you can guarantee the input ',
1786 'string is always null-terminated. Otherwise, please use charntorune ',
1787 'from libphonenumber instead.'),
1788 True,
1789 [
1790 _THIRD_PARTY_EXCEPT_BLINK,
1791 # Exceptions to this rule should have a fuzzer.
1792 ],
Robert Ogden92101dcb2022-10-19 23:49:361793 ),
Arthur Sonzogni1da65fa2023-03-27 16:01:521794 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531795 r'/\b#include "base/atomicops\.h"\b',
1796 ('Do not use base::subtle atomics, but std::atomic, which are simpler '
1797 'to use, have better understood, clearer and richer semantics, and are '
1798 'harder to mis-use. See details in base/atomicops.h.', ),
1799 False,
1800 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Benoit Lize79cf0592023-01-27 10:01:571801 ),
Daniel Cheng566634ff2024-06-29 14:56:531802 BanRule(r'CrossThreadPersistent<', (
Arthur Sonzogni603485722023-04-07 10:22:521803 'Do not use blink::CrossThreadPersistent, but '
Daniel Cheng566634ff2024-06-29 14:56:531804 'blink::CrossThreadHandle. It is harder to mis-use.', 'More info: '
Arthur Sonzogni603485722023-04-07 10:22:521805 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1806 'Please contact platform-architecture-dev@ before adding new instances.'
Daniel Cheng566634ff2024-06-29 14:56:531807 ), False, []),
1808 BanRule(r'CrossThreadWeakPersistent<', (
Arthur Sonzogni603485722023-04-07 10:22:521809 'Do not use blink::CrossThreadWeakPersistent, but '
Daniel Cheng566634ff2024-06-29 14:56:531810 'blink::CrossThreadWeakHandle. It is harder to mis-use.', 'More info: '
Arthur Sonzogni603485722023-04-07 10:22:521811 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1812 'Please contact platform-architecture-dev@ before adding new instances.'
Daniel Cheng566634ff2024-06-29 14:56:531813 ), False, []),
1814 BanRule(r'objc/objc.h', (
Avi Drissman491617c2023-04-13 17:33:151815 'Do not include <objc/objc.h>. It defines away ARC lifetime '
1816 'annotations, and is thus dangerous.',
1817 'Please use the pimpl pattern; search for `ObjCStorage` for examples.',
1818 'For further reading on how to safely mix C++ and Obj-C, see',
1819 'https://chromium.googlesource.com/chromium/src/+/main/docs/mac/mixing_cpp_and_objc.md'
Daniel Cheng566634ff2024-06-29 14:56:531820 ), True, []),
1821 BanRule(
1822 r'/#include <filesystem>',
1823 ('libc++ <filesystem> is banned per the Google C++ styleguide.', ),
1824 True,
1825 # This fuzzing framework is a standalone open source project and
1826 # cannot rely on Chromium base.
1827 (r'third_party/centipede'),
Avi Drissman491617c2023-04-13 17:33:151828 ),
Grace Park8d59b54b2023-04-26 17:53:351829 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531830 r'TopDocument()',
1831 ('TopDocument() does not work correctly with out-of-process iframes. '
1832 'Please do not introduce new uses.', ),
1833 True,
1834 (
1835 # TODO(crbug.com/617677): Remove all remaining uses.
1836 r'^third_party/blink/renderer/core/dom/document\.cc',
1837 r'^third_party/blink/renderer/core/dom/document\.h',
1838 r'^third_party/blink/renderer/core/dom/element\.cc',
1839 r'^third_party/blink/renderer/core/exported/web_disallow_transition_scope_test\.cc',
1840 r'^third_party/blink/renderer/core/exported/web_document_test\.cc',
1841 r'^third_party/blink/renderer/core/html/html_anchor_element\.cc',
1842 r'^third_party/blink/renderer/core/html/html_dialog_element\.cc',
1843 r'^third_party/blink/renderer/core/html/html_element\.cc',
1844 r'^third_party/blink/renderer/core/html/html_frame_owner_element\.cc',
1845 r'^third_party/blink/renderer/core/html/media/video_wake_lock\.cc',
1846 r'^third_party/blink/renderer/core/loader/anchor_element_interaction_tracker\.cc',
1847 r'^third_party/blink/renderer/core/page/scrolling/root_scroller_controller\.cc',
1848 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.cc',
1849 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.h',
1850 r'^third_party/blink/renderer/core/script/classic_pending_script\.cc',
1851 r'^third_party/blink/renderer/core/script/script_loader\.cc',
1852 ),
Grace Park8d59b54b2023-04-26 17:53:351853 ),
Daniel Cheng72153e02023-05-18 21:18:141854 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531855 pattern=r'base::raw_ptr<',
1856 explanation=('Do not use base::raw_ptr, use raw_ptr.', ),
1857 treat_as_error=True,
1858 excluded_paths=(
1859 '^base/',
1860 '^tools/',
1861 ),
Daniel Cheng72153e02023-05-18 21:18:141862 ),
Arthur Sonzognif0eea302023-08-18 19:20:311863 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531864 pattern=r'base:raw_ref<',
1865 explanation=('Do not use base::raw_ref, use raw_ref.', ),
1866 treat_as_error=True,
1867 excluded_paths=(
1868 '^base/',
1869 '^tools/',
1870 ),
Arthur Sonzognif0eea302023-08-18 19:20:311871 ),
1872 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531873 pattern=r'/raw_ptr<[^;}]*\w{};',
1874 explanation=(
1875 'Do not use {} for raw_ptr initialization, use = nullptr instead.',
1876 ),
1877 treat_as_error=True,
1878 excluded_paths=(
1879 '^base/',
1880 '^tools/',
1881 ),
Arthur Sonzognif0eea302023-08-18 19:20:311882 ),
Anton Maliev66751812023-08-24 16:28:131883 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531884 pattern=r'/#include "base/allocator/.*/raw_'
1885 r'(ptr|ptr_cast|ptr_exclusion|ref).h"',
1886 explanation=(
1887 'Please include the corresponding facade headers:',
1888 '- #include "base/memory/raw_ptr.h"',
1889 '- #include "base/memory/raw_ptr_cast.h"',
1890 '- #include "base/memory/raw_ptr_exclusion.h"',
1891 '- #include "base/memory/raw_ref.h"',
1892 ),
1893 treat_as_error=True,
1894 excluded_paths=(
1895 '^base/',
1896 '^tools/',
1897 ),
Tom Sepez41eb158d2023-09-12 16:16:221898 ),
1899 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531900 pattern=r'ContentSettingsType::COOKIES',
1901 explanation=
1902 ('Do not use ContentSettingsType::COOKIES to check whether cookies are '
1903 'supported in the provided context. Instead rely on the '
1904 'content_settings::CookieSettings API. If you are using '
1905 'ContentSettingsType::COOKIES to check the user preference setting '
1906 'specifically, disregard this warning.', ),
1907 treat_as_error=False,
1908 excluded_paths=(
1909 '^chrome/browser/ui/content_settings/',
1910 '^components/content_settings/',
1911 '^services/network/cookie_settings.cc',
1912 '.*test.cc',
1913 ),
Arthur Sonzogni48c6aea22023-09-04 22:25:201914 ),
1915 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531916 pattern=r'ContentSettingsType::TRACKING_PROTECTION',
1917 explanation=
1918 ('Do not directly use ContentSettingsType::TRACKING_PROTECTION to check '
1919 'for tracking protection exceptions. Instead rely on the '
1920 'privacy_sandbox::TrackingProtectionSettings API.', ),
1921 treat_as_error=False,
1922 excluded_paths=(
1923 '^chrome/browser/ui/content_settings/',
1924 '^components/content_settings/',
1925 '^components/privacy_sandbox/tracking_protection_settings.cc',
1926 '.*test.cc',
1927 ),
Anton Maliev66751812023-08-24 16:28:131928 ),
Tom Andersoncd522072023-10-03 00:52:351929 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531930 pattern=r'/\bg_signal_connect',
1931 explanation=('Use ScopedGSignal instead of g_signal_connect*()', ),
1932 treat_as_error=True,
1933 excluded_paths=('^ui/base/glib/scoped_gsignal.h', ),
Michelle Abreo6b7437822024-04-26 17:29:041934 ),
1935 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531936 pattern=r'features::kIsolatedWebApps',
1937 explanation=(
1938 'Do not use `features::kIsolatedWebApps` directly to guard Isolated ',
1939 'Web App code. ',
Andrew Rayskiy7ae2b5d2025-02-28 16:59:381940 'Use `content::AreIsolatedWebAppsEnabled()` in the browser process '
1941 'or check the `kEnableIsolatedWebAppsInRenderer` command line flag '
1942 'in the renderer process.',
Daniel Cheng566634ff2024-06-29 14:56:531943 ),
1944 treat_as_error=True,
Andrew Rayskiy7ae2b5d2025-02-28 16:59:381945 excluded_paths=_TEST_CODE_EXCLUDED_PATHS + (
1946 '^chrome/browser/about_flags.cc',
1947 '^chrome/browser/component_updater/iwa_key_distribution_component_installer.cc',
1948 '^chrome/browser/web_applications/isolated_web_apps/chrome_content_browser_client_isolated_web_apps_part.cc',
1949 '^chrome/browser/ui/startup/bad_flags_prompt.cc',
1950 '^content/shell/browser/shell_content_browser_client.cc',
1951 )),
Daniel Cheng566634ff2024-06-29 14:56:531952 BanRule(
1953 pattern=r'features::kIsolatedWebAppDevMode',
1954 explanation=(
1955 'Do not use `features::kIsolatedWebAppDevMode` directly to guard code ',
1956 'related to Isolated Web App Developer Mode. ',
1957 'Use `web_app::IsIwaDevModeEnabled()` instead.',
1958 ),
1959 treat_as_error=True,
1960 excluded_paths=_TEST_CODE_EXCLUDED_PATHS + (
1961 '^chrome/browser/about_flags.cc',
1962 '^chrome/browser/web_applications/isolated_web_apps/isolated_web_app_features.cc',
1963 '^chrome/browser/ui/startup/bad_flags_prompt.cc',
1964 )),
1965 BanRule(
1966 pattern=r'features::kIsolatedWebAppUnmanagedInstall',
1967 explanation=(
1968 'Do not use `features::kIsolatedWebAppUnmanagedInstall` directly to ',
1969 'guard code related to unmanaged install flow for Isolated Web Apps. ',
1970 'Use `web_app::IsIwaUnmanagedInstallEnabled()` instead.',
1971 ),
1972 treat_as_error=True,
1973 excluded_paths=_TEST_CODE_EXCLUDED_PATHS + (
1974 '^chrome/browser/about_flags.cc',
1975 '^chrome/browser/web_applications/isolated_web_apps/isolated_web_app_features.cc',
1976 )),
1977 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531978 pattern='/(CUIAutomation|AccessibleObjectFromWindow)',
1979 explanation=
1980 ('Direct usage of UIAutomation or IAccessible2 in client code is '
1981 'discouraged in Chromium, as it is not an assistive technology and '
1982 'should not rely on accessibility APIs directly. These APIs can '
1983 'introduce significant performance overhead. However, if you believe '
1984 'your use case warrants an exception, please discuss it with an '
1985 'accessibility owner before proceeding. For more information on the '
1986 'performance implications, see https://docs.google.com/document/d/1jN4itpCe_bDXF0BhFaYwv4xVLsCWkL9eULdzjmLzkuk/edit#heading=h.pwth3nbwdub0.',
1987 ),
1988 treat_as_error=False,
Andrew Rayskiycdd45e732024-03-20 14:32:391989 ),
1990 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531991 pattern=r'/WIDGET_OWNS_NATIVE_WIDGET|'
1992 r'NATIVE_WIDGET_OWNS_WIDGET',
1993 explanation=
1994 ('WIDGET_OWNS_NATIVE_WIDGET and NATIVE_WIDGET_OWNS_WIDGET are in the '
1995 'process of being deprecated. Consider using the new '
1996 'CLIENT_OWNS_WIDGET ownership model. Eventually, this will be the only '
1997 'available ownership model available and the associated enumeration'
1998 'will be removed.', ),
1999 treat_as_error=False,
Andrew Rayskiycdd45e732024-03-20 14:32:392000 ),
2001 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:532002 pattern='ProfileManager::GetLastUsedProfile',
2003 explanation=
2004 ('Most code should already be scoped to a Profile. Pass in a Profile* '
2005 'or retreive from an existing entity with a reference to the Profile '
2006 '(e.g. WebContents).', ),
2007 treat_as_error=False,
Arthur Sonzogni5cbd3e32024-02-08 17:51:322008 ),
Helmut Januschkab3f71ab52024-03-12 02:48:052009 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:532010 pattern=(r'/FindBrowserWithUiElementContext|'
2011 r'FindBrowserWithTab|'
2012 r'FindBrowserWithGroup|'
2013 r'FindTabbedBrowser|'
2014 r'FindAnyBrowser|'
2015 r'FindBrowserWithProfile|'
Erik Chen5f02eb4c2024-08-23 06:30:442016 r'FindLastActive|'
Daniel Cheng566634ff2024-06-29 14:56:532017 r'FindBrowserWithActiveWindow'),
2018 explanation=
2019 ('Most code should already be scoped to a Browser. Pass in a Browser* '
2020 'or retreive from an existing entity with a reference to the Browser.',
2021 ),
2022 treat_as_error=False,
Helmut Januschkab3f71ab52024-03-12 02:48:052023 ),
2024 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:532025 pattern='BrowserUserData',
2026 explanation=
2027 ('Do not use BrowserUserData to store state on a Browser instance. '
2028 'Instead use BrowserWindowFeatures. BrowserWindowFeatures is '
2029 'functionally identical but has two benefits: it does not force a '
2030 'dependency onto class Browser, and lifetime semantics are explicit '
2031 'rather than implicit. See BrowserUserData header file for more '
2032 'details.', ),
2033 treat_as_error=False,
Mike Doughertyab1bdec2024-08-06 16:39:012034 excluded_paths=(
2035 # Exclude iOS as the iOS implementation of BrowserUserData is separate
2036 # and still in use.
2037 '^ios/',
2038 ),
Erik Chen87358e82024-06-04 02:13:122039 ),
Tom Sepezea67b6e2024-08-08 18:17:272040 BanRule(
Tom Sepezd3272cd2025-02-21 19:11:312041 pattern=r'subspan(0u,',
2042 explanation=
2043 ('Prefer first(n) over subspan(0u, n) as it is shorter, and the '
2044 'compiler may have to emit a branch for the n == dynamic_extent '
2045 'case of subspan().',
2046 ),
2047 treat_as_error=False,
2048 ),
2049 BanRule(
Tom Sepezea67b6e2024-08-08 18:17:272050 pattern=r'UNSAFE_TODO(',
2051 explanation=
2052 ('Do not use UNSAFE_TODO() to write new unsafe code. Use only when '
Tom Sepeza90f92b2024-08-15 16:01:352053 'removing a pre-existing file-wide allow_unsafe_buffers pragma, or '
2054 'when incrementally converting code off of unsafe interfaces',
Tom Sepezea67b6e2024-08-08 18:17:272055 ),
2056 treat_as_error=False,
2057 ),
2058 BanRule(
Claudio DeSouzaad1d1f252025-04-22 23:38:582059 pattern='#pragma allow_unsafe_buffers',
2060 explanation=
2061 ('Do not use allow_unsafe_buffers to write new unsafe code. Use only '
2062 'when enabling unsafe buffers checks under a new uncovered path.',
2063 ),
2064 treat_as_error=False,
2065 ),
2066 BanRule(
Tom Sepezea67b6e2024-08-08 18:17:272067 pattern=r'UNSAFE_BUFFERS(',
2068 explanation=
Tom Sepeza90f92b2024-08-15 16:01:352069 ('Try to avoid using UNSAFE_BUFFERS() if at all possible. Otherwise, '
2070 'be sure to justify in a // SAFETY comment why other options are not '
2071 'available, and why the code is safe.',
Tom Sepezea67b6e2024-08-08 18:17:272072 ),
2073 treat_as_error=False,
2074 ),
Erik Chend086ae02024-08-20 22:53:332075 BanRule(
2076 pattern='BrowserWithTestWindowTest',
2077 explanation=
2078 ('Do not use BrowserWithTestWindowTest. By instantiating an instance '
2079 'of class Browser, the test is no longer a unit test but is instead a '
2080 'browser test. The class BrowserWithTestWindowTest forces production '
2081 'logic to take on test-only conditionals, which is an anti-pattern. '
2082 'Features should be performing dependency injection rather than '
2083 'directly using class Browser. See '
mikt19226ff22024-08-27 05:28:212084 'docs/chrome_browser_design_principles.md for more details.',
Erik Chend086ae02024-08-20 22:53:332085 ),
2086 treat_as_error=False,
2087 ),
Erik Chen8cf3a652024-08-23 17:13:302088 BanRule(
Erik Chen959cdd72024-08-29 02:11:212089 pattern='TestWithBrowserView',
2090 explanation=
2091 ('Do not use TestWithBrowserView. See '
2092 'docs/chrome_browser_design_principles.md for details. If you want '
2093 'to write a test that has both a Browser and a BrowserView, create '
2094 'a browser_test. If you want to write a unit_test, your code must '
Erik Chendba23692024-09-26 06:43:362095 'not reference Browser*.',
Erik Chen959cdd72024-08-29 02:11:212096 ),
2097 treat_as_error=False,
2098 ),
2099 BanRule(
Erik Chene89ebe32025-02-22 02:46:492100 pattern='CreateBrowserWithTestWindow',
2101 explanation=
2102 ('Do not use CreateBrowserWithTestWindow. See '
2103 'docs/chrome_browser_design_principles.md for details. If you want '
2104 'to write a test that has a Browser, create a browser_test. If you '
2105 'want to write a unit_test, your code must not reference Browser*.',
2106 ),
2107 treat_as_error=False,
2108 ),
2109 BanRule(
Erik Chenf12a06642025-03-13 23:30:342110 pattern='CreateBrowserWithTestWindowForParams',
2111 explanation=
2112 ('Do not use CreateBrowserWithTestWindowForParams. See '
2113 'docs/chrome_browser_design_principles.md for details. If you want '
2114 'to write a test that has a Browser, create a browser_test and use '
2115 'Browser::Browser. If you want to write a unit_test, your code must '
2116 'not reference Browser*.',
2117 ),
2118 treat_as_error=False,
2119 ),
2120 BanRule(
Erik Chen8cf3a652024-08-23 17:13:302121 pattern='RunUntilIdle',
2122 explanation=
2123 ('Do not RunUntilIdle. If possible, explicitly quit the run loop using '
2124 'run_loop.Quit() or run_loop.QuitClosure() if completion can be '
2125 'observed using a lambda or callback. Otherwise, wait for the '
mikt19226ff22024-08-27 05:28:212126 'condition to be true via base::test::RunUntil().',
Erik Chen8cf3a652024-08-23 17:13:302127 ),
2128 treat_as_error=False,
2129 ),
Daniel Chengddde13a2024-09-05 21:39:282130 BanRule(
2131 pattern=r'/\bstd::(literals|string_literals|string_view_literals)\b',
2132 explanation = (
2133 'User-defined literals are banned by the Google C++ style guide. '
2134 'Exceptions are provided in Chrome for string and string_view '
2135 'literals that embed \\0.',
2136 ),
2137 treat_as_error=True,
2138 excluded_paths=(
2139 # Various tests or test helpers that embed NUL in strings or
2140 # string_views.
Daniel Chengddde13a2024-09-05 21:39:282141 r'^base/strings/string_util_unittest\.cc',
2142 r'^base/strings/utf_string_conversions_unittest\.cc',
2143 r'^chrome/browser/ash/crosapi/browser_data_back_migrator_unittest\.cc',
2144 r'^chrome/browser/ash/crosapi/browser_data_migrator_util_unittest\.cc',
2145 r'^chrome/browser/ash/crosapi/move_migrator_unittest\.cc',
Hidehiko Abe51601812025-01-12 16:17:352146 r'^chromeos/ash/experiences/arc/session/serial_number_util_unittest\.cc',
Daniel Chengddde13a2024-09-05 21:39:282147 r'^components/history/core/browser/visit_annotations_database\.cc',
2148 r'^components/history/core/browser/visit_annotations_database_unittest\.cc',
2149 r'^components/os_crypt/sync/os_crypt_unittest\.cc',
2150 r'^components/password_manager/core/browser/credentials_cleaner_unittest\.cc',
2151 r'^content/browser/file_system_access/file_system_access_file_writer_impl_unittest\.cc',
2152 r'^net/cookies/parsed_cookie_unittest\.cc',
2153 r'^third_party/blink/renderer/modules/webcodecs/test_helpers\.cc',
2154 r'^third_party/blink/renderer/modules/websockets/websocket_channel_impl_test\.cc',
2155 ),
Erik Chenba8b0cd32024-10-01 08:36:362156 ),
2157 BanRule(
2158 pattern='BUILDFLAG(GOOGLE_CHROME_BRANDING)',
2159 explanation=
2160 ('Code gated by GOOGLE_CHROME_BRANDING is effectively untested. This '
2161 'is typically wrong. Valid use cases are glue for private modules '
2162 'shipped alongside Chrome, and installation-related logic.',
2163 ),
2164 treat_as_error=False,
2165 ),
2166 BanRule(
2167 pattern='defined(OFFICIAL_BUILD)',
2168 explanation=
2169 ('Code gated by OFFICIAL_BUILD is effectively untested. This '
2170 'is typically wrong. One valid use case is low-level code that '
2171 'handles subtleties related to high-levels of optimizations that come '
2172 'with OFFICIAL_BUILD.',
2173 ),
2174 treat_as_error=False,
2175 ),
Erik Chen95b9c782024-11-08 03:26:272176 BanRule(
2177 pattern='WebContentsDestroyed',
2178 explanation=
2179 ('Do not use this method. It is invoked half-way through the '
2180 'destructor of WebContentsImpl and using it often results in crashes '
2181 'or surprising behavior. Conceptually, this is only necessary by '
2182 'objects that depend on, but outlive the WebContents. These objects '
2183 'should instead coordinate with the owner of the WebContents which is '
2184 'responsible for destroying the WebContents.',
2185 ),
2186 treat_as_error=False,
2187 ),
Maksim Sisovc98fdfa2024-11-16 20:12:272188 BanRule(
Georg Neisa7f94e62025-02-28 07:01:482189 pattern='IS_CHROMEOS_ASH',
Maksim Sisovc98fdfa2024-11-16 20:12:272190 explanation=
Georg Neisa7f94e62025-02-28 07:01:482191 ('IS_CHROMEOS_ASH is deprecated. Please use the equivalent IS_CHROMEOS '
2192 'instead (Lacros is gone).',
Maksim Sisovc98fdfa2024-11-16 20:12:272193 ),
2194 treat_as_error=False,
2195 ),
Erik Chen1396bbe2025-01-27 23:39:362196 BanRule(
2197 pattern=(r'namespace {'),
2198 explanation=
2199 ('Anonymous namespaces are disallowed in C++ header files. See '
2200 'https://google.github.io/styleguide/cppguide.html#Internal_Linkage '
2201 ' for details.',
2202 ),
2203 treat_as_error=False,
2204 excluded_paths=[
2205 _THIRD_PARTY_EXCEPT_BLINK, # Don't warn in third_party folders.
2206 r'^(?!.*\.h$).*$', # Exclude all files except those that end in .h
2207 ],
2208 ),
Keren Zhuf06d757d2025-03-04 05:32:362209 BanRule(
2210 pattern=('AddChildViewRaw'),
2211 explanation=(
2212 'Do not use AddChildViewRaw. It is prone to memory leaks and '
2213 'use-after-free bugs. Instead, use AddChildView(std::unique_ptr). '
2214 'See https://crbug.com/40485510 for more details.', ),
2215 treat_as_error=False,
2216 ),
Nate Fischerd541ff82025-03-11 21:34:192217 BanRule(
2218 pattern=(r'IS_DESKTOP_ANDROID'),
2219 explanation=(
2220 'Features which depend on IS_DESKTOP_ANDROID should only exist in '
2221 'chrome/ layer and similar layers. Lower layers such as content/ '
2222 'should not have features which are only designed for '
2223 'desktop-android builds. See https://crbug.com/401628399.', ),
2224 treat_as_error=False,
2225 excluded_paths=[
2226 _THIRD_PARTY_EXCEPT_BLINK, # Don't warn in third_party folders.
2227 r'^build/', # This is permitted in build/ folder.
2228 r'^chrome/', # This is permitted in chrome/ folder.
2229 r'^components/', # This is permitted only for components/ that are not shared by WebView.
2230 r'^extensions/', # This is permitted in chrome/ folder.
2231 r'^infra/', # This is permitted in infra/ folder.
2232 r'^tools/', # This is permitted in tools/ folder.
2233 ],
Ben Pastenee79d66112025-04-23 19:46:152234 surface_as_gerrit_lint=True,
Nate Fischerd541ff82025-03-11 21:34:192235 ),
[email protected]127f18ec2012-06-16 05:05:592236)
2237
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152238_DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING = (
2239 'Used a predicate related to signin::ConsentLevel::kSync which will always '
2240 'return false in the future (crbug.com/40066949). Prefer using a predicate '
2241 'that also supports signin::ConsentLevel::kSignin when appropriate. It is '
2242 'safe to ignore this warning if you are just moving an existing call, or if '
2243 'you want special handling for users in the legacy state. In doubt, reach '
Victor Hugo Vianna Silvae2292972024-06-04 17:11:552244 'out to //components/sync/OWNERS.',
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152245)
2246
2247# C++ functions related to signin::ConsentLevel::kSync which are deprecated.
2248_DEPRECATED_SYNC_CONSENT_CPP_FUNCTIONS : Sequence[BanRule] = (
2249 BanRule(
2250 'HasSyncConsent',
2251 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2252 False,
2253 ),
2254 BanRule(
2255 'CanSyncFeatureStart',
2256 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2257 False,
2258 ),
2259 BanRule(
2260 'IsSyncFeatureEnabled',
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152261 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152262 False,
2263 ),
2264 BanRule(
2265 'IsSyncFeatureActive',
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152266 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152267 False,
2268 ),
2269)
2270
2271# Java functions related to signin::ConsentLevel::kSync which are deprecated.
2272_DEPRECATED_SYNC_CONSENT_JAVA_FUNCTIONS : Sequence[BanRule] = (
2273 BanRule(
2274 'hasSyncConsent',
2275 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2276 False,
2277 ),
2278 BanRule(
2279 'canSyncFeatureStart',
2280 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2281 False,
2282 ),
2283 BanRule(
2284 'isSyncFeatureEnabled',
2285 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2286 False,
2287 ),
2288 BanRule(
2289 'isSyncFeatureActive',
2290 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2291 False,
2292 ),
2293)
2294
Justin Lulejian09fd06872025-04-01 22:03:282295_BANNED_MOJOM_PATTERNS: Sequence[BanRule] = (
Daniel Cheng92c15e32022-03-16 17:48:222296 BanRule(
2297 'handle<shared_buffer>',
2298 (
Justin Lulejian09fd06872025-04-01 22:03:282299 'Please use one of the more specific shared memory types instead:',
2300 ' mojo_base.mojom.ReadOnlySharedMemoryRegion',
2301 ' mojo_base.mojom.WritableSharedMemoryRegion',
2302 ' mojo_base.mojom.UnsafeSharedMemoryRegion',
Daniel Cheng92c15e32022-03-16 17:48:222303 ),
2304 True,
2305 ),
Justin Lulejian09fd06872025-04-01 22:03:282306 BanRule(
2307 'string extension_id',
2308 (
2309 'Please use the extensions::mojom::ExtensionId struct when '
2310 'passing extensions::ExtensionIds as mojom messages in order to ',
2311 'provide message validation.',
2312 ),
2313 True,
2314 # Only apply this to (mojom) files in a subdirectory of extensions.
2315 excluded_paths=(r'^((?!extensions/).)*$', ),
2316 ),
Daniel Cheng92c15e32022-03-16 17:48:222317)
2318
mlamouria82272622014-09-16 18:45:042319_IPC_ENUM_TRAITS_DEPRECATED = (
2320 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:502321 'See http://www.chromium.org/Home/chromium-security/education/'
2322 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:042323
Stephen Martinis97a394142018-06-07 23:06:052324_LONG_PATH_ERROR = (
2325 'Some files included in this CL have file names that are too long (> 200'
2326 ' characters). If committed, these files will cause issues on Windows. See'
2327 ' https://crbug.com/612667 for more details.'
2328)
2329
Shenghua Zhangbfaa38b82017-11-16 21:58:022330_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Bruce Dawson40fece62022-09-16 19:58:312331 r".*/BuildHooksAndroidImpl\.java",
2332 r".*/LicenseContentProvider\.java",
2333 r".*/PlatformServiceBridgeImpl.java",
2334 r".*chrome/android/feed/dummy/.*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:022335]
[email protected]127f18ec2012-06-16 05:05:592336
Mohamed Heikald048240a2019-11-12 16:57:372337# List of image extensions that are used as resources in chromium.
2338_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
2339
Sean Kau46e29bc2017-08-28 16:31:162340# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:402341_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Bruce Dawson40fece62022-09-16 19:58:312342 r'test/data/',
2343 r'testing/buildbot/',
2344 r'^components/policy/resources/policy_templates\.json$',
2345 r'^third_party/protobuf/',
Camillo Bruni1411a352023-05-24 12:39:032346 r'^third_party/blink/perf_tests/speedometer.*/resources/todomvc/learn\.json',
Bruce Dawson40fece62022-09-16 19:58:312347 r'^third_party/blink/renderer/devtools/protocol\.json$',
2348 r'^third_party/blink/web_tests/external/wpt/',
2349 r'^tools/perf/',
2350 r'^tools/traceline/svgui/startup-release.json',
Daniel Cheng2d4c2d192022-07-01 01:38:312351 # vscode configuration files allow comments
Bruce Dawson40fece62022-09-16 19:58:312352 r'^tools/vscode/',
Sean Kau46e29bc2017-08-28 16:31:162353]
2354
Andrew Grieveb773bad2020-06-05 18:00:382355# These are not checked on the public chromium-presubmit trybot.
2356# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:042357# checkouts.
agrievef32bcc72016-04-04 14:57:402358_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:382359 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382360]
2361
2362
2363_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:042364 'android_webview/tools/run_cts.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:362365 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042366 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362367 'build/android/gyp/aar.pydeps',
2368 'build/android/gyp/aidl.pydeps',
2369 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:382370 'build/android/gyp/assert_static_initializers.pydeps',
Mohamed Heikal133e1f22023-04-18 20:04:372371 'build/android/gyp/binary_baseline_profile.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:022372 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:222373 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieveacac4242024-12-20 19:39:422374 'build/android/gyp/check_for_missing_direct_deps.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:112375 'build/android/gyp/compile_java.pydeps',
Peter Weneaa963f2023-01-20 19:40:302376 'build/android/gyp/compile_kt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362377 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362378 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362379 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:112380 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042381 'build/android/gyp/create_app_bundle_apks.pydeps',
2382 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362383 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:122384 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:092385 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:222386 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve2d972e5f2025-01-28 18:28:142387 'build/android/gyp/create_stub_manifest.pydeps',
Peter Wene6e017e2022-07-27 21:40:402388 'build/android/gyp/create_test_apk_wrapper_script.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002389 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362390 'build/android/gyp/dex.pydeps',
2391 'build/android/gyp/dist_aar.pydeps',
Andrew Grieve651ddb32025-01-23 03:27:342392 'build/android/gyp/errorprone.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362393 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:212394 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362395 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:362396 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362397 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:582398 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362399 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:142400 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:262401 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:472402 'build/android/gyp/java_google_api_keys.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042403 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362404 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362405 'build/android/gyp/merge_manifest.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:102406 'build/android/gyp/optimize_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362407 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:222408 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362409 'build/android/gyp/proguard.pydeps',
Mohamed Heikaldd52b452024-09-10 17:10:502410 'build/android/gyp/rename_java_classes.pydeps',
Andrew Grievee3a775ab2022-05-16 15:59:222411 'build/android/gyp/system_image_apks.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:102412 'build/android/gyp/trace_event_bytecode_rewriter.pydeps',
Andrew Grieve170b9782025-02-03 15:54:532413 'build/android/gyp/tracereferences.pydeps',
Peter Wen578730b2020-03-19 19:55:462414 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:302415 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:242416 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362417 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:462418 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:562419 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362420 'build/android/incremental_install/generate_android_manifest.pydeps',
2421 'build/android/incremental_install/write_installer_json.pydeps',
Stephanie Kim392913b452022-06-15 17:25:322422 'build/android/pylib/results/presentation/test_results_presentation.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042423 'build/android/resource_sizes.pydeps',
2424 'build/android/test_runner.pydeps',
2425 'build/android/test_wrapper/logdog_wrapper.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362426 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:322427 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:272428 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
2429 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Bailey Myers-Morganbd122132025-03-26 23:09:162430 'chrome/test/media_router/performance/performance_test.pydeps',
Junbo Kedcd3a452021-03-19 17:55:042431 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Mohannad Farrag19102742023-12-01 01:16:302432 'components/cronet/tools/check_combined_proguard_file.pydeps',
2433 'components/cronet/tools/generate_proguard_file.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002434 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382435 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002436 'content/public/android/generate_child_service.pydeps',
Hzj_jie77bdb802024-07-22 18:14:512437 'fuchsia_web/av_testing/av_sync_tests.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382438 'net/tools/testserver/testserver.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:182439 'testing/scripts/run_isolated_script_test.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:412440 'testing/merge_scripts/standard_isolated_script_merge.pydeps',
2441 'testing/merge_scripts/standard_gtest_merge.pydeps',
2442 'testing/merge_scripts/code_coverage/merge_results.pydeps',
2443 'testing/merge_scripts/code_coverage/merge_steps.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042444 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:422445 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
Yuki Shiino38eeaad12022-08-11 06:40:252446 'third_party/blink/renderer/bindings/scripts/check_generated_file_list.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:422447 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:132448 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Yuki Shiinoea477d32023-08-21 06:24:342449 'third_party/blink/renderer/bindings/scripts/generate_event_interface_names.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:502450 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:412451 'third_party/blink/tools/blinkpy/web_tests/merge_results.pydeps',
2452 'third_party/blink/tools/merge_web_test_results.pydeps',
John Budorickbc3571aa2019-04-25 02:20:062453 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:222454 'tools/binary_size/supersize.pydeps',
Peter Wen2dcfa6e2025-03-04 22:42:522455 'tools/cygprofile/generate_orderfile.pydeps',
Ben Pastene028104a2022-08-10 19:17:452456 'tools/perf/process_perf_results.pydeps',
Peter Wence103e12024-10-09 19:23:512457 'tools/pgo/generate_profile.pydeps',
agrievef32bcc72016-04-04 14:57:402458]
2459
wnwenbdc444e2016-05-25 13:44:152460
agrievef32bcc72016-04-04 14:57:402461_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
2462
2463
Eric Boren6fd2b932018-01-25 15:05:082464# Bypass the AUTHORS check for these accounts.
2465_KNOWN_ROBOTS = set(
Shuai Xia0d99ebf2025-02-11 23:47:592466 ) | set('%[email protected]' % s for s in ('findit-for-me',
2467 'luci-bisection',
2468 'predator-for-me-staging',
2469 'predator-for-me')
Achuith Bhandarkar35905562018-07-25 19:28:452470 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:592471 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:522472 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:232473 'wpt-autoroller', 'chrome-weblayer-builder',
Georg Neise5817eb2025-02-06 03:47:312474 'skylab-test-cros-roller', 'infra-try-recipes-tester',
2475 'chrome-automated-expectation',
Stephanie Kimb49bdd242023-04-28 16:46:042476 'chromium-automated-expectation', 'chrome-branch-day',
Gennady Tsitovich554fd422025-04-02 21:03:182477 'chrome-cherry-picker', 'chromium-autosharder')
Eric Boren835d71f2018-09-07 21:09:042478 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:272479 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:042480 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:162481 for s in ('chromium-internal-autoroll',)
Kyungjun Lee3b7c9352024-04-02 23:59:142482 ) | set('%[email protected]' % s
Shuai Xia174d35c2025-04-15 17:10:312483 for s in ('chrome-screen-ai-releaser', 'crash-eng', 'crash')
Yulan Lineb0cfba2021-04-09 18:43:162484 ) | set('%[email protected]' % s
Chong Gub277e342022-10-15 03:30:552485 for s in ('swarming-tasks',)
2486 ) | set('%[email protected]' % s
2487 for s in ('global-integration-try-builder',
Joey Scarr1103c5d2023-09-14 01:17:552488 'global-integration-ci-builder')
Suma Kasa3b9cf7a2023-09-21 22:05:542489 ) | set('%[email protected]' % s
2490 for s in ('chops-security-borg',
2491 'chops-security-cronjobs-cpesuggest'))
Eric Boren6fd2b932018-01-25 15:05:082492
Matt Stark6ef08872021-07-29 01:21:462493_INVALID_GRD_FILE_LINE = [
2494 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
2495]
Eric Boren6fd2b932018-01-25 15:05:082496
Daniel Bratell65b033262019-04-23 08:17:062497def _IsCPlusPlusFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502498 """Returns True if this file contains C++-like code (and not Python,
2499 Go, Java, MarkDown, ...)"""
Daniel Bratell65b033262019-04-23 08:17:062500
Sam Maiera6e76d72022-02-11 21:43:502501 ext = input_api.os_path.splitext(file_path)[1]
2502 # This list is compatible with CppChecker.IsCppFile but we should
2503 # consider adding ".c" to it. If we do that we can use this function
2504 # at more places in the code.
2505 return ext in (
2506 '.h',
2507 '.cc',
2508 '.cpp',
2509 '.m',
2510 '.mm',
2511 )
2512
Daniel Bratell65b033262019-04-23 08:17:062513
2514def _IsCPlusPlusHeaderFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502515 return input_api.os_path.splitext(file_path)[1] == ".h"
Daniel Bratell65b033262019-04-23 08:17:062516
2517
2518def _IsJavaFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502519 return input_api.os_path.splitext(file_path)[1] == ".java"
Daniel Bratell65b033262019-04-23 08:17:062520
2521
2522def _IsProtoFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502523 return input_api.os_path.splitext(file_path)[1] == ".proto"
Daniel Bratell65b033262019-04-23 08:17:062524
Mohamed Heikal5e5b7922020-10-29 18:57:592525
Erik Staabc734cd7a2021-11-23 03:11:522526def _IsXmlOrGrdFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502527 ext = input_api.os_path.splitext(file_path)[1]
2528 return ext in ('.grd', '.xml')
Erik Staabc734cd7a2021-11-23 03:11:522529
2530
Sven Zheng76a79ea2022-12-21 21:25:242531def _IsMojomFile(input_api, file_path):
2532 return input_api.os_path.splitext(file_path)[1] == ".mojom"
2533
2534
Mohamed Heikal5e5b7922020-10-29 18:57:592535def CheckNoUpstreamDepsOnClank(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502536 """Prevent additions of dependencies from the upstream repo on //clank."""
2537 # clank can depend on clank
2538 if input_api.change.RepositoryRoot().endswith('clank'):
2539 return []
2540 build_file_patterns = [
2541 r'(.+/)?BUILD\.gn',
2542 r'.+\.gni',
2543 ]
2544 excluded_files = [r'build[/\\]config[/\\]android[/\\]config\.gni']
2545 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
Mohamed Heikal5e5b7922020-10-29 18:57:592546
Sam Maiera6e76d72022-02-11 21:43:502547 error_message = 'Disallowed import on //clank in an upstream build file:'
Mohamed Heikal5e5b7922020-10-29 18:57:592548
Sam Maiera6e76d72022-02-11 21:43:502549 def FilterFile(affected_file):
2550 return input_api.FilterSourceFile(affected_file,
2551 files_to_check=build_file_patterns,
2552 files_to_skip=excluded_files)
Mohamed Heikal5e5b7922020-10-29 18:57:592553
Sam Maiera6e76d72022-02-11 21:43:502554 problems = []
2555 for f in input_api.AffectedSourceFiles(FilterFile):
2556 local_path = f.LocalPath()
2557 for line_number, line in f.ChangedContents():
2558 if (bad_pattern.search(line)):
2559 problems.append('%s:%d\n %s' %
2560 (local_path, line_number, line.strip()))
2561 if problems:
2562 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
2563 else:
2564 return []
Mohamed Heikal5e5b7922020-10-29 18:57:592565
2566
Saagar Sanghavifceeaae2020-08-12 16:40:362567def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502568 """Attempts to prevent use of functions intended only for testing in
2569 non-testing code. For now this is just a best-effort implementation
2570 that ignores header files and may have some false positives. A
2571 better implementation would probably need a proper C++ parser.
2572 """
2573 # We only scan .cc files and the like, as the declaration of
2574 # for-testing functions in header files are hard to distinguish from
2575 # calls to such functions without a proper C++ parser.
2576 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:192577
Sam Maiera6e76d72022-02-11 21:43:502578 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
2579 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' %
2580 base_function_pattern)
2581 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
2582 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
2583 exclusion_pattern = input_api.re.compile(
2584 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' %
2585 (base_function_pattern, base_function_pattern))
2586 # Avoid a false positive in this case, where the method name, the ::, and
2587 # the closing { are all on different lines due to line wrapping.
2588 # HelperClassForTesting::
2589 # HelperClassForTesting(
2590 # args)
2591 # : member(0) {}
2592 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:192593
Sam Maiera6e76d72022-02-11 21:43:502594 def FilterFile(affected_file):
2595 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2596 input_api.DEFAULT_FILES_TO_SKIP)
2597 return input_api.FilterSourceFile(
2598 affected_file,
2599 files_to_check=file_inclusion_pattern,
2600 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:192601
Sam Maiera6e76d72022-02-11 21:43:502602 problems = []
2603 for f in input_api.AffectedSourceFiles(FilterFile):
2604 local_path = f.LocalPath()
2605 in_method_defn = False
2606 for line_number, line in f.ChangedContents():
2607 if (inclusion_pattern.search(line)
2608 and not comment_pattern.search(line)
2609 and not exclusion_pattern.search(line)
2610 and not allowlist_pattern.search(line)
2611 and not in_method_defn):
2612 problems.append('%s:%d\n %s' %
2613 (local_path, line_number, line.strip()))
2614 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:192615
Sam Maiera6e76d72022-02-11 21:43:502616 if problems:
2617 return [
2618 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
2619 ]
2620 else:
2621 return []
[email protected]55459852011-08-10 15:17:192622
2623
Saagar Sanghavifceeaae2020-08-12 16:40:362624def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502625 """This is a simplified version of
2626 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
2627 """
2628 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
2629 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
2630 name_pattern = r'ForTest(s|ing)?'
2631 # Describes an occurrence of "ForTest*" inside a // comment.
2632 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
2633 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
2634 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
2635 # Catch calls.
2636 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
2637 # Ignore definitions. (Comments are ignored separately.)
2638 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
Andrew Grieve40f451d2023-07-06 19:46:512639 allowlist_re = input_api.re.compile(r'// IN-TEST$')
Vaclav Brozek7dbc28c2018-03-27 08:35:232640
Sam Maiera6e76d72022-02-11 21:43:502641 problems = []
2642 sources = lambda x: input_api.FilterSourceFile(
2643 x,
2644 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
2645 DEFAULT_FILES_TO_SKIP),
2646 files_to_check=[r'.*\.java$'])
2647 for f in input_api.AffectedFiles(include_deletes=False,
2648 file_filter=sources):
2649 local_path = f.LocalPath()
Vaclav Brozek7dbc28c2018-03-27 08:35:232650 is_inside_javadoc = False
Sam Maiera6e76d72022-02-11 21:43:502651 for line_number, line in f.ChangedContents():
2652 if is_inside_javadoc and javadoc_end_re.search(line):
2653 is_inside_javadoc = False
2654 if not is_inside_javadoc and javadoc_start_re.search(line):
2655 is_inside_javadoc = True
2656 if is_inside_javadoc:
2657 continue
2658 if (inclusion_re.search(line) and not comment_re.search(line)
2659 and not annotation_re.search(line)
Andrew Grieve40f451d2023-07-06 19:46:512660 and not allowlist_re.search(line)
Sam Maiera6e76d72022-02-11 21:43:502661 and not exclusion_re.search(line)):
2662 problems.append('%s:%d\n %s' %
2663 (local_path, line_number, line.strip()))
Vaclav Brozek7dbc28c2018-03-27 08:35:232664
Sam Maiera6e76d72022-02-11 21:43:502665 if problems:
2666 return [
2667 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
2668 ]
2669 else:
2670 return []
Vaclav Brozek7dbc28c2018-03-27 08:35:232671
2672
Saagar Sanghavifceeaae2020-08-12 16:40:362673def CheckNoIOStreamInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502674 """Checks to make sure no .h files include <iostream>."""
2675 files = []
2676 pattern = input_api.re.compile(r'^#include\s*<iostream>',
2677 input_api.re.MULTILINE)
2678 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2679 if not f.LocalPath().endswith('.h'):
2680 continue
2681 contents = input_api.ReadFile(f)
2682 if pattern.search(contents):
2683 files.append(f)
[email protected]10689ca2011-09-02 02:31:542684
Sam Maiera6e76d72022-02-11 21:43:502685 if len(files):
2686 return [
2687 output_api.PresubmitError(
2688 'Do not #include <iostream> in header files, since it inserts static '
2689 'initialization into every file including the header. Instead, '
2690 '#include <ostream>. See http://crbug.com/94794', files)
2691 ]
2692 return []
2693
[email protected]10689ca2011-09-02 02:31:542694
Aleksey Khoroshilov9b28c032022-06-03 16:35:322695def CheckNoStrCatRedefines(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502696 """Checks no windows headers with StrCat redefined are included directly."""
2697 files = []
Aleksey Khoroshilov9b28c032022-06-03 16:35:322698 files_to_check = (r'.+%s' % _HEADER_EXTENSIONS,
2699 r'.+%s' % _IMPLEMENTATION_EXTENSIONS)
2700 files_to_skip = (input_api.DEFAULT_FILES_TO_SKIP +
2701 _NON_BASE_DEPENDENT_PATHS)
2702 sources_filter = lambda f: input_api.FilterSourceFile(
2703 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
2704
Sam Maiera6e76d72022-02-11 21:43:502705 pattern_deny = input_api.re.compile(
2706 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
2707 input_api.re.MULTILINE)
2708 pattern_allow = input_api.re.compile(
2709 r'^#include\s"base/win/windows_defines.inc"', input_api.re.MULTILINE)
Aleksey Khoroshilov9b28c032022-06-03 16:35:322710 for f in input_api.AffectedSourceFiles(sources_filter):
Sam Maiera6e76d72022-02-11 21:43:502711 contents = input_api.ReadFile(f)
2712 if pattern_deny.search(
2713 contents) and not pattern_allow.search(contents):
2714 files.append(f.LocalPath())
Danil Chapovalov3518f362018-08-11 16:13:432715
Sam Maiera6e76d72022-02-11 21:43:502716 if len(files):
2717 return [
2718 output_api.PresubmitError(
2719 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
2720 'directly since they pollute code with StrCat macro. Instead, '
2721 'include matching header from base/win. See http://crbug.com/856536',
2722 files)
2723 ]
2724 return []
Danil Chapovalov3518f362018-08-11 16:13:432725
[email protected]10689ca2011-09-02 02:31:542726
Andrew Williamsc9f69b482023-07-10 16:07:362727def _CheckNoUNIT_TESTInSourceFiles(input_api, f):
2728 problems = []
2729
2730 unit_test_macro = input_api.re.compile(
Riley Wong49be8a882025-02-27 00:38:232731 r'^\s*#.*(?:ifn?def\s+UNIT_TEST|defined\s*\(?\s*UNIT_TEST\s*\)?)(?:$|\s+)')
Andrew Williamsc9f69b482023-07-10 16:07:362732 for line_num, line in f.ChangedContents():
2733 if unit_test_macro.match(line):
2734 problems.append(' %s:%d' % (f.LocalPath(), line_num))
2735
2736 return problems
2737
2738
Saagar Sanghavifceeaae2020-08-12 16:40:362739def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502740 """Checks to make sure no source files use UNIT_TEST."""
2741 problems = []
2742 for f in input_api.AffectedFiles():
2743 if (not f.LocalPath().endswith(('.cc', '.mm'))):
2744 continue
Andrew Williamsc9f69b482023-07-10 16:07:362745 problems.extend(
2746 _CheckNoUNIT_TESTInSourceFiles(input_api, f))
[email protected]72df4e782012-06-21 16:28:182747
Sam Maiera6e76d72022-02-11 21:43:502748 if not problems:
2749 return []
2750 return [
2751 output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
2752 '\n'.join(problems))
2753 ]
2754
[email protected]72df4e782012-06-21 16:28:182755
Saagar Sanghavifceeaae2020-08-12 16:40:362756def CheckNoDISABLETypoInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502757 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
Dominic Battre033531052018-09-24 15:45:342758
Sam Maiera6e76d72022-02-11 21:43:502759 This test warns if somebody tries to disable a test with the DISABLE_ prefix
2760 instead of DISABLED_. To filter false positives, reports are only generated
2761 if a corresponding MAYBE_ line exists.
2762 """
2763 problems = []
Dominic Battre033531052018-09-24 15:45:342764
Sam Maiera6e76d72022-02-11 21:43:502765 # The following two patterns are looked for in tandem - is a test labeled
2766 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
2767 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
2768 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
Dominic Battre033531052018-09-24 15:45:342769
Sam Maiera6e76d72022-02-11 21:43:502770 # This is for the case that a test is disabled on all platforms.
2771 full_disable_pattern = input_api.re.compile(
2772 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
2773 input_api.re.MULTILINE)
Dominic Battre033531052018-09-24 15:45:342774
Arthur Sonzognic66e9c82024-04-23 07:53:042775 for f in input_api.AffectedFiles(include_deletes=False):
Sam Maiera6e76d72022-02-11 21:43:502776 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2777 continue
Dominic Battre033531052018-09-24 15:45:342778
Arthur Sonzognic66e9c82024-04-23 07:53:042779 # Search for MAYBE_, DISABLE_ pairs.
Sam Maiera6e76d72022-02-11 21:43:502780 disable_lines = {} # Maps of test name to line number.
2781 maybe_lines = {}
2782 for line_num, line in f.ChangedContents():
2783 disable_match = disable_pattern.search(line)
2784 if disable_match:
2785 disable_lines[disable_match.group(1)] = line_num
2786 maybe_match = maybe_pattern.search(line)
2787 if maybe_match:
2788 maybe_lines[maybe_match.group(1)] = line_num
Dominic Battre033531052018-09-24 15:45:342789
Sam Maiera6e76d72022-02-11 21:43:502790 # Search for DISABLE_ occurrences within a TEST() macro.
2791 disable_tests = set(disable_lines.keys())
2792 maybe_tests = set(maybe_lines.keys())
2793 for test in disable_tests.intersection(maybe_tests):
2794 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
Dominic Battre033531052018-09-24 15:45:342795
Sam Maiera6e76d72022-02-11 21:43:502796 contents = input_api.ReadFile(f)
2797 full_disable_match = full_disable_pattern.search(contents)
2798 if full_disable_match:
2799 problems.append(' %s' % f.LocalPath())
Dominic Battre033531052018-09-24 15:45:342800
Sam Maiera6e76d72022-02-11 21:43:502801 if not problems:
2802 return []
2803 return [
2804 output_api.PresubmitPromptWarning(
2805 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
2806 '\n'.join(problems))
2807 ]
2808
Dominic Battre033531052018-09-24 15:45:342809
Nina Satragnof7660532021-09-20 18:03:352810def CheckForgettingMAYBEInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502811 """Checks to make sure tests disabled conditionally are not missing a
2812 corresponding MAYBE_ prefix.
2813 """
2814 # Expect at least a lowercase character in the test name. This helps rule out
2815 # false positives with macros wrapping the actual tests name.
2816 define_maybe_pattern = input_api.re.compile(
2817 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
Bruce Dawsonffc55292022-04-20 04:18:192818 # The test_maybe_pattern needs to handle all of these forms. The standard:
2819 # IN_PROC_TEST_F(SyncTest, MAYBE_Start) {
2820 # With a wrapper macro around the test name:
2821 # IN_PROC_TEST_F(SyncTest, E2E_ENABLED(MAYBE_Start)) {
2822 # And the odd-ball NACL_BROWSER_TEST_f format:
2823 # NACL_BROWSER_TEST_F(NaClBrowserTest, SimpleLoad, {
2824 # The optional E2E_ENABLED-style is handled with (\w*\()?
2825 # The NACL_BROWSER_TEST_F pattern is handled by allowing a trailing comma or
2826 # trailing ')'.
2827 test_maybe_pattern = (
2828 r'^\s*\w*TEST[^(]*\(\s*\w+,\s*(\w*\()?MAYBE_{test_name}[\),]')
Sam Maiera6e76d72022-02-11 21:43:502829 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
2830 warnings = []
Nina Satragnof7660532021-09-20 18:03:352831
Sam Maiera6e76d72022-02-11 21:43:502832 # Read the entire files. We can't just read the affected lines, forgetting to
2833 # add MAYBE_ on a change would not show up otherwise.
Arthur Sonzognic66e9c82024-04-23 07:53:042834 for f in input_api.AffectedFiles(include_deletes=False):
Sam Maiera6e76d72022-02-11 21:43:502835 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2836 continue
2837 contents = input_api.ReadFile(f)
2838 lines = contents.splitlines(True)
2839 current_position = 0
2840 warning_test_names = set()
2841 for line_num, line in enumerate(lines, start=1):
2842 current_position += len(line)
2843 maybe_match = define_maybe_pattern.search(line)
2844 if maybe_match:
2845 test_name = maybe_match.group('test_name')
2846 # Do not warn twice for the same test.
2847 if (test_name in warning_test_names):
2848 continue
2849 warning_test_names.add(test_name)
Nina Satragnof7660532021-09-20 18:03:352850
Sam Maiera6e76d72022-02-11 21:43:502851 # Attempt to find the corresponding MAYBE_ test or suite, starting from
2852 # the current position.
2853 test_match = input_api.re.compile(
2854 test_maybe_pattern.format(test_name=test_name),
2855 input_api.re.MULTILINE).search(contents, current_position)
2856 suite_match = input_api.re.compile(
2857 suite_maybe_pattern.format(test_name=test_name),
2858 input_api.re.MULTILINE).search(contents, current_position)
2859 if not test_match and not suite_match:
2860 warnings.append(
2861 output_api.PresubmitPromptWarning(
2862 '%s:%d found MAYBE_ defined without corresponding test %s'
2863 % (f.LocalPath(), line_num, test_name)))
2864 return warnings
2865
[email protected]72df4e782012-06-21 16:28:182866
Saagar Sanghavifceeaae2020-08-12 16:40:362867def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502868 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
2869 errors = []
Kalvin Lee4a3b79de2022-05-26 16:00:162870 pattern = input_api.re.compile(r'\bDCHECK_IS_ON\b(?!\(\))',
Sam Maiera6e76d72022-02-11 21:43:502871 input_api.re.MULTILINE)
2872 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2873 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
2874 continue
2875 for lnum, line in f.ChangedContents():
2876 if input_api.re.search(pattern, line):
2877 errors.append(
2878 output_api.PresubmitError((
2879 '%s:%d: Use of DCHECK_IS_ON() must be written as "#if '
2880 + 'DCHECK_IS_ON()", not forgetting the parentheses.') %
2881 (f.LocalPath(), lnum)))
2882 return errors
danakj61c1aa22015-10-26 19:55:522883
2884
Weilun Shia487fad2020-10-28 00:10:342885# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
2886# more reliable way. See
2887# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:192888
wnwenbdc444e2016-05-25 13:44:152889
Saagar Sanghavifceeaae2020-08-12 16:40:362890def CheckFlakyTestUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502891 """Check that FlakyTest annotation is our own instead of the android one"""
2892 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
2893 files = []
2894 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2895 if f.LocalPath().endswith('Test.java'):
2896 if pattern.search(input_api.ReadFile(f)):
2897 files.append(f)
2898 if len(files):
2899 return [
2900 output_api.PresubmitError(
2901 'Use org.chromium.base.test.util.FlakyTest instead of '
2902 'android.test.FlakyTest', files)
2903 ]
2904 return []
mcasasb7440c282015-02-04 14:52:192905
wnwenbdc444e2016-05-25 13:44:152906
Saagar Sanghavifceeaae2020-08-12 16:40:362907def CheckNoDEPSGIT(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502908 """Make sure .DEPS.git is never modified manually."""
2909 if any(f.LocalPath().endswith('.DEPS.git')
2910 for f in input_api.AffectedFiles()):
2911 return [
2912 output_api.PresubmitError(
2913 'Never commit changes to .DEPS.git. This file is maintained by an\n'
2914 'automated system based on what\'s in DEPS and your changes will be\n'
2915 'overwritten.\n'
2916 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
2917 'get-the-code#Rolling_DEPS\n'
2918 'for more information')
2919 ]
2920 return []
[email protected]2a8ac9c2011-10-19 17:20:442921
2922
Sven Zheng76a79ea2022-12-21 21:25:242923def CheckCrosApiNeedBrowserTest(input_api, output_api):
2924 """Check new crosapi should add browser test."""
2925 has_new_crosapi = False
2926 has_browser_test = False
2927 for f in input_api.AffectedFiles():
Anton Bershanskyi4253349482025-02-11 21:01:272928 path = f.UnixLocalPath()
Sven Zheng76a79ea2022-12-21 21:25:242929 if (path.startswith('chromeos/crosapi/mojom') and
2930 _IsMojomFile(input_api, path) and f.Action() == 'A'):
2931 has_new_crosapi = True
2932 if path.endswith('browsertest.cc') or path.endswith('browser_test.cc'):
2933 has_browser_test = True
2934 if has_new_crosapi and not has_browser_test:
2935 return [
2936 output_api.PresubmitPromptWarning(
2937 'You are adding a new crosapi, but there is no file ends with '
2938 'browsertest.cc file being added or modified. It is important '
2939 'to add crosapi browser test coverage to avoid version '
2940 ' skew issues.\n'
2941 'Check //docs/lacros/test_instructions.md for more information.'
2942 )
2943 ]
2944 return []
2945
2946
Saagar Sanghavifceeaae2020-08-12 16:40:362947def CheckValidHostsInDEPSOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502948 """Checks that DEPS file deps are from allowed_hosts."""
2949 # Run only if DEPS file has been modified to annoy fewer bystanders.
2950 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
2951 return []
2952 # Outsource work to gclient verify
2953 try:
2954 gclient_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
2955 'third_party', 'depot_tools',
2956 'gclient.py')
2957 input_api.subprocess.check_output(
Bruce Dawson8a43cf72022-05-13 17:10:322958 [input_api.python3_executable, gclient_path, 'verify'],
Sam Maiera6e76d72022-02-11 21:43:502959 stderr=input_api.subprocess.STDOUT)
2960 return []
2961 except input_api.subprocess.CalledProcessError as error:
2962 return [
2963 output_api.PresubmitError(
2964 'DEPS file must have only git dependencies.',
2965 long_text=error.output)
2966 ]
tandriief664692014-09-23 14:51:472967
2968
Mario Sanchez Prada2472cab2019-09-18 10:58:312969def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152970 ban_rule):
Allen Bauer84778682022-09-22 16:28:562971 """Helper method for checking for banned constructs.
Mario Sanchez Prada2472cab2019-09-18 10:58:312972
Sam Maiera6e76d72022-02-11 21:43:502973 Returns an string composed of the name of the file, the line number where the
2974 match has been found and the additional text passed as |message| in case the
2975 target type name matches the text inside the line passed as parameter.
2976 """
2977 result = []
Peng Huang9c5949a02020-06-11 19:20:542978
Daniel Chenga44a1bcd2022-03-15 20:00:152979 # Ignore comments about banned types.
2980 if input_api.re.search(r"^ *//", line):
Sam Maiera6e76d72022-02-11 21:43:502981 return result
Daniel Chenga44a1bcd2022-03-15 20:00:152982 # A // nocheck comment will bypass this error.
2983 if line.endswith(" nocheck"):
Sam Maiera6e76d72022-02-11 21:43:502984 return result
2985
2986 matched = False
Daniel Chenga44a1bcd2022-03-15 20:00:152987 if ban_rule.pattern[0:1] == '/':
2988 regex = ban_rule.pattern[1:]
Sam Maiera6e76d72022-02-11 21:43:502989 if input_api.re.search(regex, line):
2990 matched = True
Daniel Chenga44a1bcd2022-03-15 20:00:152991 elif ban_rule.pattern in line:
Sam Maiera6e76d72022-02-11 21:43:502992 matched = True
2993
2994 if matched:
2995 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
Daniel Chenga44a1bcd2022-03-15 20:00:152996 for line in ban_rule.explanation:
2997 result.append(' %s' % line)
Sam Maiera6e76d72022-02-11 21:43:502998
danakjd18e8892020-12-17 17:42:012999 return result
Mario Sanchez Prada2472cab2019-09-18 10:58:313000
3001
Saagar Sanghavifceeaae2020-08-12 16:40:363002def CheckNoBannedFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503003 """Make sure that banned functions are not used."""
Ben Pastenee79d66112025-04-23 19:46:153004 results= []
[email protected]127f18ec2012-06-16 05:05:593005
Sam Maiera6e76d72022-02-11 21:43:503006 def IsExcludedFile(affected_file, excluded_paths):
Daniel Chenga44a1bcd2022-03-15 20:00:153007 if not excluded_paths:
3008 return False
3009
Anton Bershanskyi4253349482025-02-11 21:01:273010 local_path = affected_file.UnixLocalPath()
Sam Maiera6e76d72022-02-11 21:43:503011 for item in excluded_paths:
3012 if input_api.re.match(item, local_path):
3013 return True
3014 return False
wnwenbdc444e2016-05-25 13:44:153015
Sam Maiera6e76d72022-02-11 21:43:503016 def IsIosObjcFile(affected_file):
3017 local_path = affected_file.LocalPath()
3018 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m',
3019 '.h'):
3020 return False
3021 basename = input_api.os_path.basename(local_path)
3022 if 'ios' in basename.split('_'):
3023 return True
3024 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
3025 if sep and 'ios' in local_path.split(sep):
3026 return True
3027 return False
Sylvain Defresnea8b73d252018-02-28 15:45:543028
Daniel Chenga44a1bcd2022-03-15 20:00:153029 def CheckForMatch(affected_file, line_num: int, line: str,
3030 ban_rule: BanRule):
3031 if IsExcludedFile(affected_file, ban_rule.excluded_paths):
3032 return
3033
Ben Pastenee79d66112025-04-23 19:46:153034 message = _GetMessageForMatchingType(input_api, f, line_num, line,
3035 ban_rule)
3036 if message:
3037 result_loc = []
3038 if ban_rule.surface_as_gerrit_lint:
3039 result_loc.append(output_api.PresubmitResultLocation(
3040 file_path=affected_file.LocalPath(),
3041 start_line=line_num,
3042 end_line=line_num,
3043 ))
Daniel Chenga44a1bcd2022-03-15 20:00:153044 if ban_rule.treat_as_error is not None and ban_rule.treat_as_error:
Ben Pastenee79d66112025-04-23 19:46:153045 results.append(
3046 output_api.PresubmitError('A banned function was used.\n' +
3047 '\n'.join(message),
3048 locations=result_loc))
3049
Sam Maiera6e76d72022-02-11 21:43:503050 else:
Ben Pastenee79d66112025-04-23 19:46:153051 results.append(
3052 output_api.PresubmitPromptWarning('A banned function was used.\n' +
3053 '\n'.join(message),
3054 locations=result_loc))
wnwenbdc444e2016-05-25 13:44:153055
Sam Maiera6e76d72022-02-11 21:43:503056 file_filter = lambda f: f.LocalPath().endswith(('.java'))
3057 for f in input_api.AffectedFiles(file_filter=file_filter):
3058 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:153059 for ban_rule in _BANNED_JAVA_FUNCTIONS:
3060 CheckForMatch(f, line_num, line, ban_rule)
Eric Stevensona9a980972017-09-23 00:04:413061
Clement Yan9b330cb2022-11-17 05:25:293062 file_filter = lambda f: f.LocalPath().endswith(('.js', '.ts'))
3063 for f in input_api.AffectedFiles(file_filter=file_filter):
3064 for line_num, line in f.ChangedContents():
3065 for ban_rule in _BANNED_JAVASCRIPT_FUNCTIONS:
3066 CheckForMatch(f, line_num, line, ban_rule)
3067
Sam Maiera6e76d72022-02-11 21:43:503068 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
3069 for f in input_api.AffectedFiles(file_filter=file_filter):
3070 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:153071 for ban_rule in _BANNED_OBJC_FUNCTIONS:
3072 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:593073
Sam Maiera6e76d72022-02-11 21:43:503074 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
3075 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:153076 for ban_rule in _BANNED_IOS_OBJC_FUNCTIONS:
3077 CheckForMatch(f, line_num, line, ban_rule)
Sylvain Defresnea8b73d252018-02-28 15:45:543078
Sam Maiera6e76d72022-02-11 21:43:503079 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
3080 for f in input_api.AffectedFiles(file_filter=egtest_filter):
3081 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:153082 for ban_rule in _BANNED_IOS_EGTEST_FUNCTIONS:
3083 CheckForMatch(f, line_num, line, ban_rule)
Peter K. Lee6c03ccff2019-07-15 14:40:053084
Sam Maiera6e76d72022-02-11 21:43:503085 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
3086 for f in input_api.AffectedFiles(file_filter=file_filter):
3087 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:153088 for ban_rule in _BANNED_CPP_FUNCTIONS:
3089 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:593090
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:153091 # As of 05/2024, iOS fully migrated ConsentLevel::kSync to kSignin, and
3092 # Android is in the process of preventing new users from entering kSync.
3093 # So the warning is restricted to those platforms.
Riley Wong49be8a882025-02-27 00:38:233094 ios_pattern = input_api.re.compile(r'(^|[\W_])ios[\W_]')
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:153095 file_filter = lambda f: (f.LocalPath().endswith(('.cc', '.mm', '.h')) and
3096 ('android' in f.LocalPath() or
3097 # Simply checking for an 'ios' substring would
3098 # catch unrelated cases, use a regex.
3099 ios_pattern.search(f.LocalPath())))
3100 for f in input_api.AffectedFiles(file_filter=file_filter):
3101 for line_num, line in f.ChangedContents():
3102 for ban_rule in _DEPRECATED_SYNC_CONSENT_CPP_FUNCTIONS:
3103 CheckForMatch(f, line_num, line, ban_rule)
3104
3105 file_filter = lambda f: f.LocalPath().endswith(('.java'))
3106 for f in input_api.AffectedFiles(file_filter=file_filter):
3107 for line_num, line in f.ChangedContents():
3108 for ban_rule in _DEPRECATED_SYNC_CONSENT_JAVA_FUNCTIONS:
3109 CheckForMatch(f, line_num, line, ban_rule)
3110
Daniel Cheng92c15e32022-03-16 17:48:223111 file_filter = lambda f: f.LocalPath().endswith(('.mojom'))
3112 for f in input_api.AffectedFiles(file_filter=file_filter):
3113 for line_num, line in f.ChangedContents():
3114 for ban_rule in _BANNED_MOJOM_PATTERNS:
3115 CheckForMatch(f, line_num, line, ban_rule)
3116
Ben Pastenee79d66112025-04-23 19:46:153117 return results
Daniel Cheng92c15e32022-03-16 17:48:223118
[email protected]127f18ec2012-06-16 05:05:593119
Michael Thiessen44457642020-02-06 00:24:153120def _CheckAndroidNoBannedImports(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503121 """Make sure that banned java imports are not used."""
3122 errors = []
Michael Thiessen44457642020-02-06 00:24:153123
Sam Maiera6e76d72022-02-11 21:43:503124 file_filter = lambda f: f.LocalPath().endswith(('.java'))
3125 for f in input_api.AffectedFiles(file_filter=file_filter):
3126 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:153127 for ban_rule in _BANNED_JAVA_IMPORTS:
3128 # Consider merging this into the above function. There is no
3129 # real difference anymore other than helping with a little
3130 # bit of boilerplate text. Doing so means things like
3131 # `treat_as_error` will also be uniformly handled.
Sam Maiera6e76d72022-02-11 21:43:503132 problems = _GetMessageForMatchingType(input_api, f, line_num,
Daniel Chenga44a1bcd2022-03-15 20:00:153133 line, ban_rule)
Sam Maiera6e76d72022-02-11 21:43:503134 if problems:
3135 errors.extend(problems)
3136 result = []
3137 if (errors):
3138 result.append(
3139 output_api.PresubmitError('Banned imports were used.\n' +
3140 '\n'.join(errors)))
3141 return result
Michael Thiessen44457642020-02-06 00:24:153142
3143
Saagar Sanghavifceeaae2020-08-12 16:40:363144def CheckNoPragmaOnce(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503145 """Make sure that banned functions are not used."""
3146 files = []
3147 pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
3148 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
3149 if not f.LocalPath().endswith('.h'):
3150 continue
Bruce Dawson4c4c2922022-05-02 18:07:333151 if f.LocalPath().endswith('com_imported_mstscax.h'):
3152 continue
Sam Maiera6e76d72022-02-11 21:43:503153 contents = input_api.ReadFile(f)
3154 if pattern.search(contents):
3155 files.append(f)
[email protected]6c063c62012-07-11 19:11:063156
Sam Maiera6e76d72022-02-11 21:43:503157 if files:
3158 return [
3159 output_api.PresubmitError(
3160 'Do not use #pragma once in header files.\n'
3161 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
3162 files)
3163 ]
3164 return []
[email protected]6c063c62012-07-11 19:11:063165
[email protected]127f18ec2012-06-16 05:05:593166
Saagar Sanghavifceeaae2020-08-12 16:40:363167def CheckNoTrinaryTrueFalse(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503168 """Checks to make sure we don't introduce use of foo ? true : false."""
3169 problems = []
3170 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
3171 for f in input_api.AffectedFiles():
3172 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
3173 continue
[email protected]e7479052012-09-19 00:26:123174
Sam Maiera6e76d72022-02-11 21:43:503175 for line_num, line in f.ChangedContents():
3176 if pattern.match(line):
3177 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]e7479052012-09-19 00:26:123178
Sam Maiera6e76d72022-02-11 21:43:503179 if not problems:
3180 return []
3181 return [
3182 output_api.PresubmitPromptWarning(
3183 'Please consider avoiding the "? true : false" pattern if possible.\n'
3184 + '\n'.join(problems))
3185 ]
[email protected]e7479052012-09-19 00:26:123186
3187
Saagar Sanghavifceeaae2020-08-12 16:40:363188def CheckUnwantedDependencies(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503189 """Runs checkdeps on #include and import statements added in this
3190 change. Breaking - rules is an error, breaking ! rules is a
3191 warning.
3192 """
3193 # Return early if no relevant file types were modified.
3194 for f in input_api.AffectedFiles():
3195 path = f.LocalPath()
3196 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path)
3197 or _IsJavaFile(input_api, path)):
3198 break
[email protected]55f9f382012-07-31 11:02:183199 else:
Sam Maiera6e76d72022-02-11 21:43:503200 return []
rhalavati08acd232017-04-03 07:23:283201
Sam Maiera6e76d72022-02-11 21:43:503202 import sys
3203 # We need to wait until we have an input_api object and use this
3204 # roundabout construct to import checkdeps because this file is
3205 # eval-ed and thus doesn't have __file__.
3206 original_sys_path = sys.path
3207 try:
3208 sys.path = sys.path + [
3209 input_api.os_path.join(input_api.PresubmitLocalPath(),
3210 'buildtools', 'checkdeps')
3211 ]
3212 import checkdeps
3213 from rules import Rule
3214 finally:
3215 # Restore sys.path to what it was before.
3216 sys.path = original_sys_path
[email protected]55f9f382012-07-31 11:02:183217
Sam Maiera6e76d72022-02-11 21:43:503218 added_includes = []
3219 added_imports = []
3220 added_java_imports = []
3221 for f in input_api.AffectedFiles():
3222 if _IsCPlusPlusFile(input_api, f.LocalPath()):
3223 changed_lines = [line for _, line in f.ChangedContents()]
3224 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
3225 elif _IsProtoFile(input_api, f.LocalPath()):
3226 changed_lines = [line for _, line in f.ChangedContents()]
3227 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
3228 elif _IsJavaFile(input_api, f.LocalPath()):
3229 changed_lines = [line for _, line in f.ChangedContents()]
3230 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:243231
Sam Maiera6e76d72022-02-11 21:43:503232 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
3233
3234 error_descriptions = []
3235 warning_descriptions = []
3236 error_subjects = set()
3237 warning_subjects = set()
3238
3239 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
3240 added_includes):
3241 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3242 description_with_path = '%s\n %s' % (path, rule_description)
3243 if rule_type == Rule.DISALLOW:
3244 error_descriptions.append(description_with_path)
3245 error_subjects.add("#includes")
3246 else:
3247 warning_descriptions.append(description_with_path)
3248 warning_subjects.add("#includes")
3249
3250 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
3251 added_imports):
3252 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3253 description_with_path = '%s\n %s' % (path, rule_description)
3254 if rule_type == Rule.DISALLOW:
3255 error_descriptions.append(description_with_path)
3256 error_subjects.add("imports")
3257 else:
3258 warning_descriptions.append(description_with_path)
3259 warning_subjects.add("imports")
3260
3261 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
3262 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
3263 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3264 description_with_path = '%s\n %s' % (path, rule_description)
3265 if rule_type == Rule.DISALLOW:
3266 error_descriptions.append(description_with_path)
3267 error_subjects.add("imports")
3268 else:
3269 warning_descriptions.append(description_with_path)
3270 warning_subjects.add("imports")
3271
3272 results = []
3273 if error_descriptions:
3274 results.append(
3275 output_api.PresubmitError(
3276 'You added one or more %s that violate checkdeps rules.' %
3277 " and ".join(error_subjects), error_descriptions))
3278 if warning_descriptions:
3279 results.append(
3280 output_api.PresubmitPromptOrNotify(
3281 'You added one or more %s of files that are temporarily\n'
3282 'allowed but being removed. Can you avoid introducing the\n'
3283 '%s? See relevant DEPS file(s) for details and contacts.' %
3284 (" and ".join(warning_subjects), "/".join(warning_subjects)),
3285 warning_descriptions))
3286 return results
[email protected]55f9f382012-07-31 11:02:183287
3288
Saagar Sanghavifceeaae2020-08-12 16:40:363289def CheckFilePermissions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503290 """Check that all files have their permissions properly set."""
3291 if input_api.platform == 'win32':
3292 return []
3293 checkperms_tool = input_api.os_path.join(input_api.PresubmitLocalPath(),
3294 'tools', 'checkperms',
3295 'checkperms.py')
3296 args = [
Bruce Dawson8a43cf72022-05-13 17:10:323297 input_api.python3_executable, checkperms_tool, '--root',
Sam Maiera6e76d72022-02-11 21:43:503298 input_api.change.RepositoryRoot()
3299 ]
3300 with input_api.CreateTemporaryFile() as file_list:
3301 for f in input_api.AffectedFiles():
3302 # checkperms.py file/directory arguments must be relative to the
3303 # repository.
3304 file_list.write((f.LocalPath() + '\n').encode('utf8'))
3305 file_list.close()
3306 args += ['--file-list', file_list.name]
3307 try:
3308 input_api.subprocess.check_output(args)
3309 return []
3310 except input_api.subprocess.CalledProcessError as error:
3311 return [
3312 output_api.PresubmitError('checkperms.py failed:',
3313 long_text=error.output.decode(
3314 'utf-8', 'ignore'))
3315 ]
[email protected]fbcafe5a2012-08-08 15:31:223316
3317
Saagar Sanghavifceeaae2020-08-12 16:40:363318def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503319 """Makes sure we don't include ui/aura/window_property.h
3320 in header files.
3321 """
3322 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
3323 errors = []
3324 for f in input_api.AffectedFiles():
3325 if not f.LocalPath().endswith('.h'):
3326 continue
3327 for line_num, line in f.ChangedContents():
3328 if pattern.match(line):
3329 errors.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]c8278b32012-10-30 20:35:493330
Sam Maiera6e76d72022-02-11 21:43:503331 results = []
3332 if errors:
3333 results.append(
3334 output_api.PresubmitError(
3335 'Header files should not include ui/aura/window_property.h',
3336 errors))
3337 return results
[email protected]c8278b32012-10-30 20:35:493338
3339
Omer Katzcc77ea92021-04-26 10:23:283340def CheckNoInternalHeapIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503341 """Makes sure we don't include any headers from
3342 third_party/blink/renderer/platform/heap/impl or
3343 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
3344 third_party/blink/renderer/platform/heap
3345 """
3346 impl_pattern = input_api.re.compile(
3347 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
3348 v8_wrapper_pattern = input_api.re.compile(
3349 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"'
3350 )
3351 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:313352 r"^third_party/blink/renderer/platform/heap/.*",
Anton Bershanskyi4253349482025-02-11 21:01:273353 f.UnixLocalPath())
Sam Maiera6e76d72022-02-11 21:43:503354 errors = []
Omer Katzcc77ea92021-04-26 10:23:283355
Sam Maiera6e76d72022-02-11 21:43:503356 for f in input_api.AffectedFiles(file_filter=file_filter):
3357 for line_num, line in f.ChangedContents():
3358 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
3359 errors.append(' %s:%d' % (f.LocalPath(), line_num))
Omer Katzcc77ea92021-04-26 10:23:283360
Sam Maiera6e76d72022-02-11 21:43:503361 results = []
3362 if errors:
3363 results.append(
3364 output_api.PresubmitError(
3365 'Do not include files from third_party/blink/renderer/platform/heap/impl'
3366 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
3367 'relevant counterparts from third_party/blink/renderer/platform/heap',
3368 errors))
3369 return results
Omer Katzcc77ea92021-04-26 10:23:283370
3371
[email protected]70ca77752012-11-20 03:45:033372def _CheckForVersionControlConflictsInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:503373 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
3374 errors = []
3375 for line_num, line in f.ChangedContents():
3376 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
3377 # First-level headers in markdown look a lot like version control
3378 # conflict markers. http://daringfireball.net/projects/markdown/basics
3379 continue
3380 if pattern.match(line):
3381 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
3382 return errors
[email protected]70ca77752012-11-20 03:45:033383
3384
Saagar Sanghavifceeaae2020-08-12 16:40:363385def CheckForVersionControlConflicts(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503386 """Usually this is not intentional and will cause a compile failure."""
3387 errors = []
3388 for f in input_api.AffectedFiles():
3389 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
[email protected]70ca77752012-11-20 03:45:033390
Sam Maiera6e76d72022-02-11 21:43:503391 results = []
3392 if errors:
3393 results.append(
3394 output_api.PresubmitError(
3395 'Version control conflict markers found, please resolve.',
3396 errors))
3397 return results
[email protected]70ca77752012-11-20 03:45:033398
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203399
Saagar Sanghavifceeaae2020-08-12 16:40:363400def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
Dirk Prankee4df27972025-02-26 18:39:353401 pattern = input_api.re.compile(r'support\.google\.com\/chrome.*/answer')
Sam Maiera6e76d72022-02-11 21:43:503402 errors = []
3403 for f in input_api.AffectedFiles():
3404 for line_num, line in f.ChangedContents():
3405 if pattern.search(line):
3406 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
estadee17314a02017-01-12 16:22:163407
Sam Maiera6e76d72022-02-11 21:43:503408 results = []
3409 if errors:
3410 results.append(
3411 output_api.PresubmitPromptWarning(
3412 'Found Google support URL addressed by answer number. Please replace '
3413 'with a p= identifier instead. See crbug.com/679462\n',
3414 errors))
3415 return results
estadee17314a02017-01-12 16:22:163416
[email protected]70ca77752012-11-20 03:45:033417
Saagar Sanghavifceeaae2020-08-12 16:40:363418def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503419 def FilterFile(affected_file):
3420 """Filter function for use with input_api.AffectedSourceFiles,
3421 below. This filters out everything except non-test files from
3422 top-level directories that generally speaking should not hard-code
3423 service URLs (e.g. src/android_webview/, src/content/ and others).
3424 """
3425 return input_api.FilterSourceFile(
3426 affected_file,
Bruce Dawson40fece62022-09-16 19:58:313427 files_to_check=[r'^(android_webview|base|content|net)/.*'],
Sam Maiera6e76d72022-02-11 21:43:503428 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3429 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:443430
Dirk Prankee4df27972025-02-26 18:39:353431 base_pattern = (r'"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
3432 r'\.(com|net)[^"]*"')
Sam Maiera6e76d72022-02-11 21:43:503433 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
3434 pattern = input_api.re.compile(base_pattern)
3435 problems = [] # items are (filename, line_number, line)
3436 for f in input_api.AffectedSourceFiles(FilterFile):
3437 for line_num, line in f.ChangedContents():
3438 if not comment_pattern.search(line) and pattern.search(line):
3439 problems.append((f.LocalPath(), line_num, line))
[email protected]06e6d0ff2012-12-11 01:36:443440
Sam Maiera6e76d72022-02-11 21:43:503441 if problems:
3442 return [
3443 output_api.PresubmitPromptOrNotify(
3444 'Most layers below src/chrome/ should not hardcode service URLs.\n'
3445 'Are you sure this is correct?', [
3446 ' %s:%d: %s' % (problem[0], problem[1], problem[2])
3447 for problem in problems
3448 ])
3449 ]
3450 else:
3451 return []
[email protected]06e6d0ff2012-12-11 01:36:443452
3453
Saagar Sanghavifceeaae2020-08-12 16:40:363454def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503455 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
James Cook6b6597c2019-11-06 22:05:293456
Sam Maiera6e76d72022-02-11 21:43:503457 def FileFilter(affected_file):
3458 """Includes directories known to be Chrome OS only."""
3459 return input_api.FilterSourceFile(
3460 affected_file,
3461 files_to_check=(
3462 '^ash/',
3463 '^chromeos/', # Top-level src/chromeos.
3464 '.*/chromeos/', # Any path component.
3465 '^components/arc',
3466 '^components/exo'),
3467 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:293468
Sam Maiera6e76d72022-02-11 21:43:503469 prefs = []
3470 priority_prefs = []
3471 for f in input_api.AffectedFiles(file_filter=FileFilter):
3472 for line_num, line in f.ChangedContents():
3473 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF',
3474 line):
3475 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
3476 prefs.append(' %s' % line)
3477 if input_api.re.search(
3478 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
3479 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
3480 priority_prefs.append(' %s' % line)
3481
3482 results = []
3483 if (prefs):
3484 results.append(
3485 output_api.PresubmitPromptWarning(
3486 'Preferences were registered as SYNCABLE_PREF and will be controlled '
3487 'by browser sync settings. If these prefs should be controlled by OS '
3488 'sync settings use SYNCABLE_OS_PREF instead.\n' +
3489 '\n'.join(prefs)))
3490 if (priority_prefs):
3491 results.append(
3492 output_api.PresubmitPromptWarning(
3493 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
3494 'controlled by browser sync settings. If these prefs should be '
3495 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
3496 'instead.\n' + '\n'.join(prefs)))
3497 return results
James Cook6b6597c2019-11-06 22:05:293498
3499
Saagar Sanghavifceeaae2020-08-12 16:40:363500def CheckNoAbbreviationInPngFileName(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503501 """Makes sure there are no abbreviations in the name of PNG files.
3502 The native_client_sdk directory is excluded because it has auto-generated PNG
3503 files for documentation.
3504 """
3505 errors = []
Yuanqing Zhu9eef02832022-12-04 14:42:173506 files_to_check = [r'.*\.png$']
Bruce Dawson40fece62022-09-16 19:58:313507 files_to_skip = [r'^native_client_sdk/',
3508 r'^services/test/',
3509 r'^third_party/blink/web_tests/',
Bruce Dawson3db456212022-05-02 05:34:183510 ]
Sam Maiera6e76d72022-02-11 21:43:503511 file_filter = lambda f: input_api.FilterSourceFile(
3512 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Dirk Prankee4df27972025-02-26 18:39:353513 abbreviation = input_api.re.compile(r'.+_[a-z]\.png|.+_[a-z]_.*\.png')
Sam Maiera6e76d72022-02-11 21:43:503514 for f in input_api.AffectedFiles(include_deletes=False,
3515 file_filter=file_filter):
Yuanqing Zhu9eef02832022-12-04 14:42:173516 file_name = input_api.os_path.split(f.LocalPath())[1]
3517 if abbreviation.search(file_name):
3518 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:273519
Sam Maiera6e76d72022-02-11 21:43:503520 results = []
3521 if errors:
3522 results.append(
3523 output_api.PresubmitError(
3524 'The name of PNG files should not have abbreviations. \n'
3525 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
3526 'Contact [email protected] if you have questions.', errors))
3527 return results
[email protected]d2530012013-01-25 16:39:273528
Evan Stade7cd4a2c2022-08-04 23:37:253529def CheckNoProductIconsAddedToPublicRepo(input_api, output_api):
3530 """Heuristically identifies product icons based on their file name and reminds
3531 contributors not to add them to the Chromium repository.
3532 """
Peter Kotwiczf634d072025-04-28 22:48:153533
3534 if input_api.change.RepositoryRoot().endswith('clank'):
3535 # TODO(crbug.com/414435241): Change check to compute whether change
3536 # belongs to internal repository instead of relying on string matching.
3537 return []
3538
Evan Stade7cd4a2c2022-08-04 23:37:253539 errors = []
3540 files_to_check = [r'.*google.*\.png$|.*google.*\.svg$|.*google.*\.icon$']
3541 file_filter = lambda f: input_api.FilterSourceFile(
3542 f, files_to_check=files_to_check)
3543 for f in input_api.AffectedFiles(include_deletes=False,
3544 file_filter=file_filter):
3545 errors.append(' %s' % f.LocalPath())
3546
3547 results = []
3548 if errors:
Bruce Dawson3bcf0c92022-08-12 00:03:083549 # Give warnings instead of errors on presubmit --all and presubmit
3550 # --files.
3551 message_type = (output_api.PresubmitNotifyResult if input_api.no_diffs
3552 else output_api.PresubmitError)
Evan Stade7cd4a2c2022-08-04 23:37:253553 results.append(
Bruce Dawson3bcf0c92022-08-12 00:03:083554 message_type(
Evan Stade7cd4a2c2022-08-04 23:37:253555 'Trademarked images should not be added to the public repo. '
3556 'See crbug.com/944754', errors))
3557 return results
3558
[email protected]d2530012013-01-25 16:39:273559
Daniel Cheng4dcdb6b2017-04-13 08:30:173560def _ExtractAddRulesFromParsedDeps(parsed_deps):
Sam Maiera6e76d72022-02-11 21:43:503561 """Extract the rules that add dependencies from a parsed DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:173562
Sam Maiera6e76d72022-02-11 21:43:503563 Args:
3564 parsed_deps: the locals dictionary from evaluating the DEPS file."""
3565 add_rules = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:173566 add_rules.update([
Sam Maiera6e76d72022-02-11 21:43:503567 rule[1:] for rule in parsed_deps.get('include_rules', [])
Daniel Cheng4dcdb6b2017-04-13 08:30:173568 if rule.startswith('+') or rule.startswith('!')
3569 ])
Sam Maiera6e76d72022-02-11 21:43:503570 for _, rules in parsed_deps.get('specific_include_rules', {}).items():
3571 add_rules.update([
3572 rule[1:] for rule in rules
3573 if rule.startswith('+') or rule.startswith('!')
3574 ])
3575 return add_rules
Daniel Cheng4dcdb6b2017-04-13 08:30:173576
3577
3578def _ParseDeps(contents):
Sam Maiera6e76d72022-02-11 21:43:503579 """Simple helper for parsing DEPS files."""
Daniel Cheng4dcdb6b2017-04-13 08:30:173580
Sam Maiera6e76d72022-02-11 21:43:503581 # Stubs for handling special syntax in the root DEPS file.
3582 class _VarImpl:
3583 def __init__(self, local_scope):
3584 self._local_scope = local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:173585
Sam Maiera6e76d72022-02-11 21:43:503586 def Lookup(self, var_name):
3587 """Implements the Var syntax."""
3588 try:
3589 return self._local_scope['vars'][var_name]
3590 except KeyError:
3591 raise Exception('Var is not defined: %s' % var_name)
Daniel Cheng4dcdb6b2017-04-13 08:30:173592
Sam Maiera6e76d72022-02-11 21:43:503593 local_scope = {}
3594 global_scope = {
3595 'Var': _VarImpl(local_scope).Lookup,
3596 'Str': str,
3597 }
Dirk Pranke1b9e06382021-05-14 01:16:223598
Sam Maiera6e76d72022-02-11 21:43:503599 exec(contents, global_scope, local_scope)
3600 return local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:173601
3602
Andrew Grieveb77ac762024-11-29 15:01:483603def _FindAllDepsFilesForSubpath(input_api, subpath):
3604 ret = []
3605 while subpath:
3606 cur = input_api.os_path.join(input_api.change.RepositoryRoot(), subpath, 'DEPS')
Joanna Wang130e7bdd2024-12-10 17:39:033607 if input_api.os_path.isfile(cur):
Andrew Grieveb77ac762024-11-29 15:01:483608 ret.append(cur)
3609 subpath = input_api.os_path.dirname(subpath)
3610 return ret
3611
3612
3613def _FindAddedDepsThatRequireReview(input_api, depended_on_paths):
3614 """Filters to those whose DEPS set new_usages_require_review=True"""
3615 ret = set()
3616 cache = {}
3617 for target_path in depended_on_paths:
3618 for subpath in _FindAllDepsFilesForSubpath(input_api, target_path):
3619 config = cache.get(subpath)
3620 if config is None:
3621 config = _ParseDeps(input_api.ReadFile(subpath))
3622 cache[subpath] = config
3623 if config.get('new_usages_require_review'):
3624 ret.add(target_path)
3625 break
3626 return ret
3627
3628
Daniel Cheng4dcdb6b2017-04-13 08:30:173629def _CalculateAddedDeps(os_path, old_contents, new_contents):
Sam Maiera6e76d72022-02-11 21:43:503630 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
3631 a set of DEPS entries that we should look up.
[email protected]14a6131c2014-01-08 01:15:413632
Sam Maiera6e76d72022-02-11 21:43:503633 For a directory (rather than a specific filename) we fake a path to
3634 a specific filename by adding /DEPS. This is chosen as a file that
3635 will seldom or never be subject to per-file include_rules.
3636 """
3637 # We ignore deps entries on auto-generated directories.
3638 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:083639
Sam Maiera6e76d72022-02-11 21:43:503640 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
3641 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
Daniel Cheng4dcdb6b2017-04-13 08:30:173642
Sam Maiera6e76d72022-02-11 21:43:503643 added_deps = new_deps.difference(old_deps)
Daniel Cheng4dcdb6b2017-04-13 08:30:173644
Sam Maiera6e76d72022-02-11 21:43:503645 results = set()
3646 for added_dep in added_deps:
3647 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
3648 continue
3649 # Assume that a rule that ends in .h is a rule for a specific file.
3650 if added_dep.endswith('.h'):
3651 results.add(added_dep)
3652 else:
3653 results.add(os_path.join(added_dep, 'DEPS'))
3654 return results
[email protected]f32e2d1e2013-07-26 21:39:083655
Stephanie Kimec4f55a2024-04-24 16:54:023656def CheckForNewDEPSDownloadFromGoogleStorageHooks(input_api, output_api):
3657 """Checks that there are no new download_from_google_storage hooks"""
3658 for f in input_api.AffectedFiles(include_deletes=False):
3659 if f.LocalPath() == 'DEPS':
3660 old_hooks = _ParseDeps('\n'.join(f.OldContents()))['hooks']
3661 new_hooks = _ParseDeps('\n'.join(f.NewContents()))['hooks']
3662 old_name_to_hook = {hook['name']: hook for hook in old_hooks}
3663 new_name_to_hook = {hook['name']: hook for hook in new_hooks}
3664 added_hook_names = set(new_name_to_hook.keys()) - set(
3665 old_name_to_hook.keys())
3666 if not added_hook_names:
3667 return []
3668 new_download_from_google_storage_hooks = []
3669 for new_hook in added_hook_names:
3670 hook = new_name_to_hook[new_hook]
3671 action_cmd = hook['action']
3672 if any('download_from_google_storage' in arg
3673 for arg in action_cmd):
3674 new_download_from_google_storage_hooks.append(new_hook)
3675 if new_download_from_google_storage_hooks:
3676 return [
3677 output_api.PresubmitError(
3678 'Please do not add new download_from_google_storage '
3679 'hooks. Instead, add a `gcs` dep_type entry to `deps`. '
3680 'See https://chromium.googlesource.com/chromium/src.git'
3681 '/+/refs/heads/main/docs/gcs_dependencies.md for more '
3682 'info. Added hooks:',
3683 items=new_download_from_google_storage_hooks)
3684 ]
3685 return []
3686
[email protected]f32e2d1e2013-07-26 21:39:083687
Rasika Navarangec2d33d22024-05-23 15:19:023688def CheckEachPerfettoTestDataFileHasDepsEntry(input_api, output_api):
3689 test_data_filter = lambda f: input_api.FilterSourceFile(
Rasika Navarange08e542162024-05-31 13:31:263690 f, files_to_check=[r'^base/tracing/test/data_sha256/.*\.sha256'])
Rasika Navarangec2d33d22024-05-23 15:19:023691 if not any(input_api.AffectedFiles(file_filter=test_data_filter)):
3692 return []
3693
3694 # Find DEPS entry
3695 deps_entry = []
Rasika Navarange277cd662024-06-04 10:14:593696 old_deps_entry = []
Rasika Navarangec2d33d22024-05-23 15:19:023697 for f in input_api.AffectedFiles(include_deletes=False):
3698 if f.LocalPath() == 'DEPS':
3699 new_deps = _ParseDeps('\n'.join(f.NewContents()))['deps']
3700 deps_entry = new_deps['src/base/tracing/test/data']
Rasika Navarange277cd662024-06-04 10:14:593701 old_deps = _ParseDeps('\n'.join(f.OldContents()))['deps']
3702 old_deps_entry = old_deps['src/base/tracing/test/data']
Rasika Navarangec2d33d22024-05-23 15:19:023703 if not deps_entry:
Rasika Navarange08e542162024-05-31 13:31:263704 # TODO(312895063):Add back error when .sha256 files have been moved.
Rasika Navaranged977df342024-06-05 10:01:273705 return [output_api.PresubmitError(
Rasika Navarangec2d33d22024-05-23 15:19:023706 'You must update the DEPS file when you update a '
Rasika Navarange08e542162024-05-31 13:31:263707 '.sha256 file in base/tracing/test/data_sha256'
Rasika Navarangec2d33d22024-05-23 15:19:023708 )]
3709
3710 output = []
3711 for f in input_api.AffectedFiles(file_filter=test_data_filter):
3712 objects = deps_entry['objects']
3713 if not f.NewContents():
3714 # Deleted file so check that DEPS entry removed
3715 sha256_from_file = f.OldContents()[0]
3716 object_entry = next(
3717 (item for item in objects if item["sha256sum"] == sha256_from_file),
3718 None)
Rasika Navarange277cd662024-06-04 10:14:593719 old_entry = next(
3720 (item for item in old_deps_entry['objects'] if item["sha256sum"] == sha256_from_file),
3721 None)
Rasika Navarangec2d33d22024-05-23 15:19:023722 if object_entry:
Rasika Navarange277cd662024-06-04 10:14:593723 # Allow renaming of objects with the same hash
3724 if object_entry['object_name'] != old_entry['object_name']:
3725 continue
Rasika Navarangec2d33d22024-05-23 15:19:023726 output.append(output_api.PresubmitError(
3727 'You deleted %s so you must also remove the corresponding DEPS entry.'
3728 % f.LocalPath()
3729 ))
3730 continue
3731
3732 sha256_from_file = f.NewContents()[0]
3733 object_entry = next(
3734 (item for item in objects if item["sha256sum"] == sha256_from_file),
3735 None)
3736 if not object_entry:
3737 output.append(output_api.PresubmitError(
3738 'No corresponding DEPS entry found for %s. '
3739 'Run `base/tracing/test/test_data.py get_deps --filepath %s` '
3740 'to generate the DEPS entry.'
3741 % (f.LocalPath(), f.LocalPath())
3742 ))
3743
3744 if output:
3745 output.append(output_api.PresubmitError(
3746 'The DEPS entry for `src/base/tracing/test/data` in the DEPS file has not been '
3747 'updated properly. Run `base/tracing/test/test_data.py get_all_deps` to see what '
3748 'the DEPS entry should look like.'
3749 ))
3750 return output
3751
3752
Saagar Sanghavifceeaae2020-08-12 16:40:363753def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503754 """When a dependency prefixed with + is added to a DEPS file, we
3755 want to make sure that the change is reviewed by an OWNER of the
3756 target file or directory, to avoid layering violations from being
3757 introduced. This check verifies that this happens.
3758 """
3759 # We rely on Gerrit's code-owners to check approvals.
3760 # input_api.gerrit is always set for Chromium, but other projects
3761 # might not use Gerrit.
Bruce Dawson344ab262022-06-04 11:35:103762 if not input_api.gerrit or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:503763 return []
Bruce Dawsonb357aeb2022-08-09 15:38:303764 if 'PRESUBMIT_SKIP_NETWORK' in input_api.environ:
Sam Maiera6e76d72022-02-11 21:43:503765 return []
Bruce Dawsonb357aeb2022-08-09 15:38:303766 try:
3767 if (input_api.change.issue and
3768 input_api.gerrit.IsOwnersOverrideApproved(
3769 input_api.change.issue)):
3770 # Skip OWNERS check when Owners-Override label is approved. This is
3771 # intended for global owners, trusted bots, and on-call sheriffs.
3772 # Review is still required for these changes.
3773 return []
3774 except Exception as e:
Sam Maier4cef9242022-10-03 14:21:243775 return [output_api.PresubmitPromptWarning(
3776 'Failed to retrieve owner override status - %s' % str(e))]
Edward Lesmes6fba51082021-01-20 04:20:233777
Andrew Grieveb77ac762024-11-29 15:01:483778 # A set of paths (that might not exist) that are being added as DEPS
3779 # (via lines like "+foo/bar/baz").
3780 depended_on_paths = set()
jochen53efcdd2016-01-29 05:09:243781
Sam Maiera6e76d72022-02-11 21:43:503782 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:313783 r"^third_party/blink/.*",
Anton Bershanskyi4253349482025-02-11 21:01:273784 f.UnixLocalPath())
Sam Maiera6e76d72022-02-11 21:43:503785 for f in input_api.AffectedFiles(include_deletes=False,
3786 file_filter=file_filter):
3787 filename = input_api.os_path.basename(f.LocalPath())
3788 if filename == 'DEPS':
Andrew Grieveb77ac762024-11-29 15:01:483789 depended_on_paths.update(
Sam Maiera6e76d72022-02-11 21:43:503790 _CalculateAddedDeps(input_api.os_path,
3791 '\n'.join(f.OldContents()),
3792 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:553793
Andrew Grieveb77ac762024-11-29 15:01:483794 # Requiring reviews is opt-in as of https://crbug.com/365797506
3795 depended_on_paths = _FindAddedDepsThatRequireReview(input_api, depended_on_paths)
3796 if not depended_on_paths:
Sam Maiera6e76d72022-02-11 21:43:503797 return []
[email protected]e871964c2013-05-13 14:14:553798
Sam Maiera6e76d72022-02-11 21:43:503799 if input_api.is_committing:
3800 if input_api.tbr:
3801 return [
3802 output_api.PresubmitNotifyResult(
3803 '--tbr was specified, skipping OWNERS check for DEPS additions'
3804 )
3805 ]
Daniel Cheng3008dc12022-05-13 04:02:113806 # TODO(dcheng): Make this generate an error on dry runs if the reviewer
3807 # is not added, to prevent review serialization.
Sam Maiera6e76d72022-02-11 21:43:503808 if input_api.dry_run:
3809 return [
3810 output_api.PresubmitNotifyResult(
3811 'This is a dry run, skipping OWNERS check for DEPS additions'
3812 )
3813 ]
3814 if not input_api.change.issue:
3815 return [
3816 output_api.PresubmitError(
3817 "DEPS approval by OWNERS check failed: this change has "
3818 "no change number, so we can't check it for approvals.")
3819 ]
3820 output = output_api.PresubmitError
[email protected]14a6131c2014-01-08 01:15:413821 else:
Sam Maiera6e76d72022-02-11 21:43:503822 output = output_api.PresubmitNotifyResult
[email protected]e871964c2013-05-13 14:14:553823
Sam Maiera6e76d72022-02-11 21:43:503824 owner_email, reviewers = (
3825 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3826 input_api, None, approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:553827
Sam Maiera6e76d72022-02-11 21:43:503828 owner_email = owner_email or input_api.change.author_email
3829
3830 approval_status = input_api.owners_client.GetFilesApprovalStatus(
Andrew Grieveb77ac762024-11-29 15:01:483831 depended_on_paths, reviewers.union([owner_email]), [])
Sam Maiera6e76d72022-02-11 21:43:503832 missing_files = [
Andrew Grieveb77ac762024-11-29 15:01:483833 p for p in depended_on_paths
3834 if approval_status[p] != input_api.owners_client.APPROVED
Sam Maiera6e76d72022-02-11 21:43:503835 ]
3836
3837 # We strip the /DEPS part that was added by
3838 # _FilesToCheckForIncomingDeps to fake a path to a file in a
3839 # directory.
3840 def StripDeps(path):
3841 start_deps = path.rfind('/DEPS')
3842 if start_deps != -1:
3843 return path[:start_deps]
3844 else:
3845 return path
3846
Scott Leebf6a0942024-06-26 22:59:393847 submodule_paths = set(input_api.ListSubmodules())
3848 def is_from_submodules(path, submodule_paths):
3849 path = input_api.os_path.normpath(path)
3850 while path:
3851 if path in submodule_paths:
3852 return True
3853
3854 # All deps should be a relative path from the checkout.
3855 # i.e., shouldn't start with "/" or "c:\", for example.
3856 #
3857 # That said, this is to prevent an infinite loop, just in case
3858 # an input dep path starts with "/", because
3859 # os.path.dirname("/") => "/"
3860 parent = input_api.os_path.dirname(path)
3861 if parent == path:
3862 break
3863 path = parent
3864
3865 return False
3866
Sam Maiera6e76d72022-02-11 21:43:503867 unapproved_dependencies = [
3868 "'+%s'," % StripDeps(path) for path in missing_files
Scott Leebf6a0942024-06-26 22:59:393869 # if a newly added dep is from a submodule, it becomes trickier
3870 # to get suggested owners, especially it is from a different host.
3871 #
3872 # skip the review enforcement for cross-repo deps.
3873 if not is_from_submodules(path, submodule_paths)
Sam Maiera6e76d72022-02-11 21:43:503874 ]
3875
3876 if unapproved_dependencies:
3877 output_list = [
3878 output(
3879 'You need LGTM from owners of depends-on paths in DEPS that were '
3880 'modified in this CL:\n %s' %
3881 '\n '.join(sorted(unapproved_dependencies)))
3882 ]
3883 suggested_owners = input_api.owners_client.SuggestOwners(
3884 missing_files, exclude=[owner_email])
3885 output_list.append(
3886 output('Suggested missing target path OWNERS:\n %s' %
3887 '\n '.join(suggested_owners or [])))
3888 return output_list
3889
3890 return []
[email protected]e871964c2013-05-13 14:14:553891
3892
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493893# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:363894def CheckSpamLogging(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503895 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3896 files_to_skip = (
3897 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3898 input_api.DEFAULT_FILES_TO_SKIP + (
Jaewon Jung2f323bb2022-12-07 23:55:013899 r"^base/fuchsia/scoped_fx_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313900 r"^base/logging\.h$",
3901 r"^base/logging\.cc$",
3902 r"^base/task/thread_pool/task_tracker\.cc$",
3903 r"^chrome/app/chrome_main_delegate\.cc$",
Yao Li359937b2023-02-15 23:43:033904 r"^chrome/browser/ash/arc/enterprise/cert_store/arc_cert_installer\.cc$",
3905 r"^chrome/browser/ash/policy/remote_commands/user_command_arc_job\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313906 r"^chrome/browser/chrome_browser_main\.cc$",
3907 r"^chrome/browser/ui/startup/startup_browser_creator\.cc$",
3908 r"^chrome/browser/browser_switcher/bho/.*",
3909 r"^chrome/browser/diagnostics/diagnostics_writer\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313910 r"^chrome/chrome_elf/dll_hash/dll_hash_main\.cc$",
3911 r"^chrome/installer/setup/.*",
Daniel Ruberyad36eea2024-08-01 01:38:323912 # crdmg runs as a separate binary which intentionally does
3913 # not depend on base logging.
3914 r"^chrome/utility/safe_browsing/mac/crdmg\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313915 r"^chromecast/",
Vigen Issahhanjane2d93822023-06-30 15:57:203916 r"^components/cast",
Bruce Dawson40fece62022-09-16 19:58:313917 r"^components/media_control/renderer/media_playback_options\.cc$",
Salma Elmahallawy52976452023-01-27 17:04:493918 r"^components/policy/core/common/policy_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313919 r"^components/viz/service/display/"
Sam Maiera6e76d72022-02-11 21:43:503920 r"overlay_strategy_underlay_cast\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313921 r"^components/zucchini/.*",
Sam Maiera6e76d72022-02-11 21:43:503922 # TODO(peter): Remove exception. https://crbug.com/534537
Bruce Dawson40fece62022-09-16 19:58:313923 r"^content/browser/notifications/"
Sam Maiera6e76d72022-02-11 21:43:503924 r"notification_event_dispatcher_impl\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313925 r"^content/common/gpu/client/gl_helper_benchmark\.cc$",
3926 r"^courgette/courgette_minimal_tool\.cc$",
3927 r"^courgette/courgette_tool\.cc$",
3928 r"^extensions/renderer/logging_native_handler\.cc$",
3929 r"^fuchsia_web/common/init_logging\.cc$",
3930 r"^fuchsia_web/runners/common/web_component\.cc$",
Caroline Liua7050132023-02-13 22:23:153931 r"^fuchsia_web/shell/.*\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313932 r"^headless/app/headless_shell\.cc$",
3933 r"^ipc/ipc_logging\.cc$",
3934 r"^native_client_sdk/",
3935 r"^remoting/base/logging\.h$",
3936 r"^remoting/host/.*",
3937 r"^sandbox/linux/.*",
Austin Sullivana6054e02024-05-20 16:31:293938 r"^services/webnn/tflite/graph_impl_tflite\.cc$",
3939 r"^services/webnn/coreml/graph_impl_coreml\.mm$",
Bruce Dawson40fece62022-09-16 19:58:313940 r"^storage/browser/file_system/dump_file_system\.cc$",
Steinar H. Gundersone5689e42024-08-07 18:17:193941 r"^testing/perf/",
Bruce Dawson40fece62022-09-16 19:58:313942 r"^tools/",
3943 r"^ui/base/resource/data_pack\.cc$",
3944 r"^ui/aura/bench/bench_main\.cc$",
3945 r"^ui/ozone/platform/cast/",
3946 r"^ui/base/x/xwmstartupcheck/"
Sam Maiera6e76d72022-02-11 21:43:503947 r"xwmstartupcheck\.cc$"))
3948 source_file_filter = lambda x: input_api.FilterSourceFile(
3949 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:403950
Sam Maiera6e76d72022-02-11 21:43:503951 log_info = set([])
3952 printf = set([])
[email protected]85218562013-11-22 07:41:403953
Sam Maiera6e76d72022-02-11 21:43:503954 for f in input_api.AffectedSourceFiles(source_file_filter):
3955 for _, line in f.ChangedContents():
3956 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
3957 log_info.add(f.LocalPath())
3958 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
3959 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:373960
Sam Maiera6e76d72022-02-11 21:43:503961 if input_api.re.search(r"\bprintf\(", line):
3962 printf.add(f.LocalPath())
3963 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
3964 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:403965
Sam Maiera6e76d72022-02-11 21:43:503966 if log_info:
3967 return [
3968 output_api.PresubmitError(
3969 'These files spam the console log with LOG(INFO):',
3970 items=log_info)
3971 ]
3972 if printf:
3973 return [
3974 output_api.PresubmitError(
3975 'These files spam the console log with printf/fprintf:',
3976 items=printf)
3977 ]
3978 return []
[email protected]85218562013-11-22 07:41:403979
3980
Saagar Sanghavifceeaae2020-08-12 16:40:363981def CheckForAnonymousVariables(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503982 """These types are all expected to hold locks while in scope and
3983 so should never be anonymous (which causes them to be immediately
3984 destroyed)."""
3985 they_who_must_be_named = [
3986 'base::AutoLock',
3987 'base::AutoReset',
3988 'base::AutoUnlock',
3989 'SkAutoAlphaRestore',
3990 'SkAutoBitmapShaderInstall',
3991 'SkAutoBlitterChoose',
3992 'SkAutoBounderCommit',
3993 'SkAutoCallProc',
3994 'SkAutoCanvasRestore',
3995 'SkAutoCommentBlock',
3996 'SkAutoDescriptor',
3997 'SkAutoDisableDirectionCheck',
3998 'SkAutoDisableOvalCheck',
3999 'SkAutoFree',
4000 'SkAutoGlyphCache',
4001 'SkAutoHDC',
4002 'SkAutoLockColors',
4003 'SkAutoLockPixels',
4004 'SkAutoMalloc',
4005 'SkAutoMaskFreeImage',
4006 'SkAutoMutexAcquire',
4007 'SkAutoPathBoundsUpdate',
4008 'SkAutoPDFRelease',
4009 'SkAutoRasterClipValidate',
4010 'SkAutoRef',
4011 'SkAutoTime',
4012 'SkAutoTrace',
4013 'SkAutoUnref',
4014 ]
4015 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
4016 # bad: base::AutoLock(lock.get());
4017 # not bad: base::AutoLock lock(lock.get());
4018 bad_pattern = input_api.re.compile(anonymous)
4019 # good: new base::AutoLock(lock.get())
4020 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
4021 errors = []
[email protected]49aa76a2013-12-04 06:59:164022
Sam Maiera6e76d72022-02-11 21:43:504023 for f in input_api.AffectedFiles():
4024 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
4025 continue
4026 for linenum, line in f.ChangedContents():
4027 if bad_pattern.search(line) and not good_pattern.search(line):
4028 errors.append('%s:%d' % (f.LocalPath(), linenum))
[email protected]49aa76a2013-12-04 06:59:164029
Sam Maiera6e76d72022-02-11 21:43:504030 if errors:
4031 return [
4032 output_api.PresubmitError(
4033 'These lines create anonymous variables that need to be named:',
4034 items=errors)
4035 ]
4036 return []
[email protected]49aa76a2013-12-04 06:59:164037
4038
Saagar Sanghavifceeaae2020-08-12 16:40:364039def CheckUniquePtrOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504040 # Returns whether |template_str| is of the form <T, U...> for some types T
Glen Robertson9142ffd72024-05-16 01:37:474041 # and U, or is invalid due to mismatched angle bracket pairs. Assumes that
4042 # |template_str| is already in the form <...>.
4043 def HasMoreThanOneArgOrInvalid(template_str):
Sam Maiera6e76d72022-02-11 21:43:504044 # Level of <...> nesting.
4045 nesting = 0
4046 for c in template_str:
4047 if c == '<':
4048 nesting += 1
4049 elif c == '>':
4050 nesting -= 1
4051 elif c == ',' and nesting == 1:
4052 return True
Glen Robertson9142ffd72024-05-16 01:37:474053 if nesting != 0:
Daniel Cheng566634ff2024-06-29 14:56:534054 # Invalid.
4055 return True
Sam Maiera6e76d72022-02-11 21:43:504056 return False
Vaclav Brozekb7fadb692018-08-30 06:39:534057
Sam Maiera6e76d72022-02-11 21:43:504058 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
4059 sources = lambda affected_file: input_api.FilterSourceFile(
4060 affected_file,
4061 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4062 DEFAULT_FILES_TO_SKIP),
4063 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:554064
Sam Maiera6e76d72022-02-11 21:43:504065 # Pattern to capture a single "<...>" block of template arguments. It can
4066 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
4067 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
4068 # latter would likely require counting that < and > match, which is not
4069 # expressible in regular languages. Should the need arise, one can introduce
4070 # limited counting (matching up to a total number of nesting depth), which
4071 # should cover all practical cases for already a low nesting limit.
4072 template_arg_pattern = (
4073 r'<[^>]*' # Opening block of <.
4074 r'>([^<]*>)?') # Closing block of >.
4075 # Prefix expressing that whatever follows is not already inside a <...>
4076 # block.
4077 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
4078 null_construct_pattern = input_api.re.compile(
4079 not_inside_template_arg_pattern + r'\bstd::unique_ptr' +
4080 template_arg_pattern + r'\(\)')
Vaclav Brozeka54c528b2018-04-06 19:23:554081
Sam Maiera6e76d72022-02-11 21:43:504082 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
4083 template_arg_no_array_pattern = (
4084 r'<[^>]*[^]]' # Opening block of <.
4085 r'>([^(<]*[^]]>)?') # Closing block of >.
4086 # Prefix saying that what follows is the start of an expression.
4087 start_of_expr_pattern = r'(=|\breturn|^)\s*'
4088 # Suffix saying that what follows are call parentheses with a non-empty list
4089 # of arguments.
4090 nonempty_arg_list_pattern = r'\(([^)]|$)'
4091 # Put the template argument into a capture group for deeper examination later.
4092 return_construct_pattern = input_api.re.compile(
4093 start_of_expr_pattern + r'std::unique_ptr' + '(?P<template_arg>' +
4094 template_arg_no_array_pattern + ')' + nonempty_arg_list_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:554095
Sam Maiera6e76d72022-02-11 21:43:504096 problems_constructor = []
4097 problems_nullptr = []
4098 for f in input_api.AffectedSourceFiles(sources):
4099 for line_number, line in f.ChangedContents():
4100 # Disallow:
4101 # return std::unique_ptr<T>(foo);
4102 # bar = std::unique_ptr<T>(foo);
4103 # But allow:
4104 # return std::unique_ptr<T[]>(foo);
4105 # bar = std::unique_ptr<T[]>(foo);
4106 # And also allow cases when the second template argument is present. Those
4107 # cases cannot be handled by std::make_unique:
4108 # return std::unique_ptr<T, U>(foo);
4109 # bar = std::unique_ptr<T, U>(foo);
4110 local_path = f.LocalPath()
4111 return_construct_result = return_construct_pattern.search(line)
Glen Robertson9142ffd72024-05-16 01:37:474112 if return_construct_result and not HasMoreThanOneArgOrInvalid(
Sam Maiera6e76d72022-02-11 21:43:504113 return_construct_result.group('template_arg')):
4114 problems_constructor.append(
4115 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4116 # Disallow:
4117 # std::unique_ptr<T>()
4118 if null_construct_pattern.search(line):
4119 problems_nullptr.append(
4120 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Vaclav Brozek851d9602018-04-04 16:13:054121
Sam Maiera6e76d72022-02-11 21:43:504122 errors = []
4123 if problems_nullptr:
4124 errors.append(
4125 output_api.PresubmitPromptWarning(
4126 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
4127 problems_nullptr))
4128 if problems_constructor:
4129 errors.append(
4130 output_api.PresubmitError(
4131 'The following files use explicit std::unique_ptr constructor. '
4132 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
4133 'std::make_unique is not an option.', problems_constructor))
4134 return errors
Peter Kasting4844e46e2018-02-23 07:27:104135
4136
Saagar Sanghavifceeaae2020-08-12 16:40:364137def CheckUserActionUpdate(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504138 """Checks if any new user action has been added."""
4139 if any('actions.xml' == input_api.os_path.basename(f)
4140 for f in input_api.LocalPaths()):
4141 # If actions.xml is already included in the changelist, the PRESUBMIT
4142 # for actions.xml will do a more complete presubmit check.
4143 return []
4144
4145 file_inclusion_pattern = [r'.*\.(cc|mm)$']
4146 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
4147 input_api.DEFAULT_FILES_TO_SKIP)
4148 file_filter = lambda f: input_api.FilterSourceFile(
4149 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
4150
4151 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
4152 current_actions = None
4153 for f in input_api.AffectedFiles(file_filter=file_filter):
4154 for line_num, line in f.ChangedContents():
4155 match = input_api.re.search(action_re, line)
4156 if match:
4157 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
4158 # loaded only once.
4159 if not current_actions:
Bruce Dawson6cb2d4d2023-03-01 21:35:094160 with open('tools/metrics/actions/actions.xml',
4161 encoding='utf-8') as actions_f:
Sam Maiera6e76d72022-02-11 21:43:504162 current_actions = actions_f.read()
4163 # Search for the matched user action name in |current_actions|.
4164 for action_name in match.groups():
4165 action = 'name="{0}"'.format(action_name)
4166 if action not in current_actions:
4167 return [
4168 output_api.PresubmitPromptWarning(
4169 'File %s line %d: %s is missing in '
4170 'tools/metrics/actions/actions.xml. Please run '
4171 'tools/metrics/actions/extract_actions.py to update.'
4172 % (f.LocalPath(), line_num, action_name))
4173 ]
[email protected]999261d2014-03-03 20:08:084174 return []
4175
[email protected]999261d2014-03-03 20:08:084176
Daniel Cheng13ca61a882017-08-25 15:11:254177def _ImportJSONCommentEater(input_api):
Sam Maiera6e76d72022-02-11 21:43:504178 import sys
4179 sys.path = sys.path + [
4180 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4181 'json_comment_eater')
4182 ]
4183 import json_comment_eater
4184 return json_comment_eater
Daniel Cheng13ca61a882017-08-25 15:11:254185
4186
[email protected]99171a92014-06-03 08:44:474187def _GetJSONParseError(input_api, filename, eat_comments=True):
dchenge07de812016-06-20 19:27:174188 try:
Sam Maiera6e76d72022-02-11 21:43:504189 contents = input_api.ReadFile(filename)
4190 if eat_comments:
4191 json_comment_eater = _ImportJSONCommentEater(input_api)
4192 contents = json_comment_eater.Nom(contents)
dchenge07de812016-06-20 19:27:174193
Sam Maiera6e76d72022-02-11 21:43:504194 input_api.json.loads(contents)
4195 except ValueError as e:
4196 return e
Andrew Grieve4deedb12022-02-03 21:34:504197 return None
4198
4199
Sam Maiera6e76d72022-02-11 21:43:504200def _GetIDLParseError(input_api, filename):
4201 try:
4202 contents = input_api.ReadFile(filename)
Devlin Croninf7582a12022-04-21 21:14:284203 for i, char in enumerate(contents):
Daniel Chenga37c03db2022-05-12 17:20:344204 if not char.isascii():
4205 return (
4206 'Non-ascii character "%s" (ord %d) found at offset %d.' %
4207 (char, ord(char), i))
Sam Maiera6e76d72022-02-11 21:43:504208 idl_schema = input_api.os_path.join(input_api.PresubmitLocalPath(),
4209 'tools', 'json_schema_compiler',
4210 'idl_schema.py')
4211 process = input_api.subprocess.Popen(
Bruce Dawson679fb082022-04-14 00:47:284212 [input_api.python3_executable, idl_schema],
Sam Maiera6e76d72022-02-11 21:43:504213 stdin=input_api.subprocess.PIPE,
4214 stdout=input_api.subprocess.PIPE,
4215 stderr=input_api.subprocess.PIPE,
4216 universal_newlines=True)
4217 (_, error) = process.communicate(input=contents)
4218 return error or None
4219 except ValueError as e:
4220 return e
agrievef32bcc72016-04-04 14:57:404221
agrievef32bcc72016-04-04 14:57:404222
Sam Maiera6e76d72022-02-11 21:43:504223def CheckParseErrors(input_api, output_api):
4224 """Check that IDL and JSON files do not contain syntax errors."""
4225 actions = {
4226 '.idl': _GetIDLParseError,
4227 '.json': _GetJSONParseError,
4228 }
4229 # Most JSON files are preprocessed and support comments, but these do not.
4230 json_no_comments_patterns = [
Bruce Dawson40fece62022-09-16 19:58:314231 r'^testing/',
Sam Maiera6e76d72022-02-11 21:43:504232 ]
4233 # Only run IDL checker on files in these directories.
4234 idl_included_patterns = [
Bruce Dawson40fece62022-09-16 19:58:314235 r'^chrome/common/extensions/api/',
4236 r'^extensions/common/api/',
Sam Maiera6e76d72022-02-11 21:43:504237 ]
agrievef32bcc72016-04-04 14:57:404238
Sam Maiera6e76d72022-02-11 21:43:504239 def get_action(affected_file):
4240 filename = affected_file.LocalPath()
4241 return actions.get(input_api.os_path.splitext(filename)[1])
agrievef32bcc72016-04-04 14:57:404242
Sam Maiera6e76d72022-02-11 21:43:504243 def FilterFile(affected_file):
4244 action = get_action(affected_file)
4245 if not action:
4246 return False
Anton Bershanskyi4253349482025-02-11 21:01:274247 path = affected_file.UnixLocalPath()
agrievef32bcc72016-04-04 14:57:404248
Sam Maiera6e76d72022-02-11 21:43:504249 if _MatchesFile(input_api,
4250 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS, path):
4251 return False
4252
4253 if (action == _GetIDLParseError
4254 and not _MatchesFile(input_api, idl_included_patterns, path)):
4255 return False
4256 return True
4257
4258 results = []
4259 for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
4260 include_deletes=False):
4261 action = get_action(affected_file)
4262 kwargs = {}
4263 if (action == _GetJSONParseError
4264 and _MatchesFile(input_api, json_no_comments_patterns,
Anton Bershanskyi4253349482025-02-11 21:01:274265 affected_file.UnixLocalPath())):
Sam Maiera6e76d72022-02-11 21:43:504266 kwargs['eat_comments'] = False
4267 parse_error = action(input_api, affected_file.AbsoluteLocalPath(),
4268 **kwargs)
4269 if parse_error:
4270 results.append(
4271 output_api.PresubmitError(
4272 '%s could not be parsed: %s' %
4273 (affected_file.LocalPath(), parse_error)))
4274 return results
4275
4276
4277def CheckJavaStyle(input_api, output_api):
4278 """Runs checkstyle on changed java files and returns errors if any exist."""
4279
4280 # Return early if no java files were modified.
4281 if not any(
4282 _IsJavaFile(input_api, f.LocalPath())
4283 for f in input_api.AffectedFiles()):
4284 return []
4285
4286 import sys
4287 original_sys_path = sys.path
4288 try:
4289 sys.path = sys.path + [
4290 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4291 'android', 'checkstyle')
4292 ]
4293 import checkstyle
4294 finally:
4295 # Restore sys.path to what it was before.
4296 sys.path = original_sys_path
4297
Andrew Grieve4f88e3ca2022-11-22 19:09:204298 return checkstyle.run_presubmit(
Sam Maiera6e76d72022-02-11 21:43:504299 input_api,
4300 output_api,
Sam Maiera6e76d72022-02-11 21:43:504301 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
4302
4303
4304def CheckPythonDevilInit(input_api, output_api):
4305 """Checks to make sure devil is initialized correctly in python scripts."""
4306 script_common_initialize_pattern = input_api.re.compile(
4307 r'script_common\.InitializeEnvironment\(')
4308 devil_env_config_initialize = input_api.re.compile(
4309 r'devil_env\.config\.Initialize\(')
4310
4311 errors = []
4312
4313 sources = lambda affected_file: input_api.FilterSourceFile(
4314 affected_file,
4315 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314316 r'^build/android/devil_chromium\.py',
Sven Zheng8e079562024-05-10 20:11:064317 r'^tools/bisect-builds\.py',
Bruce Dawson40fece62022-09-16 19:58:314318 r'^third_party/.*',
Sam Maiera6e76d72022-02-11 21:43:504319 )),
4320 files_to_check=[r'.*\.py$'])
4321
4322 for f in input_api.AffectedSourceFiles(sources):
4323 for line_num, line in f.ChangedContents():
4324 if (script_common_initialize_pattern.search(line)
4325 or devil_env_config_initialize.search(line)):
4326 errors.append("%s:%d" % (f.LocalPath(), line_num))
4327
4328 results = []
4329
4330 if errors:
4331 results.append(
4332 output_api.PresubmitError(
4333 'Devil initialization should always be done using '
4334 'devil_chromium.Initialize() in the chromium project, to use better '
4335 'defaults for dependencies (ex. up-to-date version of adb).',
4336 errors))
4337
4338 return results
4339
4340
4341def _MatchesFile(input_api, patterns, path):
4342 for pattern in patterns:
4343 if input_api.re.search(pattern, path):
4344 return True
4345 return False
4346
4347
Daniel Chenga37c03db2022-05-12 17:20:344348def _ChangeHasSecurityReviewer(input_api, owners_file):
4349 """Returns True iff the CL has a reviewer from SECURITY_OWNERS.
Sam Maiera6e76d72022-02-11 21:43:504350
Daniel Chenga37c03db2022-05-12 17:20:344351 Args:
4352 input_api: The presubmit input API.
4353 owners_file: OWNERS file with required reviewers. Typically, this is
4354 something like ipc/SECURITY_OWNERS.
4355
4356 Note: if the presubmit is running for commit rather than for upload, this
4357 only returns True if a security reviewer has also approved the CL.
Sam Maiera6e76d72022-02-11 21:43:504358 """
Daniel Chengd88244472022-05-16 09:08:474359 # Owners-Override should bypass all additional OWNERS enforcement checks.
4360 # A CR+1 vote will still be required to land this change.
4361 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
4362 input_api.change.issue)):
4363 return True
4364
Daniel Chenga37c03db2022-05-12 17:20:344365 owner_email, reviewers = (
4366 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
Daniel Cheng3008dc12022-05-13 04:02:114367 input_api,
4368 None,
4369 approval_needed=input_api.is_committing and not input_api.dry_run))
Sam Maiera6e76d72022-02-11 21:43:504370
Daniel Chenga37c03db2022-05-12 17:20:344371 security_owners = input_api.owners_client.ListOwners(owners_file)
4372 return any(owner in reviewers for owner in security_owners)
Sam Maiera6e76d72022-02-11 21:43:504373
Daniel Chenga37c03db2022-05-12 17:20:344374
4375@dataclass
Daniel Cheng171dad8d2022-05-21 00:40:254376class _SecurityProblemWithItems:
4377 problem: str
4378 items: Sequence[str]
4379
4380
4381@dataclass
Daniel Chenga37c03db2022-05-12 17:20:344382class _MissingSecurityOwnersResult:
Daniel Cheng171dad8d2022-05-21 00:40:254383 owners_file_problems: Sequence[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:344384 has_security_sensitive_files: bool
Daniel Cheng171dad8d2022-05-21 00:40:254385 missing_reviewer_problem: Optional[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:344386
4387
4388def _FindMissingSecurityOwners(input_api,
4389 output_api,
4390 file_patterns: Sequence[str],
4391 excluded_patterns: Sequence[str],
4392 required_owners_file: str,
4393 custom_rule_function: Optional[Callable] = None
4394 ) -> _MissingSecurityOwnersResult:
4395 """Find OWNERS files missing per-file rules for security-sensitive files.
4396
4397 Args:
4398 input_api: the PRESUBMIT input API object.
4399 output_api: the PRESUBMIT output API object.
4400 file_patterns: basename patterns that require a corresponding per-file
4401 security restriction.
4402 excluded_patterns: path patterns that should be exempted from
4403 requiring a security restriction.
4404 required_owners_file: path to the required OWNERS file, e.g.
4405 ipc/SECURITY_OWNERS
4406 cc_alias: If not None, email that will be CCed automatically if the
4407 change contains security-sensitive files, as determined by
4408 `file_patterns` and `excluded_patterns`.
4409 custom_rule_function: If not None, will be called with `input_api` and
4410 the current file under consideration. Returning True will add an
4411 exact match per-file rule check for the current file.
4412 """
4413
4414 # `to_check` is a mapping of an OWNERS file path to Patterns.
4415 #
4416 # Patterns is a dictionary mapping glob patterns (suitable for use in
4417 # per-file rules) to a PatternEntry.
4418 #
Sam Maiera6e76d72022-02-11 21:43:504419 # PatternEntry is a dictionary with two keys:
4420 # - 'files': the files that are matched by this pattern
4421 # - 'rules': the per-file rules needed for this pattern
Daniel Chenga37c03db2022-05-12 17:20:344422 #
Sam Maiera6e76d72022-02-11 21:43:504423 # For example, if we expect OWNERS file to contain rules for *.mojom and
4424 # *_struct_traits*.*, Patterns might look like this:
4425 # {
4426 # '*.mojom': {
4427 # 'files': ...,
4428 # 'rules': [
4429 # 'per-file *.mojom=set noparent',
4430 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
4431 # ],
4432 # },
4433 # '*_struct_traits*.*': {
4434 # 'files': ...,
4435 # 'rules': [
4436 # 'per-file *_struct_traits*.*=set noparent',
4437 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
4438 # ],
4439 # },
4440 # }
4441 to_check = {}
Daniel Chenga37c03db2022-05-12 17:20:344442 files_to_review = []
Sam Maiera6e76d72022-02-11 21:43:504443
Daniel Chenga37c03db2022-05-12 17:20:344444 def AddPatternToCheck(file, pattern):
Sam Maiera6e76d72022-02-11 21:43:504445 owners_file = input_api.os_path.join(
Daniel Chengd88244472022-05-16 09:08:474446 input_api.os_path.dirname(file.LocalPath()), 'OWNERS')
Sam Maiera6e76d72022-02-11 21:43:504447 if owners_file not in to_check:
4448 to_check[owners_file] = {}
4449 if pattern not in to_check[owners_file]:
4450 to_check[owners_file][pattern] = {
4451 'files': [],
4452 'rules': [
Daniel Chenga37c03db2022-05-12 17:20:344453 f'per-file {pattern}=set noparent',
4454 f'per-file {pattern}=file://{required_owners_file}',
Sam Maiera6e76d72022-02-11 21:43:504455 ]
4456 }
Daniel Chenged57a162022-05-25 02:56:344457 to_check[owners_file][pattern]['files'].append(file.LocalPath())
Daniel Chenga37c03db2022-05-12 17:20:344458 files_to_review.append(file.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:504459
Daniel Chenga37c03db2022-05-12 17:20:344460 # Only enforce security OWNERS rules for a directory if that directory has a
4461 # file that matches `file_patterns`. For example, if a directory only
4462 # contains *.mojom files and no *_messages*.h files, the check should only
4463 # ensure that rules for *.mojom files are present.
4464 for file in input_api.AffectedFiles(include_deletes=False):
4465 file_basename = input_api.os_path.basename(file.LocalPath())
4466 if custom_rule_function is not None and custom_rule_function(
4467 input_api, file):
4468 AddPatternToCheck(file, file_basename)
4469 continue
Sam Maiera6e76d72022-02-11 21:43:504470
Daniel Chenga37c03db2022-05-12 17:20:344471 if any(
4472 input_api.fnmatch.fnmatch(file.LocalPath(), pattern)
4473 for pattern in excluded_patterns):
Sam Maiera6e76d72022-02-11 21:43:504474 continue
4475
4476 for pattern in file_patterns:
Daniel Chenga37c03db2022-05-12 17:20:344477 # Unlike `excluded_patterns`, `file_patterns` is checked only against the
4478 # file's basename.
4479 if input_api.fnmatch.fnmatch(file_basename, pattern):
4480 AddPatternToCheck(file, pattern)
Sam Maiera6e76d72022-02-11 21:43:504481 break
4482
Daniel Chenga37c03db2022-05-12 17:20:344483 has_security_sensitive_files = bool(to_check)
Daniel Cheng171dad8d2022-05-21 00:40:254484
4485 # Check if any newly added lines in OWNERS files intersect with required
4486 # per-file OWNERS lines. If so, ensure that a security reviewer is included.
4487 # This is a hack, but is needed because the OWNERS check (by design) ignores
4488 # new OWNERS entries; otherwise, a non-owner could add someone as a new
4489 # OWNER and have that newly-added OWNER self-approve their own addition.
4490 newly_covered_files = []
4491 for file in input_api.AffectedFiles(include_deletes=False):
4492 if not file.LocalPath() in to_check:
4493 continue
4494 for _, line in file.ChangedContents():
4495 for _, entry in to_check[file.LocalPath()].items():
4496 if line in entry['rules']:
4497 newly_covered_files.extend(entry['files'])
4498
4499 missing_reviewer_problems = None
4500 if newly_covered_files and not _ChangeHasSecurityReviewer(
Daniel Chenga37c03db2022-05-12 17:20:344501 input_api, required_owners_file):
Daniel Cheng171dad8d2022-05-21 00:40:254502 missing_reviewer_problems = _SecurityProblemWithItems(
4503 f'Review from an owner in {required_owners_file} is required for '
4504 'the following newly-added files:',
4505 [f'{file}' for file in sorted(set(newly_covered_files))])
Sam Maiera6e76d72022-02-11 21:43:504506
4507 # Go through the OWNERS files to check, filtering out rules that are already
4508 # present in that OWNERS file.
4509 for owners_file, patterns in to_check.items():
4510 try:
Daniel Cheng171dad8d2022-05-21 00:40:254511 lines = set(
4512 input_api.ReadFile(
4513 input_api.os_path.join(input_api.change.RepositoryRoot(),
4514 owners_file)).splitlines())
4515 for entry in patterns.values():
4516 entry['rules'] = [
4517 rule for rule in entry['rules'] if rule not in lines
4518 ]
Sam Maiera6e76d72022-02-11 21:43:504519 except IOError:
4520 # No OWNERS file, so all the rules are definitely missing.
4521 continue
4522
4523 # All the remaining lines weren't found in OWNERS files, so emit an error.
Daniel Cheng171dad8d2022-05-21 00:40:254524 owners_file_problems = []
Daniel Chenga37c03db2022-05-12 17:20:344525
Sam Maiera6e76d72022-02-11 21:43:504526 for owners_file, patterns in to_check.items():
4527 missing_lines = []
4528 files = []
4529 for _, entry in patterns.items():
Daniel Chenged57a162022-05-25 02:56:344530 files.extend(entry['files'])
Sam Maiera6e76d72022-02-11 21:43:504531 missing_lines.extend(entry['rules'])
Sam Maiera6e76d72022-02-11 21:43:504532 if missing_lines:
Daniel Cheng171dad8d2022-05-21 00:40:254533 joined_missing_lines = '\n'.join(line for line in missing_lines)
4534 owners_file_problems.append(
4535 _SecurityProblemWithItems(
4536 'Found missing OWNERS lines for security-sensitive files. '
4537 f'Please add the following lines to {owners_file}:\n'
4538 f'{joined_missing_lines}\n\nTo ensure security review for:',
4539 files))
Daniel Chenga37c03db2022-05-12 17:20:344540
Daniel Cheng171dad8d2022-05-21 00:40:254541 return _MissingSecurityOwnersResult(owners_file_problems,
Daniel Chenga37c03db2022-05-12 17:20:344542 has_security_sensitive_files,
Daniel Cheng171dad8d2022-05-21 00:40:254543 missing_reviewer_problems)
Daniel Chenga37c03db2022-05-12 17:20:344544
4545
4546def _CheckChangeForIpcSecurityOwners(input_api, output_api):
4547 # Whether or not a file affects IPC is (mostly) determined by a simple list
4548 # of filename patterns.
4549 file_patterns = [
4550 # Legacy IPC:
4551 '*_messages.cc',
4552 '*_messages*.h',
4553 '*_param_traits*.*',
4554 # Mojo IPC:
4555 '*.mojom',
4556 '*_mojom_traits*.*',
4557 '*_type_converter*.*',
4558 # Android native IPC:
4559 '*.aidl',
4560 ]
4561
Daniel Chenga37c03db2022-05-12 17:20:344562 excluded_patterns = [
Daniel Cheng518943f2022-05-12 22:15:464563 # These third_party directories do not contain IPCs, but contain files
4564 # matching the above patterns, which trigger false positives.
Daniel Chenga37c03db2022-05-12 17:20:344565 'third_party/crashpad/*',
4566 'third_party/blink/renderer/platform/bindings/*',
Evan Stade23a77da2025-02-06 21:15:314567 'third_party/protobuf/*',
Daniel Chenga37c03db2022-05-12 17:20:344568 'third_party/win_build_output/*',
Daniel Chengd88244472022-05-16 09:08:474569 # Enum-only mojoms used for web metrics, so no security review needed.
4570 'third_party/blink/public/mojom/use_counter/metrics/*',
Daniel Chenga37c03db2022-05-12 17:20:344571 # These files are just used to communicate between class loaders running
4572 # in the same process.
4573 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
4574 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
4575 ]
4576
4577 def IsMojoServiceManifestFile(input_api, file):
Dirk Prankee4df27972025-02-26 18:39:354578 manifest_pattern = input_api.re.compile(r'manifests?\.(cc|h)$')
4579 test_manifest_pattern = input_api.re.compile(r'test_manifests?\.(cc|h)')
Daniel Chenga37c03db2022-05-12 17:20:344580 if not manifest_pattern.search(file.LocalPath()):
4581 return False
4582
4583 if test_manifest_pattern.search(file.LocalPath()):
4584 return False
4585
4586 # All actual service manifest files should contain at least one
4587 # qualified reference to service_manager::Manifest.
4588 return any('service_manager::Manifest' in line
4589 for line in file.NewContents())
4590
4591 return _FindMissingSecurityOwners(
4592 input_api,
4593 output_api,
4594 file_patterns,
4595 excluded_patterns,
4596 'ipc/SECURITY_OWNERS',
4597 custom_rule_function=IsMojoServiceManifestFile)
4598
4599
4600def _CheckChangeForFuchsiaSecurityOwners(input_api, output_api):
4601 file_patterns = [
4602 # Component specifications.
4603 '*.cml', # Component Framework v2.
4604 '*.cmx', # Component Framework v1.
4605
4606 # Fuchsia IDL protocol specifications.
4607 '*.fidl',
4608 ]
4609
4610 # Don't check for owners files for changes in these directories.
4611 excluded_patterns = [
4612 'third_party/crashpad/*',
4613 ]
4614
4615 return _FindMissingSecurityOwners(input_api, output_api, file_patterns,
4616 excluded_patterns,
4617 'build/fuchsia/SECURITY_OWNERS')
4618
4619
4620def CheckSecurityOwners(input_api, output_api):
4621 """Checks that various security-sensitive files have an IPC OWNERS rule."""
4622 ipc_results = _CheckChangeForIpcSecurityOwners(input_api, output_api)
4623 fuchsia_results = _CheckChangeForFuchsiaSecurityOwners(
4624 input_api, output_api)
4625
4626 if ipc_results.has_security_sensitive_files:
4627 output_api.AppendCC('[email protected]')
Sam Maiera6e76d72022-02-11 21:43:504628
4629 results = []
Daniel Chenga37c03db2022-05-12 17:20:344630
Daniel Cheng171dad8d2022-05-21 00:40:254631 missing_reviewer_problems = []
4632 if ipc_results.missing_reviewer_problem:
4633 missing_reviewer_problems.append(ipc_results.missing_reviewer_problem)
4634 if fuchsia_results.missing_reviewer_problem:
4635 missing_reviewer_problems.append(
4636 fuchsia_results.missing_reviewer_problem)
Daniel Chenga37c03db2022-05-12 17:20:344637
Daniel Cheng171dad8d2022-05-21 00:40:254638 # Missing reviewers are an error unless there's no issue number
4639 # associated with this branch; in that case, the presubmit is being run
4640 # with --all or --files.
4641 #
4642 # Note that upload should never be an error; otherwise, it would be
4643 # impossible to upload changes at all.
4644 if input_api.is_committing and input_api.change.issue:
4645 make_presubmit_message = output_api.PresubmitError
4646 else:
4647 make_presubmit_message = output_api.PresubmitNotifyResult
4648 for problem in missing_reviewer_problems:
Sam Maiera6e76d72022-02-11 21:43:504649 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:254650 make_presubmit_message(problem.problem, items=problem.items))
Daniel Chenga37c03db2022-05-12 17:20:344651
Daniel Cheng171dad8d2022-05-21 00:40:254652 owners_file_problems = []
4653 owners_file_problems.extend(ipc_results.owners_file_problems)
4654 owners_file_problems.extend(fuchsia_results.owners_file_problems)
Daniel Chenga37c03db2022-05-12 17:20:344655
Daniel Cheng171dad8d2022-05-21 00:40:254656 for problem in owners_file_problems:
Daniel Cheng3008dc12022-05-13 04:02:114657 # Missing per-file rules are always an error. While swarming and caching
4658 # means that uploading a patchset with updated OWNERS files and sending
4659 # it to the CQ again should not have a large incremental cost, it is
4660 # still frustrating to discover the error only after the change has
4661 # already been uploaded.
Daniel Chenga37c03db2022-05-12 17:20:344662 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:254663 output_api.PresubmitError(problem.problem, items=problem.items))
Sam Maiera6e76d72022-02-11 21:43:504664
4665 return results
4666
4667
4668def _GetFilesUsingSecurityCriticalFunctions(input_api):
4669 """Checks affected files for changes to security-critical calls. This
4670 function checks the full change diff, to catch both additions/changes
4671 and removals.
4672
4673 Returns a dict keyed by file name, and the value is a set of detected
4674 functions.
4675 """
4676 # Map of function pretty name (displayed in an error) to the pattern to
4677 # match it with.
4678 _PATTERNS_TO_CHECK = {
4679 'content::GetServiceSandboxType<>()': 'GetServiceSandboxType\\<'
4680 }
4681 _PATTERNS_TO_CHECK = {
4682 k: input_api.re.compile(v)
4683 for k, v in _PATTERNS_TO_CHECK.items()
4684 }
4685
Sam Maiera6e76d72022-02-11 21:43:504686 # We don't want to trigger on strings within this file.
4687 def presubmit_file_filter(f):
Daniel Chenga37c03db2022-05-12 17:20:344688 return 'PRESUBMIT.py' != input_api.os_path.split(f.LocalPath())[1]
Sam Maiera6e76d72022-02-11 21:43:504689
4690 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
4691 files_to_functions = {}
4692 for f in input_api.AffectedFiles(file_filter=presubmit_file_filter):
4693 diff = f.GenerateScmDiff()
4694 for line in diff.split('\n'):
4695 # Not using just RightHandSideLines() because removing a
4696 # call to a security-critical function can be just as important
4697 # as adding or changing the arguments.
4698 if line.startswith('-') or (line.startswith('+')
4699 and not line.startswith('++')):
4700 for name, pattern in _PATTERNS_TO_CHECK.items():
4701 if pattern.search(line):
4702 path = f.LocalPath()
4703 if not path in files_to_functions:
4704 files_to_functions[path] = set()
4705 files_to_functions[path].add(name)
4706 return files_to_functions
4707
4708
4709def CheckSecurityChanges(input_api, output_api):
4710 """Checks that changes involving security-critical functions are reviewed
4711 by the security team.
4712 """
4713 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
4714 if not len(files_to_functions):
4715 return []
4716
Sam Maiera6e76d72022-02-11 21:43:504717 owners_file = 'ipc/SECURITY_OWNERS'
Daniel Chenga37c03db2022-05-12 17:20:344718 if _ChangeHasSecurityReviewer(input_api, owners_file):
Sam Maiera6e76d72022-02-11 21:43:504719 return []
4720
Daniel Chenga37c03db2022-05-12 17:20:344721 msg = 'The following files change calls to security-sensitive functions\n' \
Sam Maiera6e76d72022-02-11 21:43:504722 'that need to be reviewed by {}.\n'.format(owners_file)
4723 for path, names in files_to_functions.items():
4724 msg += ' {}\n'.format(path)
4725 for name in names:
4726 msg += ' {}\n'.format(name)
4727 msg += '\n'
4728
4729 if input_api.is_committing:
4730 output = output_api.PresubmitError
Mohamed Heikale217fc852020-07-06 19:44:034731 else:
Sam Maiera6e76d72022-02-11 21:43:504732 output = output_api.PresubmitNotifyResult
4733 return [output(msg)]
4734
4735
4736def CheckSetNoParent(input_api, output_api):
4737 """Checks that set noparent is only used together with an OWNERS file in
4738 //build/OWNERS.setnoparent (see also
4739 //docs/code_reviews.md#owners-files-details)
4740 """
4741 # Return early if no OWNERS files were modified.
4742 if not any(f.LocalPath().endswith('OWNERS')
4743 for f in input_api.AffectedFiles(include_deletes=False)):
4744 return []
4745
4746 errors = []
4747
4748 allowed_owners_files_file = 'build/OWNERS.setnoparent'
4749 allowed_owners_files = set()
Bruce Dawson58a45d22023-02-27 11:24:164750 with open(allowed_owners_files_file, 'r', encoding='utf-8') as f:
Sam Maiera6e76d72022-02-11 21:43:504751 for line in f:
4752 line = line.strip()
4753 if not line or line.startswith('#'):
4754 continue
4755 allowed_owners_files.add(line)
4756
4757 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
4758
4759 for f in input_api.AffectedFiles(include_deletes=False):
4760 if not f.LocalPath().endswith('OWNERS'):
4761 continue
4762
4763 found_owners_files = set()
4764 found_set_noparent_lines = dict()
4765
4766 # Parse the OWNERS file.
4767 for lineno, line in enumerate(f.NewContents(), 1):
4768 line = line.strip()
4769 if line.startswith('set noparent'):
4770 found_set_noparent_lines[''] = lineno
4771 if line.startswith('file://'):
4772 if line in allowed_owners_files:
4773 found_owners_files.add('')
4774 if line.startswith('per-file'):
4775 match = per_file_pattern.match(line)
4776 if match:
4777 glob = match.group(1).strip()
4778 directive = match.group(2).strip()
4779 if directive == 'set noparent':
4780 found_set_noparent_lines[glob] = lineno
4781 if directive.startswith('file://'):
4782 if directive in allowed_owners_files:
4783 found_owners_files.add(glob)
4784
4785 # Check that every set noparent line has a corresponding file:// line
4786 # listed in build/OWNERS.setnoparent. An exception is made for top level
4787 # directories since src/OWNERS shouldn't review them.
Anton Bershanskyi4253349482025-02-11 21:01:274788 linux_path = f.UnixLocalPath()
Bruce Dawson6bb0d672022-04-06 15:13:494789 if (linux_path.count('/') != 1
4790 and (not linux_path in _EXCLUDED_SET_NO_PARENT_PATHS)):
Sam Maiera6e76d72022-02-11 21:43:504791 for set_noparent_line in found_set_noparent_lines:
4792 if set_noparent_line in found_owners_files:
4793 continue
4794 errors.append(' %s:%d' %
Bruce Dawson6bb0d672022-04-06 15:13:494795 (linux_path,
Sam Maiera6e76d72022-02-11 21:43:504796 found_set_noparent_lines[set_noparent_line]))
4797
4798 results = []
4799 if errors:
4800 if input_api.is_committing:
4801 output = output_api.PresubmitError
4802 else:
4803 output = output_api.PresubmitPromptWarning
4804 results.append(
4805 output(
4806 'Found the following "set noparent" restrictions in OWNERS files that '
4807 'do not include owners from build/OWNERS.setnoparent:',
4808 long_text='\n\n'.join(errors)))
4809 return results
4810
4811
4812def CheckUselessForwardDeclarations(input_api, output_api):
4813 """Checks that added or removed lines in non third party affected
4814 header files do not lead to new useless class or struct forward
4815 declaration.
4816 """
4817 results = []
4818 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
4819 input_api.re.MULTILINE)
4820 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
4821 input_api.re.MULTILINE)
4822 for f in input_api.AffectedFiles(include_deletes=False):
Anton Bershanskyi4253349482025-02-11 21:01:274823 local_path = f.UnixLocalPath()
4824 if (local_path.startswith('third_party')
4825 and not local_path.startswith('third_party/blink')):
Sam Maiera6e76d72022-02-11 21:43:504826 continue
4827
Anton Bershanskyi4253349482025-02-11 21:01:274828 if not local_path.endswith('.h'):
Sam Maiera6e76d72022-02-11 21:43:504829 continue
4830
4831 contents = input_api.ReadFile(f)
4832 fwd_decls = input_api.re.findall(class_pattern, contents)
4833 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
4834
4835 useless_fwd_decls = []
4836 for decl in fwd_decls:
4837 count = sum(1 for _ in input_api.re.finditer(
4838 r'\b%s\b' % input_api.re.escape(decl), contents))
4839 if count == 1:
4840 useless_fwd_decls.append(decl)
4841
4842 if not useless_fwd_decls:
4843 continue
4844
4845 for line in f.GenerateScmDiff().splitlines():
4846 if (line.startswith('-') and not line.startswith('--')
4847 or line.startswith('+') and not line.startswith('++')):
4848 for decl in useless_fwd_decls:
4849 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
4850 results.append(
4851 output_api.PresubmitPromptWarning(
4852 '%s: %s forward declaration is no longer needed'
4853 % (f.LocalPath(), decl)))
4854 useless_fwd_decls.remove(decl)
4855
4856 return results
4857
4858
4859def _CheckAndroidDebuggableBuild(input_api, output_api):
4860 """Checks that code uses BuildInfo.isDebugAndroid() instead of
4861 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
4862 this is a debuggable build of Android.
4863 """
4864 build_type_check_pattern = input_api.re.compile(
4865 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
4866
4867 errors = []
4868
4869 sources = lambda affected_file: input_api.FilterSourceFile(
4870 affected_file,
4871 files_to_skip=(
4872 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4873 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314874 r"^android_webview/support_library/boundary_interfaces/",
4875 r"^chrome/android/webapk/.*",
4876 r'^third_party/.*',
4877 r"tools/android/customtabs_benchmark/.*",
4878 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504879 )),
4880 files_to_check=[r'.*\.java$'])
4881
4882 for f in input_api.AffectedSourceFiles(sources):
4883 for line_num, line in f.ChangedContents():
4884 if build_type_check_pattern.search(line):
4885 errors.append("%s:%d" % (f.LocalPath(), line_num))
4886
4887 results = []
4888
4889 if errors:
4890 results.append(
4891 output_api.PresubmitPromptWarning(
4892 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
4893 ' Please use BuildInfo.isDebugAndroid() instead.', errors))
4894
4895 return results
4896
4897# TODO: add unit tests
4898def _CheckAndroidToastUsage(input_api, output_api):
4899 """Checks that code uses org.chromium.ui.widget.Toast instead of
4900 android.widget.Toast (Chromium Toast doesn't force hardware
4901 acceleration on low-end devices, saving memory).
4902 """
4903 toast_import_pattern = input_api.re.compile(
4904 r'^import android\.widget\.Toast;$')
4905
4906 errors = []
4907
4908 sources = lambda affected_file: input_api.FilterSourceFile(
4909 affected_file,
4910 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
Bruce Dawson40fece62022-09-16 19:58:314911 DEFAULT_FILES_TO_SKIP + (r'^chromecast/.*',
4912 r'^remoting/.*')),
Sam Maiera6e76d72022-02-11 21:43:504913 files_to_check=[r'.*\.java$'])
4914
4915 for f in input_api.AffectedSourceFiles(sources):
4916 for line_num, line in f.ChangedContents():
4917 if toast_import_pattern.search(line):
4918 errors.append("%s:%d" % (f.LocalPath(), line_num))
4919
4920 results = []
4921
4922 if errors:
4923 results.append(
4924 output_api.PresubmitError(
4925 'android.widget.Toast usage is detected. Android toasts use hardware'
4926 ' acceleration, and can be\ncostly on low-end devices. Please use'
4927 ' org.chromium.ui.widget.Toast instead.\n'
4928 'Contact [email protected] if you have any questions.',
4929 errors))
4930
4931 return results
4932
4933
4934def _CheckAndroidCrLogUsage(input_api, output_api):
4935 """Checks that new logs using org.chromium.base.Log:
4936 - Are using 'TAG' as variable name for the tags (warn)
4937 - Are using a tag that is shorter than 20 characters (error)
4938 """
4939
4940 # Do not check format of logs in the given files
4941 cr_log_check_excluded_paths = [
4942 # //chrome/android/webapk cannot depend on //base
Bruce Dawson40fece62022-09-16 19:58:314943 r"^chrome/android/webapk/.*",
Sam Maiera6e76d72022-02-11 21:43:504944 # WebView license viewer code cannot depend on //base; used in stub APK.
Bruce Dawson40fece62022-09-16 19:58:314945 r"^android_webview/glue/java/src/com/android/"
4946 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504947 # The customtabs_benchmark is a small app that does not depend on Chromium
4948 # java pieces.
Bruce Dawson40fece62022-09-16 19:58:314949 r"tools/android/customtabs_benchmark/.*",
Sam Maiera6e76d72022-02-11 21:43:504950 ]
4951
4952 cr_log_import_pattern = input_api.re.compile(
4953 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
4954 class_in_base_pattern = input_api.re.compile(
4955 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
4956 has_some_log_import_pattern = input_api.re.compile(r'^import .*\.Log;$',
4957 input_api.re.MULTILINE)
4958 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
4959 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
4960 log_decl_pattern = input_api.re.compile(
4961 r'static final String TAG = "(?P<name>(.*))"')
4962 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
4963
4964 REF_MSG = ('See docs/android_logging.md for more info.')
4965 sources = lambda x: input_api.FilterSourceFile(
4966 x,
4967 files_to_check=[r'.*\.java$'],
4968 files_to_skip=cr_log_check_excluded_paths)
4969
4970 tag_decl_errors = []
Andrew Grieved3a35d82024-01-02 21:24:384971 tag_length_errors = []
Sam Maiera6e76d72022-02-11 21:43:504972 tag_errors = []
4973 tag_with_dot_errors = []
4974 util_log_errors = []
4975
4976 for f in input_api.AffectedSourceFiles(sources):
4977 file_content = input_api.ReadFile(f)
4978 has_modified_logs = False
4979 # Per line checks
4980 if (cr_log_import_pattern.search(file_content)
4981 or (class_in_base_pattern.search(file_content)
4982 and not has_some_log_import_pattern.search(file_content))):
4983 # Checks to run for files using cr log
4984 for line_num, line in f.ChangedContents():
4985 if rough_log_decl_pattern.search(line):
4986 has_modified_logs = True
4987
4988 # Check if the new line is doing some logging
4989 match = log_call_pattern.search(line)
4990 if match:
4991 has_modified_logs = True
4992
4993 # Make sure it uses "TAG"
4994 if not match.group('tag') == 'TAG':
4995 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
4996 else:
4997 # Report non cr Log function calls in changed lines
4998 for line_num, line in f.ChangedContents():
4999 if log_call_pattern.search(line):
5000 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
5001
5002 # Per file checks
5003 if has_modified_logs:
5004 # Make sure the tag is using the "cr" prefix and is not too long
5005 match = log_decl_pattern.search(file_content)
5006 tag_name = match.group('name') if match else None
5007 if not tag_name:
5008 tag_decl_errors.append(f.LocalPath())
Andrew Grieved3a35d82024-01-02 21:24:385009 elif len(tag_name) > 20:
5010 tag_length_errors.append(f.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:505011 elif '.' in tag_name:
5012 tag_with_dot_errors.append(f.LocalPath())
5013
5014 results = []
5015 if tag_decl_errors:
5016 results.append(
5017 output_api.PresubmitPromptWarning(
5018 'Please define your tags using the suggested format: .\n'
5019 '"private static final String TAG = "<package tag>".\n'
5020 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
5021 tag_decl_errors))
5022
Andrew Grieved3a35d82024-01-02 21:24:385023 if tag_length_errors:
5024 results.append(
5025 output_api.PresubmitError(
5026 'The tag length is restricted by the system to be at most '
5027 '20 characters.\n' + REF_MSG, tag_length_errors))
5028
Sam Maiera6e76d72022-02-11 21:43:505029 if tag_errors:
5030 results.append(
5031 output_api.PresubmitPromptWarning(
5032 'Please use a variable named "TAG" for your log tags.\n' +
5033 REF_MSG, tag_errors))
5034
5035 if util_log_errors:
5036 results.append(
5037 output_api.PresubmitPromptWarning(
5038 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
5039 util_log_errors))
5040
5041 if tag_with_dot_errors:
5042 results.append(
5043 output_api.PresubmitPromptWarning(
5044 'Dot in log tags cause them to be elided in crash reports.\n' +
5045 REF_MSG, tag_with_dot_errors))
5046
5047 return results
5048
5049
Sam Maiera6e76d72022-02-11 21:43:505050def _CheckAndroidTestAnnotationUsage(input_api, output_api):
5051 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
5052 deprecated_annotation_import_pattern = input_api.re.compile(
5053 r'^import android\.test\.suitebuilder\.annotation\..*;',
5054 input_api.re.MULTILINE)
5055 sources = lambda x: input_api.FilterSourceFile(
5056 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
5057 errors = []
5058 for f in input_api.AffectedFiles(file_filter=sources):
5059 for line_num, line in f.ChangedContents():
5060 if deprecated_annotation_import_pattern.search(line):
5061 errors.append("%s:%d" % (f.LocalPath(), line_num))
5062
5063 results = []
5064 if errors:
5065 results.append(
5066 output_api.PresubmitError(
5067 'Annotations in android.test.suitebuilder.annotation have been'
Mohamed Heikal3d7a94c2023-03-28 16:55:245068 ' deprecated since API level 24. Please use androidx.test.filters'
5069 ' from //third_party/androidx:androidx_test_runner_java instead.'
Sam Maiera6e76d72022-02-11 21:43:505070 ' Contact [email protected] if you have any questions.',
5071 errors))
5072 return results
5073
5074
5075def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
5076 """Checks if MDPI assets are placed in a correct directory."""
Anton Bershanskyi4253349482025-02-11 21:01:275077 file_filter = lambda f: (f.UnixLocalPath().endswith(
5078 '.png') and ('/res/drawable/' in f.
5079 UnixLocalPath() or '/res/drawable-ldrtl/' in f.UnixLocalPath()))
Sam Maiera6e76d72022-02-11 21:43:505080 errors = []
5081 for f in input_api.AffectedFiles(include_deletes=False,
5082 file_filter=file_filter):
5083 errors.append(' %s' % f.LocalPath())
5084
5085 results = []
5086 if errors:
5087 results.append(
5088 output_api.PresubmitError(
5089 'MDPI assets should be placed in /res/drawable-mdpi/ or '
5090 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
5091 '/res/drawable-ldrtl/.\n'
5092 'Contact [email protected] if you have questions.', errors))
5093 return results
5094
5095
5096def _CheckAndroidWebkitImports(input_api, output_api):
5097 """Checks that code uses org.chromium.base.Callback instead of
5098 android.webview.ValueCallback except in the WebView glue layer
5099 and WebLayer.
5100 """
5101 valuecallback_import_pattern = input_api.re.compile(
5102 r'^import android\.webkit\.ValueCallback;$')
5103
5104 errors = []
5105
5106 sources = lambda affected_file: input_api.FilterSourceFile(
5107 affected_file,
5108 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
5109 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:315110 r'^android_webview/glue/.*',
elabadysayedcbbaea72024-08-01 16:10:425111 r'^android_webview/support_library/.*',
Bruce Dawson40fece62022-09-16 19:58:315112 r'^weblayer/.*',
Sam Maiera6e76d72022-02-11 21:43:505113 )),
5114 files_to_check=[r'.*\.java$'])
5115
5116 for f in input_api.AffectedSourceFiles(sources):
5117 for line_num, line in f.ChangedContents():
5118 if valuecallback_import_pattern.search(line):
5119 errors.append("%s:%d" % (f.LocalPath(), line_num))
5120
5121 results = []
5122
5123 if errors:
5124 results.append(
5125 output_api.PresubmitError(
5126 'android.webkit.ValueCallback usage is detected outside of the glue'
5127 ' layer. To stay compatible with the support library, android.webkit.*'
5128 ' classes should only be used inside the glue layer and'
5129 ' org.chromium.base.Callback should be used instead.', errors))
5130
5131 return results
5132
5133
5134def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
5135 """Checks Android XML styles """
5136
5137 # Return early if no relevant files were modified.
5138 if not any(
5139 _IsXmlOrGrdFile(input_api, f.LocalPath())
5140 for f in input_api.AffectedFiles(include_deletes=False)):
5141 return []
5142
5143 import sys
5144 original_sys_path = sys.path
5145 try:
5146 sys.path = sys.path + [
5147 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5148 'android', 'checkxmlstyle')
5149 ]
5150 import checkxmlstyle
5151 finally:
5152 # Restore sys.path to what it was before.
5153 sys.path = original_sys_path
5154
5155 if is_check_on_upload:
5156 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
5157 else:
5158 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
5159
5160
5161def _CheckAndroidInfoBarDeprecation(input_api, output_api):
5162 """Checks Android Infobar Deprecation """
5163
5164 import sys
5165 original_sys_path = sys.path
5166 try:
5167 sys.path = sys.path + [
5168 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5169 'android', 'infobar_deprecation')
5170 ]
5171 import infobar_deprecation
5172 finally:
5173 # Restore sys.path to what it was before.
5174 sys.path = original_sys_path
5175
5176 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
5177
5178
5179class _PydepsCheckerResult:
5180 def __init__(self, cmd, pydeps_path, process, old_contents):
5181 self._cmd = cmd
5182 self._pydeps_path = pydeps_path
5183 self._process = process
5184 self._old_contents = old_contents
5185
5186 def GetError(self):
5187 """Returns an error message, or None."""
5188 import difflib
Andrew Grieved27620b62023-07-13 16:35:075189 new_contents = self._process.stdout.read().splitlines()[2:]
Sam Maiera6e76d72022-02-11 21:43:505190 if self._process.wait() != 0:
5191 # STDERR should already be printed.
5192 return 'Command failed: ' + self._cmd
Sam Maiera6e76d72022-02-11 21:43:505193 if self._old_contents != new_contents:
5194 diff = '\n'.join(
5195 difflib.context_diff(self._old_contents, new_contents))
5196 return ('File is stale: {}\n'
5197 'Diff (apply to fix):\n'
5198 '{}\n'
5199 'To regenerate, run:\n\n'
5200 ' {}').format(self._pydeps_path, diff, self._cmd)
5201 return None
5202
5203
5204class PydepsChecker:
5205 def __init__(self, input_api, pydeps_files):
5206 self._file_cache = {}
5207 self._input_api = input_api
5208 self._pydeps_files = pydeps_files
5209
5210 def _LoadFile(self, path):
5211 """Returns the list of paths within a .pydeps file relative to //."""
5212 if path not in self._file_cache:
5213 with open(path, encoding='utf-8') as f:
5214 self._file_cache[path] = f.read()
5215 return self._file_cache[path]
5216
5217 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
Gao Shenga79ebd42022-08-08 17:25:595218 """Returns an iterable of paths within the .pydep, relativized to //."""
Sam Maiera6e76d72022-02-11 21:43:505219 pydeps_data = self._LoadFile(pydeps_path)
5220 uses_gn_paths = '--gn-paths' in pydeps_data
5221 entries = (l for l in pydeps_data.splitlines()
5222 if not l.startswith('#'))
5223 if uses_gn_paths:
5224 # Paths look like: //foo/bar/baz
5225 return (e[2:] for e in entries)
5226 else:
5227 # Paths look like: path/relative/to/file.pydeps
5228 os_path = self._input_api.os_path
5229 pydeps_dir = os_path.dirname(pydeps_path)
5230 return (os_path.normpath(os_path.join(pydeps_dir, e))
5231 for e in entries)
5232
5233 def _CreateFilesToPydepsMap(self):
5234 """Returns a map of local_path -> list_of_pydeps."""
5235 ret = {}
5236 for pydep_local_path in self._pydeps_files:
5237 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
5238 ret.setdefault(path, []).append(pydep_local_path)
5239 return ret
5240
5241 def ComputeAffectedPydeps(self):
5242 """Returns an iterable of .pydeps files that might need regenerating."""
5243 affected_pydeps = set()
5244 file_to_pydeps_map = None
5245 for f in self._input_api.AffectedFiles(include_deletes=True):
5246 local_path = f.LocalPath()
5247 # Changes to DEPS can lead to .pydeps changes if any .py files are in
5248 # subrepositories. We can't figure out which files change, so re-check
5249 # all files.
5250 # Changes to print_python_deps.py affect all .pydeps.
5251 if local_path in ('DEPS', 'PRESUBMIT.py'
5252 ) or local_path.endswith('print_python_deps.py'):
5253 return self._pydeps_files
5254 elif local_path.endswith('.pydeps'):
5255 if local_path in self._pydeps_files:
5256 affected_pydeps.add(local_path)
5257 elif local_path.endswith('.py'):
5258 if file_to_pydeps_map is None:
5259 file_to_pydeps_map = self._CreateFilesToPydepsMap()
5260 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
5261 return affected_pydeps
5262
5263 def DetermineIfStaleAsync(self, pydeps_path):
5264 """Runs print_python_deps.py to see if the files is stale."""
5265 import os
5266
5267 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
5268 if old_pydeps_data:
5269 cmd = old_pydeps_data[1][1:].strip()
5270 if '--output' not in cmd:
5271 cmd += ' --output ' + pydeps_path
5272 old_contents = old_pydeps_data[2:]
5273 else:
5274 # A default cmd that should work in most cases (as long as pydeps filename
5275 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
5276 # file is empty/new.
5277 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
5278 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
5279 old_contents = []
5280 env = dict(os.environ)
5281 env['PYTHONDONTWRITEBYTECODE'] = '1'
5282 process = self._input_api.subprocess.Popen(
5283 cmd + ' --output ""',
5284 shell=True,
5285 env=env,
5286 stdout=self._input_api.subprocess.PIPE,
5287 encoding='utf-8')
5288 return _PydepsCheckerResult(cmd, pydeps_path, process, old_contents)
agrievef32bcc72016-04-04 14:57:405289
5290
Tibor Goldschwendt360793f72019-06-25 18:23:495291def _ParseGclientArgs():
Sam Maiera6e76d72022-02-11 21:43:505292 args = {}
5293 with open('build/config/gclient_args.gni', 'r') as f:
5294 for line in f:
5295 line = line.strip()
5296 if not line or line.startswith('#'):
5297 continue
5298 attribute, value = line.split('=')
5299 args[attribute.strip()] = value.strip()
5300 return args
Tibor Goldschwendt360793f72019-06-25 18:23:495301
5302
Saagar Sanghavifceeaae2020-08-12 16:40:365303def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
Sam Maiera6e76d72022-02-11 21:43:505304 """Checks if a .pydeps file needs to be regenerated."""
5305 # This check is for Python dependency lists (.pydeps files), and involves
5306 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
5307 # doesn't work on Windows and Mac, so skip it on other platforms.
5308 if not input_api.platform.startswith('linux'):
5309 return []
Erik Staabc734cd7a2021-11-23 03:11:525310
Sam Maiera6e76d72022-02-11 21:43:505311 results = []
5312 # First, check for new / deleted .pydeps.
5313 for f in input_api.AffectedFiles(include_deletes=True):
5314 # Check whether we are running the presubmit check for a file in src.
Sam Maiera6e76d72022-02-11 21:43:505315 if f.LocalPath().endswith('.pydeps'):
Andrew Grieve713b89b2024-10-15 20:20:085316 # f.LocalPath is relative to repo (src, or internal repo).
5317 # os_path.exists is relative to src repo.
5318 # Therefore if os_path.exists is true, it means f.LocalPath is relative
5319 # to src and we can conclude that the pydeps is in src.
5320 exists = input_api.os_path.exists(f.LocalPath())
5321 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
5322 results.append(
5323 output_api.PresubmitError(
5324 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
5325 'remove %s' % f.LocalPath()))
5326 elif (f.Action() != 'D' and exists
5327 and f.LocalPath() not in _ALL_PYDEPS_FILES):
5328 results.append(
5329 output_api.PresubmitError(
5330 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
5331 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:405332
Sam Maiera6e76d72022-02-11 21:43:505333 if results:
5334 return results
5335
Gavin Mak23884402024-07-25 20:39:265336 try:
5337 parsed_args = _ParseGclientArgs()
5338 except FileNotFoundError:
5339 message = (
5340 'build/config/gclient_args.gni not found. Please make sure your '
5341 'workspace has been initialized with gclient sync.'
5342 )
5343 import sys
5344 original_sys_path = sys.path
5345 try:
5346 sys.path = sys.path + [
5347 input_api.os_path.join(input_api.PresubmitLocalPath(),
5348 'third_party', 'depot_tools')
5349 ]
5350 import gclient_utils
5351 if gclient_utils.IsEnvCog():
5352 # Users will always hit this when they run presubmits before cog
5353 # workspace initialization finishes. The check shouldn't fail in
5354 # this case. This is an unavoidable workaround that's needed for
5355 # good presubmit UX for cog.
5356 results.append(output_api.PresubmitPromptWarning(message))
5357 else:
5358 results.append(output_api.PresubmitError(message))
5359 return results
5360 finally:
5361 # Restore sys.path to what it was before.
5362 sys.path = original_sys_path
5363
5364 is_android = parsed_args.get('checkout_android', 'false') == 'true'
Sam Maiera6e76d72022-02-11 21:43:505365 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
5366 affected_pydeps = set(checker.ComputeAffectedPydeps())
5367 affected_android_pydeps = affected_pydeps.intersection(
5368 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
5369 if affected_android_pydeps and not is_android:
5370 results.append(
5371 output_api.PresubmitPromptOrNotify(
5372 'You have changed python files that may affect pydeps for android\n'
Gao Shenga79ebd42022-08-08 17:25:595373 'specific scripts. However, the relevant presubmit check cannot be\n'
Sam Maiera6e76d72022-02-11 21:43:505374 'run because you are not using an Android checkout. To validate that\n'
5375 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
5376 'use the android-internal-presubmit optional trybot.\n'
5377 'Possibly stale pydeps files:\n{}'.format(
5378 '\n'.join(affected_android_pydeps))))
5379
5380 all_pydeps = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
5381 pydeps_to_check = affected_pydeps.intersection(all_pydeps)
5382 # Process these concurrently, as each one takes 1-2 seconds.
5383 pydep_results = [checker.DetermineIfStaleAsync(p) for p in pydeps_to_check]
5384 for result in pydep_results:
5385 error_msg = result.GetError()
5386 if error_msg:
5387 results.append(output_api.PresubmitError(error_msg))
5388
agrievef32bcc72016-04-04 14:57:405389 return results
5390
agrievef32bcc72016-04-04 14:57:405391
Saagar Sanghavifceeaae2020-08-12 16:40:365392def CheckSingletonInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505393 """Checks to make sure no header files have |Singleton<|."""
5394
5395 def FileFilter(affected_file):
5396 # It's ok for base/memory/singleton.h to have |Singleton<|.
5397 files_to_skip = (_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
Bruce Dawson40fece62022-09-16 19:58:315398 (r"^base/memory/singleton\.h$",
5399 r"^net/quic/platform/impl/quic_singleton_impl\.h$"))
Sam Maiera6e76d72022-02-11 21:43:505400 return input_api.FilterSourceFile(affected_file,
5401 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:435402
Sam Maiera6e76d72022-02-11 21:43:505403 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
5404 files = []
5405 for f in input_api.AffectedSourceFiles(FileFilter):
5406 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx')
5407 or f.LocalPath().endswith('.hpp')
5408 or f.LocalPath().endswith('.inl')):
5409 contents = input_api.ReadFile(f)
5410 for line in contents.splitlines(False):
5411 if (not line.lstrip().startswith('//')
5412 and # Strip C++ comment.
5413 pattern.search(line)):
5414 files.append(f)
5415 break
glidere61efad2015-02-18 17:39:435416
Sam Maiera6e76d72022-02-11 21:43:505417 if files:
5418 return [
5419 output_api.PresubmitError(
5420 'Found base::Singleton<T> in the following header files.\n' +
5421 'Please move them to an appropriate source file so that the ' +
5422 'template gets instantiated in a single compilation unit.',
5423 files)
5424 ]
5425 return []
glidere61efad2015-02-18 17:39:435426
5427
[email protected]fd20b902014-05-09 02:14:535428_DEPRECATED_CSS = [
5429 # Values
5430 ( "-webkit-box", "flex" ),
5431 ( "-webkit-inline-box", "inline-flex" ),
5432 ( "-webkit-flex", "flex" ),
5433 ( "-webkit-inline-flex", "inline-flex" ),
5434 ( "-webkit-min-content", "min-content" ),
5435 ( "-webkit-max-content", "max-content" ),
5436
5437 # Properties
5438 ( "-webkit-background-clip", "background-clip" ),
5439 ( "-webkit-background-origin", "background-origin" ),
5440 ( "-webkit-background-size", "background-size" ),
5441 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:445442 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:535443
5444 # Functions
5445 ( "-webkit-gradient", "gradient" ),
5446 ( "-webkit-repeating-gradient", "repeating-gradient" ),
5447 ( "-webkit-linear-gradient", "linear-gradient" ),
5448 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
5449 ( "-webkit-radial-gradient", "radial-gradient" ),
5450 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
5451]
5452
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:205453
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:495454# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:365455def CheckNoDeprecatedCss(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505456 """ Make sure that we don't use deprecated CSS
5457 properties, functions or values. Our external
5458 documentation and iOS CSS for dom distiller
5459 (reader mode) are ignored by the hooks as it
5460 needs to be consumed by WebKit. """
5461 results = []
5462 file_inclusion_pattern = [r".+\.css$"]
5463 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
5464 input_api.DEFAULT_FILES_TO_SKIP +
dpapad7fcdfc42024-12-06 01:21:385465 (# Legacy CSS file using deprecated CSS.
5466 r"^chrome/browser/resources/chromeos/arc_support/cr_overlay.css$",
5467 r"^chrome/common/extensions/docs", r"^chrome/docs",
Teresa Mao1d910882024-04-26 21:06:255468 r"^native_client_sdk",
5469 # The NTP team prefers reserving -webkit-line-clamp for
5470 # ellipsis effect which can only be used with -webkit-box.
5471 r"ui/webui/resources/cr_components/most_visited/.*\.css$"))
Sam Maiera6e76d72022-02-11 21:43:505472 file_filter = lambda f: input_api.FilterSourceFile(
5473 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
5474 for fpath in input_api.AffectedFiles(file_filter=file_filter):
5475 for line_num, line in fpath.ChangedContents():
5476 for (deprecated_value, value) in _DEPRECATED_CSS:
5477 if deprecated_value in line:
5478 results.append(
5479 output_api.PresubmitError(
5480 "%s:%d: Use of deprecated CSS %s, use %s instead" %
5481 (fpath.LocalPath(), line_num, deprecated_value,
5482 value)))
5483 return results
[email protected]fd20b902014-05-09 02:14:535484
mohan.reddyf21db962014-10-16 12:26:475485
Saagar Sanghavifceeaae2020-08-12 16:40:365486def CheckForRelativeIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505487 bad_files = {}
5488 for f in input_api.AffectedFiles(include_deletes=False):
Anton Bershanskyi4253349482025-02-11 21:01:275489 if (f.UnixLocalPath().startswith('third_party')
5490 and not f.LocalPath().startswith('third_party/blink')):
Sam Maiera6e76d72022-02-11 21:43:505491 continue
rlanday6802cf632017-05-30 17:48:365492
Sam Maiera6e76d72022-02-11 21:43:505493 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
5494 continue
rlanday6802cf632017-05-30 17:48:365495
Sam Maiera6e76d72022-02-11 21:43:505496 relative_includes = [
5497 line for _, line in f.ChangedContents()
5498 if "#include" in line and "../" in line
5499 ]
5500 if not relative_includes:
5501 continue
5502 bad_files[f.LocalPath()] = relative_includes
rlanday6802cf632017-05-30 17:48:365503
Sam Maiera6e76d72022-02-11 21:43:505504 if not bad_files:
5505 return []
rlanday6802cf632017-05-30 17:48:365506
Sam Maiera6e76d72022-02-11 21:43:505507 error_descriptions = []
5508 for file_path, bad_lines in bad_files.items():
5509 error_description = file_path
5510 for line in bad_lines:
5511 error_description += '\n ' + line
5512 error_descriptions.append(error_description)
rlanday6802cf632017-05-30 17:48:365513
Sam Maiera6e76d72022-02-11 21:43:505514 results = []
5515 results.append(
5516 output_api.PresubmitError(
5517 'You added one or more relative #include paths (including "../").\n'
5518 'These shouldn\'t be used because they can be used to include headers\n'
5519 'from code that\'s not correctly specified as a dependency in the\n'
5520 'relevant BUILD.gn file(s).', error_descriptions))
rlanday6802cf632017-05-30 17:48:365521
Sam Maiera6e76d72022-02-11 21:43:505522 return results
rlanday6802cf632017-05-30 17:48:365523
Takeshi Yoshinoe387aa32017-08-02 13:16:135524
Saagar Sanghavifceeaae2020-08-12 16:40:365525def CheckForCcIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505526 """Check that nobody tries to include a cc file. It's a relatively
5527 common error which results in duplicate symbols in object
5528 files. This may not always break the build until someone later gets
5529 very confusing linking errors."""
5530 results = []
5531 for f in input_api.AffectedFiles(include_deletes=False):
5532 # We let third_party code do whatever it wants
Anton Bershanskyi4253349482025-02-11 21:01:275533 if (f.UnixLocalPath().startswith('third_party')
5534 and not f.LocalPath().startswith('third_party/blink')):
Sam Maiera6e76d72022-02-11 21:43:505535 continue
Daniel Bratell65b033262019-04-23 08:17:065536
Sam Maiera6e76d72022-02-11 21:43:505537 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
5538 continue
Daniel Bratell65b033262019-04-23 08:17:065539
Sam Maiera6e76d72022-02-11 21:43:505540 for _, line in f.ChangedContents():
5541 if line.startswith('#include "'):
5542 included_file = line.split('"')[1]
5543 if _IsCPlusPlusFile(input_api, included_file):
5544 # The most common naming for external files with C++ code,
5545 # apart from standard headers, is to call them foo.inc, but
5546 # Chromium sometimes uses foo-inc.cc so allow that as well.
5547 if not included_file.endswith(('.h', '-inc.cc')):
5548 results.append(
5549 output_api.PresubmitError(
5550 'Only header files or .inc files should be included in other\n'
5551 'C++ files. Compiling the contents of a cc file more than once\n'
5552 'will cause duplicate information in the build which may later\n'
5553 'result in strange link_errors.\n' +
5554 f.LocalPath() + ':\n ' + line))
Daniel Bratell65b033262019-04-23 08:17:065555
Sam Maiera6e76d72022-02-11 21:43:505556 return results
Daniel Bratell65b033262019-04-23 08:17:065557
5558
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205559def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
Sam Maiera6e76d72022-02-11 21:43:505560 if not isinstance(key, ast.Str):
5561 return 'Key at line %d must be a string literal' % key.lineno
5562 if not isinstance(value, ast.Dict):
5563 return 'Value at line %d must be a dict' % value.lineno
5564 if len(value.keys) != 1:
5565 return 'Dict at line %d must have single entry' % value.lineno
5566 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
5567 return (
5568 'Entry at line %d must have a string literal \'filepath\' as key' %
5569 value.lineno)
5570 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:135571
Takeshi Yoshinoe387aa32017-08-02 13:16:135572
Sergey Ulanov4af16052018-11-08 02:41:465573def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Sam Maiera6e76d72022-02-11 21:43:505574 if not isinstance(key, ast.Str):
5575 return 'Key at line %d must be a string literal' % key.lineno
5576 if not isinstance(value, ast.List):
5577 return 'Value at line %d must be a list' % value.lineno
5578 for element in value.elts:
5579 if not isinstance(element, ast.Str):
5580 return 'Watchlist elements on line %d is not a string' % key.lineno
5581 if not email_regex.match(element.s):
5582 return ('Watchlist element on line %d doesn\'t look like a valid '
5583 + 'email: %s') % (key.lineno, element.s)
5584 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:135585
Takeshi Yoshinoe387aa32017-08-02 13:16:135586
Sergey Ulanov4af16052018-11-08 02:41:465587def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Sam Maiera6e76d72022-02-11 21:43:505588 mismatch_template = (
5589 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
5590 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:135591
Sam Maiera6e76d72022-02-11 21:43:505592 email_regex = input_api.re.compile(
5593 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
Sergey Ulanov4af16052018-11-08 02:41:465594
Sam Maiera6e76d72022-02-11 21:43:505595 ast = input_api.ast
5596 i = 0
5597 last_key = ''
5598 while True:
5599 if i >= len(wd_dict.keys):
5600 if i >= len(w_dict.keys):
5601 return None
5602 return mismatch_template % ('missing',
5603 'line %d' % w_dict.keys[i].lineno)
5604 elif i >= len(w_dict.keys):
5605 return (mismatch_template %
5606 ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:135607
Sam Maiera6e76d72022-02-11 21:43:505608 wd_key = wd_dict.keys[i]
5609 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:135610
Sam Maiera6e76d72022-02-11 21:43:505611 result = _CheckWatchlistDefinitionsEntrySyntax(wd_key,
5612 wd_dict.values[i], ast)
5613 if result is not None:
5614 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:135615
Sam Maiera6e76d72022-02-11 21:43:505616 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast,
5617 email_regex)
5618 if result is not None:
5619 return 'Bad entry in WATCHLISTS dict: %s' % result
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205620
Sam Maiera6e76d72022-02-11 21:43:505621 if wd_key.s != w_key.s:
5622 return mismatch_template % ('%s at line %d' %
5623 (wd_key.s, wd_key.lineno),
5624 '%s at line %d' %
5625 (w_key.s, w_key.lineno))
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205626
Sam Maiera6e76d72022-02-11 21:43:505627 if wd_key.s < last_key:
5628 return (
5629 'WATCHLISTS dict is not sorted lexicographically at line %d and %d'
5630 % (wd_key.lineno, w_key.lineno))
5631 last_key = wd_key.s
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205632
Sam Maiera6e76d72022-02-11 21:43:505633 i = i + 1
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205634
5635
Sergey Ulanov4af16052018-11-08 02:41:465636def _CheckWATCHLISTSSyntax(expression, input_api):
Sam Maiera6e76d72022-02-11 21:43:505637 ast = input_api.ast
5638 if not isinstance(expression, ast.Expression):
5639 return 'WATCHLISTS file must contain a valid expression'
5640 dictionary = expression.body
5641 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
5642 return 'WATCHLISTS file must have single dict with exactly two entries'
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205643
Sam Maiera6e76d72022-02-11 21:43:505644 first_key = dictionary.keys[0]
5645 first_value = dictionary.values[0]
5646 second_key = dictionary.keys[1]
5647 second_value = dictionary.values[1]
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205648
Sam Maiera6e76d72022-02-11 21:43:505649 if (not isinstance(first_key, ast.Str)
5650 or first_key.s != 'WATCHLIST_DEFINITIONS'
5651 or not isinstance(first_value, ast.Dict)):
5652 return ('The first entry of the dict in WATCHLISTS file must be '
5653 'WATCHLIST_DEFINITIONS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205654
Sam Maiera6e76d72022-02-11 21:43:505655 if (not isinstance(second_key, ast.Str) or second_key.s != 'WATCHLISTS'
5656 or not isinstance(second_value, ast.Dict)):
5657 return ('The second entry of the dict in WATCHLISTS file must be '
5658 'WATCHLISTS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205659
Sam Maiera6e76d72022-02-11 21:43:505660 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:135661
5662
Saagar Sanghavifceeaae2020-08-12 16:40:365663def CheckWATCHLISTS(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505664 for f in input_api.AffectedFiles(include_deletes=False):
5665 if f.LocalPath() == 'WATCHLISTS':
5666 contents = input_api.ReadFile(f, 'r')
Takeshi Yoshinoe387aa32017-08-02 13:16:135667
Sam Maiera6e76d72022-02-11 21:43:505668 try:
5669 # First, make sure that it can be evaluated.
5670 input_api.ast.literal_eval(contents)
5671 # Get an AST tree for it and scan the tree for detailed style checking.
5672 expression = input_api.ast.parse(contents,
5673 filename='WATCHLISTS',
5674 mode='eval')
5675 except ValueError as e:
5676 return [
5677 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5678 long_text=repr(e))
5679 ]
5680 except SyntaxError as e:
5681 return [
5682 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5683 long_text=repr(e))
5684 ]
5685 except TypeError as e:
5686 return [
5687 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5688 long_text=repr(e))
5689 ]
Takeshi Yoshinoe387aa32017-08-02 13:16:135690
Sam Maiera6e76d72022-02-11 21:43:505691 result = _CheckWATCHLISTSSyntax(expression, input_api)
5692 if result is not None:
5693 return [output_api.PresubmitError(result)]
5694 break
Takeshi Yoshinoe387aa32017-08-02 13:16:135695
Sam Maiera6e76d72022-02-11 21:43:505696 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:135697
Sean Kaucb7c9b32022-10-25 21:25:525698def CheckGnRebasePath(input_api, output_api):
Terrence Reilly313f44ff2025-01-22 15:10:145699 """Checks that target_gen_dir is not used with "//" in rebase_path().
Sean Kaucb7c9b32022-10-25 21:25:525700
5701 Developers should use root_build_dir instead of "//" when using target_gen_dir because
5702 Chromium is sometimes built outside of the source tree.
5703 """
5704
5705 def gn_files(f):
5706 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
5707
5708 rebase_path_regex = input_api.re.compile(r'rebase_path\(("\$target_gen_dir"|target_gen_dir), ("/"|"//")\)')
5709 problems = []
5710 for f in input_api.AffectedSourceFiles(gn_files):
5711 for line_num, line in f.ChangedContents():
5712 if rebase_path_regex.search(line):
5713 problems.append(
5714 'Absolute path in rebase_path() in %s:%d' %
5715 (f.LocalPath(), line_num))
5716
5717 if problems:
5718 return [
5719 output_api.PresubmitPromptWarning(
5720 'Using an absolute path in rebase_path()',
5721 items=sorted(problems),
5722 long_text=(
5723 'rebase_path() should use root_build_dir instead of "/" ',
5724 'since builds can be initiated from outside of the source ',
5725 'root.'))
5726 ]
5727 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:135728
Andrew Grieve1b290e4a22020-11-24 20:07:015729def CheckGnGlobForward(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505730 """Checks that forward_variables_from(invoker, "*") follows best practices.
Andrew Grieve1b290e4a22020-11-24 20:07:015731
Sam Maiera6e76d72022-02-11 21:43:505732 As documented at //build/docs/writing_gn_templates.md
5733 """
Andrew Grieve1b290e4a22020-11-24 20:07:015734
Sam Maiera6e76d72022-02-11 21:43:505735 def gn_files(f):
5736 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
Andrew Grieve1b290e4a22020-11-24 20:07:015737
Sam Maiera6e76d72022-02-11 21:43:505738 problems = []
5739 for f in input_api.AffectedSourceFiles(gn_files):
5740 for line_num, line in f.ChangedContents():
5741 if 'forward_variables_from(invoker, "*")' in line:
5742 problems.append(
5743 'Bare forward_variables_from(invoker, "*") in %s:%d' %
5744 (f.LocalPath(), line_num))
5745
5746 if problems:
5747 return [
5748 output_api.PresubmitPromptWarning(
5749 'forward_variables_from("*") without exclusions',
5750 items=sorted(problems),
5751 long_text=(
Gao Shenga79ebd42022-08-08 17:25:595752 'The variables "visibility" and "test_only" should be '
Sam Maiera6e76d72022-02-11 21:43:505753 'explicitly listed in forward_variables_from(). For more '
5754 'details, see:\n'
5755 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
5756 'build/docs/writing_gn_templates.md'
5757 '#Using-forward_variables_from'))
5758 ]
5759 return []
Andrew Grieve1b290e4a22020-11-24 20:07:015760
Saagar Sanghavifceeaae2020-08-12 16:40:365761def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505762 """Checks that newly added header files have corresponding GN changes.
5763 Note that this is only a heuristic. To be precise, run script:
5764 build/check_gn_headers.py.
5765 """
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195766
Sam Maiera6e76d72022-02-11 21:43:505767 def headers(f):
5768 return input_api.FilterSourceFile(
5769 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195770
Sam Maiera6e76d72022-02-11 21:43:505771 new_headers = []
5772 for f in input_api.AffectedSourceFiles(headers):
5773 if f.Action() != 'A':
5774 continue
5775 new_headers.append(f.LocalPath())
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195776
Sam Maiera6e76d72022-02-11 21:43:505777 def gn_files(f):
5778 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195779
Sam Maiera6e76d72022-02-11 21:43:505780 all_gn_changed_contents = ''
5781 for f in input_api.AffectedSourceFiles(gn_files):
5782 for _, line in f.ChangedContents():
5783 all_gn_changed_contents += line
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195784
Sam Maiera6e76d72022-02-11 21:43:505785 problems = []
5786 for header in new_headers:
5787 basename = input_api.os_path.basename(header)
5788 if basename not in all_gn_changed_contents:
5789 problems.append(header)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195790
Sam Maiera6e76d72022-02-11 21:43:505791 if problems:
5792 return [
5793 output_api.PresubmitPromptWarning(
5794 'Missing GN changes for new header files',
5795 items=sorted(problems),
5796 long_text=
5797 'Please double check whether newly added header files need '
5798 'corresponding changes in gn or gni files.\nThis checking is only a '
5799 'heuristic. Run build/check_gn_headers.py to be precise.\n'
5800 'Read https://crbug.com/661774 for more info.')
5801 ]
5802 return []
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195803
5804
Saagar Sanghavifceeaae2020-08-12 16:40:365805def CheckCorrectProductNameInMessages(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505806 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
Michael Giuffridad3bc8672018-10-25 22:48:025807
Sam Maiera6e76d72022-02-11 21:43:505808 This assumes we won't intentionally reference one product from the other
5809 product.
5810 """
5811 all_problems = []
5812 test_cases = [{
5813 "filename_postfix": "google_chrome_strings.grd",
5814 "correct_name": "Chrome",
5815 "incorrect_name": "Chromium",
5816 }, {
Thiago Perrotta099034f2023-06-05 18:10:205817 "filename_postfix": "google_chrome_strings.grd",
5818 "correct_name": "Chrome",
5819 "incorrect_name": "Chrome for Testing",
5820 }, {
Sam Maiera6e76d72022-02-11 21:43:505821 "filename_postfix": "chromium_strings.grd",
5822 "correct_name": "Chromium",
5823 "incorrect_name": "Chrome",
5824 }]
Michael Giuffridad3bc8672018-10-25 22:48:025825
Sam Maiera6e76d72022-02-11 21:43:505826 for test_case in test_cases:
5827 problems = []
5828 filename_filter = lambda x: x.LocalPath().endswith(test_case[
5829 "filename_postfix"])
Michael Giuffridad3bc8672018-10-25 22:48:025830
Sam Maiera6e76d72022-02-11 21:43:505831 # Check each new line. Can yield false positives in multiline comments, but
5832 # easier than trying to parse the XML because messages can have nested
5833 # children, and associating message elements with affected lines is hard.
5834 for f in input_api.AffectedSourceFiles(filename_filter):
5835 for line_num, line in f.ChangedContents():
5836 if "<message" in line or "<!--" in line or "-->" in line:
5837 continue
5838 if test_case["incorrect_name"] in line:
Thiago Perrotta099034f2023-06-05 18:10:205839 # Chrome for Testing is a special edge case: https://goo.gle/chrome-for-testing#bookmark=id.n1rat320av91
5840 if (test_case["correct_name"] == "Chromium" and line.count("Chrome") == line.count("Chrome for Testing")):
5841 continue
Sam Maiera6e76d72022-02-11 21:43:505842 problems.append("Incorrect product name in %s:%d" %
5843 (f.LocalPath(), line_num))
Michael Giuffridad3bc8672018-10-25 22:48:025844
Sam Maiera6e76d72022-02-11 21:43:505845 if problems:
5846 message = (
5847 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
5848 % (test_case["correct_name"], test_case["correct_name"],
5849 test_case["incorrect_name"]))
5850 all_problems.append(
5851 output_api.PresubmitPromptWarning(message, items=problems))
Michael Giuffridad3bc8672018-10-25 22:48:025852
Sam Maiera6e76d72022-02-11 21:43:505853 return all_problems
Michael Giuffridad3bc8672018-10-25 22:48:025854
5855
Saagar Sanghavifceeaae2020-08-12 16:40:365856def CheckForTooLargeFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505857 """Avoid large files, especially binary files, in the repository since
5858 git doesn't scale well for those. They will be in everyone's repo
5859 clones forever, forever making Chromium slower to clone and work
5860 with."""
Daniel Bratell93eb6c62019-04-29 20:13:365861
Sam Maiera6e76d72022-02-11 21:43:505862 # Uploading files to cloud storage is not trivial so we don't want
5863 # to set the limit too low, but the upper limit for "normal" large
5864 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
5865 # anything over 20 MB is exceptional.
Bruce Dawsonbb414db2022-12-27 20:21:255866 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024
Daniel Bratell93eb6c62019-04-29 20:13:365867
Sam Maiera6e76d72022-02-11 21:43:505868 too_large_files = []
5869 for f in input_api.AffectedFiles():
5870 # Check both added and modified files (but not deleted files).
5871 if f.Action() in ('A', 'M'):
5872 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Joe DeBlasio10a832f2023-04-21 20:20:185873 if size > TOO_LARGE_FILE_SIZE_LIMIT:
Sam Maiera6e76d72022-02-11 21:43:505874 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
Daniel Bratell93eb6c62019-04-29 20:13:365875
Sam Maiera6e76d72022-02-11 21:43:505876 if too_large_files:
5877 message = (
5878 'Do not commit large files to git since git scales badly for those.\n'
5879 +
5880 'Instead put the large files in cloud storage and use DEPS to\n' +
5881 'fetch them.\n' + '\n'.join(too_large_files))
5882 return [
5883 output_api.PresubmitError('Too large files found in commit',
5884 long_text=message + '\n')
5885 ]
5886 else:
5887 return []
Daniel Bratell93eb6c62019-04-29 20:13:365888
Max Morozb47503b2019-08-08 21:03:275889
Saagar Sanghavifceeaae2020-08-12 16:40:365890def CheckFuzzTargetsOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505891 """Checks specific for fuzz target sources."""
5892 EXPORTED_SYMBOLS = [
5893 'LLVMFuzzerInitialize',
5894 'LLVMFuzzerCustomMutator',
5895 'LLVMFuzzerCustomCrossOver',
5896 'LLVMFuzzerMutate',
5897 ]
Max Morozb47503b2019-08-08 21:03:275898
Sam Maiera6e76d72022-02-11 21:43:505899 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
Max Morozb47503b2019-08-08 21:03:275900
Sam Maiera6e76d72022-02-11 21:43:505901 def FilterFile(affected_file):
5902 """Ignore libFuzzer source code."""
5903 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
Bruce Dawson40fece62022-09-16 19:58:315904 files_to_skip = r"^third_party/libFuzzer"
Max Morozb47503b2019-08-08 21:03:275905
Sam Maiera6e76d72022-02-11 21:43:505906 return input_api.FilterSourceFile(affected_file,
5907 files_to_check=[files_to_check],
5908 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:275909
Sam Maiera6e76d72022-02-11 21:43:505910 files_with_missing_header = []
5911 for f in input_api.AffectedSourceFiles(FilterFile):
5912 contents = input_api.ReadFile(f, 'r')
5913 if REQUIRED_HEADER in contents:
5914 continue
Max Morozb47503b2019-08-08 21:03:275915
Sam Maiera6e76d72022-02-11 21:43:505916 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
5917 files_with_missing_header.append(f.LocalPath())
Max Morozb47503b2019-08-08 21:03:275918
Sam Maiera6e76d72022-02-11 21:43:505919 if not files_with_missing_header:
5920 return []
Max Morozb47503b2019-08-08 21:03:275921
Sam Maiera6e76d72022-02-11 21:43:505922 long_text = (
5923 'If you define any of the libFuzzer optional functions (%s), it is '
5924 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
5925 'work incorrectly on Mac (crbug.com/687076).\nNote that '
5926 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
5927 'to access command line arguments passed to the fuzzer. Instead, prefer '
5928 'static initialization and shared resources as documented in '
5929 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
5930 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n'
5931 % (', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER))
Max Morozb47503b2019-08-08 21:03:275932
Sam Maiera6e76d72022-02-11 21:43:505933 return [
5934 output_api.PresubmitPromptWarning(message="Missing '%s' in:" %
5935 REQUIRED_HEADER,
5936 items=files_with_missing_header,
5937 long_text=long_text)
5938 ]
Max Morozb47503b2019-08-08 21:03:275939
5940
Mohamed Heikald048240a2019-11-12 16:57:375941def _CheckNewImagesWarning(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505942 """
5943 Warns authors who add images into the repo to make sure their images are
5944 optimized before committing.
5945 """
5946 images_added = False
5947 image_paths = []
5948 errors = []
5949 filter_lambda = lambda x: input_api.FilterSourceFile(
5950 x,
5951 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
5952 DEFAULT_FILES_TO_SKIP),
5953 files_to_check=[r'.*\/(drawable|mipmap)'])
5954 for f in input_api.AffectedFiles(include_deletes=False,
5955 file_filter=filter_lambda):
5956 local_path = f.LocalPath().lower()
5957 if any(
5958 local_path.endswith(extension)
5959 for extension in _IMAGE_EXTENSIONS):
5960 images_added = True
5961 image_paths.append(f)
5962 if images_added:
5963 errors.append(
5964 output_api.PresubmitPromptWarning(
5965 'It looks like you are trying to commit some images. If these are '
5966 'non-test-only images, please make sure to read and apply the tips in '
5967 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
5968 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
5969 'FYI only and will not block your CL on the CQ.', image_paths))
5970 return errors
Mohamed Heikald048240a2019-11-12 16:57:375971
5972
Saagar Sanghavifceeaae2020-08-12 16:40:365973def ChecksAndroidSpecificOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505974 """Groups upload checks that target android code."""
5975 results = []
5976 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
5977 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
5978 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
5979 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505980 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
5981 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
5982 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
5983 results.extend(_CheckNewImagesWarning(input_api, output_api))
5984 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
5985 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
Henrique Nakashima224ee2482025-03-21 18:35:025986 results.extend(_CheckAndroidNullAwayAnnotatedClasses(input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505987 return results
5988
Becky Zhou7c69b50992018-12-10 19:37:575989
Saagar Sanghavifceeaae2020-08-12 16:40:365990def ChecksAndroidSpecificOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505991 """Groups commit checks that target android code."""
5992 results = []
5993 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
Henrique Nakashima0a2eb002025-04-25 16:29:375994 results.extend(_CheckAndroidNullAwayAnnotatedClasses(input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505995 return results
dgnaa68d5e2015-06-10 10:08:225996
Chris Hall59f8d0c72020-05-01 07:31:195997# TODO(chrishall): could we additionally match on any path owned by
5998# ui/accessibility/OWNERS ?
5999_ACCESSIBILITY_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:316000 r"^chrome/browser.*/accessibility/",
6001 r"^chrome/browser/extensions/api/automation.*/",
6002 r"^chrome/renderer/extensions/accessibility_.*",
6003 r"^chrome/tests/data/accessibility/",
6004 r"^content/browser/accessibility/",
6005 r"^content/renderer/accessibility/",
6006 r"^content/tests/data/accessibility/",
6007 r"^extensions/renderer/api/automation/",
Katie Dektar58ef07b2022-09-27 13:19:176008 r"^services/accessibility/",
Abigail Klein7a63c572024-02-28 20:45:096009 r"^services/screen_ai/",
Bruce Dawson40fece62022-09-16 19:58:316010 r"^ui/accessibility/",
6011 r"^ui/views/accessibility/",
Chris Hall59f8d0c72020-05-01 07:31:196012)
6013
Saagar Sanghavifceeaae2020-08-12 16:40:366014def CheckAccessibilityRelnotesField(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506015 """Checks that commits to accessibility code contain an AX-Relnotes field in
6016 their commit message."""
Chris Hall59f8d0c72020-05-01 07:31:196017
Sam Maiera6e76d72022-02-11 21:43:506018 def FileFilter(affected_file):
6019 paths = _ACCESSIBILITY_PATHS
6020 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:196021
Sam Maiera6e76d72022-02-11 21:43:506022 # Only consider changes affecting accessibility paths.
6023 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
6024 return []
Akihiro Ota08108e542020-05-20 15:30:536025
Sam Maiera6e76d72022-02-11 21:43:506026 # AX-Relnotes can appear in either the description or the footer.
6027 # When searching the description, require 'AX-Relnotes:' to appear at the
6028 # beginning of a line.
6029 ax_regex = input_api.re.compile('ax-relnotes[:=]')
6030 description_has_relnotes = any(
6031 ax_regex.match(line)
6032 for line in input_api.change.DescriptionText().lower().splitlines())
Chris Hall59f8d0c72020-05-01 07:31:196033
Sam Maiera6e76d72022-02-11 21:43:506034 footer_relnotes = input_api.change.GitFootersFromDescription().get(
6035 'AX-Relnotes', [])
6036 if description_has_relnotes or footer_relnotes:
6037 return []
Chris Hall59f8d0c72020-05-01 07:31:196038
Sam Maiera6e76d72022-02-11 21:43:506039 # TODO(chrishall): link to Relnotes documentation in message.
6040 message = (
6041 "Missing 'AX-Relnotes:' field required for accessibility changes"
6042 "\n please add 'AX-Relnotes: [release notes].' to describe any "
6043 "user-facing changes"
6044 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
6045 "user-facing effects"
6046 "\n if this is confusing or annoying then please contact members "
6047 "of ui/accessibility/OWNERS.")
6048
6049 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:226050
Mark Schillaci44c90b42024-11-22 20:44:386051
6052_ACCESSIBILITY_ARIA_METHOD_CANDIDATES_PATTERNS = r'(\-\>|\.)(get|has|FastGet|FastHas)Attribute\('
6053
6054_ACCESSIBILITY_ARIA_BAD_PARAMS_PATTERNS = (
6055 r"\(html_names::kAria(.*)Attr\)",
6056 r"\(html_names::kRoleAttr\)"
6057)
6058
6059_ACCESSIBILITY_ARIA_FILE_CANDIDATES_PATTERNS = (
6060 r".*/accessibility/.*.(cc|h)",
6061 r".*/ax_.*.(cc|h)"
6062)
6063
6064def CheckAccessibilityAriaElementAttributeGetters(input_api, output_api):
6065 """Checks that the blink accessibility code follows the defined patterns
6066 for checking aria attributes, so that ElementInternals is not bypassed."""
6067
6068 # Limit to accessibility-related files.
6069 def FileFilter(affected_file):
6070 paths = _ACCESSIBILITY_ARIA_FILE_CANDIDATES_PATTERNS
6071 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
6072
6073 aria_method_regex = input_api.re.compile(_ACCESSIBILITY_ARIA_METHOD_CANDIDATES_PATTERNS)
6074 aria_bad_params_regex = input_api.re.compile(
6075 "|".join(_ACCESSIBILITY_ARIA_BAD_PARAMS_PATTERNS)
6076 )
6077 problems = []
6078
6079 for f in input_api.AffectedSourceFiles(FileFilter):
6080 for line_num, line in f.ChangedContents():
6081 if aria_method_regex.search(line) and aria_bad_params_regex.search(line):
6082 problems.append(f"{f.LocalPath()}:{line_num}\n {line.strip()}")
6083
6084 if problems:
6085 return [
6086 output_api.PresubmitPromptWarning(
6087 "Accessibility code should not use element methods to get or check"
6088 "\nthe presence of aria attributes"
6089 "\nPlease use ARIA-specific attribute access, e.g. HasAriaAttribute(),"
6090 "\nAriaTokenAttribute(), AriaBoolAttribute(), AriaBooleanAttribute(),"
6091 "\nAriaFloatAttribute().",
6092 problems,
6093 )
6094 ]
6095 return []
6096
seanmccullough4a9356252021-04-08 19:54:096097# string pattern, sequence of strings to show when pattern matches,
6098# error flag. True if match is a presubmit error, otherwise it's a warning.
6099_NON_INCLUSIVE_TERMS = (
6100 (
6101 # Note that \b pattern in python re is pretty particular. In this
6102 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
6103 # ...' will not. This may require some tweaking to catch these cases
6104 # without triggering a lot of false positives. Leaving it naive and
6105 # less matchy for now.
Josip Sokcevic9d2806a02023-12-13 03:04:026106 r'/(?i)\b((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:096107 (
6108 'Please don\'t use blacklist, whitelist, ' # nocheck
6109 'or slave in your', # nocheck
6110 'code and make every effort to use other terms. Using "// nocheck"',
6111 '"# nocheck" or "<!-- nocheck -->"',
6112 'at the end of the offending line will bypass this PRESUBMIT error',
6113 'but avoid using this whenever possible. Reach out to',
6114 '[email protected] if you have questions'),
6115 True),)
6116
Saagar Sanghavifceeaae2020-08-12 16:40:366117def ChecksCommon(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506118 """Checks common to both upload and commit."""
6119 results = []
Eric Boren6fd2b932018-01-25 15:05:086120 results.extend(
Sam Maiera6e76d72022-02-11 21:43:506121 input_api.canned_checks.PanProjectChecks(
6122 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:086123
Sam Maiera6e76d72022-02-11 21:43:506124 author = input_api.change.author_email
6125 if author and author not in _KNOWN_ROBOTS:
6126 results.extend(
6127 input_api.canned_checks.CheckAuthorizedAuthor(
6128 input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:246129
Sam Maiera6e76d72022-02-11 21:43:506130 results.extend(
6131 input_api.canned_checks.CheckChangeHasNoTabs(
6132 input_api,
6133 output_api,
6134 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
6135 results.extend(
6136 input_api.RunTests(
6137 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Edward Lesmesce51df52020-08-04 22:10:176138
Bruce Dawsonc8054482022-03-28 15:33:376139 dirmd = 'dirmd.bat' if input_api.is_windows else 'dirmd'
Sam Maiera6e76d72022-02-11 21:43:506140 dirmd_bin = input_api.os_path.join(input_api.PresubmitLocalPath(),
Bruce Dawsonc8054482022-03-28 15:33:376141 'third_party', 'depot_tools', dirmd)
Sam Maiera6e76d72022-02-11 21:43:506142 results.extend(
6143 input_api.RunTests(
6144 input_api.canned_checks.CheckDirMetadataFormat(
6145 input_api, output_api, dirmd_bin)))
6146 results.extend(
6147 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
6148 input_api, output_api))
6149 results.extend(
6150 input_api.canned_checks.CheckNoNewMetadataInOwners(
6151 input_api, output_api))
6152 results.extend(
6153 input_api.canned_checks.CheckInclusiveLanguage(
6154 input_api,
6155 output_api,
6156 excluded_directories_relative_path=[
6157 'infra', 'inclusive_language_presubmit_exempt_dirs.txt'
6158 ],
6159 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Yiwei Zhang5341bf02025-03-20 16:34:136160 results.extend(
6161 input_api.canned_checks.CheckNewDEPSHooksHasRequiredReviewers(
6162 input_api, output_api))
Dirk Prankee3c9c62d2021-05-18 18:35:596163
Aleksey Khoroshilov2978c942022-06-13 16:14:126164 presubmit_py_filter = lambda f: input_api.FilterSourceFile(
Daniel Cheng6f3d1ae12025-04-07 17:11:276165 f, files_to_check=[r'.*PRESUBMIT(?:_test)?\.py$'])
6166 potential_paths = set(
6167 map(
6168 lambda f: input_api.os_path.dirname(f.AbsoluteLocalPath()),
6169 input_api.AffectedFiles(include_deletes=False,
6170 file_filter=presubmit_py_filter)))
6171 for full_path in potential_paths:
Aleksey Khoroshilov2978c942022-06-13 16:14:126172 test_file = input_api.os_path.join(full_path, 'PRESUBMIT_test.py')
6173 # The PRESUBMIT.py file (and the directory containing it) might have
6174 # been affected by being moved or removed, so only try to run the tests
6175 # if they still exist.
6176 if not input_api.os_path.exists(test_file):
6177 continue
Sam Maiera6e76d72022-02-11 21:43:506178
Aleksey Khoroshilov2978c942022-06-13 16:14:126179 results.extend(
6180 input_api.canned_checks.RunUnitTestsInDirectory(
6181 input_api,
6182 output_api,
6183 full_path,
Takuto Ikuta40def482023-06-02 02:23:496184 files_to_check=[r'^PRESUBMIT_test\.py$']))
Sam Maiera6e76d72022-02-11 21:43:506185 return results
[email protected]1f7b4172010-01-28 01:17:346186
[email protected]b337cb5b2011-01-23 21:24:056187
Saagar Sanghavifceeaae2020-08-12 16:40:366188def CheckPatchFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506189 problems = [
6190 f.LocalPath() for f in input_api.AffectedFiles()
6191 if f.LocalPath().endswith(('.orig', '.rej'))
6192 ]
6193 # Cargo.toml.orig files are part of third-party crates downloaded from
6194 # crates.io and should be included.
6195 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
6196 if problems:
6197 return [
6198 output_api.PresubmitError("Don't commit .rej and .orig files.",
6199 problems)
6200 ]
6201 else:
6202 return []
[email protected]b8079ae4a2012-12-05 19:56:496203
6204
Saagar Sanghavifceeaae2020-08-12 16:40:366205def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506206 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
6207 macro_re = input_api.re.compile(
6208 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
6209 include_re = input_api.re.compile(r'^#include\s+"build/build_config.h"',
6210 input_api.re.MULTILINE)
6211 extension_re = input_api.re.compile(r'\.[a-z]+$')
6212 errors = []
Bruce Dawsonf7679202022-08-09 20:24:006213 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:506214 for f in input_api.AffectedFiles(include_deletes=False):
Bruce Dawsonf7679202022-08-09 20:24:006215 # The build-config macros are allowed to be used in build_config.h
6216 # without including itself.
6217 if f.LocalPath() == config_h_file:
6218 continue
Sam Maiera6e76d72022-02-11 21:43:506219 if not f.LocalPath().endswith(
6220 ('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
6221 continue
Arthur Sonzognia3dec412024-04-29 12:05:376222
Sam Maiera6e76d72022-02-11 21:43:506223 found_line_number = None
6224 found_macro = None
6225 all_lines = input_api.ReadFile(f, 'r').splitlines()
6226 for line_num, line in enumerate(all_lines):
6227 match = macro_re.search(line)
6228 if match:
6229 found_line_number = line_num
6230 found_macro = match.group(2)
6231 break
6232 if not found_line_number:
6233 continue
Kent Tamura5a8755d2017-06-29 23:37:076234
Sam Maiera6e76d72022-02-11 21:43:506235 found_include_line = -1
6236 for line_num, line in enumerate(all_lines):
6237 if include_re.search(line):
6238 found_include_line = line_num
6239 break
6240 if found_include_line >= 0 and found_include_line < found_line_number:
6241 continue
Kent Tamura5a8755d2017-06-29 23:37:076242
Sam Maiera6e76d72022-02-11 21:43:506243 if not f.LocalPath().endswith('.h'):
6244 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
6245 try:
6246 content = input_api.ReadFile(primary_header_path, 'r')
6247 if include_re.search(content):
6248 continue
6249 except IOError:
6250 pass
6251 errors.append('%s:%d %s macro is used without first including build/'
6252 'build_config.h.' %
6253 (f.LocalPath(), found_line_number, found_macro))
6254 if errors:
6255 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
6256 return []
Kent Tamura5a8755d2017-06-29 23:37:076257
6258
Lei Zhang1c12a22f2021-05-12 11:28:456259def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506260 stl_include_re = input_api.re.compile(r'^#include\s+<('
6261 r'algorithm|'
6262 r'array|'
6263 r'limits|'
6264 r'list|'
6265 r'map|'
6266 r'memory|'
6267 r'queue|'
6268 r'set|'
6269 r'string|'
6270 r'unordered_map|'
6271 r'unordered_set|'
6272 r'utility|'
6273 r'vector)>')
6274 std_namespace_re = input_api.re.compile(r'std::')
6275 errors = []
6276 for f in input_api.AffectedFiles():
6277 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
6278 continue
Lei Zhang1c12a22f2021-05-12 11:28:456279
Sam Maiera6e76d72022-02-11 21:43:506280 uses_std_namespace = False
6281 has_stl_include = False
6282 for line in f.NewContents():
6283 if has_stl_include and uses_std_namespace:
6284 break
Lei Zhang1c12a22f2021-05-12 11:28:456285
Sam Maiera6e76d72022-02-11 21:43:506286 if not has_stl_include and stl_include_re.search(line):
6287 has_stl_include = True
6288 continue
Lei Zhang1c12a22f2021-05-12 11:28:456289
Bruce Dawson4a5579a2022-04-08 17:11:366290 if not uses_std_namespace and (std_namespace_re.search(line)
6291 or 'no-std-usage-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:506292 uses_std_namespace = True
6293 continue
Lei Zhang1c12a22f2021-05-12 11:28:456294
Sam Maiera6e76d72022-02-11 21:43:506295 if has_stl_include and not uses_std_namespace:
6296 errors.append(
6297 '%s: Includes STL header(s) but does not reference std::' %
6298 f.LocalPath())
6299 if errors:
6300 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
6301 return []
Lei Zhang1c12a22f2021-05-12 11:28:456302
6303
Xiaohan Wang42d96c22022-01-20 17:23:116304def _CheckForDeprecatedOSMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:506305 """Check for sensible looking, totally invalid OS macros."""
6306 preprocessor_statement = input_api.re.compile(r'^\s*#')
6307 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
6308 results = []
6309 for lnum, line in f.ChangedContents():
6310 if preprocessor_statement.search(line):
6311 for match in os_macro.finditer(line):
6312 results.append(
6313 ' %s:%d: %s' %
6314 (f.LocalPath(), lnum, 'defined(OS_' + match.group(1) +
6315 ') -> BUILDFLAG(IS_' + match.group(1) + ')'))
6316 return results
[email protected]b00342e7f2013-03-26 16:21:546317
6318
Xiaohan Wang42d96c22022-01-20 17:23:116319def CheckForDeprecatedOSMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506320 """Check all affected files for invalid OS macros."""
6321 bad_macros = []
Bruce Dawsonf7679202022-08-09 20:24:006322 # The OS_ macros are allowed to be used in build/build_config.h.
6323 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:506324 for f in input_api.AffectedSourceFiles(None):
Bruce Dawsonf7679202022-08-09 20:24:006325 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')) \
6326 and f.LocalPath() != config_h_file:
Sam Maiera6e76d72022-02-11 21:43:506327 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
[email protected]b00342e7f2013-03-26 16:21:546328
Sam Maiera6e76d72022-02-11 21:43:506329 if not bad_macros:
6330 return []
[email protected]b00342e7f2013-03-26 16:21:546331
Sam Maiera6e76d72022-02-11 21:43:506332 return [
6333 output_api.PresubmitError(
6334 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
6335 'defined in build_config.h):', bad_macros)
6336 ]
[email protected]b00342e7f2013-03-26 16:21:546337
lliabraa35bab3932014-10-01 12:16:446338
6339def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:506340 """Check all affected files for invalid "if defined" macros."""
6341 ALWAYS_DEFINED_MACROS = (
6342 "TARGET_CPU_PPC",
6343 "TARGET_CPU_PPC64",
6344 "TARGET_CPU_68K",
6345 "TARGET_CPU_X86",
6346 "TARGET_CPU_ARM",
6347 "TARGET_CPU_MIPS",
6348 "TARGET_CPU_SPARC",
6349 "TARGET_CPU_ALPHA",
6350 "TARGET_IPHONE_SIMULATOR",
6351 "TARGET_OS_EMBEDDED",
6352 "TARGET_OS_IPHONE",
6353 "TARGET_OS_MAC",
6354 "TARGET_OS_UNIX",
6355 "TARGET_OS_WIN32",
6356 )
6357 ifdef_macro = input_api.re.compile(
6358 r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
6359 results = []
6360 for lnum, line in f.ChangedContents():
6361 for match in ifdef_macro.finditer(line):
6362 if match.group(1) in ALWAYS_DEFINED_MACROS:
6363 always_defined = ' %s is always defined. ' % match.group(1)
6364 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
6365 results.append(
6366 ' %s:%d %s\n\t%s' %
6367 (f.LocalPath(), lnum, always_defined, did_you_mean))
6368 return results
lliabraa35bab3932014-10-01 12:16:446369
6370
Saagar Sanghavifceeaae2020-08-12 16:40:366371def CheckForInvalidIfDefinedMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506372 """Check all affected files for invalid "if defined" macros."""
Arthur Sonzogni4fd14fd2024-06-02 18:42:526373 SKIPPED_PATHS = [
6374 'base/allocator/partition_allocator/src/partition_alloc/build_config.h',
6375 'build/build_config.h',
6376 'third_party/abseil-cpp/',
6377 'third_party/sqlite/',
6378 ]
6379 def affected_files_filter(f):
6380 # Normalize the local path to Linux-style path separators so that the
6381 # path comparisons work on Windows as well.
Anton Bershanskyi4253349482025-02-11 21:01:276382 path = f.UnixLocalPath()
Arthur Sonzogni4fd14fd2024-06-02 18:42:526383
6384 for skipped_path in SKIPPED_PATHS:
6385 if path.startswith(skipped_path):
6386 return False
6387
6388 return path.endswith(('.h', '.c', '.cc', '.m', '.mm'))
6389
Sam Maiera6e76d72022-02-11 21:43:506390 bad_macros = []
Arthur Sonzogni4fd14fd2024-06-02 18:42:526391 for f in input_api.AffectedSourceFiles(affected_files_filter):
6392 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
lliabraa35bab3932014-10-01 12:16:446393
Sam Maiera6e76d72022-02-11 21:43:506394 if not bad_macros:
6395 return []
lliabraa35bab3932014-10-01 12:16:446396
Sam Maiera6e76d72022-02-11 21:43:506397 return [
6398 output_api.PresubmitError(
6399 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
6400 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
6401 bad_macros)
6402 ]
lliabraa35bab3932014-10-01 12:16:446403
Saagar Sanghavifceeaae2020-08-12 16:40:366404def CheckForIPCRules(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506405 """Check for same IPC rules described in
6406 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
6407 """
6408 base_pattern = r'IPC_ENUM_TRAITS\('
6409 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
6410 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
mlamouria82272622014-09-16 18:45:046411
Sam Maiera6e76d72022-02-11 21:43:506412 problems = []
6413 for f in input_api.AffectedSourceFiles(None):
6414 local_path = f.LocalPath()
6415 if not local_path.endswith('.h'):
6416 continue
6417 for line_number, line in f.ChangedContents():
6418 if inclusion_pattern.search(
6419 line) and not comment_pattern.search(line):
6420 problems.append('%s:%d\n %s' %
6421 (local_path, line_number, line.strip()))
mlamouria82272622014-09-16 18:45:046422
Sam Maiera6e76d72022-02-11 21:43:506423 if problems:
6424 return [
6425 output_api.PresubmitPromptWarning(_IPC_ENUM_TRAITS_DEPRECATED,
6426 problems)
6427 ]
6428 else:
6429 return []
mlamouria82272622014-09-16 18:45:046430
[email protected]b00342e7f2013-03-26 16:21:546431
Saagar Sanghavifceeaae2020-08-12 16:40:366432def CheckForLongPathnames(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506433 """Check to make sure no files being submitted have long paths.
6434 This causes issues on Windows.
6435 """
6436 problems = []
6437 for f in input_api.AffectedTestableFiles():
6438 local_path = f.LocalPath()
6439 # Windows has a path limit of 260 characters. Limit path length to 200 so
6440 # that we have some extra for the prefix on dev machines and the bots.
Weizhong Xia8b461f12024-06-21 21:46:336441 if (local_path.startswith('third_party/blink/web_tests/platform/') and
6442 not local_path.startswith('third_party/blink/web_tests/platform/win')):
6443 # Do not check length of the path for files not used by Windows
6444 continue
Sam Maiera6e76d72022-02-11 21:43:506445 if len(local_path) > 200:
6446 problems.append(local_path)
Stephen Martinis97a394142018-06-07 23:06:056447
Sam Maiera6e76d72022-02-11 21:43:506448 if problems:
6449 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
6450 else:
6451 return []
Stephen Martinis97a394142018-06-07 23:06:056452
6453
Saagar Sanghavifceeaae2020-08-12 16:40:366454def CheckForIncludeGuards(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506455 """Check that header files have proper guards against multiple inclusion.
6456 If a file should not have such guards (and it probably should) then it
Bruce Dawson4a5579a2022-04-08 17:11:366457 should include the string "no-include-guard-because-multiply-included" or
6458 "no-include-guard-because-pch-file".
Sam Maiera6e76d72022-02-11 21:43:506459 """
Daniel Bratell8ba52722018-03-02 16:06:146460
Sam Maiera6e76d72022-02-11 21:43:506461 def is_chromium_header_file(f):
6462 # We only check header files under the control of the Chromium
mikt84d6c712024-03-27 13:29:036463 # project. This excludes:
6464 # - third_party/*, except blink.
6465 # - base/allocator/partition_allocator/: PartitionAlloc is a standalone
6466 # library used outside of Chrome. Includes are referenced from its
6467 # own base directory. It has its own `CheckForIncludeGuards`
6468 # PRESUBMIT.py check.
6469 # - *_message_generator.h: They use include guards in a special,
6470 # non-typical way.
Sam Maiera6e76d72022-02-11 21:43:506471 file_with_path = input_api.os_path.normpath(f.LocalPath())
6472 return (file_with_path.endswith('.h')
6473 and not file_with_path.endswith('_message_generator.h')
Bruce Dawson4c4c2922022-05-02 18:07:336474 and not file_with_path.endswith('com_imported_mstscax.h')
Peter Kasting66c1f752024-12-02 15:28:376475 and not file_with_path.startswith(
6476 input_api.os_path.join('base', 'allocator',
6477 'partition_allocator'))
Sam Maiera6e76d72022-02-11 21:43:506478 and (not file_with_path.startswith('third_party')
6479 or file_with_path.startswith(
6480 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:146481
Sam Maiera6e76d72022-02-11 21:43:506482 def replace_special_with_underscore(string):
6483 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:146484
Sam Maiera6e76d72022-02-11 21:43:506485 errors = []
Daniel Bratell8ba52722018-03-02 16:06:146486
Sam Maiera6e76d72022-02-11 21:43:506487 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
6488 guard_name = None
6489 guard_line_number = None
6490 seen_guard_end = False
Lei Zhangd84f9512024-05-28 19:43:306491 bypass_checks_at_end_of_file = False
Daniel Bratell8ba52722018-03-02 16:06:146492
Sam Maiera6e76d72022-02-11 21:43:506493 file_with_path = input_api.os_path.normpath(f.LocalPath())
6494 base_file_name = input_api.os_path.splitext(
6495 input_api.os_path.basename(file_with_path))[0]
6496 upper_base_file_name = base_file_name.upper()
Daniel Bratell8ba52722018-03-02 16:06:146497
Sam Maiera6e76d72022-02-11 21:43:506498 expected_guard = replace_special_with_underscore(
6499 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:146500
Sam Maiera6e76d72022-02-11 21:43:506501 # For "path/elem/file_name.h" we should really only accept
6502 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
6503 # are too many (1000+) files with slight deviations from the
6504 # coding style. The most important part is that the include guard
6505 # is there, and that it's unique, not the name so this check is
6506 # forgiving for existing files.
6507 #
6508 # As code becomes more uniform, this could be made stricter.
Daniel Bratell8ba52722018-03-02 16:06:146509
Sam Maiera6e76d72022-02-11 21:43:506510 guard_name_pattern_list = [
6511 # Anything with the right suffix (maybe with an extra _).
6512 r'\w+_H__?',
Daniel Bratell8ba52722018-03-02 16:06:146513
Sam Maiera6e76d72022-02-11 21:43:506514 # To cover include guards with old Blink style.
6515 r'\w+_h',
Daniel Bratell8ba52722018-03-02 16:06:146516
Sam Maiera6e76d72022-02-11 21:43:506517 # Anything including the uppercase name of the file.
6518 r'\w*' + input_api.re.escape(
6519 replace_special_with_underscore(upper_base_file_name)) +
6520 r'\w*',
6521 ]
6522 guard_name_pattern = '|'.join(guard_name_pattern_list)
6523 guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
6524 guard_name_pattern + ')')
Daniel Bratell8ba52722018-03-02 16:06:146525
Sam Maiera6e76d72022-02-11 21:43:506526 for line_number, line in enumerate(f.NewContents()):
Bruce Dawson4a5579a2022-04-08 17:11:366527 if ('no-include-guard-because-multiply-included' in line
6528 or 'no-include-guard-because-pch-file' in line):
Lei Zhangd84f9512024-05-28 19:43:306529 bypass_checks_at_end_of_file = True
Sam Maiera6e76d72022-02-11 21:43:506530 break
Daniel Bratell8ba52722018-03-02 16:06:146531
Sam Maiera6e76d72022-02-11 21:43:506532 if guard_name is None:
6533 match = guard_pattern.match(line)
6534 if match:
6535 guard_name = match.group(1)
6536 guard_line_number = line_number
Daniel Bratell8ba52722018-03-02 16:06:146537
Sam Maiera6e76d72022-02-11 21:43:506538 # We allow existing files to use include guards whose names
6539 # don't match the chromium style guide, but new files should
6540 # get it right.
Bruce Dawson6cc154e2022-04-12 20:39:496541 if guard_name != expected_guard:
Bruce Dawson95eb7562022-09-14 15:27:166542 if f.Action() == 'A': # If file was just 'A'dded
Sam Maiera6e76d72022-02-11 21:43:506543 errors.append(
6544 output_api.PresubmitPromptWarning(
6545 'Header using the wrong include guard name %s'
6546 % guard_name, [
6547 '%s:%d' %
6548 (f.LocalPath(), line_number + 1)
6549 ], 'Expected: %r\nFound: %r' %
6550 (expected_guard, guard_name)))
6551 else:
6552 # The line after #ifndef should have a #define of the same name.
6553 if line_number == guard_line_number + 1:
6554 expected_line = '#define %s' % guard_name
6555 if line != expected_line:
6556 errors.append(
6557 output_api.PresubmitPromptWarning(
6558 'Missing "%s" for include guard' %
6559 expected_line,
6560 ['%s:%d' % (f.LocalPath(), line_number + 1)],
6561 'Expected: %r\nGot: %r' %
6562 (expected_line, line)))
Daniel Bratell8ba52722018-03-02 16:06:146563
Sam Maiera6e76d72022-02-11 21:43:506564 if not seen_guard_end and line == '#endif // %s' % guard_name:
6565 seen_guard_end = True
6566 elif seen_guard_end:
6567 if line.strip() != '':
6568 errors.append(
6569 output_api.PresubmitPromptWarning(
6570 'Include guard %s not covering the whole file'
6571 % (guard_name), [f.LocalPath()]))
6572 break # Nothing else to check and enough to warn once.
Daniel Bratell8ba52722018-03-02 16:06:146573
Lei Zhangd84f9512024-05-28 19:43:306574 if bypass_checks_at_end_of_file:
6575 continue
6576
Sam Maiera6e76d72022-02-11 21:43:506577 if guard_name is None:
6578 errors.append(
6579 output_api.PresubmitPromptWarning(
Bruce Dawson32114b62022-04-11 16:45:496580 'Missing include guard in %s\n'
Sam Maiera6e76d72022-02-11 21:43:506581 'Recommended name: %s\n'
6582 'This check can be disabled by having the string\n'
Bruce Dawson4a5579a2022-04-08 17:11:366583 '"no-include-guard-because-multiply-included" or\n'
6584 '"no-include-guard-because-pch-file" in the header.'
Sam Maiera6e76d72022-02-11 21:43:506585 % (f.LocalPath(), expected_guard)))
Lei Zhangd84f9512024-05-28 19:43:306586 elif not seen_guard_end:
6587 errors.append(
6588 output_api.PresubmitPromptWarning(
6589 'Incorrect or missing include guard #endif in %s\n'
6590 'Recommended #endif comment: // %s'
6591 % (f.LocalPath(), expected_guard)))
Sam Maiera6e76d72022-02-11 21:43:506592
6593 return errors
Daniel Bratell8ba52722018-03-02 16:06:146594
6595
Saagar Sanghavifceeaae2020-08-12 16:40:366596def CheckForWindowsLineEndings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506597 """Check source code and known ascii text files for Windows style line
6598 endings.
6599 """
Bruce Dawson5efbdc652022-04-11 19:29:516600 known_text_files = r'.*\.(txt|html|htm|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:236601
dpapadfd421fb2025-02-13 00:47:326602 _WEBUI_FILES_EXTENSIONS = r'\.(css|html|js|ts|svg)$'
6603
Sam Maiera6e76d72022-02-11 21:43:506604 file_inclusion_pattern = (known_text_files,
6605 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
dpapadfd421fb2025-02-13 00:47:326606 r'.+%s' % _HEADER_EXTENSIONS,
6607 r'.+%s' % _WEBUI_FILES_EXTENSIONS)
6608
6609 # Exclude folder that contains .ts files that are actually binary video
6610 # format and not TypeScript.
6611 file_exclusion_pattern = (r'media/test/data/')
mostynbb639aca52015-01-07 20:31:236612
Sam Maiera6e76d72022-02-11 21:43:506613 problems = []
6614 source_file_filter = lambda f: input_api.FilterSourceFile(
dpapadfd421fb2025-02-13 00:47:326615 f, files_to_check=file_inclusion_pattern,
6616 files_to_skip=file_exclusion_pattern)
Sam Maiera6e76d72022-02-11 21:43:506617 for f in input_api.AffectedSourceFiles(source_file_filter):
Bruce Dawson5efbdc652022-04-11 19:29:516618 # Ignore test files that contain crlf intentionally.
6619 if f.LocalPath().endswith('crlf.txt'):
Daniel Chenga37c03db2022-05-12 17:20:346620 continue
Sam Maiera6e76d72022-02-11 21:43:506621 include_file = False
6622 for line in input_api.ReadFile(f, 'r').splitlines(True):
6623 if line.endswith('\r\n'):
6624 include_file = True
6625 if include_file:
6626 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:236627
Sam Maiera6e76d72022-02-11 21:43:506628 if problems:
6629 return [
6630 output_api.PresubmitPromptWarning(
6631 'Are you sure that you want '
6632 'these files to contain Windows style line endings?\n' +
6633 '\n'.join(problems))
6634 ]
mostynbb639aca52015-01-07 20:31:236635
Sam Maiera6e76d72022-02-11 21:43:506636 return []
6637
mostynbb639aca52015-01-07 20:31:236638
Evan Stade6cfc964c12021-05-18 20:21:166639def CheckIconFilesForLicenseHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506640 """Check that .icon files (which are fragments of C++) have license headers.
6641 """
Evan Stade6cfc964c12021-05-18 20:21:166642
Sam Maiera6e76d72022-02-11 21:43:506643 icon_files = (r'.*\.icon$', )
Evan Stade6cfc964c12021-05-18 20:21:166644
Sam Maiera6e76d72022-02-11 21:43:506645 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
6646 return input_api.canned_checks.CheckLicense(input_api,
6647 output_api,
6648 source_file_filter=icons)
6649
Evan Stade6cfc964c12021-05-18 20:21:166650
Jose Magana2b456f22021-03-09 23:26:406651def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506652 """Check source code for use of Chrome App technologies being
6653 deprecated.
6654 """
Jose Magana2b456f22021-03-09 23:26:406655
Sam Maiera6e76d72022-02-11 21:43:506656 def _CheckForDeprecatedTech(input_api,
6657 output_api,
6658 detection_list,
6659 files_to_check=None,
6660 files_to_skip=None):
Jose Magana2b456f22021-03-09 23:26:406661
Sam Maiera6e76d72022-02-11 21:43:506662 if (files_to_check or files_to_skip):
6663 source_file_filter = lambda f: input_api.FilterSourceFile(
6664 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
6665 else:
6666 source_file_filter = None
6667
6668 problems = []
6669
6670 for f in input_api.AffectedSourceFiles(source_file_filter):
6671 if f.Action() == 'D':
6672 continue
6673 for _, line in f.ChangedContents():
6674 if any(detect in line for detect in detection_list):
6675 problems.append(f.LocalPath())
6676
6677 return problems
6678
6679 # to avoid this presubmit script triggering warnings
6680 files_to_skip = ['PRESUBMIT.py', 'PRESUBMIT_test.py']
Jose Magana2b456f22021-03-09 23:26:406681
6682 problems = []
6683
Sam Maiera6e76d72022-02-11 21:43:506684 # NMF: any files with extensions .nmf or NMF
6685 _NMF_FILES = r'\.(nmf|NMF)$'
6686 problems += _CheckForDeprecatedTech(
6687 input_api,
6688 output_api,
6689 detection_list=[''], # any change to the file will trigger warning
6690 files_to_check=[r'.+%s' % _NMF_FILES])
Jose Magana2b456f22021-03-09 23:26:406691
Sam Maiera6e76d72022-02-11 21:43:506692 # MANIFEST: any manifest.json that in its diff includes "app":
6693 _MANIFEST_FILES = r'(manifest\.json)$'
6694 problems += _CheckForDeprecatedTech(
6695 input_api,
6696 output_api,
6697 detection_list=['"app":'],
6698 files_to_check=[r'.*%s' % _MANIFEST_FILES])
Jose Magana2b456f22021-03-09 23:26:406699
Sam Maiera6e76d72022-02-11 21:43:506700 # NaCl / PNaCl: any file that in its diff contains the strings in the list
6701 problems += _CheckForDeprecatedTech(
6702 input_api,
6703 output_api,
6704 detection_list=['config=nacl', 'enable-nacl', 'cpu=pnacl', 'nacl_io'],
Bruce Dawson40fece62022-09-16 19:58:316705 files_to_skip=files_to_skip + [r"^native_client_sdk/"])
Jose Magana2b456f22021-03-09 23:26:406706
Gao Shenga79ebd42022-08-08 17:25:596707 # PPAPI: any C/C++ file that in its diff includes a ppapi library
Sam Maiera6e76d72022-02-11 21:43:506708 problems += _CheckForDeprecatedTech(
6709 input_api,
6710 output_api,
6711 detection_list=['#include "ppapi', '#include <ppapi'],
6712 files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,
6713 r'.+%s' % _IMPLEMENTATION_EXTENSIONS),
Bruce Dawson40fece62022-09-16 19:58:316714 files_to_skip=[r"^ppapi/"])
Jose Magana2b456f22021-03-09 23:26:406715
Sam Maiera6e76d72022-02-11 21:43:506716 if problems:
6717 return [
6718 output_api.PresubmitPromptWarning(
6719 'You are adding/modifying code'
6720 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
6721 ' PNaCl, PPAPI). See this blog post for more details:\n'
6722 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
6723 'and this documentation for options to replace these technologies:\n'
6724 'https://developer.chrome.com/docs/apps/migration/\n' +
6725 '\n'.join(problems))
6726 ]
Jose Magana2b456f22021-03-09 23:26:406727
Sam Maiera6e76d72022-02-11 21:43:506728 return []
Jose Magana2b456f22021-03-09 23:26:406729
mostynbb639aca52015-01-07 20:31:236730
Saagar Sanghavifceeaae2020-08-12 16:40:366731def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
Sam Maiera6e76d72022-02-11 21:43:506732 """Checks that all source files use SYSLOG properly."""
6733 syslog_files = []
6734 for f in input_api.AffectedSourceFiles(src_file_filter):
6735 for line_number, line in f.ChangedContents():
6736 if 'SYSLOG' in line:
6737 syslog_files.append(f.LocalPath() + ':' + str(line_number))
pastarmovj032ba5bc2017-01-12 10:41:566738
Sam Maiera6e76d72022-02-11 21:43:506739 if syslog_files:
6740 return [
6741 output_api.PresubmitPromptWarning(
6742 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
6743 ' calls.\nFiles to check:\n',
6744 items=syslog_files)
6745 ]
6746 return []
pastarmovj89f7ee12016-09-20 14:58:136747
6748
[email protected]1f7b4172010-01-28 01:17:346749def CheckChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506750 if input_api.version < [2, 0, 0]:
6751 return [
6752 output_api.PresubmitError(
6753 "Your depot_tools is out of date. "
6754 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
6755 "but your version is %d.%d.%d" % tuple(input_api.version))
6756 ]
6757 results = []
6758 results.extend(
6759 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
6760 return results
[email protected]ca8d1982009-02-19 16:33:126761
6762
6763def CheckChangeOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506764 if input_api.version < [2, 0, 0]:
6765 return [
6766 output_api.PresubmitError(
6767 "Your depot_tools is out of date. "
6768 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
6769 "but your version is %d.%d.%d" % tuple(input_api.version))
6770 ]
Saagar Sanghavifceeaae2020-08-12 16:40:366771
Sam Maiera6e76d72022-02-11 21:43:506772 results = []
6773 # Make sure the tree is 'open'.
6774 results.extend(
6775 input_api.canned_checks.CheckTreeIsOpen(
6776 input_api,
6777 output_api,
6778 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:276779
Sam Maiera6e76d72022-02-11 21:43:506780 results.extend(
6781 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
6782 results.extend(
6783 input_api.canned_checks.CheckChangeHasBugField(input_api, output_api))
6784 results.extend(
6785 input_api.canned_checks.CheckChangeHasNoUnwantedTags(
6786 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:506787 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146788
6789
Saagar Sanghavifceeaae2020-08-12 16:40:366790def CheckStrings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506791 """Check string ICU syntax validity and if translation screenshots exist."""
6792 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
6793 # footer is set to true.
6794 git_footers = input_api.change.GitFootersFromDescription()
6795 skip_screenshot_check_footer = [
6796 footer.lower() for footer in git_footers.get(
6797 u'Skip-Translation-Screenshots-Check', [])
6798 ]
6799 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:026800
Sam Maiera6e76d72022-02-11 21:43:506801 import os
6802 import re
6803 import sys
6804 from io import StringIO
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146805
Sam Maiera6e76d72022-02-11 21:43:506806 new_or_added_paths = set(f.LocalPath() for f in input_api.AffectedFiles()
6807 if (f.Action() == 'A' or f.Action() == 'M'))
6808 removed_paths = set(f.LocalPath()
6809 for f in input_api.AffectedFiles(include_deletes=True)
6810 if f.Action() == 'D')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146811
Sam Maiera6e76d72022-02-11 21:43:506812 affected_grds = [
6813 f for f in input_api.AffectedFiles()
6814 if f.LocalPath().endswith(('.grd', '.grdp'))
6815 ]
6816 affected_grds = [
6817 f for f in affected_grds if not 'testdata' in f.LocalPath()
6818 ]
6819 if not affected_grds:
6820 return []
meacer8c0d3832019-12-26 21:46:166821
Sam Maiera6e76d72022-02-11 21:43:506822 affected_png_paths = [
Andrew Grieve713b89b2024-10-15 20:20:086823 f.LocalPath() for f in input_api.AffectedFiles()
6824 if f.LocalPath().endswith('.png')
Sam Maiera6e76d72022-02-11 21:43:506825 ]
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146826
Sam Maiera6e76d72022-02-11 21:43:506827 # Check for screenshots. Developers can upload screenshots using
6828 # tools/translation/upload_screenshots.py which finds and uploads
6829 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
6830 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
6831 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
6832 #
6833 # The logic here is as follows:
6834 #
6835 # - If the CL has a .png file under the screenshots directory for a grd
6836 # file, warn the developer. Actual images should never be checked into the
6837 # Chrome repo.
6838 #
6839 # - If the CL contains modified or new messages in grd files and doesn't
6840 # contain the corresponding .sha1 files, warn the developer to add images
6841 # and upload them via tools/translation/upload_screenshots.py.
6842 #
6843 # - If the CL contains modified or new messages in grd files and the
6844 # corresponding .sha1 files, everything looks good.
6845 #
6846 # - If the CL contains removed messages in grd files but the corresponding
6847 # .sha1 files aren't removed, warn the developer to remove them.
6848 unnecessary_screenshots = []
Jens Mueller054652c2023-05-10 15:12:306849 invalid_sha1 = []
Sam Maiera6e76d72022-02-11 21:43:506850 missing_sha1 = []
Bruce Dawson55776c42022-12-09 17:23:476851 missing_sha1_modified = []
Sam Maiera6e76d72022-02-11 21:43:506852 unnecessary_sha1_files = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146853
Sam Maiera6e76d72022-02-11 21:43:506854 # This checks verifies that the ICU syntax of messages this CL touched is
6855 # valid, and reports any found syntax errors.
6856 # Without this presubmit check, ICU syntax errors in Chromium strings can land
6857 # without developers being aware of them. Later on, such ICU syntax errors
6858 # break message extraction for translation, hence would block Chromium
6859 # translations until they are fixed.
6860 icu_syntax_errors = []
Jens Mueller054652c2023-05-10 15:12:306861 sha1_pattern = input_api.re.compile(r'^[a-fA-F0-9]{40}$',
6862 input_api.re.MULTILINE)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146863
Sam Maiera6e76d72022-02-11 21:43:506864 def _CheckScreenshotAdded(screenshots_dir, message_id):
6865 sha1_path = input_api.os_path.join(screenshots_dir,
6866 message_id + '.png.sha1')
6867 if sha1_path not in new_or_added_paths:
6868 missing_sha1.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306869 elif not _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256870 invalid_sha1.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146871
Bruce Dawson55776c42022-12-09 17:23:476872 def _CheckScreenshotModified(screenshots_dir, message_id):
6873 sha1_path = input_api.os_path.join(screenshots_dir,
6874 message_id + '.png.sha1')
6875 if sha1_path not in new_or_added_paths:
6876 missing_sha1_modified.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306877 elif not _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256878 invalid_sha1.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306879
6880 def _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256881 return sha1_pattern.search(
6882 next("\n".join(f.NewContents()) for f in input_api.AffectedFiles()
6883 if f.LocalPath() == sha1_path))
Bruce Dawson55776c42022-12-09 17:23:476884
Sam Maiera6e76d72022-02-11 21:43:506885 def _CheckScreenshotRemoved(screenshots_dir, message_id):
6886 sha1_path = input_api.os_path.join(screenshots_dir,
6887 message_id + '.png.sha1')
6888 if input_api.os_path.exists(
6889 sha1_path) and sha1_path not in removed_paths:
6890 unnecessary_sha1_files.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146891
Sam Maiera6e76d72022-02-11 21:43:506892 def _ValidateIcuSyntax(text, level, signatures):
6893 """Validates ICU syntax of a text string.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146894
Sam Maiera6e76d72022-02-11 21:43:506895 Check if text looks similar to ICU and checks for ICU syntax correctness
6896 in this case. Reports various issues with ICU syntax and values of
6897 variants. Supports checking of nested messages. Accumulate information of
6898 each ICU messages found in the text for further checking.
Rainhard Findlingfc31844c52020-05-15 09:58:266899
Sam Maiera6e76d72022-02-11 21:43:506900 Args:
6901 text: a string to check.
6902 level: a number of current nesting level.
6903 signatures: an accumulator, a list of tuple of (level, variable,
6904 kind, variants).
Rainhard Findlingfc31844c52020-05-15 09:58:266905
Sam Maiera6e76d72022-02-11 21:43:506906 Returns:
6907 None if a string is not ICU or no issue detected.
6908 A tuple of (message, start index, end index) if an issue detected.
6909 """
6910 valid_types = {
6911 'plural': (frozenset(
Rainhard Findling3cde3ef02024-02-05 18:40:326912 ['=0', '=1', '=2', '=3', 'zero', 'one', 'two', 'few', 'many',
Sam Maiera6e76d72022-02-11 21:43:506913 'other']), frozenset(['=1', 'other'])),
6914 'selectordinal': (frozenset(
Rainhard Findling3cde3ef02024-02-05 18:40:326915 ['=0', '=1', '=2', '=3', 'zero', 'one', 'two', 'few', 'many',
Sam Maiera6e76d72022-02-11 21:43:506916 'other']), frozenset(['one', 'other'])),
6917 'select': (frozenset(), frozenset(['other'])),
6918 }
Rainhard Findlingfc31844c52020-05-15 09:58:266919
Sam Maiera6e76d72022-02-11 21:43:506920 # Check if the message looks like an attempt to use ICU
6921 # plural. If yes - check if its syntax strictly matches ICU format.
6922 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b',
6923 text)
6924 if not like:
6925 signatures.append((level, None, None, None))
6926 return
Rainhard Findlingfc31844c52020-05-15 09:58:266927
Sam Maiera6e76d72022-02-11 21:43:506928 # Check for valid prefix and suffix
6929 m = re.match(
6930 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
6931 r'(plural|selectordinal|select),\s*'
6932 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
6933 if not m:
6934 return (('This message looks like an ICU plural, '
6935 'but does not follow ICU syntax.'), like.start(),
6936 like.end())
6937 starting, variable, kind, variant_pairs = m.groups()
6938 variants, depth, last_pos = _ParseIcuVariants(variant_pairs,
6939 m.start(4))
6940 if depth:
6941 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
6942 len(text))
6943 first = text[0]
6944 ending = text[last_pos:]
6945 if not starting:
6946 return ('Invalid ICU format. No initial opening bracket',
6947 last_pos - 1, last_pos)
6948 if not ending or '}' not in ending:
6949 return ('Invalid ICU format. No final closing bracket',
6950 last_pos - 1, last_pos)
6951 elif first != '{':
6952 return ((
6953 'Invalid ICU format. Extra characters at the start of a complex '
6954 'message (go/icu-message-migration): "%s"') % starting, 0,
6955 len(starting))
6956 elif ending != '}':
6957 return ((
6958 'Invalid ICU format. Extra characters at the end of a complex '
6959 'message (go/icu-message-migration): "%s"') % ending,
6960 last_pos - 1, len(text) - 1)
6961 if kind not in valid_types:
6962 return (('Unknown ICU message type %s. '
6963 'Valid types are: plural, select, selectordinal') % kind,
6964 0, 0)
6965 known, required = valid_types[kind]
6966 defined_variants = set()
6967 for variant, variant_range, value, value_range in variants:
6968 start, end = variant_range
6969 if variant in defined_variants:
6970 return ('Variant "%s" is defined more than once' % variant,
6971 start, end)
6972 elif known and variant not in known:
6973 return ('Variant "%s" is not valid for %s message' %
6974 (variant, kind), start, end)
6975 defined_variants.add(variant)
6976 # Check for nested structure
6977 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
6978 if res:
6979 return (res[0], res[1] + value_range[0] + 1,
6980 res[2] + value_range[0] + 1)
6981 missing = required - defined_variants
6982 if missing:
6983 return ('Required variants missing: %s' % ', '.join(missing), 0,
6984 len(text))
6985 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:266986
Sam Maiera6e76d72022-02-11 21:43:506987 def _ParseIcuVariants(text, offset=0):
6988 """Parse variants part of ICU complex message.
Rainhard Findlingfc31844c52020-05-15 09:58:266989
Sam Maiera6e76d72022-02-11 21:43:506990 Builds a tuple of variant names and values, as well as
6991 their offsets in the input string.
Rainhard Findlingfc31844c52020-05-15 09:58:266992
Sam Maiera6e76d72022-02-11 21:43:506993 Args:
6994 text: a string to parse
6995 offset: additional offset to add to positions in the text to get correct
6996 position in the complete ICU string.
Rainhard Findlingfc31844c52020-05-15 09:58:266997
Sam Maiera6e76d72022-02-11 21:43:506998 Returns:
6999 List of tuples, each tuple consist of four fields: variant name,
7000 variant name span (tuple of two integers), variant value, value
7001 span (tuple of two integers).
7002 """
7003 depth, start, end = 0, -1, -1
7004 variants = []
7005 key = None
7006 for idx, char in enumerate(text):
7007 if char == '{':
7008 if not depth:
7009 start = idx
7010 chunk = text[end + 1:start]
7011 key = chunk.strip()
7012 pos = offset + end + 1 + chunk.find(key)
7013 span = (pos, pos + len(key))
7014 depth += 1
7015 elif char == '}':
7016 if not depth:
7017 return variants, depth, offset + idx
7018 depth -= 1
7019 if not depth:
7020 end = idx
7021 variants.append((key, span, text[start:end + 1],
7022 (offset + start, offset + end + 1)))
7023 return variants, depth, offset + end + 1
Rainhard Findlingfc31844c52020-05-15 09:58:267024
Terrence Reilly313f44ff2025-01-22 15:10:147025 old_sys_path = sys.path
Sam Maiera6e76d72022-02-11 21:43:507026 try:
Sam Maiera6e76d72022-02-11 21:43:507027 sys.path = sys.path + [
7028 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
7029 'translation')
7030 ]
7031 from helper import grd_helper
7032 finally:
7033 sys.path = old_sys_path
Rainhard Findlingfc31844c52020-05-15 09:58:267034
Sam Maiera6e76d72022-02-11 21:43:507035 for f in affected_grds:
7036 file_path = f.LocalPath()
7037 old_id_to_msg_map = {}
7038 new_id_to_msg_map = {}
7039 # Note that this code doesn't check if the file has been deleted. This is
7040 # OK because it only uses the old and new file contents and doesn't load
7041 # the file via its path.
7042 # It's also possible that a file's content refers to a renamed or deleted
7043 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
7044 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
7045 # .grdp files.
7046 if file_path.endswith('.grdp'):
7047 if f.OldContents():
7048 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
7049 '\n'.join(f.OldContents()))
7050 if f.NewContents():
7051 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
7052 '\n'.join(f.NewContents()))
7053 else:
7054 file_dir = input_api.os_path.dirname(file_path) or '.'
7055 if f.OldContents():
7056 old_id_to_msg_map = grd_helper.GetGrdMessages(
7057 StringIO('\n'.join(f.OldContents())), file_dir)
7058 if f.NewContents():
7059 new_id_to_msg_map = grd_helper.GetGrdMessages(
7060 StringIO('\n'.join(f.NewContents())), file_dir)
Rainhard Findlingfc31844c52020-05-15 09:58:267061
Sam Maiera6e76d72022-02-11 21:43:507062 grd_name, ext = input_api.os_path.splitext(
7063 input_api.os_path.basename(file_path))
7064 screenshots_dir = input_api.os_path.join(
7065 input_api.os_path.dirname(file_path),
7066 grd_name + ext.replace('.', '_'))
Rainhard Findlingfc31844c52020-05-15 09:58:267067
Sam Maiera6e76d72022-02-11 21:43:507068 # Compute added, removed and modified message IDs.
7069 old_ids = set(old_id_to_msg_map)
7070 new_ids = set(new_id_to_msg_map)
7071 added_ids = new_ids - old_ids
7072 removed_ids = old_ids - new_ids
7073 modified_ids = set([])
7074 for key in old_ids.intersection(new_ids):
7075 if (old_id_to_msg_map[key].ContentsAsXml('', True) !=
7076 new_id_to_msg_map[key].ContentsAsXml('', True)):
7077 # The message content itself changed. Require an updated screenshot.
7078 modified_ids.add(key)
7079 elif old_id_to_msg_map[key].attrs['meaning'] != \
7080 new_id_to_msg_map[key].attrs['meaning']:
Jens Mueller054652c2023-05-10 15:12:307081 # The message meaning changed. We later check for a screenshot.
7082 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147083
Sam Maiera6e76d72022-02-11 21:43:507084 if run_screenshot_check:
7085 # Check the screenshot directory for .png files. Warn if there is any.
7086 for png_path in affected_png_paths:
7087 if png_path.startswith(screenshots_dir):
7088 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147089
Sam Maiera6e76d72022-02-11 21:43:507090 for added_id in added_ids:
7091 _CheckScreenshotAdded(screenshots_dir, added_id)
Rainhard Findlingd8d04372020-08-13 13:30:097092
Sam Maiera6e76d72022-02-11 21:43:507093 for modified_id in modified_ids:
Bruce Dawson55776c42022-12-09 17:23:477094 _CheckScreenshotModified(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147095
Sam Maiera6e76d72022-02-11 21:43:507096 for removed_id in removed_ids:
7097 _CheckScreenshotRemoved(screenshots_dir, removed_id)
7098
7099 # Check new and changed strings for ICU syntax errors.
7100 for key in added_ids.union(modified_ids):
7101 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
7102 err = _ValidateIcuSyntax(msg, 0, [])
7103 if err is not None:
7104 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
7105
7106 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:267107 if run_screenshot_check:
Sam Maiera6e76d72022-02-11 21:43:507108 if unnecessary_screenshots:
7109 results.append(
7110 output_api.PresubmitError(
7111 'Do not include actual screenshots in the changelist. Run '
7112 'tools/translate/upload_screenshots.py to upload them instead:',
7113 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147114
Sam Maiera6e76d72022-02-11 21:43:507115 if missing_sha1:
7116 results.append(
7117 output_api.PresubmitError(
Bruce Dawson55776c42022-12-09 17:23:477118 'You are adding UI strings.\n'
Sam Maiera6e76d72022-02-11 21:43:507119 'To ensure the best translations, take screenshots of the relevant UI '
7120 '(https://g.co/chrome/translation) and add these files to your '
7121 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147122
Jens Mueller054652c2023-05-10 15:12:307123 if invalid_sha1:
7124 results.append(
7125 output_api.PresubmitError(
7126 'The following files do not seem to contain valid sha1 hashes. '
7127 'Make sure they contain hashes created by '
7128 'tools/translate/upload_screenshots.py:', sorted(invalid_sha1)))
7129
Bruce Dawson55776c42022-12-09 17:23:477130 if missing_sha1_modified:
7131 results.append(
7132 output_api.PresubmitError(
7133 'You are modifying UI strings or their meanings.\n'
7134 'To ensure the best translations, take screenshots of the relevant UI '
7135 '(https://g.co/chrome/translation) and add these files to your '
7136 'changelist:', sorted(missing_sha1_modified)))
7137
Sam Maiera6e76d72022-02-11 21:43:507138 if unnecessary_sha1_files:
7139 results.append(
7140 output_api.PresubmitError(
7141 'You removed strings associated with these files. Remove:',
7142 sorted(unnecessary_sha1_files)))
7143 else:
7144 results.append(
7145 output_api.PresubmitPromptOrNotify('Skipping translation '
7146 'screenshots check.'))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147147
Sam Maiera6e76d72022-02-11 21:43:507148 if icu_syntax_errors:
7149 results.append(
7150 output_api.PresubmitPromptWarning(
7151 'ICU syntax errors were found in the following strings (problems or '
7152 'feedback? Contact [email protected]):',
7153 items=icu_syntax_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:267154
Sam Maiera6e76d72022-02-11 21:43:507155 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:127156
7157
Saagar Sanghavifceeaae2020-08-12 16:40:367158def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:127159 repo_root=None,
7160 translation_expectations_path=None,
7161 grd_files=None):
Sam Maiera6e76d72022-02-11 21:43:507162 import sys
7163 affected_grds = [
7164 f for f in input_api.AffectedFiles()
7165 if (f.LocalPath().endswith('.grd') or f.LocalPath().endswith('.grdp'))
7166 ]
7167 if not affected_grds:
7168 return []
7169
Terrence Reilly313f44ff2025-01-22 15:10:147170 old_sys_path = sys.path
Sam Maiera6e76d72022-02-11 21:43:507171 try:
Sam Maiera6e76d72022-02-11 21:43:507172 sys.path = sys.path + [
7173 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
7174 'translation')
7175 ]
Terrence Reilly313f44ff2025-01-22 15:10:147176 sys.path = sys.path + [
7177 input_api.os_path.join(input_api.PresubmitLocalPath(),
7178 'third_party', 'depot_tools')
7179 ]
Sam Maiera6e76d72022-02-11 21:43:507180 from helper import git_helper
7181 from helper import translation_helper
Terrence Reilly313f44ff2025-01-22 15:10:147182 import gclient_utils
Sam Maiera6e76d72022-02-11 21:43:507183 finally:
7184 sys.path = old_sys_path
7185
7186 # Check that translation expectations can be parsed and we can get a list of
7187 # translatable grd files. |repo_root| and |translation_expectations_path| are
7188 # only passed by tests.
7189 if not repo_root:
7190 repo_root = input_api.PresubmitLocalPath()
7191 if not translation_expectations_path:
7192 translation_expectations_path = input_api.os_path.join(
7193 repo_root, 'tools', 'gritsettings', 'translation_expectations.pyl')
Terrence Reilly313f44ff2025-01-22 15:10:147194 is_cog = gclient_utils.IsEnvCog()
7195 # Git is not available in cog workspaces.
7196 if not grd_files and not is_cog:
Sam Maiera6e76d72022-02-11 21:43:507197 grd_files = git_helper.list_grds_in_repository(repo_root)
Terrence Reilly313f44ff2025-01-22 15:10:147198 if not grd_files:
7199 grd_files = []
Sam Maiera6e76d72022-02-11 21:43:507200
7201 # Ignore bogus grd files used only for testing
Gao Shenga79ebd42022-08-08 17:25:597202 # ui/webui/resources/tools/generate_grd.py.
Sam Maiera6e76d72022-02-11 21:43:507203 ignore_path = input_api.os_path.join('ui', 'webui', 'resources', 'tools',
7204 'tests')
7205 grd_files = [p for p in grd_files if ignore_path not in p]
7206
Ben Mason5d4c3242025-04-15 20:28:377207 # Ensure no duplicate basenames.
7208 basename_to_src_paths = {}
7209 for grd_path in grd_files:
7210 basename = input_api.os_path.basename(grd_path)
7211 basename_to_src_paths.setdefault(basename, [])
7212 basename_to_src_paths[basename].append(grd_path)
7213 for src_paths in basename_to_src_paths.values():
7214 if len(src_paths) > 1:
7215 return [
7216 output_api.PresubmitNotifyResult(
7217 'Multiple string files have the same basename. This will result in '
7218 'missing translations. Files: %s'
7219 % ', '.join(src_paths))
7220 ]
7221
Sam Maiera6e76d72022-02-11 21:43:507222 try:
7223 translation_helper.get_translatable_grds(
Terrence Reilly313f44ff2025-01-22 15:10:147224 repo_root, grd_files, translation_expectations_path, is_cog)
Sam Maiera6e76d72022-02-11 21:43:507225 except Exception as e:
7226 return [
7227 output_api.PresubmitNotifyResult(
7228 'Failed to get a list of translatable grd files. This happens when:\n'
7229 ' - One of the modified grd or grdp files cannot be parsed or\n'
7230 ' - %s is not updated.\n'
7231 'Stack:\n%s' % (translation_expectations_path, str(e)))
7232 ]
Mustafa Emre Acer51f2f742020-03-09 19:41:127233 return []
7234
Ken Rockotc31f4832020-05-29 18:58:517235
Saagar Sanghavifceeaae2020-08-12 16:40:367236def CheckStableMojomChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507237 """Changes to [Stable] mojom types must preserve backward-compatibility."""
7238 changed_mojoms = input_api.AffectedFiles(
7239 include_deletes=True,
7240 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:527241
Bruce Dawson344ab262022-06-04 11:35:107242 if not changed_mojoms or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:507243 return []
7244
7245 delta = []
7246 for mojom in changed_mojoms:
Sam Maiera6e76d72022-02-11 21:43:507247 delta.append({
7248 'filename': mojom.LocalPath(),
7249 'old': '\n'.join(mojom.OldContents()) or None,
7250 'new': '\n'.join(mojom.NewContents()) or None,
7251 })
7252
7253 process = input_api.subprocess.Popen([
Takuto Ikutadca10222022-04-13 02:51:217254 input_api.python3_executable,
Sam Maiera6e76d72022-02-11 21:43:507255 input_api.os_path.join(
7256 input_api.PresubmitLocalPath(), 'mojo', 'public', 'tools', 'mojom',
7257 'check_stable_mojom_compatibility.py'), '--src-root',
7258 input_api.PresubmitLocalPath()
7259 ],
7260 stdin=input_api.subprocess.PIPE,
7261 stdout=input_api.subprocess.PIPE,
7262 stderr=input_api.subprocess.PIPE,
7263 universal_newlines=True)
7264 (x, error) = process.communicate(input=input_api.json.dumps(delta))
7265 if process.returncode:
7266 return [
7267 output_api.PresubmitError(
7268 'One or more [Stable] mojom definitions appears to have been changed '
Alex Goughc99921652024-02-15 22:59:127269 'in a way that is not backward-compatible. See '
7270 'https://chromium.googlesource.com/chromium/src/+/HEAD/mojo/public/tools/bindings/README.md#versioning'
7271 ' for details.',
Sam Maiera6e76d72022-02-11 21:43:507272 long_text=error)
7273 ]
Erik Staabc734cd7a2021-11-23 03:11:527274 return []
7275
Dominic Battre645d42342020-12-04 16:14:107276def CheckDeprecationOfPreferences(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507277 """Removing a preference should come with a deprecation."""
Dominic Battre645d42342020-12-04 16:14:107278
Sam Maiera6e76d72022-02-11 21:43:507279 def FilterFile(affected_file):
7280 """Accept only .cc files and the like."""
7281 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
7282 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
7283 input_api.DEFAULT_FILES_TO_SKIP)
7284 return input_api.FilterSourceFile(
7285 affected_file,
7286 files_to_check=file_inclusion_pattern,
7287 files_to_skip=files_to_skip)
Dominic Battre645d42342020-12-04 16:14:107288
Sam Maiera6e76d72022-02-11 21:43:507289 def ModifiedLines(affected_file):
7290 """Returns a list of tuples (line number, line text) of added and removed
7291 lines.
Dominic Battre645d42342020-12-04 16:14:107292
Sam Maiera6e76d72022-02-11 21:43:507293 Deleted lines share the same line number as the previous line.
Dominic Battre645d42342020-12-04 16:14:107294
Sam Maiera6e76d72022-02-11 21:43:507295 This relies on the scm diff output describing each changed code section
7296 with a line of the form
Dominic Battre645d42342020-12-04 16:14:107297
Sam Maiera6e76d72022-02-11 21:43:507298 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
7299 """
7300 line_num = 0
7301 modified_lines = []
7302 for line in affected_file.GenerateScmDiff().splitlines():
7303 # Extract <new line num> of the patch fragment (see format above).
7304 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@',
7305 line)
7306 if m:
7307 line_num = int(m.groups(1)[0])
7308 continue
7309 if ((line.startswith('+') and not line.startswith('++'))
7310 or (line.startswith('-') and not line.startswith('--'))):
7311 modified_lines.append((line_num, line))
Dominic Battre645d42342020-12-04 16:14:107312
Sam Maiera6e76d72022-02-11 21:43:507313 if not line.startswith('-'):
7314 line_num += 1
7315 return modified_lines
Dominic Battre645d42342020-12-04 16:14:107316
Sam Maiera6e76d72022-02-11 21:43:507317 def FindLineWith(lines, needle):
7318 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
Dominic Battre645d42342020-12-04 16:14:107319
Sam Maiera6e76d72022-02-11 21:43:507320 If 0 or >1 lines contain `needle`, -1 is returned.
7321 """
7322 matching_line_numbers = [
7323 # + 1 for 1-based counting of line numbers.
7324 i + 1 for i, line in enumerate(lines) if needle in line
7325 ]
7326 return matching_line_numbers[0] if len(
7327 matching_line_numbers) == 1 else -1
Dominic Battre645d42342020-12-04 16:14:107328
Sam Maiera6e76d72022-02-11 21:43:507329 def ModifiedPrefMigration(affected_file):
7330 """Returns whether the MigrateObsolete.*Pref functions were modified."""
7331 # Determine first and last lines of MigrateObsolete.*Pref functions.
7332 new_contents = affected_file.NewContents()
7333 range_1 = (FindLineWith(new_contents,
7334 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
7335 FindLineWith(new_contents,
7336 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
7337 range_2 = (FindLineWith(new_contents,
7338 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
7339 FindLineWith(new_contents,
7340 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
7341 if (-1 in range_1 + range_2):
7342 raise Exception(
7343 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.'
7344 )
Dominic Battre645d42342020-12-04 16:14:107345
Sam Maiera6e76d72022-02-11 21:43:507346 # Check whether any of the modified lines are part of the
7347 # MigrateObsolete.*Pref functions.
7348 for line_nr, line in ModifiedLines(affected_file):
7349 if (range_1[0] <= line_nr <= range_1[1]
7350 or range_2[0] <= line_nr <= range_2[1]):
7351 return True
7352 return False
Dominic Battre645d42342020-12-04 16:14:107353
Sam Maiera6e76d72022-02-11 21:43:507354 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
7355 browser_prefs_file_pattern = input_api.re.compile(
7356 r'chrome/browser/prefs/browser_prefs.cc')
Dominic Battre645d42342020-12-04 16:14:107357
Sam Maiera6e76d72022-02-11 21:43:507358 changes = input_api.AffectedFiles(include_deletes=True,
7359 file_filter=FilterFile)
7360 potential_problems = []
7361 for f in changes:
7362 for line in f.GenerateScmDiff().splitlines():
7363 # Check deleted lines for pref registrations.
7364 if (line.startswith('-') and not line.startswith('--')
7365 and register_pref_pattern.search(line)):
7366 potential_problems.append('%s: %s' % (f.LocalPath(), line))
Dominic Battre645d42342020-12-04 16:14:107367
Sam Maiera6e76d72022-02-11 21:43:507368 if browser_prefs_file_pattern.search(f.LocalPath()):
7369 # If the developer modified the MigrateObsolete.*Prefs() functions, we
7370 # assume that they knew that they have to deprecate preferences and don't
7371 # warn.
7372 try:
7373 if ModifiedPrefMigration(f):
7374 return []
7375 except Exception as e:
7376 return [output_api.PresubmitError(str(e))]
Dominic Battre645d42342020-12-04 16:14:107377
Sam Maiera6e76d72022-02-11 21:43:507378 if potential_problems:
7379 return [
7380 output_api.PresubmitPromptWarning(
7381 'Discovered possible removal of preference registrations.\n\n'
7382 'Please make sure to properly deprecate preferences by clearing their\n'
7383 'value for a couple of milestones before finally removing the code.\n'
7384 'Otherwise data may stay in the preferences files forever. See\n'
7385 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
7386 'chrome/browser/prefs/README.md for examples.\n'
7387 'This may be a false positive warning (e.g. if you move preference\n'
7388 'registrations to a different place).\n', potential_problems)
7389 ]
7390 return []
7391
Matt Stark6ef08872021-07-29 01:21:467392
7393def CheckConsistentGrdChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507394 """Changes to GRD files must be consistent for tools to read them."""
7395 changed_grds = input_api.AffectedFiles(
7396 include_deletes=False,
7397 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
7398 errors = []
7399 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
7400 for matcher, msg in _INVALID_GRD_FILE_LINE]
7401 for grd in changed_grds:
7402 for i, line in enumerate(grd.NewContents()):
7403 for matcher, msg in invalid_file_regexes:
7404 if matcher.search(line):
7405 errors.append(
7406 output_api.PresubmitError(
7407 'Problem on {grd}:{i} - {msg}'.format(
7408 grd=grd.LocalPath(), i=i + 1, msg=msg)))
7409 return errors
7410
Kevin McNee967dd2d22021-11-15 16:09:297411
Henrique Ferreiro2a4b55942021-11-29 23:45:367412def CheckAssertAshOnlyCode(input_api, output_api):
7413 """Errors if a BUILD.gn file in an ash/ directory doesn't include
Georg Neis94f87f02024-10-22 08:20:137414 assert(is_chromeos).
7415 For a transition period, assert(is_chromeos_ash) is also accepted.
Henrique Ferreiro2a4b55942021-11-29 23:45:367416 """
7417
7418 def FileFilter(affected_file):
7419 """Includes directories known to be Ash only."""
7420 return input_api.FilterSourceFile(
7421 affected_file,
7422 files_to_check=(
7423 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
7424 r'.*/ash/.*BUILD\.gn'), # Any path component.
7425 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
7426
7427 errors = []
Georg Neis94f87f02024-10-22 08:20:137428 pattern = input_api.re.compile(r'assert\(is_chromeos(_ash)?\b')
Jameson Thies0ce669f2021-12-09 15:56:567429 for f in input_api.AffectedFiles(include_deletes=False,
7430 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:367431 if (not pattern.search(input_api.ReadFile(f))):
7432 errors.append(
7433 output_api.PresubmitError(
Georg Neis94f87f02024-10-22 08:20:137434 'Please add assert(is_chromeos) to %s. If that\'s not '
7435 'possible, please create an issue and add a comment such '
Alison Galed6b25fe2024-04-17 13:59:047436 'as:\n # TODO(crbug.com/XXX): add '
Georg Neis94f87f02024-10-22 08:20:137437 'assert(is_chromeos) when ...' % f.LocalPath()))
Henrique Ferreiro2a4b55942021-11-29 23:45:367438 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:277439
7440
Kalvin Lee84ad17a2023-09-25 11:14:417441def _IsMiraclePtrDisallowed(input_api, affected_file):
Anton Bershanskyi4253349482025-02-11 21:01:277442 path = affected_file.UnixLocalPath()
Sam Maiera6e76d72022-02-11 21:43:507443 if not _IsCPlusPlusFile(input_api, path):
7444 return False
7445
Bartek Nowierski49b1a452024-06-08 00:24:357446 # Renderer-only code is generally allowed to use MiraclePtr. These
7447 # directories, however, are specifically disallowed, for perf reasons.
Kalvin Lee84ad17a2023-09-25 11:14:417448 if ("third_party/blink/renderer/core/" in path
7449 or "third_party/blink/renderer/platform/heap/" in path
Bartek Nowierski49b1a452024-06-08 00:24:357450 or "third_party/blink/renderer/platform/wtf/" in path
7451 or "third_party/blink/renderer/platform/fonts/" in path):
7452 return True
7453
7454 # The below paths are an explicitly listed subset of Renderer-only code,
7455 # because the plan is to Oilpanize it.
7456 # TODO(crbug.com/330759291): Remove once Oilpanization is completed or
7457 # abandoned.
7458 if ("third_party/blink/renderer/core/paint/" in path
7459 or "third_party/blink/renderer/platform/graphics/compositing/" in path
7460 or "third_party/blink/renderer/platform/graphics/paint/" in path):
Sam Maiera6e76d72022-02-11 21:43:507461 return True
7462
Sam Maiera6e76d72022-02-11 21:43:507463 # We assume that everything else may be used outside of Renderer processes.
Lukasz Anforowicz7016d05e2021-11-30 03:56:277464 return False
7465
Alison Galed6b25fe2024-04-17 13:59:047466# TODO(crbug.com/40206238): Remove these checks, once they are replaced
Lukasz Anforowicz7016d05e2021-11-30 03:56:277467# by the Chromium Clang Plugin (which will be preferable because it will
7468# 1) report errors earlier - at compile-time and 2) cover more rules).
7469def CheckRawPtrUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507470 """Rough checks that raw_ptr<T> usage guidelines are followed."""
7471 errors = []
7472 # The regex below matches "raw_ptr<" following a word boundary, but not in a
7473 # C++ comment.
7474 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
Kalvin Lee84ad17a2023-09-25 11:14:417475 file_filter = lambda f: _IsMiraclePtrDisallowed(input_api, f)
Sam Maiera6e76d72022-02-11 21:43:507476 for f, line_num, line in input_api.RightHandSideLines(file_filter):
7477 if raw_ptr_matcher.search(line):
7478 errors.append(
7479 output_api.PresubmitError(
7480 'Problem on {path}:{line} - '\
Kalvin Lee84ad17a2023-09-25 11:14:417481 'raw_ptr<T> should not be used in this renderer code '\
Sam Maiera6e76d72022-02-11 21:43:507482 '(as documented in the "Pointers to unprotected memory" '\
7483 'section in //base/memory/raw_ptr.md)'.format(
7484 path=f.LocalPath(), line=line_num)))
7485 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:567486
mikt9337567c2023-09-08 18:38:177487def CheckAdvancedMemorySafetyChecksUsage(input_api, output_api):
7488 """Checks that ADVANCED_MEMORY_SAFETY_CHECKS() macro is neither added nor
7489 removed as it is managed by the memory safety team internally.
7490 Do not add / remove it manually."""
7491 paths = set([])
7492 # The regex below matches "ADVANCED_MEMORY_SAFETY_CHECKS(" following a word
7493 # boundary, but not in a C++ comment.
7494 macro_matcher = input_api.re.compile(
7495 r'^((?!//).)*\bADVANCED_MEMORY_SAFETY_CHECKS\(', input_api.re.MULTILINE)
7496 for f in input_api.AffectedFiles():
7497 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
7498 continue
7499 if macro_matcher.search(f.GenerateScmDiff()):
7500 paths.add(f.LocalPath())
7501 if not paths:
7502 return []
7503 return [output_api.PresubmitPromptWarning(
7504 'ADVANCED_MEMORY_SAFETY_CHECKS() macro is managed by ' \
7505 'the memory safety team (chrome-memory-safety@). ' \
7506 'Please contact us to add/delete the uses of the macro.',
7507 paths)]
Henrique Ferreirof9819f2e32021-11-30 13:31:567508
7509def CheckPythonShebang(input_api, output_api):
7510 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
7511 system-wide python.
7512 """
7513 errors = []
7514 sources = lambda affected_file: input_api.FilterSourceFile(
7515 affected_file,
7516 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
7517 r'third_party/blink/web_tests/external/') + input_api.
7518 DEFAULT_FILES_TO_SKIP),
7519 files_to_check=[r'.*\.py$'])
7520 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:277521 for line_num, line in f.ChangedContents():
7522 if line_num == 1 and line.startswith('#!/usr/bin/python'):
7523 errors.append(f.LocalPath())
7524 break
Henrique Ferreirof9819f2e32021-11-30 13:31:567525
7526 result = []
7527 for file in errors:
7528 result.append(
7529 output_api.PresubmitError(
7530 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
7531 file))
7532 return result
James Shen81cc0e22022-06-15 21:10:457533
7534
Andrew Grieve5a66ae72024-12-13 15:21:537535def CheckAndroidTestAnnotations(input_api, output_api):
James Shen81cc0e22022-06-15 21:10:457536 """Checks that tests have either @Batch or @DoNotBatch annotation. If this
7537 is not an instrumentation test, disregard."""
7538
7539 batch_annotation = input_api.re.compile(r'^\s*@Batch')
7540 do_not_batch_annotation = input_api.re.compile(r'^\s*@DoNotBatch')
Andrew Grieve5a66ae72024-12-13 15:21:537541 robolectric_test = input_api.re.compile(r'@RunWith\((.*?)RobolectricTestRunner')
James Shen81cc0e22022-06-15 21:10:457542 test_class_declaration = input_api.re.compile(r'^\s*public\sclass.*Test')
7543 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
Mark Schillaci8ef0d872023-07-18 22:07:597544 test_annotation_declaration = input_api.re.compile(r'^\s*public\s@interface\s.*{')
James Shen81cc0e22022-06-15 21:10:457545
ckitagawae8fd23b2022-06-17 15:29:387546 missing_annotation_errors = []
7547 extra_annotation_errors = []
Andrew Grieve5a66ae72024-12-13 15:21:537548 wrong_robolectric_test_runner_errors = []
James Shen81cc0e22022-06-15 21:10:457549
7550 def _FilterFile(affected_file):
7551 return input_api.FilterSourceFile(
7552 affected_file,
7553 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
7554 files_to_check=[r'.*Test\.java$'])
7555
7556 for f in input_api.AffectedSourceFiles(_FilterFile):
7557 batch_matched = None
7558 do_not_batch_matched = None
7559 is_instrumentation_test = True
Mark Schillaci8ef0d872023-07-18 22:07:597560 test_annotation_declaration_matched = None
Andrew Grieve5a66ae72024-12-13 15:21:537561 has_base_robolectric_rule = False
James Shen81cc0e22022-06-15 21:10:457562 for line in f.NewContents():
Andrew Grieve5a66ae72024-12-13 15:21:537563 if 'BaseRobolectricTestRule' in line:
7564 has_base_robolectric_rule = True
7565 continue
7566 if m := robolectric_test.search(line):
7567 is_instrumentation_test = False
7568 if m.group(1) == '' and not has_base_robolectric_rule:
Yiwei Zhang5341bf02025-03-20 16:34:137569 path = str(f.LocalPath())
7570 # These two spots cannot use it.
7571 if 'webapk' not in path and 'build' not in path:
7572 wrong_robolectric_test_runner_errors.append(path)
Andrew Grieve5a66ae72024-12-13 15:21:537573 break
7574 if uiautomator_test.search(line):
James Shen81cc0e22022-06-15 21:10:457575 is_instrumentation_test = False
7576 break
7577 if not batch_matched:
7578 batch_matched = batch_annotation.search(line)
7579 if not do_not_batch_matched:
7580 do_not_batch_matched = do_not_batch_annotation.search(line)
7581 test_class_declaration_matched = test_class_declaration.search(
7582 line)
Mark Schillaci8ef0d872023-07-18 22:07:597583 test_annotation_declaration_matched = test_annotation_declaration.search(line)
7584 if test_class_declaration_matched or test_annotation_declaration_matched:
James Shen81cc0e22022-06-15 21:10:457585 break
Mark Schillaci8ef0d872023-07-18 22:07:597586 if test_annotation_declaration_matched:
7587 continue
James Shen81cc0e22022-06-15 21:10:457588 if (is_instrumentation_test and
7589 not batch_matched and
7590 not do_not_batch_matched):
Sam Maier4cef9242022-10-03 14:21:247591 missing_annotation_errors.append(str(f.LocalPath()))
ckitagawae8fd23b2022-06-17 15:29:387592 if (not is_instrumentation_test and
7593 (batch_matched or
7594 do_not_batch_matched)):
Sam Maier4cef9242022-10-03 14:21:247595 extra_annotation_errors.append(str(f.LocalPath()))
James Shen81cc0e22022-06-15 21:10:457596
7597 results = []
7598
ckitagawae8fd23b2022-06-17 15:29:387599 if missing_annotation_errors:
James Shen81cc0e22022-06-15 21:10:457600 results.append(
7601 output_api.PresubmitPromptWarning(
7602 """
Andrew Grieve43a5cf82023-09-08 15:09:467603A change was made to an on-device test that has neither been annotated with
7604@Batch nor @DoNotBatch. If this is a new test, please add the annotation. If
7605this is an existing test, please consider adding it if you are sufficiently
7606familiar with the test (but do so as a separate change).
7607
Jens Mueller2085ff82023-02-27 11:54:497608See https://source.chromium.org/chromium/chromium/src/+/main:docs/testing/batching_instrumentation_tests.md
ckitagawae8fd23b2022-06-17 15:29:387609""", missing_annotation_errors))
7610 if extra_annotation_errors:
7611 results.append(
7612 output_api.PresubmitPromptWarning(
7613 """
7614Robolectric tests do not need a @Batch or @DoNotBatch annotations.
7615""", extra_annotation_errors))
Andrew Grieve5a66ae72024-12-13 15:21:537616 if wrong_robolectric_test_runner_errors:
7617 results.append(
7618 output_api.PresubmitPromptWarning(
7619 """
Wenyu Fu0005ab82025-01-03 18:13:267620Robolectric tests should use either @RunWith(BaseRobolectricTestRunner.class) (or
Andrew Grieve5a66ae72024-12-13 15:21:537621a subclass of it), or use "@Rule BaseRobolectricTestRule".
7622""", wrong_robolectric_test_runner_errors))
James Shen81cc0e22022-06-15 21:10:457623
7624 return results
Sam Maier4cef9242022-10-03 14:21:247625
7626
Henrique Nakashima224ee2482025-03-21 18:35:027627def _CheckAndroidNullAwayAnnotatedClasses(input_api, output_api):
7628 """Checks that Java classes/interfaces/annotations are null-annotated."""
7629
Henrique Nakashima2bdd8ad2025-04-08 18:24:577630 # Temporary, crbug.com/389129271
7631 if input_api.change.RepositoryRoot().endswith('clank'):
7632 return []
7633
Henrique Nakashima224ee2482025-03-21 18:35:027634 nullmarked_annotation = input_api.re.compile(r'^\s*@(NullMarked|NullUnmarked)')
7635
7636 missing_annotation_errors = []
7637
7638 def _FilterFile(affected_file):
7639 return input_api.FilterSourceFile(
7640 affected_file,
7641 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
7642 DEFAULT_FILES_TO_SKIP + (
7643 r'.*Test.*\.java',
7644 r'^android_webview/.*', # Temporary, crbug.com/389129271
7645 r'^build/.*',
Henrique Nakashimaf0a604802025-04-17 14:10:347646 r'^chrome/android/.*', # Temporary, crbug.com/389129271
Henrique Nakashima224ee2482025-03-21 18:35:027647 r'^chromecast/.*',
7648 r'^components/cronet/.*',
7649 r'^tools/.*',
7650 )),
7651 files_to_check=[r'.*\.java$'])
7652
7653 for f in input_api.AffectedSourceFiles(_FilterFile):
Henrique Nakashimac6605432025-04-24 18:11:597654 if f.Action() != 'A':
7655 continue
Henrique Nakashima224ee2482025-03-21 18:35:027656 for line in f.NewContents():
7657 if nullmarked_annotation.search(line):
7658 break
7659 else:
7660 missing_annotation_errors.append(str(f.LocalPath()))
7661
7662 results = []
7663
7664 if missing_annotation_errors:
7665 results.append(
Henrique Nakashima8bafbc52025-04-22 19:38:427666 output_api.PresubmitError(
Henrique Nakashima224ee2482025-03-21 18:35:027667 """
7668Please add @NullMarked and fix the NullAway warnings in the following files
7669(see https://chromium.googlesource.com/chromium/src/+/main/styleguide/java/nullaway.md):
7670""", missing_annotation_errors))
7671
7672 return results
7673
7674
Mike Dougherty1b8be712022-10-20 00:15:137675def CheckNoJsInIos(input_api, output_api):
7676 """Checks to make sure that JavaScript files are not used on iOS."""
7677
7678 def _FilterFile(affected_file):
7679 return input_api.FilterSourceFile(
7680 affected_file,
7681 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP +
Daniel White44b8bd02023-08-22 16:20:367682 (r'^ios/third_party/*', r'^ios/tools/*', r'^third_party/*',
7683 r'^components/autofill/ios/form_util/resources/*'),
Mike Dougherty1b8be712022-10-20 00:15:137684 files_to_check=[r'^ios/.*\.js$', r'.*/ios/.*\.js$'])
7685
Mike Dougherty4d1050b2023-03-14 15:59:537686 deleted_files = []
7687
7688 # Collect filenames of all removed JS files.
Arthur Sonzognic66e9c82024-04-23 07:53:047689 for f in input_api.AffectedFiles(file_filter=_FilterFile):
Mike Dougherty4d1050b2023-03-14 15:59:537690 local_path = f.LocalPath()
7691
7692 if input_api.os_path.splitext(local_path)[1] == '.js' and f.Action() == 'D':
7693 deleted_files.append(input_api.os_path.basename(local_path))
7694
Mike Dougherty1b8be712022-10-20 00:15:137695 error_paths = []
Mike Dougherty4d1050b2023-03-14 15:59:537696 moved_paths = []
Mike Dougherty1b8be712022-10-20 00:15:137697 warning_paths = []
7698
7699 for f in input_api.AffectedSourceFiles(_FilterFile):
7700 local_path = f.LocalPath()
7701
7702 if input_api.os_path.splitext(local_path)[1] == '.js':
7703 if f.Action() == 'A':
Mike Dougherty4d1050b2023-03-14 15:59:537704 if input_api.os_path.basename(local_path) in deleted_files:
7705 # This script was probably moved rather than newly created.
7706 # Present a warning instead of an error for these cases.
7707 moved_paths.append(local_path)
7708 else:
7709 error_paths.append(local_path)
Mike Dougherty1b8be712022-10-20 00:15:137710 elif f.Action() != 'D':
7711 warning_paths.append(local_path)
7712
7713 results = []
7714
7715 if warning_paths:
7716 results.append(output_api.PresubmitPromptWarning(
7717 'TypeScript is now fully supported for iOS feature scripts. '
7718 'Consider converting JavaScript files to TypeScript. See '
7719 '//ios/web/public/js_messaging/README.md for more details.',
7720 warning_paths))
7721
Mike Dougherty4d1050b2023-03-14 15:59:537722 if moved_paths:
7723 results.append(output_api.PresubmitPromptWarning(
7724 'Do not use JavaScript on iOS for new files as TypeScript is '
7725 'fully supported. (If this is a moved file, you may leave the '
7726 'script unconverted.) See //ios/web/public/js_messaging/README.md '
7727 'for help using scripts on iOS.', moved_paths))
7728
Mike Dougherty1b8be712022-10-20 00:15:137729 if error_paths:
7730 results.append(output_api.PresubmitError(
7731 'Do not use JavaScript on iOS as TypeScript is fully supported. '
7732 'See //ios/web/public/js_messaging/README.md for help using '
7733 'scripts on iOS.', error_paths))
7734
7735 return results
Hans Wennborg23a81d52023-03-24 16:38:137736
7737def CheckLibcxxRevisionsMatch(input_api, output_api):
7738 """Check to make sure the libc++ version matches across deps files."""
Andrew Grieve21bb6792023-03-27 19:06:487739 # Disable check for changes to sub-repositories.
7740 if input_api.PresubmitLocalPath() != input_api.change.RepositoryRoot():
Sam Maierb926c58c2023-08-08 19:58:257741 return []
Hans Wennborg23a81d52023-03-24 16:38:137742
7743 DEPS_FILES = [ 'DEPS', 'buildtools/deps_revisions.gni' ]
7744
Anton Bershanskyi4253349482025-02-11 21:01:277745 file_filter = lambda f: f.UnixLocalPath() in DEPS_FILES
Hans Wennborg23a81d52023-03-24 16:38:137746 changed_deps_files = input_api.AffectedFiles(file_filter=file_filter)
7747 if not changed_deps_files:
7748 return []
7749
7750 def LibcxxRevision(file):
7751 file = input_api.os_path.join(input_api.PresubmitLocalPath(),
7752 *file.split('/'))
7753 return input_api.re.search(
7754 r'libcxx_revision.*[:=].*[\'"](\w+)[\'"]',
7755 input_api.ReadFile(file)).group(1)
7756
7757 if len(set([LibcxxRevision(f) for f in DEPS_FILES])) == 1:
7758 return []
7759
7760 return [output_api.PresubmitError(
7761 'libcxx_revision not equal across %s' % ', '.join(DEPS_FILES),
7762 changed_deps_files)]
Arthur Sonzogni7109bd32023-10-03 10:34:427763
7764
7765def CheckDanglingUntriaged(input_api, output_api):
7766 """Warn developers adding DanglingUntriaged raw_ptr."""
7767
7768 # Ignore during git presubmit --all.
7769 #
7770 # This would be too costly, because this would check every lines of every
7771 # C++ files. Check from _BANNED_CPP_FUNCTIONS are also reading the whole
7772 # source code, but only once to apply every checks. It seems the bots like
7773 # `win-presubmit` are particularly sensitive to reading the files. Adding
7774 # this check caused the bot to run 2x longer. See https://crbug.com/1486612.
7775 if input_api.no_diffs:
Arthur Sonzogni9eafd222023-11-10 08:50:397776 return []
Arthur Sonzogni7109bd32023-10-03 10:34:427777
7778 def FilterFile(file):
7779 return input_api.FilterSourceFile(
7780 file,
7781 files_to_check=[r".*\.(h|cc|cpp|cxx|m|mm)$"],
7782 files_to_skip=[r"^base/allocator.*"],
7783 )
7784
7785 count = 0
Arthur Sonzognic66e9c82024-04-23 07:53:047786 for f in input_api.AffectedFiles(file_filter=FilterFile):
Arthur Sonzogni9eafd222023-11-10 08:50:397787 count -= sum([l.count("DanglingUntriaged") for l in f.OldContents()])
7788 count += sum([l.count("DanglingUntriaged") for l in f.NewContents()])
Arthur Sonzogni7109bd32023-10-03 10:34:427789
7790 # Most likely, nothing changed:
7791 if count == 0:
7792 return []
7793
7794 # Congrats developers for improving it:
7795 if count < 0:
Arthur Sonzogni9eafd222023-11-10 08:50:397796 message = f"DanglingUntriaged pointers removed: {-count}\nThank you!"
Arthur Sonzogni7109bd32023-10-03 10:34:427797 return [output_api.PresubmitNotifyResult(message)]
7798
7799 # Check for 'DanglingUntriaged-notes' in the description:
7800 notes_regex = input_api.re.compile("DanglingUntriaged-notes[:=]")
7801 if any(
7802 notes_regex.match(line)
7803 for line in input_api.change.DescriptionText().splitlines()):
7804 return []
7805
7806 # Check for DanglingUntriaged-notes in the git footer:
7807 if input_api.change.GitFootersFromDescription().get(
7808 "DanglingUntriaged-notes", []):
7809 return []
7810
7811 message = (
Arthur Sonzogni9eafd222023-11-10 08:50:397812 "Unexpected new occurrences of `DanglingUntriaged` detected. Please\n" +
7813 "avoid adding new ones\n" +
7814 "\n" +
7815 "See documentation:\n" +
7816 "https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr.md\n" +
7817 "\n" +
7818 "See also the guide to fix dangling pointers:\n" +
7819 "https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr_guide.md\n" +
7820 "\n" +
7821 "To disable this warning, please add in the commit description:\n" +
Alex Gough26dcd852023-12-22 16:47:197822 "DanglingUntriaged-notes: <rationale for new untriaged dangling " +
Arthur Sonzogni9eafd222023-11-10 08:50:397823 "pointers>"
Arthur Sonzogni7109bd32023-10-03 10:34:427824 )
7825 return [output_api.PresubmitPromptWarning(message)]
Jan Keitel77be7522023-10-12 20:40:497826
7827def CheckInlineConstexprDefinitionsInHeaders(input_api, output_api):
7828 """Checks that non-static constexpr definitions in headers are inline."""
7829 # In a properly formatted file, constexpr definitions inside classes or
7830 # structs will have additional whitespace at the beginning of the line.
7831 # The pattern looks for variables initialized as constexpr kVar = ...; or
7832 # constexpr kVar{...};
7833 # The pattern does not match expressions that have braces in kVar to avoid
7834 # matching constexpr functions.
7835 pattern = input_api.re.compile(r'^constexpr (?!inline )[^\(\)]*[={]')
7836 attribute_pattern = input_api.re.compile(r'(\[\[[a-zA-Z_:]+\]\]|[A-Z]+[A-Z_]+) ')
7837 problems = []
7838 for f in input_api.AffectedFiles():
7839 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
7840 continue
7841
7842 for line_number, line in f.ChangedContents():
7843 line = attribute_pattern.sub('', line)
7844 if pattern.search(line):
7845 problems.append(
7846 f"{f.LocalPath()}: {line_number}\n {line}")
7847
7848 if problems:
7849 return [
7850 output_api.PresubmitPromptWarning(
7851 'Consider inlining constexpr variable definitions in headers '
7852 'outside of classes to avoid unnecessary copies of the '
7853 'constant. See https://abseil.io/tips/168 for more details.',
7854 problems)
7855 ]
7856 else:
7857 return []
Alison Galed6b25fe2024-04-17 13:59:047858
7859def CheckTodoBugReferences(input_api, output_api):
7860 """Checks that bugs in TODOs use updated issue tracker IDs."""
7861
Manish Goregaokardc9e3512025-02-03 15:30:587862 files_to_skip = ['PRESUBMIT_test.py', r"^third_party/rust/chromium_crates_io/vendor/.*"]
Alison Galed6b25fe2024-04-17 13:59:047863
7864 def _FilterFile(affected_file):
7865 return input_api.FilterSourceFile(
7866 affected_file,
7867 files_to_skip=files_to_skip)
7868
7869 # Monorail bug IDs are all less than or equal to 1524553 so check that all
7870 # bugs in TODOs are greater than that value.
Tom Sepez8e628582025-02-14 02:18:557871 pattern = input_api.re.compile(r'.*\bTODO\([^\)0-9]*([0-9]+)\).*')
Alison Galed6b25fe2024-04-17 13:59:047872 problems = []
7873 for f in input_api.AffectedSourceFiles(_FilterFile):
7874 for line_number, line in f.ChangedContents():
7875 match = pattern.match(line)
7876 if match and int(match.group(1)) <= 1524553:
7877 problems.append(
7878 f"{f.LocalPath()}: {line_number}\n {line}")
7879
7880 if problems:
7881 return [
7882 output_api.PresubmitPromptWarning(
Alison Galecb598de52024-04-26 17:03:257883 'TODOs should use the new Chromium Issue Tracker IDs which can '
7884 'be found by navigating to the bug. See '
7885 'https://crbug.com/336778624 for more details.',
Alison Galed6b25fe2024-04-17 13:59:047886 problems)
7887 ]
7888 else:
7889 return []