blob: 5ecfe1420ba78d017fed3787dcd565f620d1c6c4 [file] [log] [blame]
Avi Drissman24976592022-09-12 15:24:311# Copyright 2012 The Chromium Authors
[email protected]ca8d19842009-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]ca8d19842009-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]ca8d19842009-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]ca8d19842009-02-19 16:33:12115
Daniel Bratell609102be2019-03-27 20:53:21116_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:15117
[email protected]eea609a2011-11-18 13:10:12118_TEST_ONLY_WARNING = (
119 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:55120 'production code. If you are doing this from inside another method\n'
121 'named as *ForTesting(), then consider exposing things to have tests\n'
122 'make that same call directly.\n'
123 'If that is not possible, you may put a comment on the same line with\n'
124 ' // IN-TEST \n'
125 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
126 'method and can be ignored. Do not do this inside production code.\n'
127 'The android-binary-size trybot will block if the method exists in the\n'
Yulun Zeng08d7d8c2024-02-01 18:46:54128 'release apk.\n'
129 'Note: this warning might be a false positive (crbug.com/1196548).')
[email protected]eea609a2011-11-18 13:10:12130
131
Daniel Chenga44a1bcd2022-03-15 20:00:15132@dataclass
133class BanRule:
Daniel Chenga37c03db2022-05-12 17:20:34134 # String pattern. If the pattern begins with a slash, the pattern will be
135 # treated as a regular expression instead.
136 pattern: str
137 # Explanation as a sequence of strings. Each string in the sequence will be
138 # printed on its own line.
mikt19226ff22024-08-27 05:28:21139 explanation: Tuple[str, ...]
Daniel Chenga37c03db2022-05-12 17:20:34140 # Whether or not to treat this ban as a fatal error. If unspecified,
141 # defaults to true.
142 treat_as_error: Optional[bool] = None
143 # Paths that should be excluded from the ban check. Each string is a regular
144 # expression that will be matched against the path of the file being checked
145 # relative to the root of the source tree.
146 excluded_paths: Optional[Sequence[str]] = None
[email protected]cf9b78f2012-11-14 11:40:28147
Daniel Chenga44a1bcd2022-03-15 20:00:15148
Daniel Cheng917ce542022-03-15 20:46:57149_BANNED_JAVA_IMPORTS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15150 BanRule(
151 'import java.net.URI;',
152 (
153 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
154 ),
155 excluded_paths=(
156 (r'net/android/javatests/src/org/chromium/net/'
157 'AndroidProxySelectorTest\.java'),
158 r'components/cronet/',
159 r'third_party/robolectric/local/',
160 ),
Michael Thiessen44457642020-02-06 00:24:15161 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15162 BanRule(
163 'import android.annotation.TargetApi;',
164 (
165 'Do not use TargetApi, use @androidx.annotation.RequiresApi instead. '
166 'RequiresApi ensures that any calls are guarded by the appropriate '
167 'SDK_INT check. See https://crbug.com/1116486.',
168 ),
169 ),
170 BanRule(
Mohamed Heikal3d7a94c2023-03-28 16:55:24171 'import androidx.test.rule.UiThreadTestRule;',
Daniel Chenga44a1bcd2022-03-15 20:00:15172 (
173 'Do not use UiThreadTestRule, just use '
174 '@org.chromium.base.test.UiThreadTest on test methods that should run '
175 'on the UI thread. See https://crbug.com/1111893.',
176 ),
177 ),
178 BanRule(
Mohamed Heikal3d7a94c2023-03-28 16:55:24179 'import androidx.test.annotation.UiThreadTest;',
180 ('Do not use androidx.test.annotation.UiThreadTest, use '
Daniel Chenga44a1bcd2022-03-15 20:00:15181 'org.chromium.base.test.UiThreadTest instead. See '
182 'https://crbug.com/1111893.',
183 ),
184 ),
185 BanRule(
Mohamed Heikal3d7a94c2023-03-28 16:55:24186 'import androidx.test.rule.ActivityTestRule;',
Daniel Chenga44a1bcd2022-03-15 20:00:15187 (
188 'Do not use ActivityTestRule, use '
189 'org.chromium.base.test.BaseActivityTestRule instead.',
190 ),
191 excluded_paths=(
192 'components/cronet/',
193 ),
194 ),
Min Qinbc44383c2023-02-22 17:25:26195 BanRule(
196 'import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;',
197 (
198 'Do not use VectorDrawableCompat, use getResources().getDrawable() to '
199 'avoid extra indirections. Please also add trace event as the call '
200 'might take more than 20 ms to complete.',
201 ),
202 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15203)
wnwenbdc444e2016-05-25 13:44:15204
Daniel Cheng917ce542022-03-15 20:46:57205_BANNED_JAVA_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15206 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41207 'StrictMode.allowThreadDiskReads()',
208 (
209 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
210 'directly.',
211 ),
212 False,
213 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15214 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41215 'StrictMode.allowThreadDiskWrites()',
216 (
217 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
218 'directly.',
219 ),
220 False,
221 ),
Daniel Cheng917ce542022-03-15 20:46:57222 BanRule(
Michael Thiessen0f2547e2020-07-27 21:55:36223 '.waitForIdleSync()',
224 (
225 'Do not use waitForIdleSync as it masks underlying issues. There is '
226 'almost always something else you should wait on instead.',
227 ),
228 False,
229 ),
Ashley Newson09cbd602022-10-26 11:40:14230 BanRule(
Ashley Newsoneb6f5ced2022-10-26 14:45:42231 r'/(?<!\bsuper\.)(?<!\bIntent )\bregisterReceiver\(',
Ashley Newson09cbd602022-10-26 11:40:14232 (
233 'Do not call android.content.Context.registerReceiver (or an override) '
234 'directly. Use one of the wrapper methods defined in '
235 'org.chromium.base.ContextUtils, such as '
236 'registerProtectedBroadcastReceiver, '
237 'registerExportedBroadcastReceiver, or '
238 'registerNonExportedBroadcastReceiver. See their documentation for '
239 'which one to use.',
240 ),
241 True,
242 excluded_paths=(
Ashley Newson22bc26d2022-11-01 20:30:57243 r'.*Test[^a-z]',
244 r'third_party/',
Ashley Newson09cbd602022-10-26 11:40:14245 'base/android/java/src/org/chromium/base/ContextUtils.java',
Brandon Mousseau7e76a9c2022-12-08 22:08:38246 'chromecast/browser/android/apk/src/org/chromium/chromecast/shell/BroadcastReceiverScope.java',
Ashley Newson09cbd602022-10-26 11:40:14247 ),
248 ),
Ted Chocd5b327b12022-11-05 02:13:22249 BanRule(
250 r'/(?:extends|new)\s*(?:android.util.)?Property<[A-Za-z.]+,\s*(?:Integer|Float)>',
251 (
252 'Do not use Property<..., Integer|Float>, but use FloatProperty or '
253 'IntProperty because it will avoid unnecessary autoboxing of '
254 'primitives.',
255 ),
256 ),
Peilin Wangbba4a8652022-11-10 16:33:57257 BanRule(
258 'requestLayout()',
259 (
260 'Layouts can be expensive. Prefer using ViewUtils.requestLayout(), '
261 'which emits a trace event with additional information to help with '
262 'scroll jank investigations. See http://crbug.com/1354176.',
263 ),
264 False,
265 excluded_paths=(
266 'ui/android/java/src/org/chromium/ui/base/ViewUtils.java',
267 ),
268 ),
Ted Chocf40ea9152023-02-14 19:02:39269 BanRule(
Ted Chocf486e3f2024-02-17 05:37:03270 'ProfileManager.getLastUsedRegularProfile()',
Ted Chocf40ea9152023-02-14 19:02:39271 (
272 'Prefer passing in the Profile reference instead of relying on the '
273 'static getLastUsedRegularProfile() call. Only top level entry points '
274 '(e.g. Activities) should call this method. Otherwise, the Profile '
275 'should either be passed in explicitly or retreived from an existing '
276 'entity with a reference to the Profile (e.g. WebContents).',
277 ),
278 False,
279 excluded_paths=(
280 r'.*Test[A-Z]?.*\.java',
281 ),
282 ),
Min Qinbc44383c2023-02-22 17:25:26283 BanRule(
284 r'/(ResourcesCompat|getResources\(\))\.getDrawable\(\)',
285 (
286 'getDrawable() can be expensive. If you have a lot of calls to '
287 'GetDrawable() or your code may introduce janks, please put your calls '
288 'inside a trace().',
289 ),
290 False,
291 excluded_paths=(
292 r'.*Test[A-Z]?.*\.java',
293 ),
294 ),
Henrique Nakashimabbf2b262023-03-10 17:21:39295 BanRule(
296 r'/RecordHistogram\.getHistogram(ValueCount|TotalCount|Samples)ForTesting\(',
297 (
298 'Raw histogram counts are easy to misuse; for example they don\'t reset '
Thiago Perrotta099034f2023-06-05 18:10:20299 'between batched tests. Use HistogramWatcher to check histogram records '
300 'instead.',
Henrique Nakashimabbf2b262023-03-10 17:21:39301 ),
302 False,
303 excluded_paths=(
304 'base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java',
305 'base/test/android/javatests/src/org/chromium/base/test/util/HistogramWatcher.java',
306 ),
307 ),
Eric Stevensona9a980972017-09-23 00:04:41308)
309
Clement Yan9b330cb2022-11-17 05:25:29310_BANNED_JAVASCRIPT_FUNCTIONS : Sequence [BanRule] = (
311 BanRule(
312 r'/\bchrome\.send\b',
313 (
314 '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).',
315 'Please use mojo instead for new webuis. https://docs.google.com/document/d/1RF-GSUoveYa37eoyZ9EhwMtaIwoW7Z88pIgNZ9YzQi4/edit#heading=h.gkk22wgk6wff',
316 ),
317 True,
318 (
319 r'^(?!ash\/webui).+',
320 # TODO(crbug.com/1385601): pre-existing violations still need to be
321 # cleaned up.
Rebekah Potter57aa94df2022-12-13 20:30:58322 'ash/webui/common/resources/cr.m.js',
Clement Yan9b330cb2022-11-17 05:25:29323 'ash/webui/common/resources/multidevice_setup/multidevice_setup_browser_proxy.js',
Martin Bidlingmaiera921fee72023-06-03 07:52:22324 'ash/webui/common/resources/quick_unlock/lock_screen_constants.ts',
Clement Yan9b330cb2022-11-17 05:25:29325 'ash/webui/common/resources/smb_shares/smb_browser_proxy.js',
Chad Duffin06e47de2023-12-14 18:04:13326 'ash/webui/connectivity_diagnostics/resources/connectivity_diagnostics.ts',
Clement Yan9b330cb2022-11-17 05:25:29327 'ash/webui/diagnostics_ui/resources/diagnostics_browser_proxy.ts',
328 'ash/webui/multidevice_debug/resources/logs.js',
329 'ash/webui/multidevice_debug/resources/webui.js',
330 'ash/webui/projector_app/resources/annotator/trusted/annotator_browser_proxy.js',
331 'ash/webui/projector_app/resources/app/trusted/projector_browser_proxy.js',
Ashley Prasad71f9024e2023-09-25 22:33:55332 # TODO(b/301634378): Remove violation exception once Scanning App
333 # migrated off usage of `chrome.send`.
334 'ash/webui/scanning/resources/scanning_browser_proxy.ts',
Clement Yan9b330cb2022-11-17 05:25:29335 ),
336 ),
337)
338
Daniel Cheng917ce542022-03-15 20:46:57339_BANNED_OBJC_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15340 BanRule(
[email protected]127f18ec2012-06-16 05:05:59341 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20342 (
343 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59344 'prohibited. Please use CrTrackingArea instead.',
345 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
346 ),
347 False,
348 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15349 BanRule(
[email protected]eaae1972014-04-16 04:17:26350 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20351 (
352 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59353 'instead.',
354 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
355 ),
356 False,
357 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15358 BanRule(
[email protected]127f18ec2012-06-16 05:05:59359 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20360 (
361 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59362 'Please use |convertPoint:(point) fromView:nil| instead.',
363 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
364 ),
365 True,
366 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15367 BanRule(
[email protected]127f18ec2012-06-16 05:05:59368 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20369 (
370 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59371 'Please use |convertPoint:(point) toView:nil| instead.',
372 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
373 ),
374 True,
375 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15376 BanRule(
[email protected]127f18ec2012-06-16 05:05:59377 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20378 (
379 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59380 'Please use |convertRect:(point) fromView:nil| instead.',
381 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
382 ),
383 True,
384 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15385 BanRule(
[email protected]127f18ec2012-06-16 05:05:59386 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20387 (
388 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59389 'Please use |convertRect:(point) toView:nil| instead.',
390 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
391 ),
392 True,
393 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15394 BanRule(
[email protected]127f18ec2012-06-16 05:05:59395 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20396 (
397 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59398 'Please use |convertSize:(point) fromView:nil| instead.',
399 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
400 ),
401 True,
402 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15403 BanRule(
[email protected]127f18ec2012-06-16 05:05:59404 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20405 (
406 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59407 'Please use |convertSize:(point) toView:nil| instead.',
408 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
409 ),
410 True,
411 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15412 BanRule(
jif65398702016-10-27 10:19:48413 r"/\s+UTF8String\s*]",
414 (
415 'The use of -[NSString UTF8String] is dangerous as it can return null',
416 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
417 'Please use |SysNSStringToUTF8| instead.',
418 ),
419 True,
Marijn Kruisselbrink1b7c48952023-08-31 16:58:34420 excluded_paths = (
421 '^third_party/ocmock/OCMock/',
422 ),
jif65398702016-10-27 10:19:48423 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15424 BanRule(
Sylvain Defresne4cf1d182017-09-18 14:16:34425 r'__unsafe_unretained',
426 (
427 'The use of __unsafe_unretained is almost certainly wrong, unless',
428 'when interacting with NSFastEnumeration or NSInvocation.',
429 'Please use __weak in files build with ARC, nothing otherwise.',
430 ),
431 False,
432 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15433 BanRule(
Avi Drissman7382afa02019-04-29 23:27:13434 'freeWhenDone:NO',
435 (
436 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
437 'Foundation types is prohibited.',
438 ),
439 True,
440 ),
Avi Drissman3d243a42023-08-01 16:53:59441 BanRule(
442 'This file requires ARC support.',
443 (
444 'ARC compilation is default in Chromium; do not add boilerplate to ',
445 'files that require ARC.',
446 ),
447 True,
448 ),
[email protected]127f18ec2012-06-16 05:05:59449)
450
Sylvain Defresnea8b73d252018-02-28 15:45:54451_BANNED_IOS_OBJC_FUNCTIONS = (
Daniel Chenga44a1bcd2022-03-15 20:00:15452 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54453 r'/\bTEST[(]',
454 (
455 'TEST() macro should not be used in Objective-C++ code as it does not ',
456 'drain the autorelease pool at the end of the test. Use TEST_F() ',
457 'macro instead with a fixture inheriting from PlatformTest (or a ',
458 'typedef).'
459 ),
460 True,
461 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15462 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54463 r'/\btesting::Test\b',
464 (
465 'testing::Test should not be used in Objective-C++ code as it does ',
466 'not drain the autorelease pool at the end of the test. Use ',
467 'PlatformTest instead.'
468 ),
469 True,
470 ),
Ewann2ecc8d72022-07-18 07:41:23471 BanRule(
472 ' systemImageNamed:',
473 (
474 '+[UIImage systemImageNamed:] should not be used to create symbols.',
475 'Instead use a wrapper defined in:',
Slobodan Pejic8ef56c702024-07-12 18:21:26476 'ios/chrome/browser/shared/ui/symbols/symbol_helpers.h'
Ewann2ecc8d72022-07-18 07:41:23477 ),
478 True,
Ewann450a2ef2022-07-19 14:38:23479 excluded_paths=(
Gauthier Ambard4d8756b2023-04-07 17:26:41480 'ios/chrome/browser/shared/ui/symbols/symbol_helpers.mm',
Slobodan Pejic8ef56c702024-07-12 18:21:26481 'ios/chrome/common',
Gauthier Ambardd36c10b12023-03-16 08:45:03482 'ios/chrome/search_widget_extension/',
Ewann450a2ef2022-07-19 14:38:23483 ),
Ewann2ecc8d72022-07-18 07:41:23484 ),
Sylvain Defresnea8b73d252018-02-28 15:45:54485)
486
Daniel Cheng917ce542022-03-15 20:46:57487_BANNED_IOS_EGTEST_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15488 BanRule(
Peter K. Lee6c03ccff2019-07-15 14:40:05489 r'/\bEXPECT_OCMOCK_VERIFY\b',
490 (
491 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
492 'it is meant for GTests. Use [mock verify] instead.'
493 ),
494 True,
495 ),
496)
497
Daniel Cheng566634ff2024-06-29 14:56:53498_BANNED_CPP_FUNCTIONS: Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15499 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53500 '%#0',
501 (
502 'Zero-padded values that use "#" to add prefixes don\'t exhibit ',
503 'consistent behavior, since the prefix is not prepended for zero ',
504 'values. Use "0x%0..." instead.',
505 ),
506 False,
507 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting7c0d98a2023-10-06 15:42:39508 ),
509 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53510 r'/\busing namespace ',
511 (
512 'Using directives ("using namespace x") are banned by the Google Style',
513 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
514 'Explicitly qualify symbols or use using declarations ("using x::foo").',
515 ),
516 True,
517 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting94a56c42019-10-25 21:54:04518 ),
Antonio Gomes07300d02019-03-13 20:59:57519 # Make sure that gtest's FRIEND_TEST() macro is not used; the
520 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
521 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
Daniel Chenga44a1bcd2022-03-15 20:00:15522 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53523 'FRIEND_TEST(',
524 (
525 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
526 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
527 ),
528 False,
529 excluded_paths=(
530 "base/gtest_prod_util.h",
531 "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/gtest_prod_util.h",
532 ),
[email protected]23e6cbc2012-06-16 18:51:20533 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15534 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53535 'setMatrixClip',
536 (
537 'Overriding setMatrixClip() is prohibited; ',
538 'the base function is deprecated. ',
539 ),
540 True,
541 (),
tomhudsone2c14d552016-05-26 17:07:46542 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15543 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53544 'SkRefPtr',
545 ('The use of SkRefPtr is prohibited. ', 'Please use sk_sp<> instead.'),
546 True,
547 (),
[email protected]52657f62013-05-20 05:30:31548 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15549 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53550 'SkAutoRef',
551 ('The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
552 'Please use sk_sp<> instead.'),
553 True,
554 (),
[email protected]52657f62013-05-20 05:30:31555 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15556 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53557 'SkAutoTUnref',
558 ('The use of SkAutoTUnref is dangerous because it implicitly ',
559 'converts to a raw pointer. Please use sk_sp<> instead.'),
560 True,
561 (),
[email protected]52657f62013-05-20 05:30:31562 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15563 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53564 'SkAutoUnref',
565 ('The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
566 'because it implicitly converts to a raw pointer. ',
567 'Please use sk_sp<> instead.'),
568 True,
569 (),
[email protected]52657f62013-05-20 05:30:31570 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15571 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53572 r'/HANDLE_EINTR\(.*close',
573 ('HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
574 'descriptor will be closed, and it is incorrect to retry the close.',
575 'Either call close directly and ignore its return value, or wrap close',
576 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
577 ),
578 True,
579 (),
[email protected]d89eec82013-12-03 14:10:59580 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15581 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53582 r'/IGNORE_EINTR\((?!.*close)',
583 (
584 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
585 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
586 ),
587 True,
588 (
589 # Files that #define IGNORE_EINTR.
590 r'^base/posix/eintr_wrapper\.h$',
591 r'^ppapi/tests/test_broker\.cc$',
592 ),
[email protected]d89eec82013-12-03 14:10:59593 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15594 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53595 r'/v8::Extension\(',
596 (
597 'Do not introduce new v8::Extensions into the code base, use',
598 'gin::Wrappable instead. See http://crbug.com/334679',
599 ),
600 True,
601 (r'extensions/renderer/safe_builtins\.*', ),
[email protected]ec5b3f02014-04-04 18:43:43602 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15603 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53604 '#pragma comment(lib,',
605 ('Specify libraries to link with in build files and not in the source.',
606 ),
607 True,
608 (
609 r'^base/third_party/symbolize/.*',
610 r'^third_party/abseil-cpp/.*',
611 ),
jame2d1a952016-04-02 00:27:10612 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15613 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53614 r'/base::SequenceChecker\b',
615 ('Consider using SEQUENCE_CHECKER macros instead of the class directly.',
616 ),
617 False,
618 (),
gabd52c912a2017-05-11 04:15:59619 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15620 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53621 r'/base::ThreadChecker\b',
622 ('Consider using THREAD_CHECKER macros instead of the class directly.',
623 ),
624 False,
625 (),
gabd52c912a2017-05-11 04:15:59626 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15627 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53628 r'/\b(?!(Sequenced|SingleThread))\w*TaskRunner::(GetCurrentDefault|CurrentDefaultHandle)',
629 (
630 'It is not allowed to call these methods from the subclasses ',
631 'of Sequenced or SingleThread task runners.',
632 ),
633 True,
634 (),
Sean Maher03efef12022-09-23 22:43:13635 ),
636 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53637 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
638 (
639 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
640 'deprecated (http://crbug.com/634507). Please avoid converting away',
641 'from the Time types in Chromium code, especially if any math is',
642 'being done on time values. For interfacing with platform/library',
643 'APIs, use base::Time::(From,To)DeltaSinceWindowsEpoch() or',
644 'base::{TimeDelta::In}Microseconds(), or one of the other type',
645 'converter methods instead. For faking TimeXXX values (for unit',
646 'testing only), use TimeXXX() + Microseconds(N). For',
647 'other use cases, please contact base/time/OWNERS.',
648 ),
649 False,
650 excluded_paths=(
651 "base/time/time.h",
652 "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/time/time.h",
653 ),
Yuri Wiitala2f8de5c2017-07-21 00:11:06654 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15655 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53656 'CallJavascriptFunctionUnsafe',
657 (
658 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
659 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
660 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
661 ),
662 False,
663 (
664 r'^content/browser/webui/web_ui_impl\.(cc|h)$',
665 r'^content/public/browser/web_ui\.h$',
666 r'^content/public/test/test_web_ui\.(cc|h)$',
667 ),
dbeamb6f4fde2017-06-15 04:03:06668 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15669 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53670 'leveldb::DB::Open',
671 (
672 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
673 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
674 "Chrome's tracing, making their memory usage visible.",
675 ),
676 True,
677 (r'^third_party/leveldatabase/.*\.(cc|h)$', ),
Gabriel Charette0592c3a2017-07-26 12:02:04678 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15679 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53680 'leveldb::NewMemEnv',
681 (
682 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
683 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
684 "to Chrome's tracing, making their memory usage visible.",
685 ),
686 True,
687 (r'^third_party/leveldatabase/.*\.(cc|h)$', ),
Chris Mumfordc38afb62017-10-09 17:55:08688 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15689 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53690 'RunLoop::QuitCurrent',
691 (
692 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
693 'methods of a specific RunLoop instance instead.',
694 ),
695 False,
696 (),
Gabriel Charettea44975052017-08-21 23:14:04697 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15698 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53699 'base::ScopedMockTimeMessageLoopTaskRunner',
700 (
701 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
702 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
703 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
704 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
705 'with gab@ first if you think you need it)',
706 ),
707 False,
708 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57709 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15710 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53711 'std::regex',
712 (
713 'Using std::regex adds unnecessary binary size to Chrome. Please use',
714 're2::RE2 instead (crbug.com/755321)',
715 ),
716 True,
717 [
718 # Abseil's benchmarks never linked into chrome.
719 'third_party/abseil-cpp/.*_benchmark.cc',
720 ],
Francois Doray43670e32017-09-27 12:40:38721 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15722 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53723 r'/\bstd::sto(i|l|ul|ll|ull)\b',
724 (
725 'std::sto{i,l,ul,ll,ull}() use exceptions to communicate results. ',
726 'Use base::StringTo[U]Int[64]() instead.',
727 ),
728 True,
729 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting991618a62019-06-17 22:00:09730 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15731 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53732 r'/\bstd::sto(f|d|ld)\b',
733 (
734 'std::sto{f,d,ld}() use exceptions to communicate results. ',
735 'For locale-independent values, e.g. reading numbers from disk',
736 'profiles, use base::StringToDouble().',
737 'For user-visible values, parse using ICU.',
738 ),
739 True,
740 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting991618a62019-06-17 22:00:09741 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15742 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53743 r'/\bstd::to_string\b',
744 (
745 'std::to_string() is locale dependent and slower than alternatives.',
746 'For locale-independent strings, e.g. writing numbers to disk',
747 'profiles, use base::NumberToString().',
748 'For user-visible strings, use base::FormatNumber() and',
749 'the related functions in base/i18n/number_formatting.h.',
750 ),
751 True,
752 [
753 # TODO(crbug.com/335672557): Please do not add to this list. Existing
754 # uses should removed.
755 "base/linux_util.cc",
Daniel Cheng566634ff2024-06-29 14:56:53756 "device/fido/mock_fido_device.cc",
757 "gpu/command_buffer/tests/gl_webgl_multi_draw_test.cc",
758 "gpu/config/gpu_control_list.cc",
759 "media/audio/win/core_audio_util_win.cc",
760 "media/gpu/android/media_codec_video_decoder.cc",
761 "media/gpu/vaapi/vaapi_wrapper.cc",
762 "remoting/host/linux/certificate_watcher_unittest.cc",
763 "testing/libfuzzer/fuzzers/url_parse_proto_fuzzer.cc",
764 "testing/libfuzzer/proto/url_proto_converter.cc",
765 "third_party/blink/renderer/core/css/parser/css_proto_converter.cc",
766 "third_party/blink/renderer/core/editing/ime/edit_context.cc",
767 "third_party/blink/renderer/platform/graphics/bitmap_image_test.cc",
768 "tools/binary_size/libsupersize/viewer/caspian/diff_test.cc",
769 "tools/binary_size/libsupersize/viewer/caspian/tree_builder_test.cc",
770 "ui/base/ime/win/tsf_text_store.cc",
771 "ui/ozone/platform/drm/gpu/hardware_display_plane.cc",
772 _THIRD_PARTY_EXCEPT_BLINK
773 ],
Daniel Bratell69334cc2019-03-26 11:07:45774 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15775 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53776 r'/#include <(cctype|ctype\.h|cwctype|wctype.h)>',
777 (
778 '<cctype>/<ctype.h>/<cwctype>/<wctype.h> are banned. Use',
779 '"third_party/abseil-cpp/absl/strings/ascii.h" instead.',
780 ),
781 True,
782 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting6f79b202023-08-09 21:25:41783 ),
784 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53785 r'/\bstd::shared_ptr\b',
786 ('std::shared_ptr is banned. Use scoped_refptr instead.', ),
787 True,
788 [
789 # Needed for interop with third-party library.
790 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
791 'array_buffer_contents\.(cc|h)',
792 '^third_party/blink/renderer/core/typed_arrays/dom_array_buffer\.cc',
793 '^third_party/blink/renderer/bindings/core/v8/' +
794 'v8_wasm_response_extensions.cc',
795 '^gin/array_buffer\.(cc|h)',
796 '^gin/per_isolate_data\.(cc|h)',
797 '^chrome/services/sharing/nearby/',
798 # Needed for interop with third-party library libunwindstack.
799 '^base/profiler/libunwindstack_unwinder_android\.(cc|h)',
800 '^base/profiler/native_unwinder_android_memory_regions_map_impl.(cc|h)',
801 # Needed for interop with third-party boringssl cert verifier
802 '^third_party/boringssl/',
803 '^net/cert/',
804 '^net/tools/cert_verify_tool/',
805 '^services/cert_verifier/',
806 '^components/certificate_transparency/',
807 '^components/media_router/common/providers/cast/certificate/',
808 # gRPC provides some C++ libraries that use std::shared_ptr<>.
809 '^chromeos/ash/services/libassistant/grpc/',
810 '^chromecast/cast_core/grpc',
811 '^chromecast/cast_core/runtime/browser',
812 '^ios/chrome/test/earl_grey/chrome_egtest_plugin_client\.(mm|h)',
813 # Fuchsia provides C++ libraries that use std::shared_ptr<>.
814 '^base/fuchsia/.*\.(cc|h)',
815 '.*fuchsia.*test\.(cc|h)',
816 # Clang plugins have different build config.
817 '^tools/clang/plugins/',
818 _THIRD_PARTY_EXCEPT_BLINK
819 ], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21820 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15821 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53822 r'/\bstd::weak_ptr\b',
823 ('std::weak_ptr is banned. Use base::WeakPtr instead.', ),
824 True,
825 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting991618a62019-06-17 22:00:09826 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15827 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53828 r'/\blong long\b',
829 ('long long is banned. Use [u]int64_t instead.', ),
830 False, # Only a warning since it is already used.
831 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21832 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15833 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53834 r'/\b(absl|std)::any\b',
835 (
836 '{absl,std}::any are banned due to incompatibility with the component ',
837 'build.',
838 ),
839 True,
840 # Not an error in third party folders, though it probably should be :)
841 [_THIRD_PARTY_EXCEPT_BLINK],
Daniel Chengc05fcc62022-01-12 16:54:29842 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15843 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53844 r'/\bstd::bind\b',
845 (
846 'std::bind() is banned because of lifetime risks. Use ',
847 'base::Bind{Once,Repeating}() instead.',
848 ),
849 True,
850 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21851 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15852 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53853 (r'/\bstd::(?:'
854 r'linear_congruential_engine|mersenne_twister_engine|'
855 r'subtract_with_carry_engine|discard_block_engine|'
856 r'independent_bits_engine|shuffle_order_engine|'
857 r'minstd_rand0?|mt19937(_64)?|ranlux(24|48)(_base)?|knuth_b|'
858 r'default_random_engine|'
859 r'random_device|'
860 r'seed_seq'
861 r')\b'),
862 (
863 'STL random number engines and generators are banned. Use the ',
864 'helpers in base/rand_util.h instead, e.g. base::RandBytes() or ',
865 'base::RandomBitGenerator.'
866 '',
867 'Please reach out to [email protected] if the base APIs are ',
868 'insufficient for your needs.',
869 ),
870 True,
871 [
872 # Not an error in third_party folders.
873 _THIRD_PARTY_EXCEPT_BLINK,
874 # Various tools which build outside of Chrome.
875 r'testing/libfuzzer',
Steinar H. Gundersone5689e42024-08-07 18:17:19876 r'testing/perf/confidence',
Daniel Cheng566634ff2024-06-29 14:56:53877 r'tools/android/io_benchmark/',
878 # Fuzzers are allowed to use standard library random number generators
879 # since fuzzing speed + reproducibility is important.
880 r'tools/ipc_fuzzer/',
881 r'.+_fuzzer\.cc$',
882 r'.+_fuzzertest\.cc$',
883 # TODO(https://crbug.com/1380528): These are all unsanctioned uses of
884 # the standard library's random number generators, and should be
885 # migrated to the //base equivalent.
886 r'ash/ambient/model/ambient_topic_queue\.cc',
887 r'base/allocator/partition_allocator/src/partition_alloc/partition_alloc_unittest\.cc',
888 r'base/ranges/algorithm_unittest\.cc',
889 r'base/test/launcher/test_launcher\.cc',
890 r'cc/metrics/video_playback_roughness_reporter_unittest\.cc',
891 r'chrome/browser/apps/app_service/metrics/website_metrics\.cc',
892 r'chrome/browser/ash/power/auto_screen_brightness/monotone_cubic_spline_unittest\.cc',
893 r'chrome/browser/ash/printing/zeroconf_printer_detector_unittest\.cc',
894 r'chrome/browser/nearby_sharing/contacts/nearby_share_contact_manager_impl_unittest\.cc',
895 r'chrome/browser/nearby_sharing/contacts/nearby_share_contacts_sorter_unittest\.cc',
896 r'chrome/browser/privacy_budget/mesa_distribution_unittest\.cc',
897 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
898 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
899 r'chrome/browser/win/conflicts/module_blocklist_cache_util_unittest\.cc',
900 r'chromeos/ash/components/memory/userspace_swap/swap_storage_unittest\.cc',
901 r'chromeos/ash/components/memory/userspace_swap/userspace_swap\.cc',
902 r'components/metrics/metrics_state_manager\.cc',
903 r'components/omnibox/browser/history_quick_provider_performance_unittest\.cc',
904 r'components/zucchini/disassembler_elf_unittest\.cc',
905 r'content/browser/webid/federated_auth_request_impl\.cc',
906 r'content/browser/webid/federated_auth_request_impl\.cc',
907 r'media/cast/test/utility/udp_proxy\.h',
908 r'sql/recover_module/module_unittest\.cc',
909 r'components/search_engines/template_url_prepopulate_data.cc',
910 # Do not add new entries to this list. If you have a use case which is
911 # not satisfied by the current APIs (i.e. you need an explicitly-seeded
912 # sequence, or stability of some sort is required), please contact
913 # [email protected].
914 ],
Daniel Cheng192683f2022-11-01 20:52:44915 ),
916 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53917 r'/\b(absl,std)::bind_front\b',
918 ('{absl,std}::bind_front() are banned. Use base::Bind{Once,Repeating}() '
919 'instead.', ),
920 True,
921 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12922 ),
923 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53924 r'/\bABSL_FLAG\b',
925 ('ABSL_FLAG is banned. Use base::CommandLine instead.', ),
926 True,
927 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12928 ),
929 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53930 r'/\babsl::c_',
931 (
932 'Abseil container utilities are banned. Use base/ranges/algorithm.h ',
933 'instead.',
934 ),
935 True,
936 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12937 ),
938 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53939 r'/\babsl::FixedArray\b',
940 ('absl::FixedArray is banned. Use base::FixedArray instead.', ),
941 True,
942 [
943 # base::FixedArray provides canonical access.
944 r'^base/types/fixed_array.h',
945 # Not an error in third_party folders.
946 _THIRD_PARTY_EXCEPT_BLINK,
947 ],
Peter Kasting431239a2023-09-29 03:11:44948 ),
949 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53950 r'/\babsl::FunctionRef\b',
951 ('absl::FunctionRef is banned. Use base::FunctionRef instead.', ),
952 True,
953 [
954 # base::Bind{Once,Repeating} references absl::FunctionRef to disallow
955 # interoperability.
956 r'^base/functional/bind_internal\.h',
957 # base::FunctionRef is implemented on top of absl::FunctionRef.
958 r'^base/functional/function_ref.*\..+',
959 # Not an error in third_party folders.
960 _THIRD_PARTY_EXCEPT_BLINK,
961 ],
Peter Kasting4f35bfc2022-10-18 18:39:12962 ),
963 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53964 r'/\babsl::(Insecure)?BitGen\b',
965 ('absl random number generators are banned. Use the helpers in '
966 'base/rand_util.h instead, e.g. base::RandBytes() or ',
967 'base::RandomBitGenerator.'),
968 True,
969 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12970 ),
971 BanRule(
Peter Kasting3b77a0c2024-08-22 00:22:26972 pattern=
973 r'/\babsl::(optional|nullopt|make_optional)\b',
974 explanation=('absl::optional is banned. Use std::optional instead.', ),
975 treat_as_error=True,
976 excluded_paths=[
977 _THIRD_PARTY_EXCEPT_BLINK,
978 ]),
979 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53980 r'/(\babsl::Span\b|#include <span>|\bstd::span\b)',
981 (
982 'absl::Span and std::span are not allowed ',
983 '(https://crbug.com/1414652). Use base::span instead.',
984 ),
985 True,
986 [
987 # Included for conversions between base and std.
988 r'base/containers/span.h',
989 # Test base::span<> compatibility against std::span<>.
990 r'base/containers/span_unittest.cc',
991 # //base/numerics can't use base or absl. So it uses std.
992 r'base/numerics/.*'
Lei Zhang1f9d9ec42024-06-20 18:42:27993
Daniel Cheng566634ff2024-06-29 14:56:53994 # Needed to use QUICHE API.
Ciara McMullinc029c8e2024-08-21 14:22:32995 r'android_webview/browser/ip_protection/.*',
Daniel Cheng566634ff2024-06-29 14:56:53996 r'chrome/browser/ip_protection/.*',
997 r'components/ip_protection/.*',
998 r'net/third_party/quiche/overrides/quiche_platform_impl/quiche_stack_trace_impl\.*',
999 r'services/network/web_transport\.cc',
Lei Zhang1f9d9ec42024-06-20 18:42:271000
Daniel Cheng566634ff2024-06-29 14:56:531001 # Not an error in third_party folders.
1002 _THIRD_PARTY_EXCEPT_BLINK,
1003 ],
Peter Kasting4f35bfc2022-10-18 18:39:121004 ),
1005 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531006 r'/\babsl::StatusOr\b',
1007 ('absl::StatusOr is banned. Use base::expected instead.', ),
1008 True,
1009 [
1010 # Needed to use liburlpattern API.
1011 r'components/url_pattern/.*',
1012 r'services/network/shared_dictionary/simple_url_pattern_matcher\.cc',
1013 r'third_party/blink/renderer/core/url_pattern/.*',
1014 r'third_party/blink/renderer/modules/manifest/manifest_parser\.cc',
Lei Zhang1f9d9ec42024-06-20 18:42:271015
Daniel Cheng566634ff2024-06-29 14:56:531016 # Needed to use QUICHE API.
Ciara McMullinc029c8e2024-08-21 14:22:321017 r'android_webview/browser/ip_protection/.*',
Daniel Cheng566634ff2024-06-29 14:56:531018 r'chrome/browser/ip_protection/.*',
1019 r'components/ip_protection/.*',
Lei Zhang1f9d9ec42024-06-20 18:42:271020
Daniel Cheng566634ff2024-06-29 14:56:531021 # Needed to use MediaPipe API.
1022 r'components/media_effects/.*\.cc',
1023 # Not an error in third_party folders.
1024 _THIRD_PARTY_EXCEPT_BLINK
1025 ],
Peter Kasting4f35bfc2022-10-18 18:39:121026 ),
1027 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531028 r'/\babsl::(StrSplit|StrJoin|StrCat|StrAppend|Substitute|StrContains)\b',
1029 ('Abseil string utilities are banned. Use base/strings instead.', ),
1030 True,
1031 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:121032 ),
1033 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531034 r'/\babsl::(Mutex|CondVar|Notification|Barrier|BlockingCounter)\b',
1035 (
1036 'Abseil synchronization primitives are banned. Use',
1037 'base/synchronization instead.',
1038 ),
1039 True,
1040 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:121041 ),
1042 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531043 r'/\babsl::(Duration|Time|TimeZone|CivilDay)\b',
1044 ('Abseil\'s time library is banned. Use base/time instead.', ),
1045 True,
1046 [
1047 # Needed to use QUICHE API.
Ciara McMullinc029c8e2024-08-21 14:22:321048 r'android_webview/browser/ip_protection/.*',
Daniel Cheng566634ff2024-06-29 14:56:531049 r'chrome/browser/ip_protection/.*',
1050 r'components/ip_protection/.*',
Lei Zhang1f9d9ec42024-06-20 18:42:271051
Daniel Cheng566634ff2024-06-29 14:56:531052 # Needed to integrate with //third_party/nearby
1053 r'components/cross_device/nearby/system_clock.cc',
1054 _THIRD_PARTY_EXCEPT_BLINK # Not an error in third_party folders.
1055 ],
1056 ),
1057 BanRule(
1058 r'/#include <chrono>',
1059 ('<chrono> is banned. Use base/time instead.', ),
1060 True,
1061 [
1062 # Not an error in third_party folders:
1063 _THIRD_PARTY_EXCEPT_BLINK,
Daniel Cheng566634ff2024-06-29 14:56:531064 # This uses openscreen API depending on std::chrono.
1065 "components/openscreen_platform/task_runner.cc",
1066 ]),
1067 BanRule(
1068 r'/#include <exception>',
1069 ('Exceptions are banned and disabled in Chromium.', ),
1070 True,
1071 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1072 ),
1073 BanRule(
1074 r'/\bstd::function\b',
1075 ('std::function is banned. Use base::{Once,Repeating}Callback instead.',
1076 ),
1077 True,
1078 [
1079 # Has tests that template trait helpers don't unintentionally match
1080 # std::function.
1081 r'base/functional/callback_helpers_unittest\.cc',
1082 # Required to implement interfaces from the third-party perfetto
1083 # library.
1084 r'base/tracing/perfetto_task_runner\.cc',
1085 r'base/tracing/perfetto_task_runner\.h',
1086 # Needed for interop with the third-party nearby library type
1087 # location::nearby::connections::ResultCallback.
1088 'chrome/services/sharing/nearby/nearby_connections_conversions\.cc'
1089 # Needed for interop with the internal libassistant library.
1090 'chromeos/ash/services/libassistant/callback_utils\.h',
1091 # Needed for interop with Fuchsia fidl APIs.
1092 'fuchsia_web/webengine/browser/context_impl_browsertest\.cc',
1093 'fuchsia_web/webengine/browser/cookie_manager_impl_unittest\.cc',
1094 'fuchsia_web/webengine/browser/media_player_impl_unittest\.cc',
1095 # Required to interop with interfaces from the third-party ChromeML
1096 # library API.
1097 'services/on_device_model/ml/chrome_ml_api\.h',
1098 'services/on_device_model/ml/on_device_model_executor\.cc',
1099 'services/on_device_model/ml/on_device_model_executor\.h',
1100 # Required to interop with interfaces from the third-party perfetto
1101 # library.
1102 'services/tracing/public/cpp/perfetto/custom_event_recorder\.cc',
1103 'services/tracing/public/cpp/perfetto/perfetto_traced_process\.cc',
1104 'services/tracing/public/cpp/perfetto/perfetto_traced_process\.h',
1105 'services/tracing/public/cpp/perfetto/perfetto_tracing_backend\.cc',
1106 'services/tracing/public/cpp/perfetto/producer_client\.cc',
1107 'services/tracing/public/cpp/perfetto/producer_client\.h',
1108 'services/tracing/public/cpp/perfetto/producer_test_utils\.cc',
1109 'services/tracing/public/cpp/perfetto/producer_test_utils\.h',
1110 # Required for interop with the third-party webrtc library.
1111 'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.cc',
1112 'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.h',
1113 # TODO(https://crbug.com/1364577): Various uses that should be
1114 # migrated to something else.
1115 # Should use base::OnceCallback or base::RepeatingCallback.
1116 'base/allocator/dispatcher/initializer_unittest\.cc',
1117 'chrome/browser/ash/accessibility/speech_monitor\.cc',
1118 'chrome/browser/ash/accessibility/speech_monitor\.h',
1119 'chrome/browser/ash/login/ash_hud_login_browsertest\.cc',
1120 'chromecast/base/observer_unittest\.cc',
1121 'chromecast/browser/cast_web_view\.h',
1122 'chromecast/public/cast_media_shlib\.h',
1123 'device/bluetooth/floss/exported_callback_manager\.h',
1124 'device/bluetooth/floss/floss_dbus_client\.h',
1125 'device/fido/cable/v2_handshake_unittest\.cc',
1126 'device/fido/pin\.cc',
1127 'services/tracing/perfetto/test_utils\.h',
1128 # Should use base::FunctionRef.
1129 'chrome/browser/media/webrtc/test_stats_dictionary\.cc',
1130 'chrome/browser/media/webrtc/test_stats_dictionary\.h',
1131 'chromeos/ash/services/libassistant/device_settings_controller\.cc',
1132 'components/browser_ui/client_certificate/android/ssl_client_certificate_request\.cc',
1133 'components/gwp_asan/client/sampling_malloc_shims_unittest\.cc',
1134 'content/browser/font_unique_name_lookup/font_unique_name_lookup_unittest\.cc',
1135 # Does not need std::function at all.
1136 'components/omnibox/browser/autocomplete_result\.cc',
1137 'device/fido/win/webauthn_api\.cc',
1138 'media/audio/alsa/alsa_util\.cc',
1139 'media/remoting/stream_provider\.h',
1140 'sql/vfs_wrapper\.cc',
1141 # TODO(https://crbug.com/1364585): Remove usage and exception list
1142 # entries.
1143 'extensions/renderer/api/automation/automation_internal_custom_bindings\.cc',
1144 'extensions/renderer/api/automation/automation_internal_custom_bindings\.h',
1145 # TODO(https://crbug.com/1364579): Remove usage and exception list
1146 # entry.
1147 'ui/views/controls/focus_ring\.h',
Lei Zhang1f9d9ec42024-06-20 18:42:271148
Daniel Cheng566634ff2024-06-29 14:56:531149 # Various pre-existing uses in //tools that is low-priority to fix.
1150 'tools/binary_size/libsupersize/viewer/caspian/diff\.cc',
1151 'tools/binary_size/libsupersize/viewer/caspian/model\.cc',
1152 'tools/binary_size/libsupersize/viewer/caspian/model\.h',
1153 'tools/binary_size/libsupersize/viewer/caspian/tree_builder\.h',
1154 'tools/clang/base_bind_rewriters/BaseBindRewriters\.cpp',
Daniel Chenge5583e3c2022-09-22 00:19:411155
Daniel Cheng566634ff2024-06-29 14:56:531156 # Not an error in third_party folders.
1157 _THIRD_PARTY_EXCEPT_BLINK
1158 ],
Daniel Bratell609102be2019-03-27 20:53:211159 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151160 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531161 r'/#include <X11/',
1162 ('Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.', ),
1163 True,
1164 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Tom Andersona95e12042020-09-09 23:08:001165 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151166 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531167 r'/\bstd::ratio\b',
1168 ('std::ratio is banned by the Google Style Guide.', ),
1169 True,
1170 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:451171 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151172 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531173 r'/\bstd::aligned_alloc\b',
1174 (
1175 'std::aligned_alloc() is not yet allowed (crbug.com/1412818). Use ',
1176 'base::AlignedAlloc() instead.',
1177 ),
1178 True,
1179 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181180 ),
1181 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531182 r'/#include <(barrier|latch|semaphore|stop_token)>',
1183 ('The thread support library is banned. Use base/synchronization '
1184 'instead.', ),
1185 True,
1186 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181187 ),
1188 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531189 r'/\bstd::execution::(par|seq)\b',
1190 ('std::execution::(par|seq) is banned; they do not fit into '
1191 ' Chrome\'s threading model, and libc++ doesn\'t have full '
mikt19226ff22024-08-27 05:28:211192 'support.', ),
Daniel Cheng566634ff2024-06-29 14:56:531193 True,
1194 [_THIRD_PARTY_EXCEPT_BLINK],
Helmut Januschka7cc8a84f2024-02-07 22:50:411195 ),
1196 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531197 r'/\bstd::bit_cast\b',
1198 ('std::bit_cast is banned; use base::bit_cast instead for values and '
1199 'standard C++ casting when pointers are involved.', ),
1200 True,
1201 [
1202 # Don't warn in third_party folders.
1203 _THIRD_PARTY_EXCEPT_BLINK,
1204 # //base/numerics can't use base or absl.
1205 r'base/numerics/.*'
1206 ],
Avi Drissman70cb7f72023-12-12 17:44:371207 ),
1208 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531209 r'/\bstd::(c8rtomb|mbrtoc8)\b',
1210 ('std::c8rtomb() and std::mbrtoc8() are banned.', ),
1211 True,
1212 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181213 ),
1214 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531215 r'/\bchar8_t|std::u8string\b',
1216 (
1217 'char8_t and std::u8string are not yet allowed. Can you use [unsigned]',
1218 ' char and std::string instead?',
1219 ),
1220 True,
1221 [
1222 # The demangler does not use this type but needs to know about it.
1223 'base/third_party/symbolize/demangle\.cc',
1224 # Don't warn in third_party folders.
1225 _THIRD_PARTY_EXCEPT_BLINK
1226 ],
Peter Kastinge2c5ee82023-02-15 17:23:081227 ),
1228 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531229 r'/(\b(co_await|co_return|co_yield)\b|#include <coroutine>)',
1230 ('Coroutines are not yet allowed (https://crbug.com/1403840).', ),
1231 True,
1232 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081233 ),
1234 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531235 r'/^\s*(export\s|import\s+["<:\w]|module(;|\s+[:\w]))',
1236 ('Modules are disallowed for now due to lack of toolchain support.', ),
1237 True,
1238 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting69357dc2023-03-14 01:34:291239 ),
1240 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531241 r'/\[\[(\w*::)?no_unique_address\]\]',
1242 (
1243 '[[no_unique_address]] does not work as expected on Windows ',
1244 '(https://crbug.com/1414621). Use NO_UNIQUE_ADDRESS instead.',
1245 ),
1246 True,
1247 [
1248 # NO_UNIQUE_ADDRESS / PA_NO_UNIQUE_ADDRESS provide canonical access.
1249 r'^base/compiler_specific\.h',
1250 r'^base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/compiler_specific\.h',
1251 # Not an error in third_party folders.
1252 _THIRD_PARTY_EXCEPT_BLINK,
1253 ],
Peter Kasting8bc046d22023-11-14 00:38:031254 ),
1255 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531256 r'/#include <format>',
1257 ('<format> is not yet allowed. Use base::StringPrintf() instead.', ),
1258 True,
1259 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081260 ),
1261 BanRule(
Daniel Cheng89719222024-07-04 04:59:291262 pattern='std::views',
1263 explanation=(
1264 'Use of std::views is banned in Chrome. If you need this '
1265 'functionality, please contact [email protected].',
1266 ),
1267 treat_as_error=True,
1268 excluded_paths=[
1269 # Don't warn in third_party folders.
1270 _THIRD_PARTY_EXCEPT_BLINK
1271 ],
1272 ),
1273 BanRule(
1274 # Ban everything except specifically allowlisted constructs.
1275 pattern=r'/std::ranges::(?!' + '|'.join((
1276 # From https://en.cppreference.com/w/cpp/ranges:
1277 # Range access
1278 'begin',
1279 'end',
1280 'cbegin',
1281 'cend',
1282 'rbegin',
1283 'rend',
1284 'crbegin',
1285 'crend',
1286 'size',
1287 'ssize',
1288 'empty',
1289 'data',
1290 'cdata',
1291 # Range primitives
1292 'iterator_t',
1293 'const_iterator_t',
1294 'sentinel_t',
1295 'const_sentinel_t',
1296 'range_difference_t',
1297 'range_size_t',
1298 'range_value_t',
1299 'range_reference_t',
1300 'range_const_reference_t',
1301 'range_rvalue_reference_t',
1302 'range_common_reference_t',
1303 # Dangling iterator handling
1304 'dangling',
1305 'borrowed_iterator_t',
1306 # Banned: borrowed_subrange_t
1307 # Range concepts
1308 'range',
1309 'borrowed_range',
1310 'sized_range',
1311 'view',
1312 'input_range',
1313 'output_range',
1314 'forward_range',
1315 'bidirectional_range',
1316 'random_access_range',
1317 'contiguous_range',
1318 'common_range',
1319 'viewable_range',
1320 'constant_range',
1321 # Banned: Views
1322 # Banned: Range factories
1323 # Banned: Range adaptors
1324 # From https://en.cppreference.com/w/cpp/algorithm/ranges:
1325 # Constrained algorithms: non-modifying sequence operations
1326 'all_of',
1327 'any_of',
1328 'none_of',
1329 'for_each',
1330 'for_each_n',
1331 'count',
1332 'count_if',
1333 'mismatch',
1334 'equal',
1335 'lexicographical_compare',
1336 'find',
1337 'find_if',
1338 'find_if_not',
1339 'find_end',
1340 'find_first_of',
1341 'adjacent_find',
1342 'search',
1343 'search_n',
1344 # Constrained algorithms: modifying sequence operations
1345 'copy',
1346 'copy_if',
1347 'copy_n',
1348 'copy_backward',
1349 'move',
1350 'move_backward',
1351 'fill',
1352 'fill_n',
1353 'transform',
1354 'generate',
1355 'generate_n',
1356 'remove',
1357 'remove_if',
1358 'remove_copy',
1359 'remove_copy_if',
1360 'replace',
1361 'replace_if',
1362 'replace_copy',
1363 'replace_copy_if',
1364 'swap_ranges',
1365 'reverse',
1366 'reverse_copy',
1367 'rotate',
1368 'rotate_copy',
1369 'shuffle',
1370 'sample',
1371 'unique',
1372 'unique_copy',
1373 # Constrained algorithms: partitioning operations
1374 'is_partitioned',
1375 'partition',
1376 'partition_copy',
1377 'stable_partition',
1378 'partition_point',
1379 # Constrained algorithms: sorting operations
1380 'is_sorted',
1381 'is_sorted_until',
1382 'sort',
1383 'partial_sort',
1384 'partial_sort_copy',
1385 'stable_sort',
1386 'nth_element',
1387 # Constrained algorithms: binary search operations (on sorted ranges)
1388 'lower_bound',
1389 'upper_bound',
1390 'binary_search',
1391 'equal_range',
1392 # Constrained algorithms: set operations (on sorted ranges)
1393 'merge',
1394 'inplace_merge',
1395 'includes',
1396 'set_difference',
1397 'set_intersection',
1398 'set_symmetric_difference',
1399 'set_union',
1400 # Constrained algorithms: heap operations
1401 'is_heap',
1402 'is_heap_until',
1403 'make_heap',
1404 'push_heap',
1405 'pop_heap',
1406 'sort_heap',
1407 # Constrained algorithms: minimum/maximum operations
1408 'max',
1409 'max_element',
1410 'min',
1411 'min_element',
1412 'minmax',
1413 'minmax_element',
1414 'clamp',
1415 # Constrained algorithms: permutation operations
1416 'is_permutation',
1417 'next_permutation',
1418 'prev_premutation',
1419 # Constrained uninitialized memory algorithms
1420 'uninitialized_copy',
1421 'uninitialized_copy_n',
1422 'uninitialized_fill',
1423 'uninitialized_fill_n',
1424 'uninitialized_move',
1425 'uninitialized_move_n',
1426 'uninitialized_default_construct',
1427 'uninitialized_default_construct_n',
1428 'uninitialized_value_construct',
1429 'uninitialized_value_construct_n',
1430 'destroy',
1431 'destroy_n',
1432 'destroy_at',
1433 'construct_at',
1434 # Return types
1435 'in_fun_result',
1436 'in_in_result',
1437 'in_out_result',
1438 'in_in_out_result',
1439 'in_out_out_result',
1440 'min_max_result',
1441 'in_found_result',
danakj91c715bb2024-07-10 13:24:261442 # From https://en.cppreference.com/w/cpp/iterator
1443 'advance',
1444 'distance',
1445 'next',
1446 'prev',
Daniel Cheng89719222024-07-04 04:59:291447 )) + r')\w+',
1448 explanation=(
1449 'Use of range views and associated helpers is banned in Chrome. '
1450 'If you need this functionality, please contact [email protected].',
1451 ),
1452 treat_as_error=True,
1453 excluded_paths=[
1454 # Don't warn in third_party folders.
1455 _THIRD_PARTY_EXCEPT_BLINK
1456 ],
Peter Kastinge2c5ee82023-02-15 17:23:081457 ),
1458 BanRule(
Peter Kasting31879d82024-10-07 20:18:391459 r'/#include <regex>',
1460 ('<regex> is not allowed. Use third_party/re2 instead.',
1461 ),
1462 True,
1463 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1464 ),
1465 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531466 r'/#include <source_location>',
1467 ('<source_location> is not yet allowed. Use base/location.h instead.',
1468 ),
1469 True,
1470 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081471 ),
1472 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531473 r'/\bstd::to_address\b',
1474 (
1475 'std::to_address is banned because it is not guaranteed to be',
1476 'SFINAE-compatible. Use base::to_address from base/types/to_address.h',
1477 'instead.',
1478 ),
1479 True,
1480 [
1481 # Needed in base::to_address implementation.
1482 r'base/types/to_address.h',
1483 _THIRD_PARTY_EXCEPT_BLINK
1484 ], # Not an error in third_party folders.
Nick Diego Yamanee522ae82024-02-27 04:23:221485 ),
1486 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531487 r'/#include <syncstream>',
1488 ('<syncstream> is banned.', ),
1489 True,
1490 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181491 ),
1492 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531493 r'/\bRunMessageLoop\b',
1494 ('RunMessageLoop is deprecated, use RunLoop instead.', ),
1495 False,
1496 (),
Gabriel Charette147335ea2018-03-22 15:59:191497 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151498 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531499 'RunAllPendingInMessageLoop()',
1500 (
1501 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
1502 "if you're convinced you need this.",
1503 ),
1504 False,
1505 (),
Gabriel Charette147335ea2018-03-22 15:59:191506 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151507 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531508 'RunAllPendingInMessageLoop(BrowserThread',
1509 (
1510 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
1511 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
1512 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
1513 'async events instead of flushing threads.',
1514 ),
1515 False,
1516 (),
Gabriel Charette147335ea2018-03-22 15:59:191517 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151518 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531519 r'MessageLoopRunner',
1520 ('MessageLoopRunner is deprecated, use RunLoop instead.', ),
1521 False,
1522 (),
Gabriel Charette147335ea2018-03-22 15:59:191523 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151524 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531525 'GetDeferredQuitTaskForRunLoop',
1526 (
1527 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
1528 "gab@ if you found a use case where this is the only solution.",
1529 ),
1530 False,
1531 (),
Gabriel Charette147335ea2018-03-22 15:59:191532 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151533 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531534 'sqlite3_initialize(',
1535 (
1536 'Instead of calling sqlite3_initialize(), depend on //sql, ',
1537 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
1538 ),
1539 True,
1540 (
1541 r'^sql/initialization\.(cc|h)$',
1542 r'^third_party/sqlite/.*\.(c|cc|h)$',
1543 ),
Victor Costan3653df62018-02-08 21:38:161544 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151545 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531546 'CREATE VIEW',
1547 (
1548 'SQL views are disabled in Chromium feature code',
1549 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-views',
1550 ),
1551 True,
1552 (
1553 _THIRD_PARTY_EXCEPT_BLINK,
1554 # sql/ itself uses views when using memory-mapped IO.
1555 r'^sql/.*',
1556 # Various performance tools that do not build as part of Chrome.
1557 r'^infra/.*',
1558 r'^tools/perf.*',
1559 r'.*perfetto.*',
1560 ),
Austin Sullivand661ab52022-11-16 08:55:151561 ),
1562 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531563 'CREATE VIRTUAL TABLE',
1564 (
1565 'SQL virtual tables are disabled in Chromium feature code',
1566 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-virtual-tables',
1567 ),
1568 True,
1569 (
1570 _THIRD_PARTY_EXCEPT_BLINK,
1571 # sql/ itself uses virtual tables in the recovery module and tests.
1572 r'^sql/.*',
1573 # TODO(https://crbug.com/695592): Remove once WebSQL is deprecated.
1574 r'third_party/blink/web_tests/storage/websql/.*'
1575 # Various performance tools that do not build as part of Chrome.
1576 r'^tools/perf.*',
1577 r'.*perfetto.*',
1578 ),
Austin Sullivand661ab52022-11-16 08:55:151579 ),
1580 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531581 'std::random_shuffle',
1582 ('std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
1583 'base::RandomShuffle instead.'),
1584 True,
1585 (),
tzik5de2157f2018-05-08 03:42:471586 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151587 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531588 'ios/web/public/test/http_server',
1589 ('web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
1590 ),
1591 False,
1592 (),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:241593 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151594 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531595 'GetAddressOf',
1596 ('Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
1597 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
1598 'operator& is generally recommended. So always use operator& instead. ',
1599 'See http://crbug.com/914910 for more conversion guidance.'),
1600 True,
1601 (),
Robert Liao764c9492019-01-24 18:46:281602 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151603 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531604 'SHFileOperation',
1605 ('SHFileOperation was deprecated in Windows Vista, and there are less ',
1606 'complex functions to achieve the same goals. Use IFileOperation for ',
1607 'any esoteric actions instead.'),
1608 True,
1609 (),
Ben Lewisa9514602019-04-29 17:53:051610 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151611 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531612 'StringFromGUID2',
1613 ('StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
1614 'Use base::win::WStringFromGUID instead.'),
1615 True,
1616 (r'/base/win/win_util_unittest.cc', ),
Cliff Smolinsky81951642019-04-30 21:39:511617 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151618 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531619 'StringFromCLSID',
1620 ('StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
1621 'Use base::win::WStringFromGUID instead.'),
1622 True,
1623 (r'/base/win/win_util_unittest.cc', ),
Cliff Smolinsky81951642019-04-30 21:39:511624 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151625 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531626 'kCFAllocatorNull',
1627 (
1628 'The use of kCFAllocatorNull with the NoCopy creation of ',
1629 'CoreFoundation types is prohibited.',
1630 ),
1631 True,
1632 (),
Avi Drissman7382afa02019-04-29 23:27:131633 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151634 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531635 'mojo::ConvertTo',
1636 ('mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1637 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1638 'StringTraits if you would like to convert between custom types and',
1639 'the wire format of mojom types.'),
1640 False,
1641 (
1642 r'^fuchsia_web/webengine/browser/url_request_rewrite_rules_manager\.cc$',
1643 r'^fuchsia_web/webengine/url_request_rewrite_type_converters\.cc$',
1644 r'^third_party/blink/.*\.(cc|h)$',
1645 r'^content/renderer/.*\.(cc|h)$',
1646 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291647 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151648 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531649 'GetInterfaceProvider',
1650 ('InterfaceProvider is deprecated.',
1651 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1652 'or Platform::GetBrowserInterfaceBroker.'),
1653 False,
1654 (),
Oksana Zhuravlovac8222d22019-12-19 19:21:161655 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151656 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531657 'CComPtr',
1658 ('New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1659 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1660 'details.'),
1661 False,
1662 (),
Robert Liao1d78df52019-11-11 20:02:011663 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151664 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531665 r'/\b(IFACE|STD)METHOD_?\(',
1666 ('IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1667 'Instead, always use IFACEMETHODIMP in the declaration.'),
1668 False,
1669 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Xiaohan Wang72bd2ba2020-02-18 21:38:201670 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151671 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531672 'set_owned_by_client',
1673 ('set_owned_by_client is deprecated.',
1674 'views::View already owns the child views by default. This introduces ',
1675 'a competing ownership model which makes the code difficult to reason ',
1676 'about. See http://crbug.com/1044687 for more details.'),
1677 False,
1678 (),
Allen Bauer53b43fb12020-03-12 17:21:471679 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151680 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531681 'RemoveAllChildViewsWithoutDeleting',
1682 ('RemoveAllChildViewsWithoutDeleting is deprecated.',
1683 'This method is deemed dangerous as, unless raw pointers are re-added,',
1684 'calls to this method introduce memory leaks.'),
1685 False,
1686 (),
Peter Boström7ff41522021-07-29 03:43:271687 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151688 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531689 r'/\bTRACE_EVENT_ASYNC_',
1690 (
1691 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1692 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1693 ),
1694 False,
1695 (
1696 r'^base/trace_event/.*',
1697 r'^base/tracing/.*',
1698 ),
Eric Secklerbe6f48d2020-05-06 18:09:121699 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151700 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531701 r'/\bbase::debug::DumpWithoutCrashingUnthrottled[(][)]',
1702 (
1703 'base::debug::DumpWithoutCrashingUnthrottled() does not throttle',
1704 'dumps and may spam crash reports. Consider if the throttled',
1705 'variants suffice instead.',
1706 ),
1707 False,
1708 (),
Aditya Kushwah5a286b72022-02-10 04:54:431709 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151710 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531711 'RoInitialize',
1712 ('Improper use of [base::win]::RoInitialize() has been implicated in a ',
1713 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
1714 'instead. See http://crbug.com/1197722 for more information.'),
1715 True,
1716 (
1717 r'^base/win/scoped_winrt_initializer\.cc$',
1718 r'^third_party/abseil-cpp/absl/.*',
1719 ),
Robert Liao22f66a52021-04-10 00:57:521720 ),
Patrick Monettec343bb982022-06-01 17:18:451721 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531722 r'base::Watchdog',
1723 (
1724 'base::Watchdog is deprecated because it creates its own thread.',
1725 'Instead, manually start a timer on a SequencedTaskRunner.',
1726 ),
1727 False,
1728 (),
Patrick Monettec343bb982022-06-01 17:18:451729 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091730 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531731 'base::Passed',
1732 ('Do not use base::Passed. It is a legacy helper for capturing ',
1733 'move-only types with base::BindRepeating, but invoking the ',
1734 'resulting RepeatingCallback moves the captured value out of ',
1735 'the callback storage, and subsequent invocations may pass the ',
1736 'value in a valid but undefined state. Prefer base::BindOnce().',
1737 'See http://crbug.com/1326449 for context.'),
1738 False,
1739 (
1740 # False positive, but it is also fine to let bind internals reference
1741 # base::Passed.
1742 r'^base[\\/]functional[\\/]bind\.h',
1743 r'^base[\\/]functional[\\/]bind_internal\.h',
1744 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091745 ),
Daniel Cheng2248b332022-07-27 06:16:591746 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531747 r'base::Feature k',
1748 ('Please use BASE_DECLARE_FEATURE() or BASE_FEATURE() instead of ',
1749 'directly declaring/defining features.'),
1750 True,
1751 [
1752 # Implements BASE_DECLARE_FEATURE().
1753 r'^base/feature_list\.h',
1754 ],
Daniel Chengba3bc2e2022-10-03 02:45:431755 ),
Robert Ogden92101dcb2022-10-19 23:49:361756 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531757 r'/\bchartorune\b',
1758 ('chartorune is not memory-safe, unless you can guarantee the input ',
1759 'string is always null-terminated. Otherwise, please use charntorune ',
1760 'from libphonenumber instead.'),
1761 True,
1762 [
1763 _THIRD_PARTY_EXCEPT_BLINK,
1764 # Exceptions to this rule should have a fuzzer.
1765 ],
Robert Ogden92101dcb2022-10-19 23:49:361766 ),
Arthur Sonzogni1da65fa2023-03-27 16:01:521767 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531768 r'/\b#include "base/atomicops\.h"\b',
1769 ('Do not use base::subtle atomics, but std::atomic, which are simpler '
1770 'to use, have better understood, clearer and richer semantics, and are '
1771 'harder to mis-use. See details in base/atomicops.h.', ),
1772 False,
1773 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Benoit Lize79cf0592023-01-27 10:01:571774 ),
Daniel Cheng566634ff2024-06-29 14:56:531775 BanRule(r'CrossThreadPersistent<', (
Arthur Sonzogni60348572e2023-04-07 10:22:521776 'Do not use blink::CrossThreadPersistent, but '
Daniel Cheng566634ff2024-06-29 14:56:531777 'blink::CrossThreadHandle. It is harder to mis-use.', 'More info: '
Arthur Sonzogni60348572e2023-04-07 10:22:521778 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1779 'Please contact platform-architecture-dev@ before adding new instances.'
Daniel Cheng566634ff2024-06-29 14:56:531780 ), False, []),
1781 BanRule(r'CrossThreadWeakPersistent<', (
Arthur Sonzogni60348572e2023-04-07 10:22:521782 'Do not use blink::CrossThreadWeakPersistent, but '
Daniel Cheng566634ff2024-06-29 14:56:531783 'blink::CrossThreadWeakHandle. It is harder to mis-use.', 'More info: '
Arthur Sonzogni60348572e2023-04-07 10:22:521784 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1785 'Please contact platform-architecture-dev@ before adding new instances.'
Daniel Cheng566634ff2024-06-29 14:56:531786 ), False, []),
1787 BanRule(r'objc/objc.h', (
Avi Drissman491617c2023-04-13 17:33:151788 'Do not include <objc/objc.h>. It defines away ARC lifetime '
1789 'annotations, and is thus dangerous.',
1790 'Please use the pimpl pattern; search for `ObjCStorage` for examples.',
1791 'For further reading on how to safely mix C++ and Obj-C, see',
1792 'https://chromium.googlesource.com/chromium/src/+/main/docs/mac/mixing_cpp_and_objc.md'
Daniel Cheng566634ff2024-06-29 14:56:531793 ), True, []),
1794 BanRule(
1795 r'/#include <filesystem>',
1796 ('libc++ <filesystem> is banned per the Google C++ styleguide.', ),
1797 True,
1798 # This fuzzing framework is a standalone open source project and
1799 # cannot rely on Chromium base.
1800 (r'third_party/centipede'),
Avi Drissman491617c2023-04-13 17:33:151801 ),
Grace Park8d59b54b2023-04-26 17:53:351802 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531803 r'TopDocument()',
1804 ('TopDocument() does not work correctly with out-of-process iframes. '
1805 'Please do not introduce new uses.', ),
1806 True,
1807 (
1808 # TODO(crbug.com/617677): Remove all remaining uses.
1809 r'^third_party/blink/renderer/core/dom/document\.cc',
1810 r'^third_party/blink/renderer/core/dom/document\.h',
1811 r'^third_party/blink/renderer/core/dom/element\.cc',
1812 r'^third_party/blink/renderer/core/exported/web_disallow_transition_scope_test\.cc',
1813 r'^third_party/blink/renderer/core/exported/web_document_test\.cc',
1814 r'^third_party/blink/renderer/core/html/html_anchor_element\.cc',
1815 r'^third_party/blink/renderer/core/html/html_dialog_element\.cc',
1816 r'^third_party/blink/renderer/core/html/html_element\.cc',
1817 r'^third_party/blink/renderer/core/html/html_frame_owner_element\.cc',
1818 r'^third_party/blink/renderer/core/html/media/video_wake_lock\.cc',
1819 r'^third_party/blink/renderer/core/loader/anchor_element_interaction_tracker\.cc',
1820 r'^third_party/blink/renderer/core/page/scrolling/root_scroller_controller\.cc',
1821 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.cc',
1822 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.h',
1823 r'^third_party/blink/renderer/core/script/classic_pending_script\.cc',
1824 r'^third_party/blink/renderer/core/script/script_loader\.cc',
1825 ),
Grace Park8d59b54b2023-04-26 17:53:351826 ),
Daniel Cheng72153e02023-05-18 21:18:141827 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531828 pattern=r'base::raw_ptr<',
1829 explanation=('Do not use base::raw_ptr, use raw_ptr.', ),
1830 treat_as_error=True,
1831 excluded_paths=(
1832 '^base/',
1833 '^tools/',
1834 ),
Daniel Cheng72153e02023-05-18 21:18:141835 ),
Arthur Sonzognif0eea302023-08-18 19:20:311836 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531837 pattern=r'base:raw_ref<',
1838 explanation=('Do not use base::raw_ref, use raw_ref.', ),
1839 treat_as_error=True,
1840 excluded_paths=(
1841 '^base/',
1842 '^tools/',
1843 ),
Arthur Sonzognif0eea302023-08-18 19:20:311844 ),
1845 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531846 pattern=r'/raw_ptr<[^;}]*\w{};',
1847 explanation=(
1848 'Do not use {} for raw_ptr initialization, use = nullptr instead.',
1849 ),
1850 treat_as_error=True,
1851 excluded_paths=(
1852 '^base/',
1853 '^tools/',
1854 ),
Arthur Sonzognif0eea302023-08-18 19:20:311855 ),
Anton Maliev66751812023-08-24 16:28:131856 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531857 pattern=r'/#include "base/allocator/.*/raw_'
1858 r'(ptr|ptr_cast|ptr_exclusion|ref).h"',
1859 explanation=(
1860 'Please include the corresponding facade headers:',
1861 '- #include "base/memory/raw_ptr.h"',
1862 '- #include "base/memory/raw_ptr_cast.h"',
1863 '- #include "base/memory/raw_ptr_exclusion.h"',
1864 '- #include "base/memory/raw_ref.h"',
1865 ),
1866 treat_as_error=True,
1867 excluded_paths=(
1868 '^base/',
1869 '^tools/',
1870 ),
Tom Sepez41eb158d2023-09-12 16:16:221871 ),
1872 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531873 pattern=r'ContentSettingsType::COOKIES',
1874 explanation=
1875 ('Do not use ContentSettingsType::COOKIES to check whether cookies are '
1876 'supported in the provided context. Instead rely on the '
1877 'content_settings::CookieSettings API. If you are using '
1878 'ContentSettingsType::COOKIES to check the user preference setting '
1879 'specifically, disregard this warning.', ),
1880 treat_as_error=False,
1881 excluded_paths=(
1882 '^chrome/browser/ui/content_settings/',
1883 '^components/content_settings/',
1884 '^services/network/cookie_settings.cc',
1885 '.*test.cc',
1886 ),
Arthur Sonzogni48c6aea22023-09-04 22:25:201887 ),
1888 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531889 pattern=r'ContentSettingsType::TRACKING_PROTECTION',
1890 explanation=
1891 ('Do not directly use ContentSettingsType::TRACKING_PROTECTION to check '
1892 'for tracking protection exceptions. Instead rely on the '
1893 'privacy_sandbox::TrackingProtectionSettings API.', ),
1894 treat_as_error=False,
1895 excluded_paths=(
1896 '^chrome/browser/ui/content_settings/',
1897 '^components/content_settings/',
1898 '^components/privacy_sandbox/tracking_protection_settings.cc',
1899 '.*test.cc',
1900 ),
Anton Maliev66751812023-08-24 16:28:131901 ),
Tom Andersoncd522072023-10-03 00:52:351902 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531903 pattern=r'/\bg_signal_connect',
1904 explanation=('Use ScopedGSignal instead of g_signal_connect*()', ),
1905 treat_as_error=True,
1906 excluded_paths=('^ui/base/glib/scoped_gsignal.h', ),
Michelle Abreo6b7437822024-04-26 17:29:041907 ),
1908 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531909 pattern=r'features::kIsolatedWebApps',
1910 explanation=(
1911 'Do not use `features::kIsolatedWebApps` directly to guard Isolated ',
1912 'Web App code. ',
1913 'Use `content::IsolatedWebAppsPolicy::AreIsolatedWebAppsEnabled()` in ',
1914 'the browser process or check the `kEnableIsolatedWebAppsInRenderer` ',
1915 'command line flag in the renderer process.',
1916 ),
1917 treat_as_error=True,
1918 excluded_paths=_TEST_CODE_EXCLUDED_PATHS +
1919 ('^chrome/browser/about_flags.cc',
1920 '^chrome/browser/web_applications/isolated_web_apps/chrome_content_browser_client_isolated_web_apps_part.cc',
1921 '^chrome/browser/ui/startup/bad_flags_prompt.cc',
1922 '^content/shell/browser/shell_content_browser_client.cc')),
1923 BanRule(
1924 pattern=r'features::kIsolatedWebAppDevMode',
1925 explanation=(
1926 'Do not use `features::kIsolatedWebAppDevMode` directly to guard code ',
1927 'related to Isolated Web App Developer Mode. ',
1928 'Use `web_app::IsIwaDevModeEnabled()` instead.',
1929 ),
1930 treat_as_error=True,
1931 excluded_paths=_TEST_CODE_EXCLUDED_PATHS + (
1932 '^chrome/browser/about_flags.cc',
1933 '^chrome/browser/web_applications/isolated_web_apps/isolated_web_app_features.cc',
1934 '^chrome/browser/ui/startup/bad_flags_prompt.cc',
1935 )),
1936 BanRule(
1937 pattern=r'features::kIsolatedWebAppUnmanagedInstall',
1938 explanation=(
1939 'Do not use `features::kIsolatedWebAppUnmanagedInstall` directly to ',
1940 'guard code related to unmanaged install flow for Isolated Web Apps. ',
1941 'Use `web_app::IsIwaUnmanagedInstallEnabled()` instead.',
1942 ),
1943 treat_as_error=True,
1944 excluded_paths=_TEST_CODE_EXCLUDED_PATHS + (
1945 '^chrome/browser/about_flags.cc',
1946 '^chrome/browser/web_applications/isolated_web_apps/isolated_web_app_features.cc',
1947 )),
1948 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531949 pattern='/(CUIAutomation|AccessibleObjectFromWindow)',
1950 explanation=
1951 ('Direct usage of UIAutomation or IAccessible2 in client code is '
1952 'discouraged in Chromium, as it is not an assistive technology and '
1953 'should not rely on accessibility APIs directly. These APIs can '
1954 'introduce significant performance overhead. However, if you believe '
1955 'your use case warrants an exception, please discuss it with an '
1956 'accessibility owner before proceeding. For more information on the '
1957 'performance implications, see https://docs.google.com/document/d/1jN4itpCe_bDXF0BhFaYwv4xVLsCWkL9eULdzjmLzkuk/edit#heading=h.pwth3nbwdub0.',
1958 ),
1959 treat_as_error=False,
Andrew Rayskiycdd45e732024-03-20 14:32:391960 ),
1961 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531962 pattern=r'/WIDGET_OWNS_NATIVE_WIDGET|'
1963 r'NATIVE_WIDGET_OWNS_WIDGET',
1964 explanation=
1965 ('WIDGET_OWNS_NATIVE_WIDGET and NATIVE_WIDGET_OWNS_WIDGET are in the '
1966 'process of being deprecated. Consider using the new '
1967 'CLIENT_OWNS_WIDGET ownership model. Eventually, this will be the only '
1968 'available ownership model available and the associated enumeration'
1969 'will be removed.', ),
1970 treat_as_error=False,
Andrew Rayskiycdd45e732024-03-20 14:32:391971 ),
1972 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531973 pattern='ProfileManager::GetLastUsedProfile',
1974 explanation=
1975 ('Most code should already be scoped to a Profile. Pass in a Profile* '
1976 'or retreive from an existing entity with a reference to the Profile '
1977 '(e.g. WebContents).', ),
1978 treat_as_error=False,
Arthur Sonzogni5cbd3e32024-02-08 17:51:321979 ),
Helmut Januschkab3f71ab52024-03-12 02:48:051980 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531981 pattern=(r'/FindBrowserWithUiElementContext|'
1982 r'FindBrowserWithTab|'
1983 r'FindBrowserWithGroup|'
1984 r'FindTabbedBrowser|'
1985 r'FindAnyBrowser|'
1986 r'FindBrowserWithProfile|'
Erik Chen5f02eb4c2024-08-23 06:30:441987 r'FindLastActive|'
Daniel Cheng566634ff2024-06-29 14:56:531988 r'FindBrowserWithActiveWindow'),
1989 explanation=
1990 ('Most code should already be scoped to a Browser. Pass in a Browser* '
1991 'or retreive from an existing entity with a reference to the Browser.',
1992 ),
1993 treat_as_error=False,
Helmut Januschkab3f71ab52024-03-12 02:48:051994 ),
1995 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531996 pattern='BrowserUserData',
1997 explanation=
1998 ('Do not use BrowserUserData to store state on a Browser instance. '
1999 'Instead use BrowserWindowFeatures. BrowserWindowFeatures is '
2000 'functionally identical but has two benefits: it does not force a '
2001 'dependency onto class Browser, and lifetime semantics are explicit '
2002 'rather than implicit. See BrowserUserData header file for more '
2003 'details.', ),
2004 treat_as_error=False,
Mike Doughertyab1bdec2024-08-06 16:39:012005 excluded_paths=(
2006 # Exclude iOS as the iOS implementation of BrowserUserData is separate
2007 # and still in use.
2008 '^ios/',
2009 ),
Erik Chen87358e82024-06-04 02:13:122010 ),
Tom Sepezea67b6e2024-08-08 18:17:272011 BanRule(
2012 pattern=r'UNSAFE_TODO(',
2013 explanation=
2014 ('Do not use UNSAFE_TODO() to write new unsafe code. Use only when '
Tom Sepeza90f92b2024-08-15 16:01:352015 'removing a pre-existing file-wide allow_unsafe_buffers pragma, or '
2016 'when incrementally converting code off of unsafe interfaces',
Tom Sepezea67b6e2024-08-08 18:17:272017 ),
2018 treat_as_error=False,
2019 ),
2020 BanRule(
2021 pattern=r'UNSAFE_BUFFERS(',
2022 explanation=
Tom Sepeza90f92b2024-08-15 16:01:352023 ('Try to avoid using UNSAFE_BUFFERS() if at all possible. Otherwise, '
2024 'be sure to justify in a // SAFETY comment why other options are not '
2025 'available, and why the code is safe.',
Tom Sepezea67b6e2024-08-08 18:17:272026 ),
2027 treat_as_error=False,
2028 ),
Erik Chend086ae02024-08-20 22:53:332029 BanRule(
2030 pattern='BrowserWithTestWindowTest',
2031 explanation=
2032 ('Do not use BrowserWithTestWindowTest. By instantiating an instance '
2033 'of class Browser, the test is no longer a unit test but is instead a '
2034 'browser test. The class BrowserWithTestWindowTest forces production '
2035 'logic to take on test-only conditionals, which is an anti-pattern. '
2036 'Features should be performing dependency injection rather than '
2037 'directly using class Browser. See '
mikt19226ff22024-08-27 05:28:212038 'docs/chrome_browser_design_principles.md for more details.',
Erik Chend086ae02024-08-20 22:53:332039 ),
2040 treat_as_error=False,
2041 ),
Erik Chen8cf3a652024-08-23 17:13:302042 BanRule(
Erik Chen959cdd72024-08-29 02:11:212043 pattern='TestWithBrowserView',
2044 explanation=
2045 ('Do not use TestWithBrowserView. See '
2046 'docs/chrome_browser_design_principles.md for details. If you want '
2047 'to write a test that has both a Browser and a BrowserView, create '
2048 'a browser_test. If you want to write a unit_test, your code must '
Erik Chendba23692024-09-26 06:43:362049 'not reference Browser*.',
Erik Chen959cdd72024-08-29 02:11:212050 ),
2051 treat_as_error=False,
2052 ),
2053 BanRule(
Erik Chen8cf3a652024-08-23 17:13:302054 pattern='RunUntilIdle',
2055 explanation=
2056 ('Do not RunUntilIdle. If possible, explicitly quit the run loop using '
2057 'run_loop.Quit() or run_loop.QuitClosure() if completion can be '
2058 'observed using a lambda or callback. Otherwise, wait for the '
mikt19226ff22024-08-27 05:28:212059 'condition to be true via base::test::RunUntil().',
Erik Chen8cf3a652024-08-23 17:13:302060 ),
2061 treat_as_error=False,
2062 ),
Daniel Chengddde13a2024-09-05 21:39:282063 BanRule(
2064 pattern=r'/\bstd::(literals|string_literals|string_view_literals)\b',
2065 explanation = (
2066 'User-defined literals are banned by the Google C++ style guide. '
2067 'Exceptions are provided in Chrome for string and string_view '
2068 'literals that embed \\0.',
2069 ),
2070 treat_as_error=True,
2071 excluded_paths=(
2072 # Various tests or test helpers that embed NUL in strings or
2073 # string_views.
2074 r'^ash/components/arc/session/serial_number_util_unittest\.cc',
2075 r'^base/strings/string_util_unittest\.cc',
2076 r'^base/strings/utf_string_conversions_unittest\.cc',
2077 r'^chrome/browser/ash/crosapi/browser_data_back_migrator_unittest\.cc',
2078 r'^chrome/browser/ash/crosapi/browser_data_migrator_util_unittest\.cc',
2079 r'^chrome/browser/ash/crosapi/move_migrator_unittest\.cc',
2080 r'^components/history/core/browser/visit_annotations_database\.cc',
2081 r'^components/history/core/browser/visit_annotations_database_unittest\.cc',
2082 r'^components/os_crypt/sync/os_crypt_unittest\.cc',
2083 r'^components/password_manager/core/browser/credentials_cleaner_unittest\.cc',
2084 r'^content/browser/file_system_access/file_system_access_file_writer_impl_unittest\.cc',
2085 r'^net/cookies/parsed_cookie_unittest\.cc',
2086 r'^third_party/blink/renderer/modules/webcodecs/test_helpers\.cc',
2087 r'^third_party/blink/renderer/modules/websockets/websocket_channel_impl_test\.cc',
2088 ),
Erik Chenba8b0cd32024-10-01 08:36:362089 ),
2090 BanRule(
2091 pattern='BUILDFLAG(GOOGLE_CHROME_BRANDING)',
2092 explanation=
2093 ('Code gated by GOOGLE_CHROME_BRANDING is effectively untested. This '
2094 'is typically wrong. Valid use cases are glue for private modules '
2095 'shipped alongside Chrome, and installation-related logic.',
2096 ),
2097 treat_as_error=False,
2098 ),
2099 BanRule(
2100 pattern='defined(OFFICIAL_BUILD)',
2101 explanation=
2102 ('Code gated by OFFICIAL_BUILD is effectively untested. This '
2103 'is typically wrong. One valid use case is low-level code that '
2104 'handles subtleties related to high-levels of optimizations that come '
2105 'with OFFICIAL_BUILD.',
2106 ),
2107 treat_as_error=False,
2108 ),
[email protected]127f18ec2012-06-16 05:05:592109)
2110
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152111_DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING = (
2112 'Used a predicate related to signin::ConsentLevel::kSync which will always '
2113 'return false in the future (crbug.com/40066949). Prefer using a predicate '
2114 'that also supports signin::ConsentLevel::kSignin when appropriate. It is '
2115 'safe to ignore this warning if you are just moving an existing call, or if '
2116 'you want special handling for users in the legacy state. In doubt, reach '
Victor Hugo Vianna Silvae2292972024-06-04 17:11:552117 'out to //components/sync/OWNERS.',
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152118)
2119
2120# C++ functions related to signin::ConsentLevel::kSync which are deprecated.
2121_DEPRECATED_SYNC_CONSENT_CPP_FUNCTIONS : Sequence[BanRule] = (
2122 BanRule(
2123 'HasSyncConsent',
2124 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2125 False,
2126 ),
2127 BanRule(
2128 'CanSyncFeatureStart',
2129 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2130 False,
2131 ),
2132 BanRule(
2133 'IsSyncFeatureEnabled',
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152134 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152135 False,
2136 ),
2137 BanRule(
2138 'IsSyncFeatureActive',
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152139 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152140 False,
2141 ),
2142)
2143
2144# Java functions related to signin::ConsentLevel::kSync which are deprecated.
2145_DEPRECATED_SYNC_CONSENT_JAVA_FUNCTIONS : Sequence[BanRule] = (
2146 BanRule(
2147 'hasSyncConsent',
2148 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2149 False,
2150 ),
2151 BanRule(
2152 'canSyncFeatureStart',
2153 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2154 False,
2155 ),
2156 BanRule(
2157 'isSyncFeatureEnabled',
2158 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2159 False,
2160 ),
2161 BanRule(
2162 'isSyncFeatureActive',
2163 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2164 False,
2165 ),
2166)
2167
Daniel Cheng92c15e32022-03-16 17:48:222168_BANNED_MOJOM_PATTERNS : Sequence[BanRule] = (
2169 BanRule(
2170 'handle<shared_buffer>',
2171 (
2172 'Please use one of the more specific shared memory types instead:',
2173 ' mojo_base.mojom.ReadOnlySharedMemoryRegion',
2174 ' mojo_base.mojom.WritableSharedMemoryRegion',
2175 ' mojo_base.mojom.UnsafeSharedMemoryRegion',
2176 ),
2177 True,
2178 ),
2179)
2180
mlamouria82272622014-09-16 18:45:042181_IPC_ENUM_TRAITS_DEPRECATED = (
2182 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:502183 'See http://www.chromium.org/Home/chromium-security/education/'
2184 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:042185
Stephen Martinis97a394142018-06-07 23:06:052186_LONG_PATH_ERROR = (
2187 'Some files included in this CL have file names that are too long (> 200'
2188 ' characters). If committed, these files will cause issues on Windows. See'
2189 ' https://crbug.com/612667 for more details.'
2190)
2191
Shenghua Zhangbfaa38b82017-11-16 21:58:022192_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Bruce Dawson40fece62022-09-16 19:58:312193 r".*/BuildHooksAndroidImpl\.java",
2194 r".*/LicenseContentProvider\.java",
2195 r".*/PlatformServiceBridgeImpl.java",
2196 r".*chrome/android/feed/dummy/.*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:022197]
[email protected]127f18ec2012-06-16 05:05:592198
Mohamed Heikald048240a2019-11-12 16:57:372199# List of image extensions that are used as resources in chromium.
2200_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
2201
Sean Kau46e29bc2017-08-28 16:31:162202# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:402203_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Bruce Dawson40fece62022-09-16 19:58:312204 r'test/data/',
2205 r'testing/buildbot/',
2206 r'^components/policy/resources/policy_templates\.json$',
2207 r'^third_party/protobuf/',
Camillo Bruni1411a352023-05-24 12:39:032208 r'^third_party/blink/perf_tests/speedometer.*/resources/todomvc/learn\.json',
Bruce Dawson40fece62022-09-16 19:58:312209 r'^third_party/blink/renderer/devtools/protocol\.json$',
2210 r'^third_party/blink/web_tests/external/wpt/',
2211 r'^tools/perf/',
2212 r'^tools/traceline/svgui/startup-release.json',
Daniel Cheng2d4c2d192022-07-01 01:38:312213 # vscode configuration files allow comments
Bruce Dawson40fece62022-09-16 19:58:312214 r'^tools/vscode/',
Sean Kau46e29bc2017-08-28 16:31:162215]
2216
Andrew Grieveb773bad2020-06-05 18:00:382217# These are not checked on the public chromium-presubmit trybot.
2218# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:042219# checkouts.
agrievef32bcc72016-04-04 14:57:402220_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:382221 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382222]
2223
2224
2225_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:042226 'android_webview/tools/run_cts.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:362227 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042228 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362229 'build/android/gyp/aar.pydeps',
2230 'build/android/gyp/aidl.pydeps',
2231 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:382232 'build/android/gyp/assert_static_initializers.pydeps',
Mohamed Heikal133e1f22023-04-18 20:04:372233 'build/android/gyp/binary_baseline_profile.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362234 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:022235 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:222236 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:112237 'build/android/gyp/compile_java.pydeps',
Peter Weneaa963f2023-01-20 19:40:302238 'build/android/gyp/compile_kt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362239 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362240 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362241 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:112242 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042243 'build/android/gyp/create_app_bundle_apks.pydeps',
2244 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362245 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:122246 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:092247 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:222248 'build/android/gyp/create_size_info_files.pydeps',
Peter Wene6e017e2022-07-27 21:40:402249 'build/android/gyp/create_test_apk_wrapper_script.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002250 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362251 'build/android/gyp/dex.pydeps',
2252 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362253 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:212254 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362255 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:362256 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362257 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:582258 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362259 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:142260 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:262261 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:472262 'build/android/gyp/java_google_api_keys.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042263 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362264 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362265 'build/android/gyp/merge_manifest.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:102266 'build/android/gyp/optimize_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362267 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:222268 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362269 'build/android/gyp/proguard.pydeps',
Mohamed Heikaldd52b452024-09-10 17:10:502270 'build/android/gyp/rename_java_classes.pydeps',
Andrew Grievee3a775ab2022-05-16 15:59:222271 'build/android/gyp/system_image_apks.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:102272 'build/android/gyp/trace_event_bytecode_rewriter.pydeps',
Peter Wen578730b2020-03-19 19:55:462273 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:302274 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:242275 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362276 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:462277 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:562278 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362279 'build/android/incremental_install/generate_android_manifest.pydeps',
2280 'build/android/incremental_install/write_installer_json.pydeps',
Stephanie Kim392913b452022-06-15 17:25:322281 'build/android/pylib/results/presentation/test_results_presentation.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042282 'build/android/resource_sizes.pydeps',
2283 'build/android/test_runner.pydeps',
2284 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:362285 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362286 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:322287 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:272288 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
2289 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:042290 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Mohannad Farrag19102742023-12-01 01:16:302291 'components/cronet/tools/check_combined_proguard_file.pydeps',
2292 'components/cronet/tools/generate_proguard_file.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002293 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382294 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002295 'content/public/android/generate_child_service.pydeps',
Hzj_jie77bdb802024-07-22 18:14:512296 'fuchsia_web/av_testing/av_sync_tests.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382297 'net/tools/testserver/testserver.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:182298 'testing/scripts/run_isolated_script_test.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:412299 'testing/merge_scripts/standard_isolated_script_merge.pydeps',
2300 'testing/merge_scripts/standard_gtest_merge.pydeps',
2301 'testing/merge_scripts/code_coverage/merge_results.pydeps',
2302 'testing/merge_scripts/code_coverage/merge_steps.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042303 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:422304 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
Yuki Shiino38eeaad12022-08-11 06:40:252305 'third_party/blink/renderer/bindings/scripts/check_generated_file_list.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:422306 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:132307 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Yuki Shiinoea477d32023-08-21 06:24:342308 'third_party/blink/renderer/bindings/scripts/generate_event_interface_names.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:502309 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:412310 'third_party/blink/tools/blinkpy/web_tests/merge_results.pydeps',
2311 'third_party/blink/tools/merge_web_test_results.pydeps',
John Budorickbc3571aa2019-04-25 02:20:062312 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:222313 'tools/binary_size/supersize.pydeps',
Ben Pastene028104a2022-08-10 19:17:452314 'tools/perf/process_perf_results.pydeps',
Peter Wence103e12024-10-09 19:23:512315 'tools/pgo/generate_profile.pydeps',
agrievef32bcc72016-04-04 14:57:402316]
2317
wnwenbdc444e2016-05-25 13:44:152318
agrievef32bcc72016-04-04 14:57:402319_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
2320
2321
Eric Boren6fd2b932018-01-25 15:05:082322# Bypass the AUTHORS check for these accounts.
2323_KNOWN_ROBOTS = set(
nqmtuan918b2232024-04-11 23:09:552324 ) | set('%[email protected]' % s for s in ('findit-for-me', 'luci-bisection')
Achuith Bhandarkar35905562018-07-25 19:28:452325 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:592326 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:522327 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:232328 'wpt-autoroller', 'chrome-weblayer-builder',
Garrett Beaty4d4fcf62021-11-24 17:57:472329 'lacros-version-skew-roller', 'skylab-test-cros-roller',
Sven Zheng722960ba2022-07-18 16:40:462330 'infra-try-recipes-tester', 'lacros-tracking-roller',
Brian Sheedy1c951e62022-10-27 01:16:182331 'lacros-sdk-version-roller', 'chrome-automated-expectation',
Stephanie Kimb49bdd242023-04-28 16:46:042332 'chromium-automated-expectation', 'chrome-branch-day',
2333 'chromium-autosharder')
Eric Boren835d71f2018-09-07 21:09:042334 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:272335 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:042336 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:162337 for s in ('chromium-internal-autoroll',)
Kyungjun Lee3b7c9352024-04-02 23:59:142338 ) | set('%[email protected]' % s
2339 for s in ('chrome-screen-ai-releaser',)
Yulan Lineb0cfba2021-04-09 18:43:162340 ) | set('%[email protected]' % s
Chong Gub277e342022-10-15 03:30:552341 for s in ('swarming-tasks',)
2342 ) | set('%[email protected]' % s
2343 for s in ('global-integration-try-builder',
Joey Scarr1103c5d2023-09-14 01:17:552344 'global-integration-ci-builder')
Suma Kasa3b9cf7a2023-09-21 22:05:542345 ) | set('%[email protected]' % s
2346 for s in ('chops-security-borg',
2347 'chops-security-cronjobs-cpesuggest'))
Eric Boren6fd2b932018-01-25 15:05:082348
Matt Stark6ef08872021-07-29 01:21:462349_INVALID_GRD_FILE_LINE = [
2350 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
2351]
Eric Boren6fd2b932018-01-25 15:05:082352
Daniel Bratell65b033262019-04-23 08:17:062353def _IsCPlusPlusFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502354 """Returns True if this file contains C++-like code (and not Python,
2355 Go, Java, MarkDown, ...)"""
Daniel Bratell65b033262019-04-23 08:17:062356
Sam Maiera6e76d72022-02-11 21:43:502357 ext = input_api.os_path.splitext(file_path)[1]
2358 # This list is compatible with CppChecker.IsCppFile but we should
2359 # consider adding ".c" to it. If we do that we can use this function
2360 # at more places in the code.
2361 return ext in (
2362 '.h',
2363 '.cc',
2364 '.cpp',
2365 '.m',
2366 '.mm',
2367 )
2368
Daniel Bratell65b033262019-04-23 08:17:062369
2370def _IsCPlusPlusHeaderFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502371 return input_api.os_path.splitext(file_path)[1] == ".h"
Daniel Bratell65b033262019-04-23 08:17:062372
2373
2374def _IsJavaFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502375 return input_api.os_path.splitext(file_path)[1] == ".java"
Daniel Bratell65b033262019-04-23 08:17:062376
2377
2378def _IsProtoFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502379 return input_api.os_path.splitext(file_path)[1] == ".proto"
Daniel Bratell65b033262019-04-23 08:17:062380
Mohamed Heikal5e5b7922020-10-29 18:57:592381
Erik Staabc734cd7a2021-11-23 03:11:522382def _IsXmlOrGrdFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502383 ext = input_api.os_path.splitext(file_path)[1]
2384 return ext in ('.grd', '.xml')
Erik Staabc734cd7a2021-11-23 03:11:522385
2386
Sven Zheng76a79ea2022-12-21 21:25:242387def _IsMojomFile(input_api, file_path):
2388 return input_api.os_path.splitext(file_path)[1] == ".mojom"
2389
2390
Mohamed Heikal5e5b7922020-10-29 18:57:592391def CheckNoUpstreamDepsOnClank(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502392 """Prevent additions of dependencies from the upstream repo on //clank."""
2393 # clank can depend on clank
2394 if input_api.change.RepositoryRoot().endswith('clank'):
2395 return []
2396 build_file_patterns = [
2397 r'(.+/)?BUILD\.gn',
2398 r'.+\.gni',
2399 ]
2400 excluded_files = [r'build[/\\]config[/\\]android[/\\]config\.gni']
2401 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
Mohamed Heikal5e5b7922020-10-29 18:57:592402
Sam Maiera6e76d72022-02-11 21:43:502403 error_message = 'Disallowed import on //clank in an upstream build file:'
Mohamed Heikal5e5b7922020-10-29 18:57:592404
Sam Maiera6e76d72022-02-11 21:43:502405 def FilterFile(affected_file):
2406 return input_api.FilterSourceFile(affected_file,
2407 files_to_check=build_file_patterns,
2408 files_to_skip=excluded_files)
Mohamed Heikal5e5b7922020-10-29 18:57:592409
Sam Maiera6e76d72022-02-11 21:43:502410 problems = []
2411 for f in input_api.AffectedSourceFiles(FilterFile):
2412 local_path = f.LocalPath()
2413 for line_number, line in f.ChangedContents():
2414 if (bad_pattern.search(line)):
2415 problems.append('%s:%d\n %s' %
2416 (local_path, line_number, line.strip()))
2417 if problems:
2418 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
2419 else:
2420 return []
Mohamed Heikal5e5b7922020-10-29 18:57:592421
2422
Saagar Sanghavifceeaae2020-08-12 16:40:362423def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502424 """Attempts to prevent use of functions intended only for testing in
2425 non-testing code. For now this is just a best-effort implementation
2426 that ignores header files and may have some false positives. A
2427 better implementation would probably need a proper C++ parser.
2428 """
2429 # We only scan .cc files and the like, as the declaration of
2430 # for-testing functions in header files are hard to distinguish from
2431 # calls to such functions without a proper C++ parser.
2432 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:192433
Sam Maiera6e76d72022-02-11 21:43:502434 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
2435 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' %
2436 base_function_pattern)
2437 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
2438 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
2439 exclusion_pattern = input_api.re.compile(
2440 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' %
2441 (base_function_pattern, base_function_pattern))
2442 # Avoid a false positive in this case, where the method name, the ::, and
2443 # the closing { are all on different lines due to line wrapping.
2444 # HelperClassForTesting::
2445 # HelperClassForTesting(
2446 # args)
2447 # : member(0) {}
2448 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:192449
Sam Maiera6e76d72022-02-11 21:43:502450 def FilterFile(affected_file):
2451 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2452 input_api.DEFAULT_FILES_TO_SKIP)
2453 return input_api.FilterSourceFile(
2454 affected_file,
2455 files_to_check=file_inclusion_pattern,
2456 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:192457
Sam Maiera6e76d72022-02-11 21:43:502458 problems = []
2459 for f in input_api.AffectedSourceFiles(FilterFile):
2460 local_path = f.LocalPath()
2461 in_method_defn = False
2462 for line_number, line in f.ChangedContents():
2463 if (inclusion_pattern.search(line)
2464 and not comment_pattern.search(line)
2465 and not exclusion_pattern.search(line)
2466 and not allowlist_pattern.search(line)
2467 and not in_method_defn):
2468 problems.append('%s:%d\n %s' %
2469 (local_path, line_number, line.strip()))
2470 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:192471
Sam Maiera6e76d72022-02-11 21:43:502472 if problems:
2473 return [
2474 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
2475 ]
2476 else:
2477 return []
[email protected]55459852011-08-10 15:17:192478
2479
Saagar Sanghavifceeaae2020-08-12 16:40:362480def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502481 """This is a simplified version of
2482 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
2483 """
2484 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
2485 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
2486 name_pattern = r'ForTest(s|ing)?'
2487 # Describes an occurrence of "ForTest*" inside a // comment.
2488 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
2489 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
2490 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
2491 # Catch calls.
2492 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
2493 # Ignore definitions. (Comments are ignored separately.)
2494 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
Andrew Grieve40f451d2023-07-06 19:46:512495 allowlist_re = input_api.re.compile(r'// IN-TEST$')
Vaclav Brozek7dbc28c2018-03-27 08:35:232496
Sam Maiera6e76d72022-02-11 21:43:502497 problems = []
2498 sources = lambda x: input_api.FilterSourceFile(
2499 x,
2500 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
2501 DEFAULT_FILES_TO_SKIP),
2502 files_to_check=[r'.*\.java$'])
2503 for f in input_api.AffectedFiles(include_deletes=False,
2504 file_filter=sources):
2505 local_path = f.LocalPath()
Vaclav Brozek7dbc28c2018-03-27 08:35:232506 is_inside_javadoc = False
Sam Maiera6e76d72022-02-11 21:43:502507 for line_number, line in f.ChangedContents():
2508 if is_inside_javadoc and javadoc_end_re.search(line):
2509 is_inside_javadoc = False
2510 if not is_inside_javadoc and javadoc_start_re.search(line):
2511 is_inside_javadoc = True
2512 if is_inside_javadoc:
2513 continue
2514 if (inclusion_re.search(line) and not comment_re.search(line)
2515 and not annotation_re.search(line)
Andrew Grieve40f451d2023-07-06 19:46:512516 and not allowlist_re.search(line)
Sam Maiera6e76d72022-02-11 21:43:502517 and not exclusion_re.search(line)):
2518 problems.append('%s:%d\n %s' %
2519 (local_path, line_number, line.strip()))
Vaclav Brozek7dbc28c2018-03-27 08:35:232520
Sam Maiera6e76d72022-02-11 21:43:502521 if problems:
2522 return [
2523 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
2524 ]
2525 else:
2526 return []
Vaclav Brozek7dbc28c2018-03-27 08:35:232527
2528
Saagar Sanghavifceeaae2020-08-12 16:40:362529def CheckNoIOStreamInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502530 """Checks to make sure no .h files include <iostream>."""
2531 files = []
2532 pattern = input_api.re.compile(r'^#include\s*<iostream>',
2533 input_api.re.MULTILINE)
2534 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2535 if not f.LocalPath().endswith('.h'):
2536 continue
2537 contents = input_api.ReadFile(f)
2538 if pattern.search(contents):
2539 files.append(f)
[email protected]10689ca2011-09-02 02:31:542540
Sam Maiera6e76d72022-02-11 21:43:502541 if len(files):
2542 return [
2543 output_api.PresubmitError(
2544 'Do not #include <iostream> in header files, since it inserts static '
2545 'initialization into every file including the header. Instead, '
2546 '#include <ostream>. See http://crbug.com/94794', files)
2547 ]
2548 return []
2549
[email protected]10689ca2011-09-02 02:31:542550
Aleksey Khoroshilov9b28c032022-06-03 16:35:322551def CheckNoStrCatRedefines(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502552 """Checks no windows headers with StrCat redefined are included directly."""
2553 files = []
Aleksey Khoroshilov9b28c032022-06-03 16:35:322554 files_to_check = (r'.+%s' % _HEADER_EXTENSIONS,
2555 r'.+%s' % _IMPLEMENTATION_EXTENSIONS)
2556 files_to_skip = (input_api.DEFAULT_FILES_TO_SKIP +
2557 _NON_BASE_DEPENDENT_PATHS)
2558 sources_filter = lambda f: input_api.FilterSourceFile(
2559 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
2560
Sam Maiera6e76d72022-02-11 21:43:502561 pattern_deny = input_api.re.compile(
2562 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
2563 input_api.re.MULTILINE)
2564 pattern_allow = input_api.re.compile(
2565 r'^#include\s"base/win/windows_defines.inc"', input_api.re.MULTILINE)
Aleksey Khoroshilov9b28c032022-06-03 16:35:322566 for f in input_api.AffectedSourceFiles(sources_filter):
Sam Maiera6e76d72022-02-11 21:43:502567 contents = input_api.ReadFile(f)
2568 if pattern_deny.search(
2569 contents) and not pattern_allow.search(contents):
2570 files.append(f.LocalPath())
Danil Chapovalov3518f362018-08-11 16:13:432571
Sam Maiera6e76d72022-02-11 21:43:502572 if len(files):
2573 return [
2574 output_api.PresubmitError(
2575 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
2576 'directly since they pollute code with StrCat macro. Instead, '
2577 'include matching header from base/win. See http://crbug.com/856536',
2578 files)
2579 ]
2580 return []
Danil Chapovalov3518f362018-08-11 16:13:432581
[email protected]10689ca2011-09-02 02:31:542582
Andrew Williamsc9f69b482023-07-10 16:07:362583def _CheckNoUNIT_TESTInSourceFiles(input_api, f):
2584 problems = []
2585
2586 unit_test_macro = input_api.re.compile(
2587 '^\s*#.*(?:ifn?def\s+UNIT_TEST|defined\s*\(?\s*UNIT_TEST\s*\)?)(?:$|\s+)')
2588 for line_num, line in f.ChangedContents():
2589 if unit_test_macro.match(line):
2590 problems.append(' %s:%d' % (f.LocalPath(), line_num))
2591
2592 return problems
2593
2594
Saagar Sanghavifceeaae2020-08-12 16:40:362595def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502596 """Checks to make sure no source files use UNIT_TEST."""
2597 problems = []
2598 for f in input_api.AffectedFiles():
2599 if (not f.LocalPath().endswith(('.cc', '.mm'))):
2600 continue
Andrew Williamsc9f69b482023-07-10 16:07:362601 problems.extend(
2602 _CheckNoUNIT_TESTInSourceFiles(input_api, f))
[email protected]72df4e782012-06-21 16:28:182603
Sam Maiera6e76d72022-02-11 21:43:502604 if not problems:
2605 return []
2606 return [
2607 output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
2608 '\n'.join(problems))
2609 ]
2610
[email protected]72df4e782012-06-21 16:28:182611
Saagar Sanghavifceeaae2020-08-12 16:40:362612def CheckNoDISABLETypoInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502613 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
Dominic Battre033531052018-09-24 15:45:342614
Sam Maiera6e76d72022-02-11 21:43:502615 This test warns if somebody tries to disable a test with the DISABLE_ prefix
2616 instead of DISABLED_. To filter false positives, reports are only generated
2617 if a corresponding MAYBE_ line exists.
2618 """
2619 problems = []
Dominic Battre033531052018-09-24 15:45:342620
Sam Maiera6e76d72022-02-11 21:43:502621 # The following two patterns are looked for in tandem - is a test labeled
2622 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
2623 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
2624 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
Dominic Battre033531052018-09-24 15:45:342625
Sam Maiera6e76d72022-02-11 21:43:502626 # This is for the case that a test is disabled on all platforms.
2627 full_disable_pattern = input_api.re.compile(
2628 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
2629 input_api.re.MULTILINE)
Dominic Battre033531052018-09-24 15:45:342630
Arthur Sonzognic66e9c82024-04-23 07:53:042631 for f in input_api.AffectedFiles(include_deletes=False):
Sam Maiera6e76d72022-02-11 21:43:502632 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2633 continue
Dominic Battre033531052018-09-24 15:45:342634
Arthur Sonzognic66e9c82024-04-23 07:53:042635 # Search for MAYBE_, DISABLE_ pairs.
Sam Maiera6e76d72022-02-11 21:43:502636 disable_lines = {} # Maps of test name to line number.
2637 maybe_lines = {}
2638 for line_num, line in f.ChangedContents():
2639 disable_match = disable_pattern.search(line)
2640 if disable_match:
2641 disable_lines[disable_match.group(1)] = line_num
2642 maybe_match = maybe_pattern.search(line)
2643 if maybe_match:
2644 maybe_lines[maybe_match.group(1)] = line_num
Dominic Battre033531052018-09-24 15:45:342645
Sam Maiera6e76d72022-02-11 21:43:502646 # Search for DISABLE_ occurrences within a TEST() macro.
2647 disable_tests = set(disable_lines.keys())
2648 maybe_tests = set(maybe_lines.keys())
2649 for test in disable_tests.intersection(maybe_tests):
2650 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
Dominic Battre033531052018-09-24 15:45:342651
Sam Maiera6e76d72022-02-11 21:43:502652 contents = input_api.ReadFile(f)
2653 full_disable_match = full_disable_pattern.search(contents)
2654 if full_disable_match:
2655 problems.append(' %s' % f.LocalPath())
Dominic Battre033531052018-09-24 15:45:342656
Sam Maiera6e76d72022-02-11 21:43:502657 if not problems:
2658 return []
2659 return [
2660 output_api.PresubmitPromptWarning(
2661 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
2662 '\n'.join(problems))
2663 ]
2664
Dominic Battre033531052018-09-24 15:45:342665
Nina Satragnof7660532021-09-20 18:03:352666def CheckForgettingMAYBEInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502667 """Checks to make sure tests disabled conditionally are not missing a
2668 corresponding MAYBE_ prefix.
2669 """
2670 # Expect at least a lowercase character in the test name. This helps rule out
2671 # false positives with macros wrapping the actual tests name.
2672 define_maybe_pattern = input_api.re.compile(
2673 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
Bruce Dawsonffc55292022-04-20 04:18:192674 # The test_maybe_pattern needs to handle all of these forms. The standard:
2675 # IN_PROC_TEST_F(SyncTest, MAYBE_Start) {
2676 # With a wrapper macro around the test name:
2677 # IN_PROC_TEST_F(SyncTest, E2E_ENABLED(MAYBE_Start)) {
2678 # And the odd-ball NACL_BROWSER_TEST_f format:
2679 # NACL_BROWSER_TEST_F(NaClBrowserTest, SimpleLoad, {
2680 # The optional E2E_ENABLED-style is handled with (\w*\()?
2681 # The NACL_BROWSER_TEST_F pattern is handled by allowing a trailing comma or
2682 # trailing ')'.
2683 test_maybe_pattern = (
2684 r'^\s*\w*TEST[^(]*\(\s*\w+,\s*(\w*\()?MAYBE_{test_name}[\),]')
Sam Maiera6e76d72022-02-11 21:43:502685 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
2686 warnings = []
Nina Satragnof7660532021-09-20 18:03:352687
Sam Maiera6e76d72022-02-11 21:43:502688 # Read the entire files. We can't just read the affected lines, forgetting to
2689 # add MAYBE_ on a change would not show up otherwise.
Arthur Sonzognic66e9c82024-04-23 07:53:042690 for f in input_api.AffectedFiles(include_deletes=False):
Sam Maiera6e76d72022-02-11 21:43:502691 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2692 continue
2693 contents = input_api.ReadFile(f)
2694 lines = contents.splitlines(True)
2695 current_position = 0
2696 warning_test_names = set()
2697 for line_num, line in enumerate(lines, start=1):
2698 current_position += len(line)
2699 maybe_match = define_maybe_pattern.search(line)
2700 if maybe_match:
2701 test_name = maybe_match.group('test_name')
2702 # Do not warn twice for the same test.
2703 if (test_name in warning_test_names):
2704 continue
2705 warning_test_names.add(test_name)
Nina Satragnof7660532021-09-20 18:03:352706
Sam Maiera6e76d72022-02-11 21:43:502707 # Attempt to find the corresponding MAYBE_ test or suite, starting from
2708 # the current position.
2709 test_match = input_api.re.compile(
2710 test_maybe_pattern.format(test_name=test_name),
2711 input_api.re.MULTILINE).search(contents, current_position)
2712 suite_match = input_api.re.compile(
2713 suite_maybe_pattern.format(test_name=test_name),
2714 input_api.re.MULTILINE).search(contents, current_position)
2715 if not test_match and not suite_match:
2716 warnings.append(
2717 output_api.PresubmitPromptWarning(
2718 '%s:%d found MAYBE_ defined without corresponding test %s'
2719 % (f.LocalPath(), line_num, test_name)))
2720 return warnings
2721
[email protected]72df4e782012-06-21 16:28:182722
Saagar Sanghavifceeaae2020-08-12 16:40:362723def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502724 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
2725 errors = []
Kalvin Lee4a3b79de2022-05-26 16:00:162726 pattern = input_api.re.compile(r'\bDCHECK_IS_ON\b(?!\(\))',
Sam Maiera6e76d72022-02-11 21:43:502727 input_api.re.MULTILINE)
2728 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2729 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
2730 continue
2731 for lnum, line in f.ChangedContents():
2732 if input_api.re.search(pattern, line):
2733 errors.append(
2734 output_api.PresubmitError((
2735 '%s:%d: Use of DCHECK_IS_ON() must be written as "#if '
2736 + 'DCHECK_IS_ON()", not forgetting the parentheses.') %
2737 (f.LocalPath(), lnum)))
2738 return errors
danakj61c1aa22015-10-26 19:55:522739
2740
Weilun Shia487fad2020-10-28 00:10:342741# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
2742# more reliable way. See
2743# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:192744
wnwenbdc444e2016-05-25 13:44:152745
Saagar Sanghavifceeaae2020-08-12 16:40:362746def CheckFlakyTestUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502747 """Check that FlakyTest annotation is our own instead of the android one"""
2748 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
2749 files = []
2750 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2751 if f.LocalPath().endswith('Test.java'):
2752 if pattern.search(input_api.ReadFile(f)):
2753 files.append(f)
2754 if len(files):
2755 return [
2756 output_api.PresubmitError(
2757 'Use org.chromium.base.test.util.FlakyTest instead of '
2758 'android.test.FlakyTest', files)
2759 ]
2760 return []
mcasasb7440c282015-02-04 14:52:192761
wnwenbdc444e2016-05-25 13:44:152762
Saagar Sanghavifceeaae2020-08-12 16:40:362763def CheckNoDEPSGIT(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502764 """Make sure .DEPS.git is never modified manually."""
2765 if any(f.LocalPath().endswith('.DEPS.git')
2766 for f in input_api.AffectedFiles()):
2767 return [
2768 output_api.PresubmitError(
2769 'Never commit changes to .DEPS.git. This file is maintained by an\n'
2770 'automated system based on what\'s in DEPS and your changes will be\n'
2771 'overwritten.\n'
2772 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
2773 'get-the-code#Rolling_DEPS\n'
2774 'for more information')
2775 ]
2776 return []
[email protected]2a8ac9c2011-10-19 17:20:442777
2778
Sven Zheng76a79ea2022-12-21 21:25:242779def CheckCrosApiNeedBrowserTest(input_api, output_api):
2780 """Check new crosapi should add browser test."""
2781 has_new_crosapi = False
2782 has_browser_test = False
2783 for f in input_api.AffectedFiles():
2784 path = f.LocalPath()
2785 if (path.startswith('chromeos/crosapi/mojom') and
2786 _IsMojomFile(input_api, path) and f.Action() == 'A'):
2787 has_new_crosapi = True
2788 if path.endswith('browsertest.cc') or path.endswith('browser_test.cc'):
2789 has_browser_test = True
2790 if has_new_crosapi and not has_browser_test:
2791 return [
2792 output_api.PresubmitPromptWarning(
2793 'You are adding a new crosapi, but there is no file ends with '
2794 'browsertest.cc file being added or modified. It is important '
2795 'to add crosapi browser test coverage to avoid version '
2796 ' skew issues.\n'
2797 'Check //docs/lacros/test_instructions.md for more information.'
2798 )
2799 ]
2800 return []
2801
2802
Saagar Sanghavifceeaae2020-08-12 16:40:362803def CheckValidHostsInDEPSOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502804 """Checks that DEPS file deps are from allowed_hosts."""
2805 # Run only if DEPS file has been modified to annoy fewer bystanders.
2806 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
2807 return []
2808 # Outsource work to gclient verify
2809 try:
2810 gclient_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
2811 'third_party', 'depot_tools',
2812 'gclient.py')
2813 input_api.subprocess.check_output(
Bruce Dawson8a43cf72022-05-13 17:10:322814 [input_api.python3_executable, gclient_path, 'verify'],
Sam Maiera6e76d72022-02-11 21:43:502815 stderr=input_api.subprocess.STDOUT)
2816 return []
2817 except input_api.subprocess.CalledProcessError as error:
2818 return [
2819 output_api.PresubmitError(
2820 'DEPS file must have only git dependencies.',
2821 long_text=error.output)
2822 ]
tandriief664692014-09-23 14:51:472823
2824
Mario Sanchez Prada2472cab2019-09-18 10:58:312825def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152826 ban_rule):
Allen Bauer84778682022-09-22 16:28:562827 """Helper method for checking for banned constructs.
Mario Sanchez Prada2472cab2019-09-18 10:58:312828
Sam Maiera6e76d72022-02-11 21:43:502829 Returns an string composed of the name of the file, the line number where the
2830 match has been found and the additional text passed as |message| in case the
2831 target type name matches the text inside the line passed as parameter.
2832 """
2833 result = []
Peng Huang9c5949a02020-06-11 19:20:542834
Daniel Chenga44a1bcd2022-03-15 20:00:152835 # Ignore comments about banned types.
2836 if input_api.re.search(r"^ *//", line):
Sam Maiera6e76d72022-02-11 21:43:502837 return result
Daniel Chenga44a1bcd2022-03-15 20:00:152838 # A // nocheck comment will bypass this error.
2839 if line.endswith(" nocheck"):
Sam Maiera6e76d72022-02-11 21:43:502840 return result
2841
2842 matched = False
Daniel Chenga44a1bcd2022-03-15 20:00:152843 if ban_rule.pattern[0:1] == '/':
2844 regex = ban_rule.pattern[1:]
Sam Maiera6e76d72022-02-11 21:43:502845 if input_api.re.search(regex, line):
2846 matched = True
Daniel Chenga44a1bcd2022-03-15 20:00:152847 elif ban_rule.pattern in line:
Sam Maiera6e76d72022-02-11 21:43:502848 matched = True
2849
2850 if matched:
2851 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
Daniel Chenga44a1bcd2022-03-15 20:00:152852 for line in ban_rule.explanation:
2853 result.append(' %s' % line)
Sam Maiera6e76d72022-02-11 21:43:502854
danakjd18e8892020-12-17 17:42:012855 return result
Mario Sanchez Prada2472cab2019-09-18 10:58:312856
2857
Saagar Sanghavifceeaae2020-08-12 16:40:362858def CheckNoBannedFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502859 """Make sure that banned functions are not used."""
2860 warnings = []
2861 errors = []
[email protected]127f18ec2012-06-16 05:05:592862
Sam Maiera6e76d72022-02-11 21:43:502863 def IsExcludedFile(affected_file, excluded_paths):
Daniel Chenga44a1bcd2022-03-15 20:00:152864 if not excluded_paths:
2865 return False
2866
Sam Maiera6e76d72022-02-11 21:43:502867 local_path = affected_file.LocalPath()
Bruce Dawson40fece62022-09-16 19:58:312868 # Consistently use / as path separator to simplify the writing of regex
2869 # expressions.
2870 local_path = local_path.replace(input_api.os_path.sep, '/')
Sam Maiera6e76d72022-02-11 21:43:502871 for item in excluded_paths:
2872 if input_api.re.match(item, local_path):
2873 return True
2874 return False
wnwenbdc444e2016-05-25 13:44:152875
Sam Maiera6e76d72022-02-11 21:43:502876 def IsIosObjcFile(affected_file):
2877 local_path = affected_file.LocalPath()
2878 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m',
2879 '.h'):
2880 return False
2881 basename = input_api.os_path.basename(local_path)
2882 if 'ios' in basename.split('_'):
2883 return True
2884 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
2885 if sep and 'ios' in local_path.split(sep):
2886 return True
2887 return False
Sylvain Defresnea8b73d252018-02-28 15:45:542888
Daniel Chenga44a1bcd2022-03-15 20:00:152889 def CheckForMatch(affected_file, line_num: int, line: str,
2890 ban_rule: BanRule):
2891 if IsExcludedFile(affected_file, ban_rule.excluded_paths):
2892 return
2893
Sam Maiera6e76d72022-02-11 21:43:502894 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152895 ban_rule)
Sam Maiera6e76d72022-02-11 21:43:502896 if problems:
Daniel Chenga44a1bcd2022-03-15 20:00:152897 if ban_rule.treat_as_error is not None and ban_rule.treat_as_error:
Sam Maiera6e76d72022-02-11 21:43:502898 errors.extend(problems)
2899 else:
2900 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:152901
Sam Maiera6e76d72022-02-11 21:43:502902 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2903 for f in input_api.AffectedFiles(file_filter=file_filter):
2904 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152905 for ban_rule in _BANNED_JAVA_FUNCTIONS:
2906 CheckForMatch(f, line_num, line, ban_rule)
Eric Stevensona9a980972017-09-23 00:04:412907
Clement Yan9b330cb2022-11-17 05:25:292908 file_filter = lambda f: f.LocalPath().endswith(('.js', '.ts'))
2909 for f in input_api.AffectedFiles(file_filter=file_filter):
2910 for line_num, line in f.ChangedContents():
2911 for ban_rule in _BANNED_JAVASCRIPT_FUNCTIONS:
2912 CheckForMatch(f, line_num, line, ban_rule)
2913
Sam Maiera6e76d72022-02-11 21:43:502914 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
2915 for f in input_api.AffectedFiles(file_filter=file_filter):
2916 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152917 for ban_rule in _BANNED_OBJC_FUNCTIONS:
2918 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:592919
Sam Maiera6e76d72022-02-11 21:43:502920 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
2921 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152922 for ban_rule in _BANNED_IOS_OBJC_FUNCTIONS:
2923 CheckForMatch(f, line_num, line, ban_rule)
Sylvain Defresnea8b73d252018-02-28 15:45:542924
Sam Maiera6e76d72022-02-11 21:43:502925 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
2926 for f in input_api.AffectedFiles(file_filter=egtest_filter):
2927 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152928 for ban_rule in _BANNED_IOS_EGTEST_FUNCTIONS:
2929 CheckForMatch(f, line_num, line, ban_rule)
Peter K. Lee6c03ccff2019-07-15 14:40:052930
Sam Maiera6e76d72022-02-11 21:43:502931 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
2932 for f in input_api.AffectedFiles(file_filter=file_filter):
2933 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152934 for ban_rule in _BANNED_CPP_FUNCTIONS:
2935 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:592936
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152937 # As of 05/2024, iOS fully migrated ConsentLevel::kSync to kSignin, and
2938 # Android is in the process of preventing new users from entering kSync.
2939 # So the warning is restricted to those platforms.
2940 ios_pattern = input_api.re.compile('(^|[\W_])ios[\W_]')
2941 file_filter = lambda f: (f.LocalPath().endswith(('.cc', '.mm', '.h')) and
2942 ('android' in f.LocalPath() or
2943 # Simply checking for an 'ios' substring would
2944 # catch unrelated cases, use a regex.
2945 ios_pattern.search(f.LocalPath())))
2946 for f in input_api.AffectedFiles(file_filter=file_filter):
2947 for line_num, line in f.ChangedContents():
2948 for ban_rule in _DEPRECATED_SYNC_CONSENT_CPP_FUNCTIONS:
2949 CheckForMatch(f, line_num, line, ban_rule)
2950
2951 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2952 for f in input_api.AffectedFiles(file_filter=file_filter):
2953 for line_num, line in f.ChangedContents():
2954 for ban_rule in _DEPRECATED_SYNC_CONSENT_JAVA_FUNCTIONS:
2955 CheckForMatch(f, line_num, line, ban_rule)
2956
Daniel Cheng92c15e32022-03-16 17:48:222957 file_filter = lambda f: f.LocalPath().endswith(('.mojom'))
2958 for f in input_api.AffectedFiles(file_filter=file_filter):
2959 for line_num, line in f.ChangedContents():
2960 for ban_rule in _BANNED_MOJOM_PATTERNS:
2961 CheckForMatch(f, line_num, line, ban_rule)
2962
2963
Sam Maiera6e76d72022-02-11 21:43:502964 result = []
2965 if (warnings):
2966 result.append(
2967 output_api.PresubmitPromptWarning('Banned functions were used.\n' +
2968 '\n'.join(warnings)))
2969 if (errors):
2970 result.append(
2971 output_api.PresubmitError('Banned functions were used.\n' +
2972 '\n'.join(errors)))
2973 return result
[email protected]127f18ec2012-06-16 05:05:592974
Michael Thiessen44457642020-02-06 00:24:152975def _CheckAndroidNoBannedImports(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502976 """Make sure that banned java imports are not used."""
2977 errors = []
Michael Thiessen44457642020-02-06 00:24:152978
Sam Maiera6e76d72022-02-11 21:43:502979 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2980 for f in input_api.AffectedFiles(file_filter=file_filter):
2981 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152982 for ban_rule in _BANNED_JAVA_IMPORTS:
2983 # Consider merging this into the above function. There is no
2984 # real difference anymore other than helping with a little
2985 # bit of boilerplate text. Doing so means things like
2986 # `treat_as_error` will also be uniformly handled.
Sam Maiera6e76d72022-02-11 21:43:502987 problems = _GetMessageForMatchingType(input_api, f, line_num,
Daniel Chenga44a1bcd2022-03-15 20:00:152988 line, ban_rule)
Sam Maiera6e76d72022-02-11 21:43:502989 if problems:
2990 errors.extend(problems)
2991 result = []
2992 if (errors):
2993 result.append(
2994 output_api.PresubmitError('Banned imports were used.\n' +
2995 '\n'.join(errors)))
2996 return result
Michael Thiessen44457642020-02-06 00:24:152997
2998
Saagar Sanghavifceeaae2020-08-12 16:40:362999def CheckNoPragmaOnce(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503000 """Make sure that banned functions are not used."""
3001 files = []
3002 pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
3003 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
3004 if not f.LocalPath().endswith('.h'):
3005 continue
Bruce Dawson4c4c2922022-05-02 18:07:333006 if f.LocalPath().endswith('com_imported_mstscax.h'):
3007 continue
Sam Maiera6e76d72022-02-11 21:43:503008 contents = input_api.ReadFile(f)
3009 if pattern.search(contents):
3010 files.append(f)
[email protected]6c063c62012-07-11 19:11:063011
Sam Maiera6e76d72022-02-11 21:43:503012 if files:
3013 return [
3014 output_api.PresubmitError(
3015 'Do not use #pragma once in header files.\n'
3016 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
3017 files)
3018 ]
3019 return []
[email protected]6c063c62012-07-11 19:11:063020
[email protected]127f18ec2012-06-16 05:05:593021
Saagar Sanghavifceeaae2020-08-12 16:40:363022def CheckNoTrinaryTrueFalse(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503023 """Checks to make sure we don't introduce use of foo ? true : false."""
3024 problems = []
3025 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
3026 for f in input_api.AffectedFiles():
3027 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
3028 continue
[email protected]e7479052012-09-19 00:26:123029
Sam Maiera6e76d72022-02-11 21:43:503030 for line_num, line in f.ChangedContents():
3031 if pattern.match(line):
3032 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]e7479052012-09-19 00:26:123033
Sam Maiera6e76d72022-02-11 21:43:503034 if not problems:
3035 return []
3036 return [
3037 output_api.PresubmitPromptWarning(
3038 'Please consider avoiding the "? true : false" pattern if possible.\n'
3039 + '\n'.join(problems))
3040 ]
[email protected]e7479052012-09-19 00:26:123041
3042
Saagar Sanghavifceeaae2020-08-12 16:40:363043def CheckUnwantedDependencies(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503044 """Runs checkdeps on #include and import statements added in this
3045 change. Breaking - rules is an error, breaking ! rules is a
3046 warning.
3047 """
3048 # Return early if no relevant file types were modified.
3049 for f in input_api.AffectedFiles():
3050 path = f.LocalPath()
3051 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path)
3052 or _IsJavaFile(input_api, path)):
3053 break
[email protected]55f9f382012-07-31 11:02:183054 else:
Sam Maiera6e76d72022-02-11 21:43:503055 return []
rhalavati08acd232017-04-03 07:23:283056
Sam Maiera6e76d72022-02-11 21:43:503057 import sys
3058 # We need to wait until we have an input_api object and use this
3059 # roundabout construct to import checkdeps because this file is
3060 # eval-ed and thus doesn't have __file__.
3061 original_sys_path = sys.path
3062 try:
3063 sys.path = sys.path + [
3064 input_api.os_path.join(input_api.PresubmitLocalPath(),
3065 'buildtools', 'checkdeps')
3066 ]
3067 import checkdeps
3068 from rules import Rule
3069 finally:
3070 # Restore sys.path to what it was before.
3071 sys.path = original_sys_path
[email protected]55f9f382012-07-31 11:02:183072
Sam Maiera6e76d72022-02-11 21:43:503073 added_includes = []
3074 added_imports = []
3075 added_java_imports = []
3076 for f in input_api.AffectedFiles():
3077 if _IsCPlusPlusFile(input_api, f.LocalPath()):
3078 changed_lines = [line for _, line in f.ChangedContents()]
3079 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
3080 elif _IsProtoFile(input_api, f.LocalPath()):
3081 changed_lines = [line for _, line in f.ChangedContents()]
3082 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
3083 elif _IsJavaFile(input_api, f.LocalPath()):
3084 changed_lines = [line for _, line in f.ChangedContents()]
3085 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:243086
Sam Maiera6e76d72022-02-11 21:43:503087 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
3088
3089 error_descriptions = []
3090 warning_descriptions = []
3091 error_subjects = set()
3092 warning_subjects = set()
3093
3094 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
3095 added_includes):
3096 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3097 description_with_path = '%s\n %s' % (path, rule_description)
3098 if rule_type == Rule.DISALLOW:
3099 error_descriptions.append(description_with_path)
3100 error_subjects.add("#includes")
3101 else:
3102 warning_descriptions.append(description_with_path)
3103 warning_subjects.add("#includes")
3104
3105 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
3106 added_imports):
3107 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3108 description_with_path = '%s\n %s' % (path, rule_description)
3109 if rule_type == Rule.DISALLOW:
3110 error_descriptions.append(description_with_path)
3111 error_subjects.add("imports")
3112 else:
3113 warning_descriptions.append(description_with_path)
3114 warning_subjects.add("imports")
3115
3116 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
3117 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
3118 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3119 description_with_path = '%s\n %s' % (path, rule_description)
3120 if rule_type == Rule.DISALLOW:
3121 error_descriptions.append(description_with_path)
3122 error_subjects.add("imports")
3123 else:
3124 warning_descriptions.append(description_with_path)
3125 warning_subjects.add("imports")
3126
3127 results = []
3128 if error_descriptions:
3129 results.append(
3130 output_api.PresubmitError(
3131 'You added one or more %s that violate checkdeps rules.' %
3132 " and ".join(error_subjects), error_descriptions))
3133 if warning_descriptions:
3134 results.append(
3135 output_api.PresubmitPromptOrNotify(
3136 'You added one or more %s of files that are temporarily\n'
3137 'allowed but being removed. Can you avoid introducing the\n'
3138 '%s? See relevant DEPS file(s) for details and contacts.' %
3139 (" and ".join(warning_subjects), "/".join(warning_subjects)),
3140 warning_descriptions))
3141 return results
[email protected]55f9f382012-07-31 11:02:183142
3143
Saagar Sanghavifceeaae2020-08-12 16:40:363144def CheckFilePermissions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503145 """Check that all files have their permissions properly set."""
3146 if input_api.platform == 'win32':
3147 return []
3148 checkperms_tool = input_api.os_path.join(input_api.PresubmitLocalPath(),
3149 'tools', 'checkperms',
3150 'checkperms.py')
3151 args = [
Bruce Dawson8a43cf72022-05-13 17:10:323152 input_api.python3_executable, checkperms_tool, '--root',
Sam Maiera6e76d72022-02-11 21:43:503153 input_api.change.RepositoryRoot()
3154 ]
3155 with input_api.CreateTemporaryFile() as file_list:
3156 for f in input_api.AffectedFiles():
3157 # checkperms.py file/directory arguments must be relative to the
3158 # repository.
3159 file_list.write((f.LocalPath() + '\n').encode('utf8'))
3160 file_list.close()
3161 args += ['--file-list', file_list.name]
3162 try:
3163 input_api.subprocess.check_output(args)
3164 return []
3165 except input_api.subprocess.CalledProcessError as error:
3166 return [
3167 output_api.PresubmitError('checkperms.py failed:',
3168 long_text=error.output.decode(
3169 'utf-8', 'ignore'))
3170 ]
[email protected]fbcafe5a2012-08-08 15:31:223171
3172
Saagar Sanghavifceeaae2020-08-12 16:40:363173def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503174 """Makes sure we don't include ui/aura/window_property.h
3175 in header files.
3176 """
3177 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
3178 errors = []
3179 for f in input_api.AffectedFiles():
3180 if not f.LocalPath().endswith('.h'):
3181 continue
3182 for line_num, line in f.ChangedContents():
3183 if pattern.match(line):
3184 errors.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]c8278b32012-10-30 20:35:493185
Sam Maiera6e76d72022-02-11 21:43:503186 results = []
3187 if errors:
3188 results.append(
3189 output_api.PresubmitError(
3190 'Header files should not include ui/aura/window_property.h',
3191 errors))
3192 return results
[email protected]c8278b32012-10-30 20:35:493193
3194
Omer Katzcc77ea92021-04-26 10:23:283195def CheckNoInternalHeapIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503196 """Makes sure we don't include any headers from
3197 third_party/blink/renderer/platform/heap/impl or
3198 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
3199 third_party/blink/renderer/platform/heap
3200 """
3201 impl_pattern = input_api.re.compile(
3202 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
3203 v8_wrapper_pattern = input_api.re.compile(
3204 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"'
3205 )
Bruce Dawson40fece62022-09-16 19:58:313206 # Consistently use / as path separator to simplify the writing of regex
3207 # expressions.
Sam Maiera6e76d72022-02-11 21:43:503208 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:313209 r"^third_party/blink/renderer/platform/heap/.*",
3210 f.LocalPath().replace(input_api.os_path.sep, '/'))
Sam Maiera6e76d72022-02-11 21:43:503211 errors = []
Omer Katzcc77ea92021-04-26 10:23:283212
Sam Maiera6e76d72022-02-11 21:43:503213 for f in input_api.AffectedFiles(file_filter=file_filter):
3214 for line_num, line in f.ChangedContents():
3215 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
3216 errors.append(' %s:%d' % (f.LocalPath(), line_num))
Omer Katzcc77ea92021-04-26 10:23:283217
Sam Maiera6e76d72022-02-11 21:43:503218 results = []
3219 if errors:
3220 results.append(
3221 output_api.PresubmitError(
3222 'Do not include files from third_party/blink/renderer/platform/heap/impl'
3223 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
3224 'relevant counterparts from third_party/blink/renderer/platform/heap',
3225 errors))
3226 return results
Omer Katzcc77ea92021-04-26 10:23:283227
3228
[email protected]70ca77752012-11-20 03:45:033229def _CheckForVersionControlConflictsInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:503230 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
3231 errors = []
3232 for line_num, line in f.ChangedContents():
3233 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
3234 # First-level headers in markdown look a lot like version control
3235 # conflict markers. http://daringfireball.net/projects/markdown/basics
3236 continue
3237 if pattern.match(line):
3238 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
3239 return errors
[email protected]70ca77752012-11-20 03:45:033240
3241
Saagar Sanghavifceeaae2020-08-12 16:40:363242def CheckForVersionControlConflicts(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503243 """Usually this is not intentional and will cause a compile failure."""
3244 errors = []
3245 for f in input_api.AffectedFiles():
3246 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
[email protected]70ca77752012-11-20 03:45:033247
Sam Maiera6e76d72022-02-11 21:43:503248 results = []
3249 if errors:
3250 results.append(
3251 output_api.PresubmitError(
3252 'Version control conflict markers found, please resolve.',
3253 errors))
3254 return results
[email protected]70ca77752012-11-20 03:45:033255
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203256
Saagar Sanghavifceeaae2020-08-12 16:40:363257def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503258 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
3259 errors = []
3260 for f in input_api.AffectedFiles():
3261 for line_num, line in f.ChangedContents():
3262 if pattern.search(line):
3263 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
estadee17314a02017-01-12 16:22:163264
Sam Maiera6e76d72022-02-11 21:43:503265 results = []
3266 if errors:
3267 results.append(
3268 output_api.PresubmitPromptWarning(
3269 'Found Google support URL addressed by answer number. Please replace '
3270 'with a p= identifier instead. See crbug.com/679462\n',
3271 errors))
3272 return results
estadee17314a02017-01-12 16:22:163273
[email protected]70ca77752012-11-20 03:45:033274
Saagar Sanghavifceeaae2020-08-12 16:40:363275def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503276 def FilterFile(affected_file):
3277 """Filter function for use with input_api.AffectedSourceFiles,
3278 below. This filters out everything except non-test files from
3279 top-level directories that generally speaking should not hard-code
3280 service URLs (e.g. src/android_webview/, src/content/ and others).
3281 """
3282 return input_api.FilterSourceFile(
3283 affected_file,
Bruce Dawson40fece62022-09-16 19:58:313284 files_to_check=[r'^(android_webview|base|content|net)/.*'],
Sam Maiera6e76d72022-02-11 21:43:503285 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3286 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:443287
Sam Maiera6e76d72022-02-11 21:43:503288 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
3289 '\.(com|net)[^"]*"')
3290 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
3291 pattern = input_api.re.compile(base_pattern)
3292 problems = [] # items are (filename, line_number, line)
3293 for f in input_api.AffectedSourceFiles(FilterFile):
3294 for line_num, line in f.ChangedContents():
3295 if not comment_pattern.search(line) and pattern.search(line):
3296 problems.append((f.LocalPath(), line_num, line))
[email protected]06e6d0ff2012-12-11 01:36:443297
Sam Maiera6e76d72022-02-11 21:43:503298 if problems:
3299 return [
3300 output_api.PresubmitPromptOrNotify(
3301 'Most layers below src/chrome/ should not hardcode service URLs.\n'
3302 'Are you sure this is correct?', [
3303 ' %s:%d: %s' % (problem[0], problem[1], problem[2])
3304 for problem in problems
3305 ])
3306 ]
3307 else:
3308 return []
[email protected]06e6d0ff2012-12-11 01:36:443309
3310
Saagar Sanghavifceeaae2020-08-12 16:40:363311def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503312 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
James Cook6b6597c2019-11-06 22:05:293313
Sam Maiera6e76d72022-02-11 21:43:503314 def FileFilter(affected_file):
3315 """Includes directories known to be Chrome OS only."""
3316 return input_api.FilterSourceFile(
3317 affected_file,
3318 files_to_check=(
3319 '^ash/',
3320 '^chromeos/', # Top-level src/chromeos.
3321 '.*/chromeos/', # Any path component.
3322 '^components/arc',
3323 '^components/exo'),
3324 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:293325
Sam Maiera6e76d72022-02-11 21:43:503326 prefs = []
3327 priority_prefs = []
3328 for f in input_api.AffectedFiles(file_filter=FileFilter):
3329 for line_num, line in f.ChangedContents():
3330 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF',
3331 line):
3332 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
3333 prefs.append(' %s' % line)
3334 if input_api.re.search(
3335 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
3336 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
3337 priority_prefs.append(' %s' % line)
3338
3339 results = []
3340 if (prefs):
3341 results.append(
3342 output_api.PresubmitPromptWarning(
3343 'Preferences were registered as SYNCABLE_PREF and will be controlled '
3344 'by browser sync settings. If these prefs should be controlled by OS '
3345 'sync settings use SYNCABLE_OS_PREF instead.\n' +
3346 '\n'.join(prefs)))
3347 if (priority_prefs):
3348 results.append(
3349 output_api.PresubmitPromptWarning(
3350 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
3351 'controlled by browser sync settings. If these prefs should be '
3352 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
3353 'instead.\n' + '\n'.join(prefs)))
3354 return results
James Cook6b6597c2019-11-06 22:05:293355
3356
Saagar Sanghavifceeaae2020-08-12 16:40:363357def CheckNoAbbreviationInPngFileName(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503358 """Makes sure there are no abbreviations in the name of PNG files.
3359 The native_client_sdk directory is excluded because it has auto-generated PNG
3360 files for documentation.
3361 """
3362 errors = []
Yuanqing Zhu9eef02832022-12-04 14:42:173363 files_to_check = [r'.*\.png$']
Bruce Dawson40fece62022-09-16 19:58:313364 files_to_skip = [r'^native_client_sdk/',
3365 r'^services/test/',
3366 r'^third_party/blink/web_tests/',
Bruce Dawson3db456212022-05-02 05:34:183367 ]
Sam Maiera6e76d72022-02-11 21:43:503368 file_filter = lambda f: input_api.FilterSourceFile(
3369 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Yuanqing Zhu9eef02832022-12-04 14:42:173370 abbreviation = input_api.re.compile('.+_[a-z]\.png|.+_[a-z]_.*\.png')
Sam Maiera6e76d72022-02-11 21:43:503371 for f in input_api.AffectedFiles(include_deletes=False,
3372 file_filter=file_filter):
Yuanqing Zhu9eef02832022-12-04 14:42:173373 file_name = input_api.os_path.split(f.LocalPath())[1]
3374 if abbreviation.search(file_name):
3375 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:273376
Sam Maiera6e76d72022-02-11 21:43:503377 results = []
3378 if errors:
3379 results.append(
3380 output_api.PresubmitError(
3381 'The name of PNG files should not have abbreviations. \n'
3382 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
3383 'Contact [email protected] if you have questions.', errors))
3384 return results
[email protected]d2530012013-01-25 16:39:273385
Evan Stade7cd4a2c2022-08-04 23:37:253386def CheckNoProductIconsAddedToPublicRepo(input_api, output_api):
3387 """Heuristically identifies product icons based on their file name and reminds
3388 contributors not to add them to the Chromium repository.
3389 """
3390 errors = []
3391 files_to_check = [r'.*google.*\.png$|.*google.*\.svg$|.*google.*\.icon$']
3392 file_filter = lambda f: input_api.FilterSourceFile(
3393 f, files_to_check=files_to_check)
3394 for f in input_api.AffectedFiles(include_deletes=False,
3395 file_filter=file_filter):
3396 errors.append(' %s' % f.LocalPath())
3397
3398 results = []
3399 if errors:
Bruce Dawson3bcf0c92022-08-12 00:03:083400 # Give warnings instead of errors on presubmit --all and presubmit
3401 # --files.
3402 message_type = (output_api.PresubmitNotifyResult if input_api.no_diffs
3403 else output_api.PresubmitError)
Evan Stade7cd4a2c2022-08-04 23:37:253404 results.append(
Bruce Dawson3bcf0c92022-08-12 00:03:083405 message_type(
Evan Stade7cd4a2c2022-08-04 23:37:253406 'Trademarked images should not be added to the public repo. '
3407 'See crbug.com/944754', errors))
3408 return results
3409
[email protected]d2530012013-01-25 16:39:273410
Daniel Cheng4dcdb6b2017-04-13 08:30:173411def _ExtractAddRulesFromParsedDeps(parsed_deps):
Sam Maiera6e76d72022-02-11 21:43:503412 """Extract the rules that add dependencies from a parsed DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:173413
Sam Maiera6e76d72022-02-11 21:43:503414 Args:
3415 parsed_deps: the locals dictionary from evaluating the DEPS file."""
3416 add_rules = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:173417 add_rules.update([
Sam Maiera6e76d72022-02-11 21:43:503418 rule[1:] for rule in parsed_deps.get('include_rules', [])
Daniel Cheng4dcdb6b2017-04-13 08:30:173419 if rule.startswith('+') or rule.startswith('!')
3420 ])
Sam Maiera6e76d72022-02-11 21:43:503421 for _, rules in parsed_deps.get('specific_include_rules', {}).items():
3422 add_rules.update([
3423 rule[1:] for rule in rules
3424 if rule.startswith('+') or rule.startswith('!')
3425 ])
3426 return add_rules
Daniel Cheng4dcdb6b2017-04-13 08:30:173427
3428
3429def _ParseDeps(contents):
Sam Maiera6e76d72022-02-11 21:43:503430 """Simple helper for parsing DEPS files."""
Daniel Cheng4dcdb6b2017-04-13 08:30:173431
Sam Maiera6e76d72022-02-11 21:43:503432 # Stubs for handling special syntax in the root DEPS file.
3433 class _VarImpl:
3434 def __init__(self, local_scope):
3435 self._local_scope = local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:173436
Sam Maiera6e76d72022-02-11 21:43:503437 def Lookup(self, var_name):
3438 """Implements the Var syntax."""
3439 try:
3440 return self._local_scope['vars'][var_name]
3441 except KeyError:
3442 raise Exception('Var is not defined: %s' % var_name)
Daniel Cheng4dcdb6b2017-04-13 08:30:173443
Sam Maiera6e76d72022-02-11 21:43:503444 local_scope = {}
3445 global_scope = {
3446 'Var': _VarImpl(local_scope).Lookup,
3447 'Str': str,
3448 }
Dirk Pranke1b9e06382021-05-14 01:16:223449
Sam Maiera6e76d72022-02-11 21:43:503450 exec(contents, global_scope, local_scope)
3451 return local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:173452
3453
3454def _CalculateAddedDeps(os_path, old_contents, new_contents):
Sam Maiera6e76d72022-02-11 21:43:503455 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
3456 a set of DEPS entries that we should look up.
[email protected]14a6131c2014-01-08 01:15:413457
Sam Maiera6e76d72022-02-11 21:43:503458 For a directory (rather than a specific filename) we fake a path to
3459 a specific filename by adding /DEPS. This is chosen as a file that
3460 will seldom or never be subject to per-file include_rules.
3461 """
3462 # We ignore deps entries on auto-generated directories.
3463 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:083464
Sam Maiera6e76d72022-02-11 21:43:503465 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
3466 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
Daniel Cheng4dcdb6b2017-04-13 08:30:173467
Sam Maiera6e76d72022-02-11 21:43:503468 added_deps = new_deps.difference(old_deps)
Daniel Cheng4dcdb6b2017-04-13 08:30:173469
Sam Maiera6e76d72022-02-11 21:43:503470 results = set()
3471 for added_dep in added_deps:
3472 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
3473 continue
3474 # Assume that a rule that ends in .h is a rule for a specific file.
3475 if added_dep.endswith('.h'):
3476 results.add(added_dep)
3477 else:
3478 results.add(os_path.join(added_dep, 'DEPS'))
3479 return results
[email protected]f32e2d1e2013-07-26 21:39:083480
Stephanie Kimec4f55a2024-04-24 16:54:023481def CheckForNewDEPSDownloadFromGoogleStorageHooks(input_api, output_api):
3482 """Checks that there are no new download_from_google_storage hooks"""
3483 for f in input_api.AffectedFiles(include_deletes=False):
3484 if f.LocalPath() == 'DEPS':
3485 old_hooks = _ParseDeps('\n'.join(f.OldContents()))['hooks']
3486 new_hooks = _ParseDeps('\n'.join(f.NewContents()))['hooks']
3487 old_name_to_hook = {hook['name']: hook for hook in old_hooks}
3488 new_name_to_hook = {hook['name']: hook for hook in new_hooks}
3489 added_hook_names = set(new_name_to_hook.keys()) - set(
3490 old_name_to_hook.keys())
3491 if not added_hook_names:
3492 return []
3493 new_download_from_google_storage_hooks = []
3494 for new_hook in added_hook_names:
3495 hook = new_name_to_hook[new_hook]
3496 action_cmd = hook['action']
3497 if any('download_from_google_storage' in arg
3498 for arg in action_cmd):
3499 new_download_from_google_storage_hooks.append(new_hook)
3500 if new_download_from_google_storage_hooks:
3501 return [
3502 output_api.PresubmitError(
3503 'Please do not add new download_from_google_storage '
3504 'hooks. Instead, add a `gcs` dep_type entry to `deps`. '
3505 'See https://chromium.googlesource.com/chromium/src.git'
3506 '/+/refs/heads/main/docs/gcs_dependencies.md for more '
3507 'info. Added hooks:',
3508 items=new_download_from_google_storage_hooks)
3509 ]
3510 return []
3511
[email protected]f32e2d1e2013-07-26 21:39:083512
Rasika Navarangec2d33d22024-05-23 15:19:023513def CheckEachPerfettoTestDataFileHasDepsEntry(input_api, output_api):
3514 test_data_filter = lambda f: input_api.FilterSourceFile(
Rasika Navarange08e542162024-05-31 13:31:263515 f, files_to_check=[r'^base/tracing/test/data_sha256/.*\.sha256'])
Rasika Navarangec2d33d22024-05-23 15:19:023516 if not any(input_api.AffectedFiles(file_filter=test_data_filter)):
3517 return []
3518
3519 # Find DEPS entry
3520 deps_entry = []
Rasika Navarange277cd662024-06-04 10:14:593521 old_deps_entry = []
Rasika Navarangec2d33d22024-05-23 15:19:023522 for f in input_api.AffectedFiles(include_deletes=False):
3523 if f.LocalPath() == 'DEPS':
3524 new_deps = _ParseDeps('\n'.join(f.NewContents()))['deps']
3525 deps_entry = new_deps['src/base/tracing/test/data']
Rasika Navarange277cd662024-06-04 10:14:593526 old_deps = _ParseDeps('\n'.join(f.OldContents()))['deps']
3527 old_deps_entry = old_deps['src/base/tracing/test/data']
Rasika Navarangec2d33d22024-05-23 15:19:023528 if not deps_entry:
Rasika Navarange08e542162024-05-31 13:31:263529 # TODO(312895063):Add back error when .sha256 files have been moved.
Rasika Navaranged977df342024-06-05 10:01:273530 return [output_api.PresubmitError(
Rasika Navarangec2d33d22024-05-23 15:19:023531 'You must update the DEPS file when you update a '
Rasika Navarange08e542162024-05-31 13:31:263532 '.sha256 file in base/tracing/test/data_sha256'
Rasika Navarangec2d33d22024-05-23 15:19:023533 )]
3534
3535 output = []
3536 for f in input_api.AffectedFiles(file_filter=test_data_filter):
3537 objects = deps_entry['objects']
3538 if not f.NewContents():
3539 # Deleted file so check that DEPS entry removed
3540 sha256_from_file = f.OldContents()[0]
3541 object_entry = next(
3542 (item for item in objects if item["sha256sum"] == sha256_from_file),
3543 None)
Rasika Navarange277cd662024-06-04 10:14:593544 old_entry = next(
3545 (item for item in old_deps_entry['objects'] if item["sha256sum"] == sha256_from_file),
3546 None)
Rasika Navarangec2d33d22024-05-23 15:19:023547 if object_entry:
Rasika Navarange277cd662024-06-04 10:14:593548 # Allow renaming of objects with the same hash
3549 if object_entry['object_name'] != old_entry['object_name']:
3550 continue
Rasika Navarangec2d33d22024-05-23 15:19:023551 output.append(output_api.PresubmitError(
3552 'You deleted %s so you must also remove the corresponding DEPS entry.'
3553 % f.LocalPath()
3554 ))
3555 continue
3556
3557 sha256_from_file = f.NewContents()[0]
3558 object_entry = next(
3559 (item for item in objects if item["sha256sum"] == sha256_from_file),
3560 None)
3561 if not object_entry:
3562 output.append(output_api.PresubmitError(
3563 'No corresponding DEPS entry found for %s. '
3564 'Run `base/tracing/test/test_data.py get_deps --filepath %s` '
3565 'to generate the DEPS entry.'
3566 % (f.LocalPath(), f.LocalPath())
3567 ))
3568
3569 if output:
3570 output.append(output_api.PresubmitError(
3571 'The DEPS entry for `src/base/tracing/test/data` in the DEPS file has not been '
3572 'updated properly. Run `base/tracing/test/test_data.py get_all_deps` to see what '
3573 'the DEPS entry should look like.'
3574 ))
3575 return output
3576
3577
Saagar Sanghavifceeaae2020-08-12 16:40:363578def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503579 """When a dependency prefixed with + is added to a DEPS file, we
3580 want to make sure that the change is reviewed by an OWNER of the
3581 target file or directory, to avoid layering violations from being
3582 introduced. This check verifies that this happens.
3583 """
3584 # We rely on Gerrit's code-owners to check approvals.
3585 # input_api.gerrit is always set for Chromium, but other projects
3586 # might not use Gerrit.
Bruce Dawson344ab262022-06-04 11:35:103587 if not input_api.gerrit or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:503588 return []
Bruce Dawsonb357aeb2022-08-09 15:38:303589 if 'PRESUBMIT_SKIP_NETWORK' in input_api.environ:
Sam Maiera6e76d72022-02-11 21:43:503590 return []
Bruce Dawsonb357aeb2022-08-09 15:38:303591 try:
3592 if (input_api.change.issue and
3593 input_api.gerrit.IsOwnersOverrideApproved(
3594 input_api.change.issue)):
3595 # Skip OWNERS check when Owners-Override label is approved. This is
3596 # intended for global owners, trusted bots, and on-call sheriffs.
3597 # Review is still required for these changes.
3598 return []
3599 except Exception as e:
Sam Maier4cef9242022-10-03 14:21:243600 return [output_api.PresubmitPromptWarning(
3601 'Failed to retrieve owner override status - %s' % str(e))]
Edward Lesmes6fba51082021-01-20 04:20:233602
Sam Maiera6e76d72022-02-11 21:43:503603 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:243604
Bruce Dawson40fece62022-09-16 19:58:313605 # Consistently use / as path separator to simplify the writing of regex
3606 # expressions.
Sam Maiera6e76d72022-02-11 21:43:503607 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:313608 r"^third_party/blink/.*",
3609 f.LocalPath().replace(input_api.os_path.sep, '/'))
Sam Maiera6e76d72022-02-11 21:43:503610 for f in input_api.AffectedFiles(include_deletes=False,
3611 file_filter=file_filter):
3612 filename = input_api.os_path.basename(f.LocalPath())
3613 if filename == 'DEPS':
3614 virtual_depended_on_files.update(
3615 _CalculateAddedDeps(input_api.os_path,
3616 '\n'.join(f.OldContents()),
3617 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:553618
Sam Maiera6e76d72022-02-11 21:43:503619 if not virtual_depended_on_files:
3620 return []
[email protected]e871964c2013-05-13 14:14:553621
Sam Maiera6e76d72022-02-11 21:43:503622 if input_api.is_committing:
3623 if input_api.tbr:
3624 return [
3625 output_api.PresubmitNotifyResult(
3626 '--tbr was specified, skipping OWNERS check for DEPS additions'
3627 )
3628 ]
Daniel Cheng3008dc12022-05-13 04:02:113629 # TODO(dcheng): Make this generate an error on dry runs if the reviewer
3630 # is not added, to prevent review serialization.
Sam Maiera6e76d72022-02-11 21:43:503631 if input_api.dry_run:
3632 return [
3633 output_api.PresubmitNotifyResult(
3634 'This is a dry run, skipping OWNERS check for DEPS additions'
3635 )
3636 ]
3637 if not input_api.change.issue:
3638 return [
3639 output_api.PresubmitError(
3640 "DEPS approval by OWNERS check failed: this change has "
3641 "no change number, so we can't check it for approvals.")
3642 ]
3643 output = output_api.PresubmitError
[email protected]14a6131c2014-01-08 01:15:413644 else:
Sam Maiera6e76d72022-02-11 21:43:503645 output = output_api.PresubmitNotifyResult
[email protected]e871964c2013-05-13 14:14:553646
Sam Maiera6e76d72022-02-11 21:43:503647 owner_email, reviewers = (
3648 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3649 input_api, None, approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:553650
Sam Maiera6e76d72022-02-11 21:43:503651 owner_email = owner_email or input_api.change.author_email
3652
3653 approval_status = input_api.owners_client.GetFilesApprovalStatus(
3654 virtual_depended_on_files, reviewers.union([owner_email]), [])
3655 missing_files = [
3656 f for f in virtual_depended_on_files
3657 if approval_status[f] != input_api.owners_client.APPROVED
3658 ]
3659
3660 # We strip the /DEPS part that was added by
3661 # _FilesToCheckForIncomingDeps to fake a path to a file in a
3662 # directory.
3663 def StripDeps(path):
3664 start_deps = path.rfind('/DEPS')
3665 if start_deps != -1:
3666 return path[:start_deps]
3667 else:
3668 return path
3669
Scott Leebf6a0942024-06-26 22:59:393670 submodule_paths = set(input_api.ListSubmodules())
3671 def is_from_submodules(path, submodule_paths):
3672 path = input_api.os_path.normpath(path)
3673 while path:
3674 if path in submodule_paths:
3675 return True
3676
3677 # All deps should be a relative path from the checkout.
3678 # i.e., shouldn't start with "/" or "c:\", for example.
3679 #
3680 # That said, this is to prevent an infinite loop, just in case
3681 # an input dep path starts with "/", because
3682 # os.path.dirname("/") => "/"
3683 parent = input_api.os_path.dirname(path)
3684 if parent == path:
3685 break
3686 path = parent
3687
3688 return False
3689
Sam Maiera6e76d72022-02-11 21:43:503690 unapproved_dependencies = [
3691 "'+%s'," % StripDeps(path) for path in missing_files
Scott Leebf6a0942024-06-26 22:59:393692 # if a newly added dep is from a submodule, it becomes trickier
3693 # to get suggested owners, especially it is from a different host.
3694 #
3695 # skip the review enforcement for cross-repo deps.
3696 if not is_from_submodules(path, submodule_paths)
Sam Maiera6e76d72022-02-11 21:43:503697 ]
3698
3699 if unapproved_dependencies:
3700 output_list = [
3701 output(
3702 'You need LGTM from owners of depends-on paths in DEPS that were '
3703 'modified in this CL:\n %s' %
3704 '\n '.join(sorted(unapproved_dependencies)))
3705 ]
3706 suggested_owners = input_api.owners_client.SuggestOwners(
3707 missing_files, exclude=[owner_email])
3708 output_list.append(
3709 output('Suggested missing target path OWNERS:\n %s' %
3710 '\n '.join(suggested_owners or [])))
3711 return output_list
3712
3713 return []
[email protected]e871964c2013-05-13 14:14:553714
3715
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493716# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:363717def CheckSpamLogging(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503718 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3719 files_to_skip = (
3720 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3721 input_api.DEFAULT_FILES_TO_SKIP + (
Jaewon Jung2f323bb2022-12-07 23:55:013722 r"^base/fuchsia/scoped_fx_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313723 r"^base/logging\.h$",
3724 r"^base/logging\.cc$",
3725 r"^base/task/thread_pool/task_tracker\.cc$",
3726 r"^chrome/app/chrome_main_delegate\.cc$",
Yao Li359937b2023-02-15 23:43:033727 r"^chrome/browser/ash/arc/enterprise/cert_store/arc_cert_installer\.cc$",
3728 r"^chrome/browser/ash/policy/remote_commands/user_command_arc_job\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313729 r"^chrome/browser/chrome_browser_main\.cc$",
3730 r"^chrome/browser/ui/startup/startup_browser_creator\.cc$",
3731 r"^chrome/browser/browser_switcher/bho/.*",
3732 r"^chrome/browser/diagnostics/diagnostics_writer\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313733 r"^chrome/chrome_elf/dll_hash/dll_hash_main\.cc$",
3734 r"^chrome/installer/setup/.*",
Daniel Ruberyad36eea2024-08-01 01:38:323735 # crdmg runs as a separate binary which intentionally does
3736 # not depend on base logging.
3737 r"^chrome/utility/safe_browsing/mac/crdmg\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313738 r"^chromecast/",
Vigen Issahhanjane2d93822023-06-30 15:57:203739 r"^components/cast",
Bruce Dawson40fece62022-09-16 19:58:313740 r"^components/media_control/renderer/media_playback_options\.cc$",
Salma Elmahallawy52976452023-01-27 17:04:493741 r"^components/policy/core/common/policy_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313742 r"^components/viz/service/display/"
Sam Maiera6e76d72022-02-11 21:43:503743 r"overlay_strategy_underlay_cast\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313744 r"^components/zucchini/.*",
Sam Maiera6e76d72022-02-11 21:43:503745 # TODO(peter): Remove exception. https://crbug.com/534537
Bruce Dawson40fece62022-09-16 19:58:313746 r"^content/browser/notifications/"
Sam Maiera6e76d72022-02-11 21:43:503747 r"notification_event_dispatcher_impl\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313748 r"^content/common/gpu/client/gl_helper_benchmark\.cc$",
3749 r"^courgette/courgette_minimal_tool\.cc$",
3750 r"^courgette/courgette_tool\.cc$",
3751 r"^extensions/renderer/logging_native_handler\.cc$",
3752 r"^fuchsia_web/common/init_logging\.cc$",
3753 r"^fuchsia_web/runners/common/web_component\.cc$",
Caroline Liua7050132023-02-13 22:23:153754 r"^fuchsia_web/shell/.*\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313755 r"^headless/app/headless_shell\.cc$",
3756 r"^ipc/ipc_logging\.cc$",
3757 r"^native_client_sdk/",
3758 r"^remoting/base/logging\.h$",
3759 r"^remoting/host/.*",
3760 r"^sandbox/linux/.*",
Austin Sullivana6054e02024-05-20 16:31:293761 r"^services/webnn/tflite/graph_impl_tflite\.cc$",
3762 r"^services/webnn/coreml/graph_impl_coreml\.mm$",
Bruce Dawson40fece62022-09-16 19:58:313763 r"^storage/browser/file_system/dump_file_system\.cc$",
Steinar H. Gundersone5689e42024-08-07 18:17:193764 r"^testing/perf/",
Bruce Dawson40fece62022-09-16 19:58:313765 r"^tools/",
3766 r"^ui/base/resource/data_pack\.cc$",
3767 r"^ui/aura/bench/bench_main\.cc$",
3768 r"^ui/ozone/platform/cast/",
3769 r"^ui/base/x/xwmstartupcheck/"
Sam Maiera6e76d72022-02-11 21:43:503770 r"xwmstartupcheck\.cc$"))
3771 source_file_filter = lambda x: input_api.FilterSourceFile(
3772 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:403773
Sam Maiera6e76d72022-02-11 21:43:503774 log_info = set([])
3775 printf = set([])
[email protected]85218562013-11-22 07:41:403776
Sam Maiera6e76d72022-02-11 21:43:503777 for f in input_api.AffectedSourceFiles(source_file_filter):
3778 for _, line in f.ChangedContents():
3779 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
3780 log_info.add(f.LocalPath())
3781 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
3782 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:373783
Sam Maiera6e76d72022-02-11 21:43:503784 if input_api.re.search(r"\bprintf\(", line):
3785 printf.add(f.LocalPath())
3786 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
3787 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:403788
Sam Maiera6e76d72022-02-11 21:43:503789 if log_info:
3790 return [
3791 output_api.PresubmitError(
3792 'These files spam the console log with LOG(INFO):',
3793 items=log_info)
3794 ]
3795 if printf:
3796 return [
3797 output_api.PresubmitError(
3798 'These files spam the console log with printf/fprintf:',
3799 items=printf)
3800 ]
3801 return []
[email protected]85218562013-11-22 07:41:403802
3803
Saagar Sanghavifceeaae2020-08-12 16:40:363804def CheckForAnonymousVariables(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503805 """These types are all expected to hold locks while in scope and
3806 so should never be anonymous (which causes them to be immediately
3807 destroyed)."""
3808 they_who_must_be_named = [
3809 'base::AutoLock',
3810 'base::AutoReset',
3811 'base::AutoUnlock',
3812 'SkAutoAlphaRestore',
3813 'SkAutoBitmapShaderInstall',
3814 'SkAutoBlitterChoose',
3815 'SkAutoBounderCommit',
3816 'SkAutoCallProc',
3817 'SkAutoCanvasRestore',
3818 'SkAutoCommentBlock',
3819 'SkAutoDescriptor',
3820 'SkAutoDisableDirectionCheck',
3821 'SkAutoDisableOvalCheck',
3822 'SkAutoFree',
3823 'SkAutoGlyphCache',
3824 'SkAutoHDC',
3825 'SkAutoLockColors',
3826 'SkAutoLockPixels',
3827 'SkAutoMalloc',
3828 'SkAutoMaskFreeImage',
3829 'SkAutoMutexAcquire',
3830 'SkAutoPathBoundsUpdate',
3831 'SkAutoPDFRelease',
3832 'SkAutoRasterClipValidate',
3833 'SkAutoRef',
3834 'SkAutoTime',
3835 'SkAutoTrace',
3836 'SkAutoUnref',
3837 ]
3838 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
3839 # bad: base::AutoLock(lock.get());
3840 # not bad: base::AutoLock lock(lock.get());
3841 bad_pattern = input_api.re.compile(anonymous)
3842 # good: new base::AutoLock(lock.get())
3843 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
3844 errors = []
[email protected]49aa76a2013-12-04 06:59:163845
Sam Maiera6e76d72022-02-11 21:43:503846 for f in input_api.AffectedFiles():
3847 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
3848 continue
3849 for linenum, line in f.ChangedContents():
3850 if bad_pattern.search(line) and not good_pattern.search(line):
3851 errors.append('%s:%d' % (f.LocalPath(), linenum))
[email protected]49aa76a2013-12-04 06:59:163852
Sam Maiera6e76d72022-02-11 21:43:503853 if errors:
3854 return [
3855 output_api.PresubmitError(
3856 'These lines create anonymous variables that need to be named:',
3857 items=errors)
3858 ]
3859 return []
[email protected]49aa76a2013-12-04 06:59:163860
3861
Saagar Sanghavifceeaae2020-08-12 16:40:363862def CheckUniquePtrOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503863 # Returns whether |template_str| is of the form <T, U...> for some types T
Glen Robertson9142ffd72024-05-16 01:37:473864 # and U, or is invalid due to mismatched angle bracket pairs. Assumes that
3865 # |template_str| is already in the form <...>.
3866 def HasMoreThanOneArgOrInvalid(template_str):
Sam Maiera6e76d72022-02-11 21:43:503867 # Level of <...> nesting.
3868 nesting = 0
3869 for c in template_str:
3870 if c == '<':
3871 nesting += 1
3872 elif c == '>':
3873 nesting -= 1
3874 elif c == ',' and nesting == 1:
3875 return True
Glen Robertson9142ffd72024-05-16 01:37:473876 if nesting != 0:
Daniel Cheng566634ff2024-06-29 14:56:533877 # Invalid.
3878 return True
Sam Maiera6e76d72022-02-11 21:43:503879 return False
Vaclav Brozekb7fadb692018-08-30 06:39:533880
Sam Maiera6e76d72022-02-11 21:43:503881 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3882 sources = lambda affected_file: input_api.FilterSourceFile(
3883 affected_file,
3884 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3885 DEFAULT_FILES_TO_SKIP),
3886 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:553887
Sam Maiera6e76d72022-02-11 21:43:503888 # Pattern to capture a single "<...>" block of template arguments. It can
3889 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
3890 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
3891 # latter would likely require counting that < and > match, which is not
3892 # expressible in regular languages. Should the need arise, one can introduce
3893 # limited counting (matching up to a total number of nesting depth), which
3894 # should cover all practical cases for already a low nesting limit.
3895 template_arg_pattern = (
3896 r'<[^>]*' # Opening block of <.
3897 r'>([^<]*>)?') # Closing block of >.
3898 # Prefix expressing that whatever follows is not already inside a <...>
3899 # block.
3900 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
3901 null_construct_pattern = input_api.re.compile(
3902 not_inside_template_arg_pattern + r'\bstd::unique_ptr' +
3903 template_arg_pattern + r'\(\)')
Vaclav Brozeka54c528b2018-04-06 19:23:553904
Sam Maiera6e76d72022-02-11 21:43:503905 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
3906 template_arg_no_array_pattern = (
3907 r'<[^>]*[^]]' # Opening block of <.
3908 r'>([^(<]*[^]]>)?') # Closing block of >.
3909 # Prefix saying that what follows is the start of an expression.
3910 start_of_expr_pattern = r'(=|\breturn|^)\s*'
3911 # Suffix saying that what follows are call parentheses with a non-empty list
3912 # of arguments.
3913 nonempty_arg_list_pattern = r'\(([^)]|$)'
3914 # Put the template argument into a capture group for deeper examination later.
3915 return_construct_pattern = input_api.re.compile(
3916 start_of_expr_pattern + r'std::unique_ptr' + '(?P<template_arg>' +
3917 template_arg_no_array_pattern + ')' + nonempty_arg_list_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:553918
Sam Maiera6e76d72022-02-11 21:43:503919 problems_constructor = []
3920 problems_nullptr = []
3921 for f in input_api.AffectedSourceFiles(sources):
3922 for line_number, line in f.ChangedContents():
3923 # Disallow:
3924 # return std::unique_ptr<T>(foo);
3925 # bar = std::unique_ptr<T>(foo);
3926 # But allow:
3927 # return std::unique_ptr<T[]>(foo);
3928 # bar = std::unique_ptr<T[]>(foo);
3929 # And also allow cases when the second template argument is present. Those
3930 # cases cannot be handled by std::make_unique:
3931 # return std::unique_ptr<T, U>(foo);
3932 # bar = std::unique_ptr<T, U>(foo);
3933 local_path = f.LocalPath()
3934 return_construct_result = return_construct_pattern.search(line)
Glen Robertson9142ffd72024-05-16 01:37:473935 if return_construct_result and not HasMoreThanOneArgOrInvalid(
Sam Maiera6e76d72022-02-11 21:43:503936 return_construct_result.group('template_arg')):
3937 problems_constructor.append(
3938 '%s:%d\n %s' % (local_path, line_number, line.strip()))
3939 # Disallow:
3940 # std::unique_ptr<T>()
3941 if null_construct_pattern.search(line):
3942 problems_nullptr.append(
3943 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Vaclav Brozek851d9602018-04-04 16:13:053944
Sam Maiera6e76d72022-02-11 21:43:503945 errors = []
3946 if problems_nullptr:
3947 errors.append(
3948 output_api.PresubmitPromptWarning(
3949 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
3950 problems_nullptr))
3951 if problems_constructor:
3952 errors.append(
3953 output_api.PresubmitError(
3954 'The following files use explicit std::unique_ptr constructor. '
3955 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
3956 'std::make_unique is not an option.', problems_constructor))
3957 return errors
Peter Kasting4844e46e2018-02-23 07:27:103958
3959
Saagar Sanghavifceeaae2020-08-12 16:40:363960def CheckUserActionUpdate(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503961 """Checks if any new user action has been added."""
3962 if any('actions.xml' == input_api.os_path.basename(f)
3963 for f in input_api.LocalPaths()):
3964 # If actions.xml is already included in the changelist, the PRESUBMIT
3965 # for actions.xml will do a more complete presubmit check.
3966 return []
3967
3968 file_inclusion_pattern = [r'.*\.(cc|mm)$']
3969 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3970 input_api.DEFAULT_FILES_TO_SKIP)
3971 file_filter = lambda f: input_api.FilterSourceFile(
3972 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
3973
3974 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
3975 current_actions = None
3976 for f in input_api.AffectedFiles(file_filter=file_filter):
3977 for line_num, line in f.ChangedContents():
3978 match = input_api.re.search(action_re, line)
3979 if match:
3980 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
3981 # loaded only once.
3982 if not current_actions:
Bruce Dawson6cb2d4d2023-03-01 21:35:093983 with open('tools/metrics/actions/actions.xml',
3984 encoding='utf-8') as actions_f:
Sam Maiera6e76d72022-02-11 21:43:503985 current_actions = actions_f.read()
3986 # Search for the matched user action name in |current_actions|.
3987 for action_name in match.groups():
3988 action = 'name="{0}"'.format(action_name)
3989 if action not in current_actions:
3990 return [
3991 output_api.PresubmitPromptWarning(
3992 'File %s line %d: %s is missing in '
3993 'tools/metrics/actions/actions.xml. Please run '
3994 'tools/metrics/actions/extract_actions.py to update.'
3995 % (f.LocalPath(), line_num, action_name))
3996 ]
[email protected]999261d2014-03-03 20:08:083997 return []
3998
[email protected]999261d2014-03-03 20:08:083999
Daniel Cheng13ca61a882017-08-25 15:11:254000def _ImportJSONCommentEater(input_api):
Sam Maiera6e76d72022-02-11 21:43:504001 import sys
4002 sys.path = sys.path + [
4003 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4004 'json_comment_eater')
4005 ]
4006 import json_comment_eater
4007 return json_comment_eater
Daniel Cheng13ca61a882017-08-25 15:11:254008
4009
[email protected]99171a92014-06-03 08:44:474010def _GetJSONParseError(input_api, filename, eat_comments=True):
dchenge07de812016-06-20 19:27:174011 try:
Sam Maiera6e76d72022-02-11 21:43:504012 contents = input_api.ReadFile(filename)
4013 if eat_comments:
4014 json_comment_eater = _ImportJSONCommentEater(input_api)
4015 contents = json_comment_eater.Nom(contents)
dchenge07de812016-06-20 19:27:174016
Sam Maiera6e76d72022-02-11 21:43:504017 input_api.json.loads(contents)
4018 except ValueError as e:
4019 return e
Andrew Grieve4deedb12022-02-03 21:34:504020 return None
4021
4022
Sam Maiera6e76d72022-02-11 21:43:504023def _GetIDLParseError(input_api, filename):
4024 try:
4025 contents = input_api.ReadFile(filename)
Devlin Croninf7582a12022-04-21 21:14:284026 for i, char in enumerate(contents):
Daniel Chenga37c03db2022-05-12 17:20:344027 if not char.isascii():
4028 return (
4029 'Non-ascii character "%s" (ord %d) found at offset %d.' %
4030 (char, ord(char), i))
Sam Maiera6e76d72022-02-11 21:43:504031 idl_schema = input_api.os_path.join(input_api.PresubmitLocalPath(),
4032 'tools', 'json_schema_compiler',
4033 'idl_schema.py')
4034 process = input_api.subprocess.Popen(
Bruce Dawson679fb082022-04-14 00:47:284035 [input_api.python3_executable, idl_schema],
Sam Maiera6e76d72022-02-11 21:43:504036 stdin=input_api.subprocess.PIPE,
4037 stdout=input_api.subprocess.PIPE,
4038 stderr=input_api.subprocess.PIPE,
4039 universal_newlines=True)
4040 (_, error) = process.communicate(input=contents)
4041 return error or None
4042 except ValueError as e:
4043 return e
agrievef32bcc72016-04-04 14:57:404044
agrievef32bcc72016-04-04 14:57:404045
Sam Maiera6e76d72022-02-11 21:43:504046def CheckParseErrors(input_api, output_api):
4047 """Check that IDL and JSON files do not contain syntax errors."""
4048 actions = {
4049 '.idl': _GetIDLParseError,
4050 '.json': _GetJSONParseError,
4051 }
4052 # Most JSON files are preprocessed and support comments, but these do not.
4053 json_no_comments_patterns = [
Bruce Dawson40fece62022-09-16 19:58:314054 r'^testing/',
Sam Maiera6e76d72022-02-11 21:43:504055 ]
4056 # Only run IDL checker on files in these directories.
4057 idl_included_patterns = [
Bruce Dawson40fece62022-09-16 19:58:314058 r'^chrome/common/extensions/api/',
4059 r'^extensions/common/api/',
Sam Maiera6e76d72022-02-11 21:43:504060 ]
agrievef32bcc72016-04-04 14:57:404061
Sam Maiera6e76d72022-02-11 21:43:504062 def get_action(affected_file):
4063 filename = affected_file.LocalPath()
4064 return actions.get(input_api.os_path.splitext(filename)[1])
agrievef32bcc72016-04-04 14:57:404065
Sam Maiera6e76d72022-02-11 21:43:504066 def FilterFile(affected_file):
4067 action = get_action(affected_file)
4068 if not action:
4069 return False
4070 path = affected_file.LocalPath()
agrievef32bcc72016-04-04 14:57:404071
Sam Maiera6e76d72022-02-11 21:43:504072 if _MatchesFile(input_api,
4073 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS, path):
4074 return False
4075
4076 if (action == _GetIDLParseError
4077 and not _MatchesFile(input_api, idl_included_patterns, path)):
4078 return False
4079 return True
4080
4081 results = []
4082 for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
4083 include_deletes=False):
4084 action = get_action(affected_file)
4085 kwargs = {}
4086 if (action == _GetJSONParseError
4087 and _MatchesFile(input_api, json_no_comments_patterns,
4088 affected_file.LocalPath())):
4089 kwargs['eat_comments'] = False
4090 parse_error = action(input_api, affected_file.AbsoluteLocalPath(),
4091 **kwargs)
4092 if parse_error:
4093 results.append(
4094 output_api.PresubmitError(
4095 '%s could not be parsed: %s' %
4096 (affected_file.LocalPath(), parse_error)))
4097 return results
4098
4099
4100def CheckJavaStyle(input_api, output_api):
4101 """Runs checkstyle on changed java files and returns errors if any exist."""
4102
4103 # Return early if no java files were modified.
4104 if not any(
4105 _IsJavaFile(input_api, f.LocalPath())
4106 for f in input_api.AffectedFiles()):
4107 return []
4108
4109 import sys
4110 original_sys_path = sys.path
4111 try:
4112 sys.path = sys.path + [
4113 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4114 'android', 'checkstyle')
4115 ]
4116 import checkstyle
4117 finally:
4118 # Restore sys.path to what it was before.
4119 sys.path = original_sys_path
4120
Andrew Grieve4f88e3ca2022-11-22 19:09:204121 return checkstyle.run_presubmit(
Sam Maiera6e76d72022-02-11 21:43:504122 input_api,
4123 output_api,
Sam Maiera6e76d72022-02-11 21:43:504124 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
4125
4126
4127def CheckPythonDevilInit(input_api, output_api):
4128 """Checks to make sure devil is initialized correctly in python scripts."""
4129 script_common_initialize_pattern = input_api.re.compile(
4130 r'script_common\.InitializeEnvironment\(')
4131 devil_env_config_initialize = input_api.re.compile(
4132 r'devil_env\.config\.Initialize\(')
4133
4134 errors = []
4135
4136 sources = lambda affected_file: input_api.FilterSourceFile(
4137 affected_file,
4138 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314139 r'^build/android/devil_chromium\.py',
Sven Zheng8e079562024-05-10 20:11:064140 r'^tools/bisect-builds\.py',
Bruce Dawson40fece62022-09-16 19:58:314141 r'^third_party/.*',
Sam Maiera6e76d72022-02-11 21:43:504142 )),
4143 files_to_check=[r'.*\.py$'])
4144
4145 for f in input_api.AffectedSourceFiles(sources):
4146 for line_num, line in f.ChangedContents():
4147 if (script_common_initialize_pattern.search(line)
4148 or devil_env_config_initialize.search(line)):
4149 errors.append("%s:%d" % (f.LocalPath(), line_num))
4150
4151 results = []
4152
4153 if errors:
4154 results.append(
4155 output_api.PresubmitError(
4156 'Devil initialization should always be done using '
4157 'devil_chromium.Initialize() in the chromium project, to use better '
4158 'defaults for dependencies (ex. up-to-date version of adb).',
4159 errors))
4160
4161 return results
4162
4163
4164def _MatchesFile(input_api, patterns, path):
Bruce Dawson40fece62022-09-16 19:58:314165 # Consistently use / as path separator to simplify the writing of regex
4166 # expressions.
4167 path = path.replace(input_api.os_path.sep, '/')
Sam Maiera6e76d72022-02-11 21:43:504168 for pattern in patterns:
4169 if input_api.re.search(pattern, path):
4170 return True
4171 return False
4172
4173
Daniel Chenga37c03db2022-05-12 17:20:344174def _ChangeHasSecurityReviewer(input_api, owners_file):
4175 """Returns True iff the CL has a reviewer from SECURITY_OWNERS.
Sam Maiera6e76d72022-02-11 21:43:504176
Daniel Chenga37c03db2022-05-12 17:20:344177 Args:
4178 input_api: The presubmit input API.
4179 owners_file: OWNERS file with required reviewers. Typically, this is
4180 something like ipc/SECURITY_OWNERS.
4181
4182 Note: if the presubmit is running for commit rather than for upload, this
4183 only returns True if a security reviewer has also approved the CL.
Sam Maiera6e76d72022-02-11 21:43:504184 """
Daniel Chengd88244472022-05-16 09:08:474185 # Owners-Override should bypass all additional OWNERS enforcement checks.
4186 # A CR+1 vote will still be required to land this change.
4187 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
4188 input_api.change.issue)):
4189 return True
4190
Daniel Chenga37c03db2022-05-12 17:20:344191 owner_email, reviewers = (
4192 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
Daniel Cheng3008dc12022-05-13 04:02:114193 input_api,
4194 None,
4195 approval_needed=input_api.is_committing and not input_api.dry_run))
Sam Maiera6e76d72022-02-11 21:43:504196
Daniel Chenga37c03db2022-05-12 17:20:344197 security_owners = input_api.owners_client.ListOwners(owners_file)
4198 return any(owner in reviewers for owner in security_owners)
Sam Maiera6e76d72022-02-11 21:43:504199
Daniel Chenga37c03db2022-05-12 17:20:344200
4201@dataclass
Daniel Cheng171dad8d2022-05-21 00:40:254202class _SecurityProblemWithItems:
4203 problem: str
4204 items: Sequence[str]
4205
4206
4207@dataclass
Daniel Chenga37c03db2022-05-12 17:20:344208class _MissingSecurityOwnersResult:
Daniel Cheng171dad8d2022-05-21 00:40:254209 owners_file_problems: Sequence[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:344210 has_security_sensitive_files: bool
Daniel Cheng171dad8d2022-05-21 00:40:254211 missing_reviewer_problem: Optional[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:344212
4213
4214def _FindMissingSecurityOwners(input_api,
4215 output_api,
4216 file_patterns: Sequence[str],
4217 excluded_patterns: Sequence[str],
4218 required_owners_file: str,
4219 custom_rule_function: Optional[Callable] = None
4220 ) -> _MissingSecurityOwnersResult:
4221 """Find OWNERS files missing per-file rules for security-sensitive files.
4222
4223 Args:
4224 input_api: the PRESUBMIT input API object.
4225 output_api: the PRESUBMIT output API object.
4226 file_patterns: basename patterns that require a corresponding per-file
4227 security restriction.
4228 excluded_patterns: path patterns that should be exempted from
4229 requiring a security restriction.
4230 required_owners_file: path to the required OWNERS file, e.g.
4231 ipc/SECURITY_OWNERS
4232 cc_alias: If not None, email that will be CCed automatically if the
4233 change contains security-sensitive files, as determined by
4234 `file_patterns` and `excluded_patterns`.
4235 custom_rule_function: If not None, will be called with `input_api` and
4236 the current file under consideration. Returning True will add an
4237 exact match per-file rule check for the current file.
4238 """
4239
4240 # `to_check` is a mapping of an OWNERS file path to Patterns.
4241 #
4242 # Patterns is a dictionary mapping glob patterns (suitable for use in
4243 # per-file rules) to a PatternEntry.
4244 #
Sam Maiera6e76d72022-02-11 21:43:504245 # PatternEntry is a dictionary with two keys:
4246 # - 'files': the files that are matched by this pattern
4247 # - 'rules': the per-file rules needed for this pattern
Daniel Chenga37c03db2022-05-12 17:20:344248 #
Sam Maiera6e76d72022-02-11 21:43:504249 # For example, if we expect OWNERS file to contain rules for *.mojom and
4250 # *_struct_traits*.*, Patterns might look like this:
4251 # {
4252 # '*.mojom': {
4253 # 'files': ...,
4254 # 'rules': [
4255 # 'per-file *.mojom=set noparent',
4256 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
4257 # ],
4258 # },
4259 # '*_struct_traits*.*': {
4260 # 'files': ...,
4261 # 'rules': [
4262 # 'per-file *_struct_traits*.*=set noparent',
4263 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
4264 # ],
4265 # },
4266 # }
4267 to_check = {}
Daniel Chenga37c03db2022-05-12 17:20:344268 files_to_review = []
Sam Maiera6e76d72022-02-11 21:43:504269
Daniel Chenga37c03db2022-05-12 17:20:344270 def AddPatternToCheck(file, pattern):
Sam Maiera6e76d72022-02-11 21:43:504271 owners_file = input_api.os_path.join(
Daniel Chengd88244472022-05-16 09:08:474272 input_api.os_path.dirname(file.LocalPath()), 'OWNERS')
Sam Maiera6e76d72022-02-11 21:43:504273 if owners_file not in to_check:
4274 to_check[owners_file] = {}
4275 if pattern not in to_check[owners_file]:
4276 to_check[owners_file][pattern] = {
4277 'files': [],
4278 'rules': [
Daniel Chenga37c03db2022-05-12 17:20:344279 f'per-file {pattern}=set noparent',
4280 f'per-file {pattern}=file://{required_owners_file}',
Sam Maiera6e76d72022-02-11 21:43:504281 ]
4282 }
Daniel Chenged57a162022-05-25 02:56:344283 to_check[owners_file][pattern]['files'].append(file.LocalPath())
Daniel Chenga37c03db2022-05-12 17:20:344284 files_to_review.append(file.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:504285
Daniel Chenga37c03db2022-05-12 17:20:344286 # Only enforce security OWNERS rules for a directory if that directory has a
4287 # file that matches `file_patterns`. For example, if a directory only
4288 # contains *.mojom files and no *_messages*.h files, the check should only
4289 # ensure that rules for *.mojom files are present.
4290 for file in input_api.AffectedFiles(include_deletes=False):
4291 file_basename = input_api.os_path.basename(file.LocalPath())
4292 if custom_rule_function is not None and custom_rule_function(
4293 input_api, file):
4294 AddPatternToCheck(file, file_basename)
4295 continue
Sam Maiera6e76d72022-02-11 21:43:504296
Daniel Chenga37c03db2022-05-12 17:20:344297 if any(
4298 input_api.fnmatch.fnmatch(file.LocalPath(), pattern)
4299 for pattern in excluded_patterns):
Sam Maiera6e76d72022-02-11 21:43:504300 continue
4301
4302 for pattern in file_patterns:
Daniel Chenga37c03db2022-05-12 17:20:344303 # Unlike `excluded_patterns`, `file_patterns` is checked only against the
4304 # file's basename.
4305 if input_api.fnmatch.fnmatch(file_basename, pattern):
4306 AddPatternToCheck(file, pattern)
Sam Maiera6e76d72022-02-11 21:43:504307 break
4308
Daniel Chenga37c03db2022-05-12 17:20:344309 has_security_sensitive_files = bool(to_check)
Daniel Cheng171dad8d2022-05-21 00:40:254310
4311 # Check if any newly added lines in OWNERS files intersect with required
4312 # per-file OWNERS lines. If so, ensure that a security reviewer is included.
4313 # This is a hack, but is needed because the OWNERS check (by design) ignores
4314 # new OWNERS entries; otherwise, a non-owner could add someone as a new
4315 # OWNER and have that newly-added OWNER self-approve their own addition.
4316 newly_covered_files = []
4317 for file in input_api.AffectedFiles(include_deletes=False):
4318 if not file.LocalPath() in to_check:
4319 continue
4320 for _, line in file.ChangedContents():
4321 for _, entry in to_check[file.LocalPath()].items():
4322 if line in entry['rules']:
4323 newly_covered_files.extend(entry['files'])
4324
4325 missing_reviewer_problems = None
4326 if newly_covered_files and not _ChangeHasSecurityReviewer(
Daniel Chenga37c03db2022-05-12 17:20:344327 input_api, required_owners_file):
Daniel Cheng171dad8d2022-05-21 00:40:254328 missing_reviewer_problems = _SecurityProblemWithItems(
4329 f'Review from an owner in {required_owners_file} is required for '
4330 'the following newly-added files:',
4331 [f'{file}' for file in sorted(set(newly_covered_files))])
Sam Maiera6e76d72022-02-11 21:43:504332
4333 # Go through the OWNERS files to check, filtering out rules that are already
4334 # present in that OWNERS file.
4335 for owners_file, patterns in to_check.items():
4336 try:
Daniel Cheng171dad8d2022-05-21 00:40:254337 lines = set(
4338 input_api.ReadFile(
4339 input_api.os_path.join(input_api.change.RepositoryRoot(),
4340 owners_file)).splitlines())
4341 for entry in patterns.values():
4342 entry['rules'] = [
4343 rule for rule in entry['rules'] if rule not in lines
4344 ]
Sam Maiera6e76d72022-02-11 21:43:504345 except IOError:
4346 # No OWNERS file, so all the rules are definitely missing.
4347 continue
4348
4349 # All the remaining lines weren't found in OWNERS files, so emit an error.
Daniel Cheng171dad8d2022-05-21 00:40:254350 owners_file_problems = []
Daniel Chenga37c03db2022-05-12 17:20:344351
Sam Maiera6e76d72022-02-11 21:43:504352 for owners_file, patterns in to_check.items():
4353 missing_lines = []
4354 files = []
4355 for _, entry in patterns.items():
Daniel Chenged57a162022-05-25 02:56:344356 files.extend(entry['files'])
Sam Maiera6e76d72022-02-11 21:43:504357 missing_lines.extend(entry['rules'])
Sam Maiera6e76d72022-02-11 21:43:504358 if missing_lines:
Daniel Cheng171dad8d2022-05-21 00:40:254359 joined_missing_lines = '\n'.join(line for line in missing_lines)
4360 owners_file_problems.append(
4361 _SecurityProblemWithItems(
4362 'Found missing OWNERS lines for security-sensitive files. '
4363 f'Please add the following lines to {owners_file}:\n'
4364 f'{joined_missing_lines}\n\nTo ensure security review for:',
4365 files))
Daniel Chenga37c03db2022-05-12 17:20:344366
Daniel Cheng171dad8d2022-05-21 00:40:254367 return _MissingSecurityOwnersResult(owners_file_problems,
Daniel Chenga37c03db2022-05-12 17:20:344368 has_security_sensitive_files,
Daniel Cheng171dad8d2022-05-21 00:40:254369 missing_reviewer_problems)
Daniel Chenga37c03db2022-05-12 17:20:344370
4371
4372def _CheckChangeForIpcSecurityOwners(input_api, output_api):
4373 # Whether or not a file affects IPC is (mostly) determined by a simple list
4374 # of filename patterns.
4375 file_patterns = [
4376 # Legacy IPC:
4377 '*_messages.cc',
4378 '*_messages*.h',
4379 '*_param_traits*.*',
4380 # Mojo IPC:
4381 '*.mojom',
4382 '*_mojom_traits*.*',
4383 '*_type_converter*.*',
4384 # Android native IPC:
4385 '*.aidl',
4386 ]
4387
Daniel Chenga37c03db2022-05-12 17:20:344388 excluded_patterns = [
Daniel Cheng518943f2022-05-12 22:15:464389 # These third_party directories do not contain IPCs, but contain files
4390 # matching the above patterns, which trigger false positives.
Daniel Chenga37c03db2022-05-12 17:20:344391 'third_party/crashpad/*',
4392 'third_party/blink/renderer/platform/bindings/*',
4393 'third_party/protobuf/benchmarks/python/*',
4394 'third_party/win_build_output/*',
Daniel Chengd88244472022-05-16 09:08:474395 # Enum-only mojoms used for web metrics, so no security review needed.
4396 'third_party/blink/public/mojom/use_counter/metrics/*',
Daniel Chenga37c03db2022-05-12 17:20:344397 # These files are just used to communicate between class loaders running
4398 # in the same process.
4399 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
4400 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
4401 ]
4402
4403 def IsMojoServiceManifestFile(input_api, file):
4404 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
4405 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
4406 if not manifest_pattern.search(file.LocalPath()):
4407 return False
4408
4409 if test_manifest_pattern.search(file.LocalPath()):
4410 return False
4411
4412 # All actual service manifest files should contain at least one
4413 # qualified reference to service_manager::Manifest.
4414 return any('service_manager::Manifest' in line
4415 for line in file.NewContents())
4416
4417 return _FindMissingSecurityOwners(
4418 input_api,
4419 output_api,
4420 file_patterns,
4421 excluded_patterns,
4422 'ipc/SECURITY_OWNERS',
4423 custom_rule_function=IsMojoServiceManifestFile)
4424
4425
4426def _CheckChangeForFuchsiaSecurityOwners(input_api, output_api):
4427 file_patterns = [
4428 # Component specifications.
4429 '*.cml', # Component Framework v2.
4430 '*.cmx', # Component Framework v1.
4431
4432 # Fuchsia IDL protocol specifications.
4433 '*.fidl',
4434 ]
4435
4436 # Don't check for owners files for changes in these directories.
4437 excluded_patterns = [
4438 'third_party/crashpad/*',
4439 ]
4440
4441 return _FindMissingSecurityOwners(input_api, output_api, file_patterns,
4442 excluded_patterns,
4443 'build/fuchsia/SECURITY_OWNERS')
4444
4445
4446def CheckSecurityOwners(input_api, output_api):
4447 """Checks that various security-sensitive files have an IPC OWNERS rule."""
4448 ipc_results = _CheckChangeForIpcSecurityOwners(input_api, output_api)
4449 fuchsia_results = _CheckChangeForFuchsiaSecurityOwners(
4450 input_api, output_api)
4451
4452 if ipc_results.has_security_sensitive_files:
4453 output_api.AppendCC('[email protected]')
Sam Maiera6e76d72022-02-11 21:43:504454
4455 results = []
Daniel Chenga37c03db2022-05-12 17:20:344456
Daniel Cheng171dad8d2022-05-21 00:40:254457 missing_reviewer_problems = []
4458 if ipc_results.missing_reviewer_problem:
4459 missing_reviewer_problems.append(ipc_results.missing_reviewer_problem)
4460 if fuchsia_results.missing_reviewer_problem:
4461 missing_reviewer_problems.append(
4462 fuchsia_results.missing_reviewer_problem)
Daniel Chenga37c03db2022-05-12 17:20:344463
Daniel Cheng171dad8d2022-05-21 00:40:254464 # Missing reviewers are an error unless there's no issue number
4465 # associated with this branch; in that case, the presubmit is being run
4466 # with --all or --files.
4467 #
4468 # Note that upload should never be an error; otherwise, it would be
4469 # impossible to upload changes at all.
4470 if input_api.is_committing and input_api.change.issue:
4471 make_presubmit_message = output_api.PresubmitError
4472 else:
4473 make_presubmit_message = output_api.PresubmitNotifyResult
4474 for problem in missing_reviewer_problems:
Sam Maiera6e76d72022-02-11 21:43:504475 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:254476 make_presubmit_message(problem.problem, items=problem.items))
Daniel Chenga37c03db2022-05-12 17:20:344477
Daniel Cheng171dad8d2022-05-21 00:40:254478 owners_file_problems = []
4479 owners_file_problems.extend(ipc_results.owners_file_problems)
4480 owners_file_problems.extend(fuchsia_results.owners_file_problems)
Daniel Chenga37c03db2022-05-12 17:20:344481
Daniel Cheng171dad8d2022-05-21 00:40:254482 for problem in owners_file_problems:
Daniel Cheng3008dc12022-05-13 04:02:114483 # Missing per-file rules are always an error. While swarming and caching
4484 # means that uploading a patchset with updated OWNERS files and sending
4485 # it to the CQ again should not have a large incremental cost, it is
4486 # still frustrating to discover the error only after the change has
4487 # already been uploaded.
Daniel Chenga37c03db2022-05-12 17:20:344488 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:254489 output_api.PresubmitError(problem.problem, items=problem.items))
Sam Maiera6e76d72022-02-11 21:43:504490
4491 return results
4492
4493
4494def _GetFilesUsingSecurityCriticalFunctions(input_api):
4495 """Checks affected files for changes to security-critical calls. This
4496 function checks the full change diff, to catch both additions/changes
4497 and removals.
4498
4499 Returns a dict keyed by file name, and the value is a set of detected
4500 functions.
4501 """
4502 # Map of function pretty name (displayed in an error) to the pattern to
4503 # match it with.
4504 _PATTERNS_TO_CHECK = {
4505 'content::GetServiceSandboxType<>()': 'GetServiceSandboxType\\<'
4506 }
4507 _PATTERNS_TO_CHECK = {
4508 k: input_api.re.compile(v)
4509 for k, v in _PATTERNS_TO_CHECK.items()
4510 }
4511
Sam Maiera6e76d72022-02-11 21:43:504512 # We don't want to trigger on strings within this file.
4513 def presubmit_file_filter(f):
Daniel Chenga37c03db2022-05-12 17:20:344514 return 'PRESUBMIT.py' != input_api.os_path.split(f.LocalPath())[1]
Sam Maiera6e76d72022-02-11 21:43:504515
4516 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
4517 files_to_functions = {}
4518 for f in input_api.AffectedFiles(file_filter=presubmit_file_filter):
4519 diff = f.GenerateScmDiff()
4520 for line in diff.split('\n'):
4521 # Not using just RightHandSideLines() because removing a
4522 # call to a security-critical function can be just as important
4523 # as adding or changing the arguments.
4524 if line.startswith('-') or (line.startswith('+')
4525 and not line.startswith('++')):
4526 for name, pattern in _PATTERNS_TO_CHECK.items():
4527 if pattern.search(line):
4528 path = f.LocalPath()
4529 if not path in files_to_functions:
4530 files_to_functions[path] = set()
4531 files_to_functions[path].add(name)
4532 return files_to_functions
4533
4534
4535def CheckSecurityChanges(input_api, output_api):
4536 """Checks that changes involving security-critical functions are reviewed
4537 by the security team.
4538 """
4539 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
4540 if not len(files_to_functions):
4541 return []
4542
Sam Maiera6e76d72022-02-11 21:43:504543 owners_file = 'ipc/SECURITY_OWNERS'
Daniel Chenga37c03db2022-05-12 17:20:344544 if _ChangeHasSecurityReviewer(input_api, owners_file):
Sam Maiera6e76d72022-02-11 21:43:504545 return []
4546
Daniel Chenga37c03db2022-05-12 17:20:344547 msg = 'The following files change calls to security-sensitive functions\n' \
Sam Maiera6e76d72022-02-11 21:43:504548 'that need to be reviewed by {}.\n'.format(owners_file)
4549 for path, names in files_to_functions.items():
4550 msg += ' {}\n'.format(path)
4551 for name in names:
4552 msg += ' {}\n'.format(name)
4553 msg += '\n'
4554
4555 if input_api.is_committing:
4556 output = output_api.PresubmitError
Mohamed Heikale217fc852020-07-06 19:44:034557 else:
Sam Maiera6e76d72022-02-11 21:43:504558 output = output_api.PresubmitNotifyResult
4559 return [output(msg)]
4560
4561
4562def CheckSetNoParent(input_api, output_api):
4563 """Checks that set noparent is only used together with an OWNERS file in
4564 //build/OWNERS.setnoparent (see also
4565 //docs/code_reviews.md#owners-files-details)
4566 """
4567 # Return early if no OWNERS files were modified.
4568 if not any(f.LocalPath().endswith('OWNERS')
4569 for f in input_api.AffectedFiles(include_deletes=False)):
4570 return []
4571
4572 errors = []
4573
4574 allowed_owners_files_file = 'build/OWNERS.setnoparent'
4575 allowed_owners_files = set()
Bruce Dawson58a45d22023-02-27 11:24:164576 with open(allowed_owners_files_file, 'r', encoding='utf-8') as f:
Sam Maiera6e76d72022-02-11 21:43:504577 for line in f:
4578 line = line.strip()
4579 if not line or line.startswith('#'):
4580 continue
4581 allowed_owners_files.add(line)
4582
4583 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
4584
4585 for f in input_api.AffectedFiles(include_deletes=False):
4586 if not f.LocalPath().endswith('OWNERS'):
4587 continue
4588
4589 found_owners_files = set()
4590 found_set_noparent_lines = dict()
4591
4592 # Parse the OWNERS file.
4593 for lineno, line in enumerate(f.NewContents(), 1):
4594 line = line.strip()
4595 if line.startswith('set noparent'):
4596 found_set_noparent_lines[''] = lineno
4597 if line.startswith('file://'):
4598 if line in allowed_owners_files:
4599 found_owners_files.add('')
4600 if line.startswith('per-file'):
4601 match = per_file_pattern.match(line)
4602 if match:
4603 glob = match.group(1).strip()
4604 directive = match.group(2).strip()
4605 if directive == 'set noparent':
4606 found_set_noparent_lines[glob] = lineno
4607 if directive.startswith('file://'):
4608 if directive in allowed_owners_files:
4609 found_owners_files.add(glob)
4610
4611 # Check that every set noparent line has a corresponding file:// line
4612 # listed in build/OWNERS.setnoparent. An exception is made for top level
4613 # directories since src/OWNERS shouldn't review them.
Bruce Dawson6bb0d672022-04-06 15:13:494614 linux_path = f.LocalPath().replace(input_api.os_path.sep, '/')
4615 if (linux_path.count('/') != 1
4616 and (not linux_path in _EXCLUDED_SET_NO_PARENT_PATHS)):
Sam Maiera6e76d72022-02-11 21:43:504617 for set_noparent_line in found_set_noparent_lines:
4618 if set_noparent_line in found_owners_files:
4619 continue
4620 errors.append(' %s:%d' %
Bruce Dawson6bb0d672022-04-06 15:13:494621 (linux_path,
Sam Maiera6e76d72022-02-11 21:43:504622 found_set_noparent_lines[set_noparent_line]))
4623
4624 results = []
4625 if errors:
4626 if input_api.is_committing:
4627 output = output_api.PresubmitError
4628 else:
4629 output = output_api.PresubmitPromptWarning
4630 results.append(
4631 output(
4632 'Found the following "set noparent" restrictions in OWNERS files that '
4633 'do not include owners from build/OWNERS.setnoparent:',
4634 long_text='\n\n'.join(errors)))
4635 return results
4636
4637
4638def CheckUselessForwardDeclarations(input_api, output_api):
4639 """Checks that added or removed lines in non third party affected
4640 header files do not lead to new useless class or struct forward
4641 declaration.
4642 """
4643 results = []
4644 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
4645 input_api.re.MULTILINE)
4646 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
4647 input_api.re.MULTILINE)
4648 for f in input_api.AffectedFiles(include_deletes=False):
4649 if (f.LocalPath().startswith('third_party')
4650 and not f.LocalPath().startswith('third_party/blink')
4651 and not f.LocalPath().startswith('third_party\\blink')):
4652 continue
4653
4654 if not f.LocalPath().endswith('.h'):
4655 continue
4656
4657 contents = input_api.ReadFile(f)
4658 fwd_decls = input_api.re.findall(class_pattern, contents)
4659 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
4660
4661 useless_fwd_decls = []
4662 for decl in fwd_decls:
4663 count = sum(1 for _ in input_api.re.finditer(
4664 r'\b%s\b' % input_api.re.escape(decl), contents))
4665 if count == 1:
4666 useless_fwd_decls.append(decl)
4667
4668 if not useless_fwd_decls:
4669 continue
4670
4671 for line in f.GenerateScmDiff().splitlines():
4672 if (line.startswith('-') and not line.startswith('--')
4673 or line.startswith('+') and not line.startswith('++')):
4674 for decl in useless_fwd_decls:
4675 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
4676 results.append(
4677 output_api.PresubmitPromptWarning(
4678 '%s: %s forward declaration is no longer needed'
4679 % (f.LocalPath(), decl)))
4680 useless_fwd_decls.remove(decl)
4681
4682 return results
4683
4684
4685def _CheckAndroidDebuggableBuild(input_api, output_api):
4686 """Checks that code uses BuildInfo.isDebugAndroid() instead of
4687 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
4688 this is a debuggable build of Android.
4689 """
4690 build_type_check_pattern = input_api.re.compile(
4691 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
4692
4693 errors = []
4694
4695 sources = lambda affected_file: input_api.FilterSourceFile(
4696 affected_file,
4697 files_to_skip=(
4698 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4699 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314700 r"^android_webview/support_library/boundary_interfaces/",
4701 r"^chrome/android/webapk/.*",
4702 r'^third_party/.*',
4703 r"tools/android/customtabs_benchmark/.*",
4704 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504705 )),
4706 files_to_check=[r'.*\.java$'])
4707
4708 for f in input_api.AffectedSourceFiles(sources):
4709 for line_num, line in f.ChangedContents():
4710 if build_type_check_pattern.search(line):
4711 errors.append("%s:%d" % (f.LocalPath(), line_num))
4712
4713 results = []
4714
4715 if errors:
4716 results.append(
4717 output_api.PresubmitPromptWarning(
4718 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
4719 ' Please use BuildInfo.isDebugAndroid() instead.', errors))
4720
4721 return results
4722
4723# TODO: add unit tests
4724def _CheckAndroidToastUsage(input_api, output_api):
4725 """Checks that code uses org.chromium.ui.widget.Toast instead of
4726 android.widget.Toast (Chromium Toast doesn't force hardware
4727 acceleration on low-end devices, saving memory).
4728 """
4729 toast_import_pattern = input_api.re.compile(
4730 r'^import android\.widget\.Toast;$')
4731
4732 errors = []
4733
4734 sources = lambda affected_file: input_api.FilterSourceFile(
4735 affected_file,
4736 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
Bruce Dawson40fece62022-09-16 19:58:314737 DEFAULT_FILES_TO_SKIP + (r'^chromecast/.*',
4738 r'^remoting/.*')),
Sam Maiera6e76d72022-02-11 21:43:504739 files_to_check=[r'.*\.java$'])
4740
4741 for f in input_api.AffectedSourceFiles(sources):
4742 for line_num, line in f.ChangedContents():
4743 if toast_import_pattern.search(line):
4744 errors.append("%s:%d" % (f.LocalPath(), line_num))
4745
4746 results = []
4747
4748 if errors:
4749 results.append(
4750 output_api.PresubmitError(
4751 'android.widget.Toast usage is detected. Android toasts use hardware'
4752 ' acceleration, and can be\ncostly on low-end devices. Please use'
4753 ' org.chromium.ui.widget.Toast instead.\n'
4754 'Contact [email protected] if you have any questions.',
4755 errors))
4756
4757 return results
4758
4759
4760def _CheckAndroidCrLogUsage(input_api, output_api):
4761 """Checks that new logs using org.chromium.base.Log:
4762 - Are using 'TAG' as variable name for the tags (warn)
4763 - Are using a tag that is shorter than 20 characters (error)
4764 """
4765
4766 # Do not check format of logs in the given files
4767 cr_log_check_excluded_paths = [
4768 # //chrome/android/webapk cannot depend on //base
Bruce Dawson40fece62022-09-16 19:58:314769 r"^chrome/android/webapk/.*",
Sam Maiera6e76d72022-02-11 21:43:504770 # WebView license viewer code cannot depend on //base; used in stub APK.
Bruce Dawson40fece62022-09-16 19:58:314771 r"^android_webview/glue/java/src/com/android/"
4772 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504773 # The customtabs_benchmark is a small app that does not depend on Chromium
4774 # java pieces.
Bruce Dawson40fece62022-09-16 19:58:314775 r"tools/android/customtabs_benchmark/.*",
Sam Maiera6e76d72022-02-11 21:43:504776 ]
4777
4778 cr_log_import_pattern = input_api.re.compile(
4779 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
4780 class_in_base_pattern = input_api.re.compile(
4781 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
4782 has_some_log_import_pattern = input_api.re.compile(r'^import .*\.Log;$',
4783 input_api.re.MULTILINE)
4784 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
4785 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
4786 log_decl_pattern = input_api.re.compile(
4787 r'static final String TAG = "(?P<name>(.*))"')
4788 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
4789
4790 REF_MSG = ('See docs/android_logging.md for more info.')
4791 sources = lambda x: input_api.FilterSourceFile(
4792 x,
4793 files_to_check=[r'.*\.java$'],
4794 files_to_skip=cr_log_check_excluded_paths)
4795
4796 tag_decl_errors = []
Andrew Grieved3a35d82024-01-02 21:24:384797 tag_length_errors = []
Sam Maiera6e76d72022-02-11 21:43:504798 tag_errors = []
4799 tag_with_dot_errors = []
4800 util_log_errors = []
4801
4802 for f in input_api.AffectedSourceFiles(sources):
4803 file_content = input_api.ReadFile(f)
4804 has_modified_logs = False
4805 # Per line checks
4806 if (cr_log_import_pattern.search(file_content)
4807 or (class_in_base_pattern.search(file_content)
4808 and not has_some_log_import_pattern.search(file_content))):
4809 # Checks to run for files using cr log
4810 for line_num, line in f.ChangedContents():
4811 if rough_log_decl_pattern.search(line):
4812 has_modified_logs = True
4813
4814 # Check if the new line is doing some logging
4815 match = log_call_pattern.search(line)
4816 if match:
4817 has_modified_logs = True
4818
4819 # Make sure it uses "TAG"
4820 if not match.group('tag') == 'TAG':
4821 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
4822 else:
4823 # Report non cr Log function calls in changed lines
4824 for line_num, line in f.ChangedContents():
4825 if log_call_pattern.search(line):
4826 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
4827
4828 # Per file checks
4829 if has_modified_logs:
4830 # Make sure the tag is using the "cr" prefix and is not too long
4831 match = log_decl_pattern.search(file_content)
4832 tag_name = match.group('name') if match else None
4833 if not tag_name:
4834 tag_decl_errors.append(f.LocalPath())
Andrew Grieved3a35d82024-01-02 21:24:384835 elif len(tag_name) > 20:
4836 tag_length_errors.append(f.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:504837 elif '.' in tag_name:
4838 tag_with_dot_errors.append(f.LocalPath())
4839
4840 results = []
4841 if tag_decl_errors:
4842 results.append(
4843 output_api.PresubmitPromptWarning(
4844 'Please define your tags using the suggested format: .\n'
4845 '"private static final String TAG = "<package tag>".\n'
4846 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
4847 tag_decl_errors))
4848
Andrew Grieved3a35d82024-01-02 21:24:384849 if tag_length_errors:
4850 results.append(
4851 output_api.PresubmitError(
4852 'The tag length is restricted by the system to be at most '
4853 '20 characters.\n' + REF_MSG, tag_length_errors))
4854
Sam Maiera6e76d72022-02-11 21:43:504855 if tag_errors:
4856 results.append(
4857 output_api.PresubmitPromptWarning(
4858 'Please use a variable named "TAG" for your log tags.\n' +
4859 REF_MSG, tag_errors))
4860
4861 if util_log_errors:
4862 results.append(
4863 output_api.PresubmitPromptWarning(
4864 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
4865 util_log_errors))
4866
4867 if tag_with_dot_errors:
4868 results.append(
4869 output_api.PresubmitPromptWarning(
4870 'Dot in log tags cause them to be elided in crash reports.\n' +
4871 REF_MSG, tag_with_dot_errors))
4872
4873 return results
4874
4875
Sam Maiera6e76d72022-02-11 21:43:504876def _CheckAndroidTestAnnotationUsage(input_api, output_api):
4877 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
4878 deprecated_annotation_import_pattern = input_api.re.compile(
4879 r'^import android\.test\.suitebuilder\.annotation\..*;',
4880 input_api.re.MULTILINE)
4881 sources = lambda x: input_api.FilterSourceFile(
4882 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
4883 errors = []
4884 for f in input_api.AffectedFiles(file_filter=sources):
4885 for line_num, line in f.ChangedContents():
4886 if deprecated_annotation_import_pattern.search(line):
4887 errors.append("%s:%d" % (f.LocalPath(), line_num))
4888
4889 results = []
4890 if errors:
4891 results.append(
4892 output_api.PresubmitError(
4893 'Annotations in android.test.suitebuilder.annotation have been'
Mohamed Heikal3d7a94c2023-03-28 16:55:244894 ' deprecated since API level 24. Please use androidx.test.filters'
4895 ' from //third_party/androidx:androidx_test_runner_java instead.'
Sam Maiera6e76d72022-02-11 21:43:504896 ' Contact [email protected] if you have any questions.',
4897 errors))
4898 return results
4899
4900
4901def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
4902 """Checks if MDPI assets are placed in a correct directory."""
Bruce Dawson6c05e852022-07-21 15:48:514903 file_filter = lambda f: (f.LocalPath().endswith(
4904 '.png') and ('/res/drawable/'.replace('/', input_api.os_path.sep) in f.
4905 LocalPath() or '/res/drawable-ldrtl/'.replace(
4906 '/', input_api.os_path.sep) in f.LocalPath()))
Sam Maiera6e76d72022-02-11 21:43:504907 errors = []
4908 for f in input_api.AffectedFiles(include_deletes=False,
4909 file_filter=file_filter):
4910 errors.append(' %s' % f.LocalPath())
4911
4912 results = []
4913 if errors:
4914 results.append(
4915 output_api.PresubmitError(
4916 'MDPI assets should be placed in /res/drawable-mdpi/ or '
4917 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
4918 '/res/drawable-ldrtl/.\n'
4919 'Contact [email protected] if you have questions.', errors))
4920 return results
4921
4922
4923def _CheckAndroidWebkitImports(input_api, output_api):
4924 """Checks that code uses org.chromium.base.Callback instead of
4925 android.webview.ValueCallback except in the WebView glue layer
4926 and WebLayer.
4927 """
4928 valuecallback_import_pattern = input_api.re.compile(
4929 r'^import android\.webkit\.ValueCallback;$')
4930
4931 errors = []
4932
4933 sources = lambda affected_file: input_api.FilterSourceFile(
4934 affected_file,
4935 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4936 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314937 r'^android_webview/glue/.*',
elabadysayedcbbaea72024-08-01 16:10:424938 r'^android_webview/support_library/.*',
Bruce Dawson40fece62022-09-16 19:58:314939 r'^weblayer/.*',
Sam Maiera6e76d72022-02-11 21:43:504940 )),
4941 files_to_check=[r'.*\.java$'])
4942
4943 for f in input_api.AffectedSourceFiles(sources):
4944 for line_num, line in f.ChangedContents():
4945 if valuecallback_import_pattern.search(line):
4946 errors.append("%s:%d" % (f.LocalPath(), line_num))
4947
4948 results = []
4949
4950 if errors:
4951 results.append(
4952 output_api.PresubmitError(
4953 'android.webkit.ValueCallback usage is detected outside of the glue'
4954 ' layer. To stay compatible with the support library, android.webkit.*'
4955 ' classes should only be used inside the glue layer and'
4956 ' org.chromium.base.Callback should be used instead.', errors))
4957
4958 return results
4959
4960
4961def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
4962 """Checks Android XML styles """
4963
4964 # Return early if no relevant files were modified.
4965 if not any(
4966 _IsXmlOrGrdFile(input_api, f.LocalPath())
4967 for f in input_api.AffectedFiles(include_deletes=False)):
4968 return []
4969
4970 import sys
4971 original_sys_path = sys.path
4972 try:
4973 sys.path = sys.path + [
4974 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4975 'android', 'checkxmlstyle')
4976 ]
4977 import checkxmlstyle
4978 finally:
4979 # Restore sys.path to what it was before.
4980 sys.path = original_sys_path
4981
4982 if is_check_on_upload:
4983 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
4984 else:
4985 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
4986
4987
4988def _CheckAndroidInfoBarDeprecation(input_api, output_api):
4989 """Checks Android Infobar Deprecation """
4990
4991 import sys
4992 original_sys_path = sys.path
4993 try:
4994 sys.path = sys.path + [
4995 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4996 'android', 'infobar_deprecation')
4997 ]
4998 import infobar_deprecation
4999 finally:
5000 # Restore sys.path to what it was before.
5001 sys.path = original_sys_path
5002
5003 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
5004
5005
5006class _PydepsCheckerResult:
5007 def __init__(self, cmd, pydeps_path, process, old_contents):
5008 self._cmd = cmd
5009 self._pydeps_path = pydeps_path
5010 self._process = process
5011 self._old_contents = old_contents
5012
5013 def GetError(self):
5014 """Returns an error message, or None."""
5015 import difflib
Andrew Grieved27620b62023-07-13 16:35:075016 new_contents = self._process.stdout.read().splitlines()[2:]
Sam Maiera6e76d72022-02-11 21:43:505017 if self._process.wait() != 0:
5018 # STDERR should already be printed.
5019 return 'Command failed: ' + self._cmd
Sam Maiera6e76d72022-02-11 21:43:505020 if self._old_contents != new_contents:
5021 diff = '\n'.join(
5022 difflib.context_diff(self._old_contents, new_contents))
5023 return ('File is stale: {}\n'
5024 'Diff (apply to fix):\n'
5025 '{}\n'
5026 'To regenerate, run:\n\n'
5027 ' {}').format(self._pydeps_path, diff, self._cmd)
5028 return None
5029
5030
5031class PydepsChecker:
5032 def __init__(self, input_api, pydeps_files):
5033 self._file_cache = {}
5034 self._input_api = input_api
5035 self._pydeps_files = pydeps_files
5036
5037 def _LoadFile(self, path):
5038 """Returns the list of paths within a .pydeps file relative to //."""
5039 if path not in self._file_cache:
5040 with open(path, encoding='utf-8') as f:
5041 self._file_cache[path] = f.read()
5042 return self._file_cache[path]
5043
5044 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
Gao Shenga79ebd42022-08-08 17:25:595045 """Returns an iterable of paths within the .pydep, relativized to //."""
Sam Maiera6e76d72022-02-11 21:43:505046 pydeps_data = self._LoadFile(pydeps_path)
5047 uses_gn_paths = '--gn-paths' in pydeps_data
5048 entries = (l for l in pydeps_data.splitlines()
5049 if not l.startswith('#'))
5050 if uses_gn_paths:
5051 # Paths look like: //foo/bar/baz
5052 return (e[2:] for e in entries)
5053 else:
5054 # Paths look like: path/relative/to/file.pydeps
5055 os_path = self._input_api.os_path
5056 pydeps_dir = os_path.dirname(pydeps_path)
5057 return (os_path.normpath(os_path.join(pydeps_dir, e))
5058 for e in entries)
5059
5060 def _CreateFilesToPydepsMap(self):
5061 """Returns a map of local_path -> list_of_pydeps."""
5062 ret = {}
5063 for pydep_local_path in self._pydeps_files:
5064 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
5065 ret.setdefault(path, []).append(pydep_local_path)
5066 return ret
5067
5068 def ComputeAffectedPydeps(self):
5069 """Returns an iterable of .pydeps files that might need regenerating."""
5070 affected_pydeps = set()
5071 file_to_pydeps_map = None
5072 for f in self._input_api.AffectedFiles(include_deletes=True):
5073 local_path = f.LocalPath()
5074 # Changes to DEPS can lead to .pydeps changes if any .py files are in
5075 # subrepositories. We can't figure out which files change, so re-check
5076 # all files.
5077 # Changes to print_python_deps.py affect all .pydeps.
5078 if local_path in ('DEPS', 'PRESUBMIT.py'
5079 ) or local_path.endswith('print_python_deps.py'):
5080 return self._pydeps_files
5081 elif local_path.endswith('.pydeps'):
5082 if local_path in self._pydeps_files:
5083 affected_pydeps.add(local_path)
5084 elif local_path.endswith('.py'):
5085 if file_to_pydeps_map is None:
5086 file_to_pydeps_map = self._CreateFilesToPydepsMap()
5087 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
5088 return affected_pydeps
5089
5090 def DetermineIfStaleAsync(self, pydeps_path):
5091 """Runs print_python_deps.py to see if the files is stale."""
5092 import os
5093
5094 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
5095 if old_pydeps_data:
5096 cmd = old_pydeps_data[1][1:].strip()
5097 if '--output' not in cmd:
5098 cmd += ' --output ' + pydeps_path
5099 old_contents = old_pydeps_data[2:]
5100 else:
5101 # A default cmd that should work in most cases (as long as pydeps filename
5102 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
5103 # file is empty/new.
5104 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
5105 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
5106 old_contents = []
5107 env = dict(os.environ)
5108 env['PYTHONDONTWRITEBYTECODE'] = '1'
5109 process = self._input_api.subprocess.Popen(
5110 cmd + ' --output ""',
5111 shell=True,
5112 env=env,
5113 stdout=self._input_api.subprocess.PIPE,
5114 encoding='utf-8')
5115 return _PydepsCheckerResult(cmd, pydeps_path, process, old_contents)
agrievef32bcc72016-04-04 14:57:405116
5117
Tibor Goldschwendt360793f72019-06-25 18:23:495118def _ParseGclientArgs():
Sam Maiera6e76d72022-02-11 21:43:505119 args = {}
5120 with open('build/config/gclient_args.gni', 'r') as f:
5121 for line in f:
5122 line = line.strip()
5123 if not line or line.startswith('#'):
5124 continue
5125 attribute, value = line.split('=')
5126 args[attribute.strip()] = value.strip()
5127 return args
Tibor Goldschwendt360793f72019-06-25 18:23:495128
5129
Saagar Sanghavifceeaae2020-08-12 16:40:365130def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
Sam Maiera6e76d72022-02-11 21:43:505131 """Checks if a .pydeps file needs to be regenerated."""
5132 # This check is for Python dependency lists (.pydeps files), and involves
5133 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
5134 # doesn't work on Windows and Mac, so skip it on other platforms.
5135 if not input_api.platform.startswith('linux'):
5136 return []
Erik Staabc734cd7a2021-11-23 03:11:525137
Sam Maiera6e76d72022-02-11 21:43:505138 results = []
5139 # First, check for new / deleted .pydeps.
5140 for f in input_api.AffectedFiles(include_deletes=True):
5141 # Check whether we are running the presubmit check for a file in src.
Sam Maiera6e76d72022-02-11 21:43:505142 if f.LocalPath().endswith('.pydeps'):
Andrew Grieve713b89b2024-10-15 20:20:085143 # f.LocalPath is relative to repo (src, or internal repo).
5144 # os_path.exists is relative to src repo.
5145 # Therefore if os_path.exists is true, it means f.LocalPath is relative
5146 # to src and we can conclude that the pydeps is in src.
5147 exists = input_api.os_path.exists(f.LocalPath())
5148 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
5149 results.append(
5150 output_api.PresubmitError(
5151 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
5152 'remove %s' % f.LocalPath()))
5153 elif (f.Action() != 'D' and exists
5154 and f.LocalPath() not in _ALL_PYDEPS_FILES):
5155 results.append(
5156 output_api.PresubmitError(
5157 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
5158 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:405159
Sam Maiera6e76d72022-02-11 21:43:505160 if results:
5161 return results
5162
Gavin Mak23884402024-07-25 20:39:265163 try:
5164 parsed_args = _ParseGclientArgs()
5165 except FileNotFoundError:
5166 message = (
5167 'build/config/gclient_args.gni not found. Please make sure your '
5168 'workspace has been initialized with gclient sync.'
5169 )
5170 import sys
5171 original_sys_path = sys.path
5172 try:
5173 sys.path = sys.path + [
5174 input_api.os_path.join(input_api.PresubmitLocalPath(),
5175 'third_party', 'depot_tools')
5176 ]
5177 import gclient_utils
5178 if gclient_utils.IsEnvCog():
5179 # Users will always hit this when they run presubmits before cog
5180 # workspace initialization finishes. The check shouldn't fail in
5181 # this case. This is an unavoidable workaround that's needed for
5182 # good presubmit UX for cog.
5183 results.append(output_api.PresubmitPromptWarning(message))
5184 else:
5185 results.append(output_api.PresubmitError(message))
5186 return results
5187 finally:
5188 # Restore sys.path to what it was before.
5189 sys.path = original_sys_path
5190
5191 is_android = parsed_args.get('checkout_android', 'false') == 'true'
Sam Maiera6e76d72022-02-11 21:43:505192 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
5193 affected_pydeps = set(checker.ComputeAffectedPydeps())
5194 affected_android_pydeps = affected_pydeps.intersection(
5195 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
5196 if affected_android_pydeps and not is_android:
5197 results.append(
5198 output_api.PresubmitPromptOrNotify(
5199 'You have changed python files that may affect pydeps for android\n'
Gao Shenga79ebd42022-08-08 17:25:595200 'specific scripts. However, the relevant presubmit check cannot be\n'
Sam Maiera6e76d72022-02-11 21:43:505201 'run because you are not using an Android checkout. To validate that\n'
5202 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
5203 'use the android-internal-presubmit optional trybot.\n'
5204 'Possibly stale pydeps files:\n{}'.format(
5205 '\n'.join(affected_android_pydeps))))
5206
5207 all_pydeps = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
5208 pydeps_to_check = affected_pydeps.intersection(all_pydeps)
5209 # Process these concurrently, as each one takes 1-2 seconds.
5210 pydep_results = [checker.DetermineIfStaleAsync(p) for p in pydeps_to_check]
5211 for result in pydep_results:
5212 error_msg = result.GetError()
5213 if error_msg:
5214 results.append(output_api.PresubmitError(error_msg))
5215
agrievef32bcc72016-04-04 14:57:405216 return results
5217
agrievef32bcc72016-04-04 14:57:405218
Saagar Sanghavifceeaae2020-08-12 16:40:365219def CheckSingletonInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505220 """Checks to make sure no header files have |Singleton<|."""
5221
5222 def FileFilter(affected_file):
5223 # It's ok for base/memory/singleton.h to have |Singleton<|.
5224 files_to_skip = (_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
Bruce Dawson40fece62022-09-16 19:58:315225 (r"^base/memory/singleton\.h$",
5226 r"^net/quic/platform/impl/quic_singleton_impl\.h$"))
Sam Maiera6e76d72022-02-11 21:43:505227 return input_api.FilterSourceFile(affected_file,
5228 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:435229
Sam Maiera6e76d72022-02-11 21:43:505230 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
5231 files = []
5232 for f in input_api.AffectedSourceFiles(FileFilter):
5233 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx')
5234 or f.LocalPath().endswith('.hpp')
5235 or f.LocalPath().endswith('.inl')):
5236 contents = input_api.ReadFile(f)
5237 for line in contents.splitlines(False):
5238 if (not line.lstrip().startswith('//')
5239 and # Strip C++ comment.
5240 pattern.search(line)):
5241 files.append(f)
5242 break
glidere61efad2015-02-18 17:39:435243
Sam Maiera6e76d72022-02-11 21:43:505244 if files:
5245 return [
5246 output_api.PresubmitError(
5247 'Found base::Singleton<T> in the following header files.\n' +
5248 'Please move them to an appropriate source file so that the ' +
5249 'template gets instantiated in a single compilation unit.',
5250 files)
5251 ]
5252 return []
glidere61efad2015-02-18 17:39:435253
5254
[email protected]fd20b902014-05-09 02:14:535255_DEPRECATED_CSS = [
5256 # Values
5257 ( "-webkit-box", "flex" ),
5258 ( "-webkit-inline-box", "inline-flex" ),
5259 ( "-webkit-flex", "flex" ),
5260 ( "-webkit-inline-flex", "inline-flex" ),
5261 ( "-webkit-min-content", "min-content" ),
5262 ( "-webkit-max-content", "max-content" ),
5263
5264 # Properties
5265 ( "-webkit-background-clip", "background-clip" ),
5266 ( "-webkit-background-origin", "background-origin" ),
5267 ( "-webkit-background-size", "background-size" ),
5268 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:445269 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:535270
5271 # Functions
5272 ( "-webkit-gradient", "gradient" ),
5273 ( "-webkit-repeating-gradient", "repeating-gradient" ),
5274 ( "-webkit-linear-gradient", "linear-gradient" ),
5275 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
5276 ( "-webkit-radial-gradient", "radial-gradient" ),
5277 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
5278]
5279
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:205280
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:495281# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:365282def CheckNoDeprecatedCss(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505283 """ Make sure that we don't use deprecated CSS
5284 properties, functions or values. Our external
5285 documentation and iOS CSS for dom distiller
5286 (reader mode) are ignored by the hooks as it
5287 needs to be consumed by WebKit. """
5288 results = []
5289 file_inclusion_pattern = [r".+\.css$"]
5290 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
5291 input_api.DEFAULT_FILES_TO_SKIP +
5292 (r"^chrome/common/extensions/docs", r"^chrome/docs",
Teresa Mao1d910882024-04-26 21:06:255293 r"^native_client_sdk",
5294 # The NTP team prefers reserving -webkit-line-clamp for
5295 # ellipsis effect which can only be used with -webkit-box.
5296 r"ui/webui/resources/cr_components/most_visited/.*\.css$"))
Sam Maiera6e76d72022-02-11 21:43:505297 file_filter = lambda f: input_api.FilterSourceFile(
5298 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
5299 for fpath in input_api.AffectedFiles(file_filter=file_filter):
5300 for line_num, line in fpath.ChangedContents():
5301 for (deprecated_value, value) in _DEPRECATED_CSS:
5302 if deprecated_value in line:
5303 results.append(
5304 output_api.PresubmitError(
5305 "%s:%d: Use of deprecated CSS %s, use %s instead" %
5306 (fpath.LocalPath(), line_num, deprecated_value,
5307 value)))
5308 return results
[email protected]fd20b902014-05-09 02:14:535309
mohan.reddyf21db962014-10-16 12:26:475310
Saagar Sanghavifceeaae2020-08-12 16:40:365311def CheckForRelativeIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505312 bad_files = {}
5313 for f in input_api.AffectedFiles(include_deletes=False):
5314 if (f.LocalPath().startswith('third_party')
5315 and not f.LocalPath().startswith('third_party/blink')
5316 and not f.LocalPath().startswith('third_party\\blink')):
5317 continue
rlanday6802cf632017-05-30 17:48:365318
Sam Maiera6e76d72022-02-11 21:43:505319 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
5320 continue
rlanday6802cf632017-05-30 17:48:365321
Sam Maiera6e76d72022-02-11 21:43:505322 relative_includes = [
5323 line for _, line in f.ChangedContents()
5324 if "#include" in line and "../" in line
5325 ]
5326 if not relative_includes:
5327 continue
5328 bad_files[f.LocalPath()] = relative_includes
rlanday6802cf632017-05-30 17:48:365329
Sam Maiera6e76d72022-02-11 21:43:505330 if not bad_files:
5331 return []
rlanday6802cf632017-05-30 17:48:365332
Sam Maiera6e76d72022-02-11 21:43:505333 error_descriptions = []
5334 for file_path, bad_lines in bad_files.items():
5335 error_description = file_path
5336 for line in bad_lines:
5337 error_description += '\n ' + line
5338 error_descriptions.append(error_description)
rlanday6802cf632017-05-30 17:48:365339
Sam Maiera6e76d72022-02-11 21:43:505340 results = []
5341 results.append(
5342 output_api.PresubmitError(
5343 'You added one or more relative #include paths (including "../").\n'
5344 'These shouldn\'t be used because they can be used to include headers\n'
5345 'from code that\'s not correctly specified as a dependency in the\n'
5346 'relevant BUILD.gn file(s).', error_descriptions))
rlanday6802cf632017-05-30 17:48:365347
Sam Maiera6e76d72022-02-11 21:43:505348 return results
rlanday6802cf632017-05-30 17:48:365349
Takeshi Yoshinoe387aa32017-08-02 13:16:135350
Saagar Sanghavifceeaae2020-08-12 16:40:365351def CheckForCcIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505352 """Check that nobody tries to include a cc file. It's a relatively
5353 common error which results in duplicate symbols in object
5354 files. This may not always break the build until someone later gets
5355 very confusing linking errors."""
5356 results = []
5357 for f in input_api.AffectedFiles(include_deletes=False):
5358 # We let third_party code do whatever it wants
5359 if (f.LocalPath().startswith('third_party')
5360 and not f.LocalPath().startswith('third_party/blink')
5361 and not f.LocalPath().startswith('third_party\\blink')):
5362 continue
Daniel Bratell65b033262019-04-23 08:17:065363
Sam Maiera6e76d72022-02-11 21:43:505364 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
5365 continue
Daniel Bratell65b033262019-04-23 08:17:065366
Sam Maiera6e76d72022-02-11 21:43:505367 for _, line in f.ChangedContents():
5368 if line.startswith('#include "'):
5369 included_file = line.split('"')[1]
5370 if _IsCPlusPlusFile(input_api, included_file):
5371 # The most common naming for external files with C++ code,
5372 # apart from standard headers, is to call them foo.inc, but
5373 # Chromium sometimes uses foo-inc.cc so allow that as well.
5374 if not included_file.endswith(('.h', '-inc.cc')):
5375 results.append(
5376 output_api.PresubmitError(
5377 'Only header files or .inc files should be included in other\n'
5378 'C++ files. Compiling the contents of a cc file more than once\n'
5379 'will cause duplicate information in the build which may later\n'
5380 'result in strange link_errors.\n' +
5381 f.LocalPath() + ':\n ' + line))
Daniel Bratell65b033262019-04-23 08:17:065382
Sam Maiera6e76d72022-02-11 21:43:505383 return results
Daniel Bratell65b033262019-04-23 08:17:065384
5385
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205386def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
Sam Maiera6e76d72022-02-11 21:43:505387 if not isinstance(key, ast.Str):
5388 return 'Key at line %d must be a string literal' % key.lineno
5389 if not isinstance(value, ast.Dict):
5390 return 'Value at line %d must be a dict' % value.lineno
5391 if len(value.keys) != 1:
5392 return 'Dict at line %d must have single entry' % value.lineno
5393 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
5394 return (
5395 'Entry at line %d must have a string literal \'filepath\' as key' %
5396 value.lineno)
5397 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:135398
Takeshi Yoshinoe387aa32017-08-02 13:16:135399
Sergey Ulanov4af16052018-11-08 02:41:465400def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Sam Maiera6e76d72022-02-11 21:43:505401 if not isinstance(key, ast.Str):
5402 return 'Key at line %d must be a string literal' % key.lineno
5403 if not isinstance(value, ast.List):
5404 return 'Value at line %d must be a list' % value.lineno
5405 for element in value.elts:
5406 if not isinstance(element, ast.Str):
5407 return 'Watchlist elements on line %d is not a string' % key.lineno
5408 if not email_regex.match(element.s):
5409 return ('Watchlist element on line %d doesn\'t look like a valid '
5410 + 'email: %s') % (key.lineno, element.s)
5411 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:135412
Takeshi Yoshinoe387aa32017-08-02 13:16:135413
Sergey Ulanov4af16052018-11-08 02:41:465414def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Sam Maiera6e76d72022-02-11 21:43:505415 mismatch_template = (
5416 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
5417 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:135418
Sam Maiera6e76d72022-02-11 21:43:505419 email_regex = input_api.re.compile(
5420 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
Sergey Ulanov4af16052018-11-08 02:41:465421
Sam Maiera6e76d72022-02-11 21:43:505422 ast = input_api.ast
5423 i = 0
5424 last_key = ''
5425 while True:
5426 if i >= len(wd_dict.keys):
5427 if i >= len(w_dict.keys):
5428 return None
5429 return mismatch_template % ('missing',
5430 'line %d' % w_dict.keys[i].lineno)
5431 elif i >= len(w_dict.keys):
5432 return (mismatch_template %
5433 ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:135434
Sam Maiera6e76d72022-02-11 21:43:505435 wd_key = wd_dict.keys[i]
5436 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:135437
Sam Maiera6e76d72022-02-11 21:43:505438 result = _CheckWatchlistDefinitionsEntrySyntax(wd_key,
5439 wd_dict.values[i], ast)
5440 if result is not None:
5441 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:135442
Sam Maiera6e76d72022-02-11 21:43:505443 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast,
5444 email_regex)
5445 if result is not None:
5446 return 'Bad entry in WATCHLISTS dict: %s' % result
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205447
Sam Maiera6e76d72022-02-11 21:43:505448 if wd_key.s != w_key.s:
5449 return mismatch_template % ('%s at line %d' %
5450 (wd_key.s, wd_key.lineno),
5451 '%s at line %d' %
5452 (w_key.s, w_key.lineno))
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205453
Sam Maiera6e76d72022-02-11 21:43:505454 if wd_key.s < last_key:
5455 return (
5456 'WATCHLISTS dict is not sorted lexicographically at line %d and %d'
5457 % (wd_key.lineno, w_key.lineno))
5458 last_key = wd_key.s
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205459
Sam Maiera6e76d72022-02-11 21:43:505460 i = i + 1
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205461
5462
Sergey Ulanov4af16052018-11-08 02:41:465463def _CheckWATCHLISTSSyntax(expression, input_api):
Sam Maiera6e76d72022-02-11 21:43:505464 ast = input_api.ast
5465 if not isinstance(expression, ast.Expression):
5466 return 'WATCHLISTS file must contain a valid expression'
5467 dictionary = expression.body
5468 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
5469 return 'WATCHLISTS file must have single dict with exactly two entries'
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205470
Sam Maiera6e76d72022-02-11 21:43:505471 first_key = dictionary.keys[0]
5472 first_value = dictionary.values[0]
5473 second_key = dictionary.keys[1]
5474 second_value = dictionary.values[1]
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205475
Sam Maiera6e76d72022-02-11 21:43:505476 if (not isinstance(first_key, ast.Str)
5477 or first_key.s != 'WATCHLIST_DEFINITIONS'
5478 or not isinstance(first_value, ast.Dict)):
5479 return ('The first entry of the dict in WATCHLISTS file must be '
5480 'WATCHLIST_DEFINITIONS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205481
Sam Maiera6e76d72022-02-11 21:43:505482 if (not isinstance(second_key, ast.Str) or second_key.s != 'WATCHLISTS'
5483 or not isinstance(second_value, ast.Dict)):
5484 return ('The second entry of the dict in WATCHLISTS file must be '
5485 'WATCHLISTS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205486
Sam Maiera6e76d72022-02-11 21:43:505487 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:135488
5489
Saagar Sanghavifceeaae2020-08-12 16:40:365490def CheckWATCHLISTS(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505491 for f in input_api.AffectedFiles(include_deletes=False):
5492 if f.LocalPath() == 'WATCHLISTS':
5493 contents = input_api.ReadFile(f, 'r')
Takeshi Yoshinoe387aa32017-08-02 13:16:135494
Sam Maiera6e76d72022-02-11 21:43:505495 try:
5496 # First, make sure that it can be evaluated.
5497 input_api.ast.literal_eval(contents)
5498 # Get an AST tree for it and scan the tree for detailed style checking.
5499 expression = input_api.ast.parse(contents,
5500 filename='WATCHLISTS',
5501 mode='eval')
5502 except ValueError as e:
5503 return [
5504 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5505 long_text=repr(e))
5506 ]
5507 except SyntaxError as e:
5508 return [
5509 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5510 long_text=repr(e))
5511 ]
5512 except TypeError as e:
5513 return [
5514 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5515 long_text=repr(e))
5516 ]
Takeshi Yoshinoe387aa32017-08-02 13:16:135517
Sam Maiera6e76d72022-02-11 21:43:505518 result = _CheckWATCHLISTSSyntax(expression, input_api)
5519 if result is not None:
5520 return [output_api.PresubmitError(result)]
5521 break
Takeshi Yoshinoe387aa32017-08-02 13:16:135522
Sam Maiera6e76d72022-02-11 21:43:505523 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:135524
Sean Kaucb7c9b32022-10-25 21:25:525525def CheckGnRebasePath(input_api, output_api):
5526 """Checks that target_gen_dir is not used wtih "//" in rebase_path().
5527
5528 Developers should use root_build_dir instead of "//" when using target_gen_dir because
5529 Chromium is sometimes built outside of the source tree.
5530 """
5531
5532 def gn_files(f):
5533 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
5534
5535 rebase_path_regex = input_api.re.compile(r'rebase_path\(("\$target_gen_dir"|target_gen_dir), ("/"|"//")\)')
5536 problems = []
5537 for f in input_api.AffectedSourceFiles(gn_files):
5538 for line_num, line in f.ChangedContents():
5539 if rebase_path_regex.search(line):
5540 problems.append(
5541 'Absolute path in rebase_path() in %s:%d' %
5542 (f.LocalPath(), line_num))
5543
5544 if problems:
5545 return [
5546 output_api.PresubmitPromptWarning(
5547 'Using an absolute path in rebase_path()',
5548 items=sorted(problems),
5549 long_text=(
5550 'rebase_path() should use root_build_dir instead of "/" ',
5551 'since builds can be initiated from outside of the source ',
5552 'root.'))
5553 ]
5554 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:135555
Andrew Grieve1b290e4a22020-11-24 20:07:015556def CheckGnGlobForward(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505557 """Checks that forward_variables_from(invoker, "*") follows best practices.
Andrew Grieve1b290e4a22020-11-24 20:07:015558
Sam Maiera6e76d72022-02-11 21:43:505559 As documented at //build/docs/writing_gn_templates.md
5560 """
Andrew Grieve1b290e4a22020-11-24 20:07:015561
Sam Maiera6e76d72022-02-11 21:43:505562 def gn_files(f):
5563 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
Andrew Grieve1b290e4a22020-11-24 20:07:015564
Sam Maiera6e76d72022-02-11 21:43:505565 problems = []
5566 for f in input_api.AffectedSourceFiles(gn_files):
5567 for line_num, line in f.ChangedContents():
5568 if 'forward_variables_from(invoker, "*")' in line:
5569 problems.append(
5570 'Bare forward_variables_from(invoker, "*") in %s:%d' %
5571 (f.LocalPath(), line_num))
5572
5573 if problems:
5574 return [
5575 output_api.PresubmitPromptWarning(
5576 'forward_variables_from("*") without exclusions',
5577 items=sorted(problems),
5578 long_text=(
Gao Shenga79ebd42022-08-08 17:25:595579 'The variables "visibility" and "test_only" should be '
Sam Maiera6e76d72022-02-11 21:43:505580 'explicitly listed in forward_variables_from(). For more '
5581 'details, see:\n'
5582 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
5583 'build/docs/writing_gn_templates.md'
5584 '#Using-forward_variables_from'))
5585 ]
5586 return []
Andrew Grieve1b290e4a22020-11-24 20:07:015587
Saagar Sanghavifceeaae2020-08-12 16:40:365588def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505589 """Checks that newly added header files have corresponding GN changes.
5590 Note that this is only a heuristic. To be precise, run script:
5591 build/check_gn_headers.py.
5592 """
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195593
Sam Maiera6e76d72022-02-11 21:43:505594 def headers(f):
5595 return input_api.FilterSourceFile(
5596 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195597
Sam Maiera6e76d72022-02-11 21:43:505598 new_headers = []
5599 for f in input_api.AffectedSourceFiles(headers):
5600 if f.Action() != 'A':
5601 continue
5602 new_headers.append(f.LocalPath())
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195603
Sam Maiera6e76d72022-02-11 21:43:505604 def gn_files(f):
5605 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195606
Sam Maiera6e76d72022-02-11 21:43:505607 all_gn_changed_contents = ''
5608 for f in input_api.AffectedSourceFiles(gn_files):
5609 for _, line in f.ChangedContents():
5610 all_gn_changed_contents += line
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195611
Sam Maiera6e76d72022-02-11 21:43:505612 problems = []
5613 for header in new_headers:
5614 basename = input_api.os_path.basename(header)
5615 if basename not in all_gn_changed_contents:
5616 problems.append(header)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195617
Sam Maiera6e76d72022-02-11 21:43:505618 if problems:
5619 return [
5620 output_api.PresubmitPromptWarning(
5621 'Missing GN changes for new header files',
5622 items=sorted(problems),
5623 long_text=
5624 'Please double check whether newly added header files need '
5625 'corresponding changes in gn or gni files.\nThis checking is only a '
5626 'heuristic. Run build/check_gn_headers.py to be precise.\n'
5627 'Read https://crbug.com/661774 for more info.')
5628 ]
5629 return []
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195630
5631
Saagar Sanghavifceeaae2020-08-12 16:40:365632def CheckCorrectProductNameInMessages(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505633 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
Michael Giuffridad3bc8672018-10-25 22:48:025634
Sam Maiera6e76d72022-02-11 21:43:505635 This assumes we won't intentionally reference one product from the other
5636 product.
5637 """
5638 all_problems = []
5639 test_cases = [{
5640 "filename_postfix": "google_chrome_strings.grd",
5641 "correct_name": "Chrome",
5642 "incorrect_name": "Chromium",
5643 }, {
Thiago Perrotta099034f2023-06-05 18:10:205644 "filename_postfix": "google_chrome_strings.grd",
5645 "correct_name": "Chrome",
5646 "incorrect_name": "Chrome for Testing",
5647 }, {
Sam Maiera6e76d72022-02-11 21:43:505648 "filename_postfix": "chromium_strings.grd",
5649 "correct_name": "Chromium",
5650 "incorrect_name": "Chrome",
5651 }]
Michael Giuffridad3bc8672018-10-25 22:48:025652
Sam Maiera6e76d72022-02-11 21:43:505653 for test_case in test_cases:
5654 problems = []
5655 filename_filter = lambda x: x.LocalPath().endswith(test_case[
5656 "filename_postfix"])
Michael Giuffridad3bc8672018-10-25 22:48:025657
Sam Maiera6e76d72022-02-11 21:43:505658 # Check each new line. Can yield false positives in multiline comments, but
5659 # easier than trying to parse the XML because messages can have nested
5660 # children, and associating message elements with affected lines is hard.
5661 for f in input_api.AffectedSourceFiles(filename_filter):
5662 for line_num, line in f.ChangedContents():
5663 if "<message" in line or "<!--" in line or "-->" in line:
5664 continue
5665 if test_case["incorrect_name"] in line:
Thiago Perrotta099034f2023-06-05 18:10:205666 # Chrome for Testing is a special edge case: https://goo.gle/chrome-for-testing#bookmark=id.n1rat320av91
5667 if (test_case["correct_name"] == "Chromium" and line.count("Chrome") == line.count("Chrome for Testing")):
5668 continue
Sam Maiera6e76d72022-02-11 21:43:505669 problems.append("Incorrect product name in %s:%d" %
5670 (f.LocalPath(), line_num))
Michael Giuffridad3bc8672018-10-25 22:48:025671
Sam Maiera6e76d72022-02-11 21:43:505672 if problems:
5673 message = (
5674 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
5675 % (test_case["correct_name"], test_case["correct_name"],
5676 test_case["incorrect_name"]))
5677 all_problems.append(
5678 output_api.PresubmitPromptWarning(message, items=problems))
Michael Giuffridad3bc8672018-10-25 22:48:025679
Sam Maiera6e76d72022-02-11 21:43:505680 return all_problems
Michael Giuffridad3bc8672018-10-25 22:48:025681
5682
Saagar Sanghavifceeaae2020-08-12 16:40:365683def CheckForTooLargeFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505684 """Avoid large files, especially binary files, in the repository since
5685 git doesn't scale well for those. They will be in everyone's repo
5686 clones forever, forever making Chromium slower to clone and work
5687 with."""
Daniel Bratell93eb6c62019-04-29 20:13:365688
Sam Maiera6e76d72022-02-11 21:43:505689 # Uploading files to cloud storage is not trivial so we don't want
5690 # to set the limit too low, but the upper limit for "normal" large
5691 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
5692 # anything over 20 MB is exceptional.
Bruce Dawsonbb414db2022-12-27 20:21:255693 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024
Daniel Bratell93eb6c62019-04-29 20:13:365694
Sam Maiera6e76d72022-02-11 21:43:505695 too_large_files = []
5696 for f in input_api.AffectedFiles():
5697 # Check both added and modified files (but not deleted files).
5698 if f.Action() in ('A', 'M'):
5699 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Joe DeBlasio10a832f2023-04-21 20:20:185700 if size > TOO_LARGE_FILE_SIZE_LIMIT:
Sam Maiera6e76d72022-02-11 21:43:505701 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
Daniel Bratell93eb6c62019-04-29 20:13:365702
Sam Maiera6e76d72022-02-11 21:43:505703 if too_large_files:
5704 message = (
5705 'Do not commit large files to git since git scales badly for those.\n'
5706 +
5707 'Instead put the large files in cloud storage and use DEPS to\n' +
5708 'fetch them.\n' + '\n'.join(too_large_files))
5709 return [
5710 output_api.PresubmitError('Too large files found in commit',
5711 long_text=message + '\n')
5712 ]
5713 else:
5714 return []
Daniel Bratell93eb6c62019-04-29 20:13:365715
Max Morozb47503b2019-08-08 21:03:275716
Saagar Sanghavifceeaae2020-08-12 16:40:365717def CheckFuzzTargetsOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505718 """Checks specific for fuzz target sources."""
5719 EXPORTED_SYMBOLS = [
5720 'LLVMFuzzerInitialize',
5721 'LLVMFuzzerCustomMutator',
5722 'LLVMFuzzerCustomCrossOver',
5723 'LLVMFuzzerMutate',
5724 ]
Max Morozb47503b2019-08-08 21:03:275725
Sam Maiera6e76d72022-02-11 21:43:505726 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
Max Morozb47503b2019-08-08 21:03:275727
Sam Maiera6e76d72022-02-11 21:43:505728 def FilterFile(affected_file):
5729 """Ignore libFuzzer source code."""
5730 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
Bruce Dawson40fece62022-09-16 19:58:315731 files_to_skip = r"^third_party/libFuzzer"
Max Morozb47503b2019-08-08 21:03:275732
Sam Maiera6e76d72022-02-11 21:43:505733 return input_api.FilterSourceFile(affected_file,
5734 files_to_check=[files_to_check],
5735 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:275736
Sam Maiera6e76d72022-02-11 21:43:505737 files_with_missing_header = []
5738 for f in input_api.AffectedSourceFiles(FilterFile):
5739 contents = input_api.ReadFile(f, 'r')
5740 if REQUIRED_HEADER in contents:
5741 continue
Max Morozb47503b2019-08-08 21:03:275742
Sam Maiera6e76d72022-02-11 21:43:505743 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
5744 files_with_missing_header.append(f.LocalPath())
Max Morozb47503b2019-08-08 21:03:275745
Sam Maiera6e76d72022-02-11 21:43:505746 if not files_with_missing_header:
5747 return []
Max Morozb47503b2019-08-08 21:03:275748
Sam Maiera6e76d72022-02-11 21:43:505749 long_text = (
5750 'If you define any of the libFuzzer optional functions (%s), it is '
5751 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
5752 'work incorrectly on Mac (crbug.com/687076).\nNote that '
5753 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
5754 'to access command line arguments passed to the fuzzer. Instead, prefer '
5755 'static initialization and shared resources as documented in '
5756 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
5757 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n'
5758 % (', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER))
Max Morozb47503b2019-08-08 21:03:275759
Sam Maiera6e76d72022-02-11 21:43:505760 return [
5761 output_api.PresubmitPromptWarning(message="Missing '%s' in:" %
5762 REQUIRED_HEADER,
5763 items=files_with_missing_header,
5764 long_text=long_text)
5765 ]
Max Morozb47503b2019-08-08 21:03:275766
5767
Mohamed Heikald048240a2019-11-12 16:57:375768def _CheckNewImagesWarning(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505769 """
5770 Warns authors who add images into the repo to make sure their images are
5771 optimized before committing.
5772 """
5773 images_added = False
5774 image_paths = []
5775 errors = []
5776 filter_lambda = lambda x: input_api.FilterSourceFile(
5777 x,
5778 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
5779 DEFAULT_FILES_TO_SKIP),
5780 files_to_check=[r'.*\/(drawable|mipmap)'])
5781 for f in input_api.AffectedFiles(include_deletes=False,
5782 file_filter=filter_lambda):
5783 local_path = f.LocalPath().lower()
5784 if any(
5785 local_path.endswith(extension)
5786 for extension in _IMAGE_EXTENSIONS):
5787 images_added = True
5788 image_paths.append(f)
5789 if images_added:
5790 errors.append(
5791 output_api.PresubmitPromptWarning(
5792 'It looks like you are trying to commit some images. If these are '
5793 'non-test-only images, please make sure to read and apply the tips in '
5794 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
5795 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
5796 'FYI only and will not block your CL on the CQ.', image_paths))
5797 return errors
Mohamed Heikald048240a2019-11-12 16:57:375798
5799
Saagar Sanghavifceeaae2020-08-12 16:40:365800def ChecksAndroidSpecificOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505801 """Groups upload checks that target android code."""
5802 results = []
5803 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
5804 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
5805 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
5806 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505807 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
5808 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
5809 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
5810 results.extend(_CheckNewImagesWarning(input_api, output_api))
5811 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
5812 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
5813 return results
5814
Becky Zhou7c69b50992018-12-10 19:37:575815
Saagar Sanghavifceeaae2020-08-12 16:40:365816def ChecksAndroidSpecificOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505817 """Groups commit checks that target android code."""
5818 results = []
5819 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
5820 return results
dgnaa68d5e2015-06-10 10:08:225821
Chris Hall59f8d0c72020-05-01 07:31:195822# TODO(chrishall): could we additionally match on any path owned by
5823# ui/accessibility/OWNERS ?
5824_ACCESSIBILITY_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:315825 r"^chrome/browser.*/accessibility/",
5826 r"^chrome/browser/extensions/api/automation.*/",
5827 r"^chrome/renderer/extensions/accessibility_.*",
5828 r"^chrome/tests/data/accessibility/",
5829 r"^content/browser/accessibility/",
5830 r"^content/renderer/accessibility/",
5831 r"^content/tests/data/accessibility/",
5832 r"^extensions/renderer/api/automation/",
Katie Dektar58ef07b2022-09-27 13:19:175833 r"^services/accessibility/",
Abigail Klein7a63c572024-02-28 20:45:095834 r"^services/screen_ai/",
Bruce Dawson40fece62022-09-16 19:58:315835 r"^ui/accessibility/",
5836 r"^ui/views/accessibility/",
Chris Hall59f8d0c72020-05-01 07:31:195837)
5838
Saagar Sanghavifceeaae2020-08-12 16:40:365839def CheckAccessibilityRelnotesField(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505840 """Checks that commits to accessibility code contain an AX-Relnotes field in
5841 their commit message."""
Chris Hall59f8d0c72020-05-01 07:31:195842
Sam Maiera6e76d72022-02-11 21:43:505843 def FileFilter(affected_file):
5844 paths = _ACCESSIBILITY_PATHS
5845 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:195846
Sam Maiera6e76d72022-02-11 21:43:505847 # Only consider changes affecting accessibility paths.
5848 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
5849 return []
Akihiro Ota08108e542020-05-20 15:30:535850
Sam Maiera6e76d72022-02-11 21:43:505851 # AX-Relnotes can appear in either the description or the footer.
5852 # When searching the description, require 'AX-Relnotes:' to appear at the
5853 # beginning of a line.
5854 ax_regex = input_api.re.compile('ax-relnotes[:=]')
5855 description_has_relnotes = any(
5856 ax_regex.match(line)
5857 for line in input_api.change.DescriptionText().lower().splitlines())
Chris Hall59f8d0c72020-05-01 07:31:195858
Sam Maiera6e76d72022-02-11 21:43:505859 footer_relnotes = input_api.change.GitFootersFromDescription().get(
5860 'AX-Relnotes', [])
5861 if description_has_relnotes or footer_relnotes:
5862 return []
Chris Hall59f8d0c72020-05-01 07:31:195863
Sam Maiera6e76d72022-02-11 21:43:505864 # TODO(chrishall): link to Relnotes documentation in message.
5865 message = (
5866 "Missing 'AX-Relnotes:' field required for accessibility changes"
5867 "\n please add 'AX-Relnotes: [release notes].' to describe any "
5868 "user-facing changes"
5869 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
5870 "user-facing effects"
5871 "\n if this is confusing or annoying then please contact members "
5872 "of ui/accessibility/OWNERS.")
5873
5874 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:225875
Mark Schillacie5a0be22022-01-19 00:38:395876
5877_ACCESSIBILITY_EVENTS_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315878 r"^content/test/data/accessibility/event/.*\.html",
Mark Schillacie5a0be22022-01-19 00:38:395879)
5880
5881_ACCESSIBILITY_TREE_TEST_PATH = (
Aaron Leventhal267119f2023-08-18 22:45:345882 r"^content/test/data/accessibility/accname/"
5883 ".*-expected-(mac|win|uia-win|auralinux).txt",
5884 r"^content/test/data/accessibility/aria/"
5885 ".*-expected-(mac|win|uia-win|auralinux).txt",
5886 r"^content/test/data/accessibility/css/"
5887 ".*-expected-(mac|win|uia-win|auralinux).txt",
5888 r"^content/test/data/accessibility/event/"
5889 ".*-expected-(mac|win|uia-win|auralinux).txt",
5890 r"^content/test/data/accessibility/html/"
5891 ".*-expected-(mac|win|uia-win|auralinux).txt",
Mark Schillacie5a0be22022-01-19 00:38:395892)
5893
5894_ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315895 r"^.*/WebContentsAccessibilityEventsTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:395896)
5897
5898_ACCESSIBILITY_ANDROID_TREE_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315899 r"^.*/WebContentsAccessibilityTreeTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:395900)
5901
5902def CheckAccessibilityEventsTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505903 """Checks that commits that include a newly added, renamed/moved, or deleted
5904 test in the DumpAccessibilityEventsTest suite also includes a corresponding
5905 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:395906
Sam Maiera6e76d72022-02-11 21:43:505907 def FilePathFilter(affected_file):
5908 paths = _ACCESSIBILITY_EVENTS_TEST_PATH
5909 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395910
Sam Maiera6e76d72022-02-11 21:43:505911 def AndroidFilePathFilter(affected_file):
5912 paths = _ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH
5913 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395914
Sam Maiera6e76d72022-02-11 21:43:505915 # Only consider changes in the events test data path with html type.
5916 if not any(
5917 input_api.AffectedFiles(include_deletes=True,
5918 file_filter=FilePathFilter)):
5919 return []
Mark Schillacie5a0be22022-01-19 00:38:395920
Sam Maiera6e76d72022-02-11 21:43:505921 # If the commit contains any change to the Android test file, ignore.
5922 if any(
5923 input_api.AffectedFiles(include_deletes=True,
5924 file_filter=AndroidFilePathFilter)):
5925 return []
Mark Schillacie5a0be22022-01-19 00:38:395926
Sam Maiera6e76d72022-02-11 21:43:505927 # Only consider changes that are adding/renaming or deleting a file
5928 message = []
5929 for f in input_api.AffectedFiles(include_deletes=True,
5930 file_filter=FilePathFilter):
Aaron Leventhal267119f2023-08-18 22:45:345931 if f.Action() == 'A':
Sam Maiera6e76d72022-02-11 21:43:505932 message = (
Aaron Leventhal267119f2023-08-18 22:45:345933 "It appears that you are adding platform expectations for a"
Aaron Leventhal0de81072023-08-21 21:26:525934 "\ndump_accessibility_events* test, but have not included"
Sam Maiera6e76d72022-02-11 21:43:505935 "\na corresponding change for Android."
Aaron Leventhal267119f2023-08-18 22:45:345936 "\nPlease include the test from:"
Sam Maiera6e76d72022-02-11 21:43:505937 "\n content/public/android/javatests/src/org/chromium/"
5938 "content/browser/accessibility/"
5939 "WebContentsAccessibilityEventsTest.java"
5940 "\nIf this message is confusing or annoying, please contact"
5941 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:395942
Sam Maiera6e76d72022-02-11 21:43:505943 # If no message was set, return empty.
5944 if not len(message):
5945 return []
5946
5947 return [output_api.PresubmitPromptWarning(message)]
5948
Mark Schillacie5a0be22022-01-19 00:38:395949
5950def CheckAccessibilityTreeTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505951 """Checks that commits that include a newly added, renamed/moved, or deleted
5952 test in the DumpAccessibilityTreeTest suite also includes a corresponding
5953 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:395954
Sam Maiera6e76d72022-02-11 21:43:505955 def FilePathFilter(affected_file):
5956 paths = _ACCESSIBILITY_TREE_TEST_PATH
5957 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395958
Sam Maiera6e76d72022-02-11 21:43:505959 def AndroidFilePathFilter(affected_file):
5960 paths = _ACCESSIBILITY_ANDROID_TREE_TEST_PATH
5961 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395962
Sam Maiera6e76d72022-02-11 21:43:505963 # Only consider changes in the various tree test data paths with html type.
5964 if not any(
5965 input_api.AffectedFiles(include_deletes=True,
5966 file_filter=FilePathFilter)):
5967 return []
Mark Schillacie5a0be22022-01-19 00:38:395968
Sam Maiera6e76d72022-02-11 21:43:505969 # If the commit contains any change to the Android test file, ignore.
5970 if any(
5971 input_api.AffectedFiles(include_deletes=True,
5972 file_filter=AndroidFilePathFilter)):
5973 return []
Mark Schillacie5a0be22022-01-19 00:38:395974
Sam Maiera6e76d72022-02-11 21:43:505975 # Only consider changes that are adding/renaming or deleting a file
5976 message = []
5977 for f in input_api.AffectedFiles(include_deletes=True,
5978 file_filter=FilePathFilter):
Aaron Leventhal0de81072023-08-21 21:26:525979 if f.Action() == 'A':
Sam Maiera6e76d72022-02-11 21:43:505980 message = (
Aaron Leventhal0de81072023-08-21 21:26:525981 "It appears that you are adding platform expectations for a"
5982 "\ndump_accessibility_tree* test, but have not included"
Sam Maiera6e76d72022-02-11 21:43:505983 "\na corresponding change for Android."
5984 "\nPlease include (or remove) the test from:"
5985 "\n content/public/android/javatests/src/org/chromium/"
5986 "content/browser/accessibility/"
5987 "WebContentsAccessibilityTreeTest.java"
5988 "\nIf this message is confusing or annoying, please contact"
5989 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:395990
Sam Maiera6e76d72022-02-11 21:43:505991 # If no message was set, return empty.
5992 if not len(message):
5993 return []
5994
5995 return [output_api.PresubmitPromptWarning(message)]
Mark Schillacie5a0be22022-01-19 00:38:395996
5997
seanmccullough4a9356252021-04-08 19:54:095998# string pattern, sequence of strings to show when pattern matches,
5999# error flag. True if match is a presubmit error, otherwise it's a warning.
6000_NON_INCLUSIVE_TERMS = (
6001 (
6002 # Note that \b pattern in python re is pretty particular. In this
6003 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
6004 # ...' will not. This may require some tweaking to catch these cases
6005 # without triggering a lot of false positives. Leaving it naive and
6006 # less matchy for now.
Josip Sokcevic9d2806a02023-12-13 03:04:026007 r'/(?i)\b((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:096008 (
6009 'Please don\'t use blacklist, whitelist, ' # nocheck
6010 'or slave in your', # nocheck
6011 'code and make every effort to use other terms. Using "// nocheck"',
6012 '"# nocheck" or "<!-- nocheck -->"',
6013 'at the end of the offending line will bypass this PRESUBMIT error',
6014 'but avoid using this whenever possible. Reach out to',
6015 '[email protected] if you have questions'),
6016 True),)
6017
Saagar Sanghavifceeaae2020-08-12 16:40:366018def ChecksCommon(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506019 """Checks common to both upload and commit."""
6020 results = []
Eric Boren6fd2b932018-01-25 15:05:086021 results.extend(
Sam Maiera6e76d72022-02-11 21:43:506022 input_api.canned_checks.PanProjectChecks(
6023 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:086024
Sam Maiera6e76d72022-02-11 21:43:506025 author = input_api.change.author_email
6026 if author and author not in _KNOWN_ROBOTS:
6027 results.extend(
6028 input_api.canned_checks.CheckAuthorizedAuthor(
6029 input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:246030
Sam Maiera6e76d72022-02-11 21:43:506031 results.extend(
6032 input_api.canned_checks.CheckChangeHasNoTabs(
6033 input_api,
6034 output_api,
6035 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
6036 results.extend(
6037 input_api.RunTests(
6038 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Edward Lesmesce51df52020-08-04 22:10:176039
Bruce Dawsonc8054482022-03-28 15:33:376040 dirmd = 'dirmd.bat' if input_api.is_windows else 'dirmd'
Sam Maiera6e76d72022-02-11 21:43:506041 dirmd_bin = input_api.os_path.join(input_api.PresubmitLocalPath(),
Bruce Dawsonc8054482022-03-28 15:33:376042 'third_party', 'depot_tools', dirmd)
Sam Maiera6e76d72022-02-11 21:43:506043 results.extend(
6044 input_api.RunTests(
6045 input_api.canned_checks.CheckDirMetadataFormat(
6046 input_api, output_api, dirmd_bin)))
6047 results.extend(
6048 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
6049 input_api, output_api))
6050 results.extend(
6051 input_api.canned_checks.CheckNoNewMetadataInOwners(
6052 input_api, output_api))
6053 results.extend(
6054 input_api.canned_checks.CheckInclusiveLanguage(
6055 input_api,
6056 output_api,
6057 excluded_directories_relative_path=[
6058 'infra', 'inclusive_language_presubmit_exempt_dirs.txt'
6059 ],
6060 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Dirk Prankee3c9c62d2021-05-18 18:35:596061
Aleksey Khoroshilov2978c942022-06-13 16:14:126062 presubmit_py_filter = lambda f: input_api.FilterSourceFile(
Bruce Dawson696963f2022-09-13 01:15:476063 f, files_to_check=[r'.*PRESUBMIT\.py$'])
Aleksey Khoroshilov2978c942022-06-13 16:14:126064 for f in input_api.AffectedFiles(include_deletes=False,
6065 file_filter=presubmit_py_filter):
6066 full_path = input_api.os_path.dirname(f.AbsoluteLocalPath())
6067 test_file = input_api.os_path.join(full_path, 'PRESUBMIT_test.py')
6068 # The PRESUBMIT.py file (and the directory containing it) might have
6069 # been affected by being moved or removed, so only try to run the tests
6070 # if they still exist.
6071 if not input_api.os_path.exists(test_file):
6072 continue
Sam Maiera6e76d72022-02-11 21:43:506073
Aleksey Khoroshilov2978c942022-06-13 16:14:126074 results.extend(
6075 input_api.canned_checks.RunUnitTestsInDirectory(
6076 input_api,
6077 output_api,
6078 full_path,
Takuto Ikuta40def482023-06-02 02:23:496079 files_to_check=[r'^PRESUBMIT_test\.py$']))
Sam Maiera6e76d72022-02-11 21:43:506080 return results
[email protected]1f7b4172010-01-28 01:17:346081
[email protected]b337cb5b2011-01-23 21:24:056082
Saagar Sanghavifceeaae2020-08-12 16:40:366083def CheckPatchFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506084 problems = [
6085 f.LocalPath() for f in input_api.AffectedFiles()
6086 if f.LocalPath().endswith(('.orig', '.rej'))
6087 ]
6088 # Cargo.toml.orig files are part of third-party crates downloaded from
6089 # crates.io and should be included.
6090 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
6091 if problems:
6092 return [
6093 output_api.PresubmitError("Don't commit .rej and .orig files.",
6094 problems)
6095 ]
6096 else:
6097 return []
[email protected]b8079ae4a2012-12-05 19:56:496098
6099
Saagar Sanghavifceeaae2020-08-12 16:40:366100def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506101 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
6102 macro_re = input_api.re.compile(
6103 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
6104 include_re = input_api.re.compile(r'^#include\s+"build/build_config.h"',
6105 input_api.re.MULTILINE)
6106 extension_re = input_api.re.compile(r'\.[a-z]+$')
6107 errors = []
Bruce Dawsonf7679202022-08-09 20:24:006108 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:506109 for f in input_api.AffectedFiles(include_deletes=False):
Bruce Dawsonf7679202022-08-09 20:24:006110 # The build-config macros are allowed to be used in build_config.h
6111 # without including itself.
6112 if f.LocalPath() == config_h_file:
6113 continue
Sam Maiera6e76d72022-02-11 21:43:506114 if not f.LocalPath().endswith(
6115 ('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
6116 continue
Arthur Sonzognia3dec412024-04-29 12:05:376117
Sam Maiera6e76d72022-02-11 21:43:506118 found_line_number = None
6119 found_macro = None
6120 all_lines = input_api.ReadFile(f, 'r').splitlines()
6121 for line_num, line in enumerate(all_lines):
6122 match = macro_re.search(line)
6123 if match:
6124 found_line_number = line_num
6125 found_macro = match.group(2)
6126 break
6127 if not found_line_number:
6128 continue
Kent Tamura5a8755d2017-06-29 23:37:076129
Sam Maiera6e76d72022-02-11 21:43:506130 found_include_line = -1
6131 for line_num, line in enumerate(all_lines):
6132 if include_re.search(line):
6133 found_include_line = line_num
6134 break
6135 if found_include_line >= 0 and found_include_line < found_line_number:
6136 continue
Kent Tamura5a8755d2017-06-29 23:37:076137
Sam Maiera6e76d72022-02-11 21:43:506138 if not f.LocalPath().endswith('.h'):
6139 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
6140 try:
6141 content = input_api.ReadFile(primary_header_path, 'r')
6142 if include_re.search(content):
6143 continue
6144 except IOError:
6145 pass
6146 errors.append('%s:%d %s macro is used without first including build/'
6147 'build_config.h.' %
6148 (f.LocalPath(), found_line_number, found_macro))
6149 if errors:
6150 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
6151 return []
Kent Tamura5a8755d2017-06-29 23:37:076152
6153
Lei Zhang1c12a22f2021-05-12 11:28:456154def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506155 stl_include_re = input_api.re.compile(r'^#include\s+<('
6156 r'algorithm|'
6157 r'array|'
6158 r'limits|'
6159 r'list|'
6160 r'map|'
6161 r'memory|'
6162 r'queue|'
6163 r'set|'
6164 r'string|'
6165 r'unordered_map|'
6166 r'unordered_set|'
6167 r'utility|'
6168 r'vector)>')
6169 std_namespace_re = input_api.re.compile(r'std::')
6170 errors = []
6171 for f in input_api.AffectedFiles():
6172 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
6173 continue
Lei Zhang1c12a22f2021-05-12 11:28:456174
Sam Maiera6e76d72022-02-11 21:43:506175 uses_std_namespace = False
6176 has_stl_include = False
6177 for line in f.NewContents():
6178 if has_stl_include and uses_std_namespace:
6179 break
Lei Zhang1c12a22f2021-05-12 11:28:456180
Sam Maiera6e76d72022-02-11 21:43:506181 if not has_stl_include and stl_include_re.search(line):
6182 has_stl_include = True
6183 continue
Lei Zhang1c12a22f2021-05-12 11:28:456184
Bruce Dawson4a5579a2022-04-08 17:11:366185 if not uses_std_namespace and (std_namespace_re.search(line)
6186 or 'no-std-usage-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:506187 uses_std_namespace = True
6188 continue
Lei Zhang1c12a22f2021-05-12 11:28:456189
Sam Maiera6e76d72022-02-11 21:43:506190 if has_stl_include and not uses_std_namespace:
6191 errors.append(
6192 '%s: Includes STL header(s) but does not reference std::' %
6193 f.LocalPath())
6194 if errors:
6195 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
6196 return []
Lei Zhang1c12a22f2021-05-12 11:28:456197
6198
Xiaohan Wang42d96c22022-01-20 17:23:116199def _CheckForDeprecatedOSMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:506200 """Check for sensible looking, totally invalid OS macros."""
6201 preprocessor_statement = input_api.re.compile(r'^\s*#')
6202 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
6203 results = []
6204 for lnum, line in f.ChangedContents():
6205 if preprocessor_statement.search(line):
6206 for match in os_macro.finditer(line):
6207 results.append(
6208 ' %s:%d: %s' %
6209 (f.LocalPath(), lnum, 'defined(OS_' + match.group(1) +
6210 ') -> BUILDFLAG(IS_' + match.group(1) + ')'))
6211 return results
[email protected]b00342e7f2013-03-26 16:21:546212
6213
Xiaohan Wang42d96c22022-01-20 17:23:116214def CheckForDeprecatedOSMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506215 """Check all affected files for invalid OS macros."""
6216 bad_macros = []
Bruce Dawsonf7679202022-08-09 20:24:006217 # The OS_ macros are allowed to be used in build/build_config.h.
6218 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:506219 for f in input_api.AffectedSourceFiles(None):
Bruce Dawsonf7679202022-08-09 20:24:006220 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')) \
6221 and f.LocalPath() != config_h_file:
Sam Maiera6e76d72022-02-11 21:43:506222 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
[email protected]b00342e7f2013-03-26 16:21:546223
Sam Maiera6e76d72022-02-11 21:43:506224 if not bad_macros:
6225 return []
[email protected]b00342e7f2013-03-26 16:21:546226
Sam Maiera6e76d72022-02-11 21:43:506227 return [
6228 output_api.PresubmitError(
6229 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
6230 'defined in build_config.h):', bad_macros)
6231 ]
[email protected]b00342e7f2013-03-26 16:21:546232
lliabraa35bab3932014-10-01 12:16:446233
6234def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:506235 """Check all affected files for invalid "if defined" macros."""
6236 ALWAYS_DEFINED_MACROS = (
6237 "TARGET_CPU_PPC",
6238 "TARGET_CPU_PPC64",
6239 "TARGET_CPU_68K",
6240 "TARGET_CPU_X86",
6241 "TARGET_CPU_ARM",
6242 "TARGET_CPU_MIPS",
6243 "TARGET_CPU_SPARC",
6244 "TARGET_CPU_ALPHA",
6245 "TARGET_IPHONE_SIMULATOR",
6246 "TARGET_OS_EMBEDDED",
6247 "TARGET_OS_IPHONE",
6248 "TARGET_OS_MAC",
6249 "TARGET_OS_UNIX",
6250 "TARGET_OS_WIN32",
6251 )
6252 ifdef_macro = input_api.re.compile(
6253 r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
6254 results = []
6255 for lnum, line in f.ChangedContents():
6256 for match in ifdef_macro.finditer(line):
6257 if match.group(1) in ALWAYS_DEFINED_MACROS:
6258 always_defined = ' %s is always defined. ' % match.group(1)
6259 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
6260 results.append(
6261 ' %s:%d %s\n\t%s' %
6262 (f.LocalPath(), lnum, always_defined, did_you_mean))
6263 return results
lliabraa35bab3932014-10-01 12:16:446264
6265
Saagar Sanghavifceeaae2020-08-12 16:40:366266def CheckForInvalidIfDefinedMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506267 """Check all affected files for invalid "if defined" macros."""
Arthur Sonzogni4fd14fd2024-06-02 18:42:526268 SKIPPED_PATHS = [
6269 'base/allocator/partition_allocator/src/partition_alloc/build_config.h',
6270 'build/build_config.h',
6271 'third_party/abseil-cpp/',
6272 'third_party/sqlite/',
6273 ]
6274 def affected_files_filter(f):
6275 # Normalize the local path to Linux-style path separators so that the
6276 # path comparisons work on Windows as well.
6277 path = f.LocalPath().replace('\\', '/')
6278
6279 for skipped_path in SKIPPED_PATHS:
6280 if path.startswith(skipped_path):
6281 return False
6282
6283 return path.endswith(('.h', '.c', '.cc', '.m', '.mm'))
6284
Sam Maiera6e76d72022-02-11 21:43:506285 bad_macros = []
Arthur Sonzogni4fd14fd2024-06-02 18:42:526286 for f in input_api.AffectedSourceFiles(affected_files_filter):
6287 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
lliabraa35bab3932014-10-01 12:16:446288
Sam Maiera6e76d72022-02-11 21:43:506289 if not bad_macros:
6290 return []
lliabraa35bab3932014-10-01 12:16:446291
Sam Maiera6e76d72022-02-11 21:43:506292 return [
6293 output_api.PresubmitError(
6294 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
6295 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
6296 bad_macros)
6297 ]
lliabraa35bab3932014-10-01 12:16:446298
Saagar Sanghavifceeaae2020-08-12 16:40:366299def CheckForIPCRules(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506300 """Check for same IPC rules described in
6301 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
6302 """
6303 base_pattern = r'IPC_ENUM_TRAITS\('
6304 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
6305 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
mlamouria82272622014-09-16 18:45:046306
Sam Maiera6e76d72022-02-11 21:43:506307 problems = []
6308 for f in input_api.AffectedSourceFiles(None):
6309 local_path = f.LocalPath()
6310 if not local_path.endswith('.h'):
6311 continue
6312 for line_number, line in f.ChangedContents():
6313 if inclusion_pattern.search(
6314 line) and not comment_pattern.search(line):
6315 problems.append('%s:%d\n %s' %
6316 (local_path, line_number, line.strip()))
mlamouria82272622014-09-16 18:45:046317
Sam Maiera6e76d72022-02-11 21:43:506318 if problems:
6319 return [
6320 output_api.PresubmitPromptWarning(_IPC_ENUM_TRAITS_DEPRECATED,
6321 problems)
6322 ]
6323 else:
6324 return []
mlamouria82272622014-09-16 18:45:046325
[email protected]b00342e7f2013-03-26 16:21:546326
Saagar Sanghavifceeaae2020-08-12 16:40:366327def CheckForLongPathnames(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506328 """Check to make sure no files being submitted have long paths.
6329 This causes issues on Windows.
6330 """
6331 problems = []
6332 for f in input_api.AffectedTestableFiles():
6333 local_path = f.LocalPath()
6334 # Windows has a path limit of 260 characters. Limit path length to 200 so
6335 # that we have some extra for the prefix on dev machines and the bots.
Weizhong Xia8b461f12024-06-21 21:46:336336 if (local_path.startswith('third_party/blink/web_tests/platform/') and
6337 not local_path.startswith('third_party/blink/web_tests/platform/win')):
6338 # Do not check length of the path for files not used by Windows
6339 continue
Sam Maiera6e76d72022-02-11 21:43:506340 if len(local_path) > 200:
6341 problems.append(local_path)
Stephen Martinis97a394142018-06-07 23:06:056342
Sam Maiera6e76d72022-02-11 21:43:506343 if problems:
6344 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
6345 else:
6346 return []
Stephen Martinis97a394142018-06-07 23:06:056347
6348
Saagar Sanghavifceeaae2020-08-12 16:40:366349def CheckForIncludeGuards(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506350 """Check that header files have proper guards against multiple inclusion.
6351 If a file should not have such guards (and it probably should) then it
Bruce Dawson4a5579a2022-04-08 17:11:366352 should include the string "no-include-guard-because-multiply-included" or
6353 "no-include-guard-because-pch-file".
Sam Maiera6e76d72022-02-11 21:43:506354 """
Daniel Bratell8ba52722018-03-02 16:06:146355
Sam Maiera6e76d72022-02-11 21:43:506356 def is_chromium_header_file(f):
6357 # We only check header files under the control of the Chromium
mikt84d6c712024-03-27 13:29:036358 # project. This excludes:
6359 # - third_party/*, except blink.
6360 # - base/allocator/partition_allocator/: PartitionAlloc is a standalone
6361 # library used outside of Chrome. Includes are referenced from its
6362 # own base directory. It has its own `CheckForIncludeGuards`
6363 # PRESUBMIT.py check.
6364 # - *_message_generator.h: They use include guards in a special,
6365 # non-typical way.
Sam Maiera6e76d72022-02-11 21:43:506366 file_with_path = input_api.os_path.normpath(f.LocalPath())
6367 return (file_with_path.endswith('.h')
6368 and not file_with_path.endswith('_message_generator.h')
Bruce Dawson4c4c2922022-05-02 18:07:336369 and not file_with_path.endswith('com_imported_mstscax.h')
mikt84d6c712024-03-27 13:29:036370 and not file_with_path.startswith('base/allocator/partition_allocator')
Sam Maiera6e76d72022-02-11 21:43:506371 and (not file_with_path.startswith('third_party')
6372 or file_with_path.startswith(
6373 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:146374
Sam Maiera6e76d72022-02-11 21:43:506375 def replace_special_with_underscore(string):
6376 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:146377
Sam Maiera6e76d72022-02-11 21:43:506378 errors = []
Daniel Bratell8ba52722018-03-02 16:06:146379
Sam Maiera6e76d72022-02-11 21:43:506380 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
6381 guard_name = None
6382 guard_line_number = None
6383 seen_guard_end = False
Lei Zhangd84f9512024-05-28 19:43:306384 bypass_checks_at_end_of_file = False
Daniel Bratell8ba52722018-03-02 16:06:146385
Sam Maiera6e76d72022-02-11 21:43:506386 file_with_path = input_api.os_path.normpath(f.LocalPath())
6387 base_file_name = input_api.os_path.splitext(
6388 input_api.os_path.basename(file_with_path))[0]
6389 upper_base_file_name = base_file_name.upper()
Daniel Bratell8ba52722018-03-02 16:06:146390
Sam Maiera6e76d72022-02-11 21:43:506391 expected_guard = replace_special_with_underscore(
6392 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:146393
Sam Maiera6e76d72022-02-11 21:43:506394 # For "path/elem/file_name.h" we should really only accept
6395 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
6396 # are too many (1000+) files with slight deviations from the
6397 # coding style. The most important part is that the include guard
6398 # is there, and that it's unique, not the name so this check is
6399 # forgiving for existing files.
6400 #
6401 # As code becomes more uniform, this could be made stricter.
Daniel Bratell8ba52722018-03-02 16:06:146402
Sam Maiera6e76d72022-02-11 21:43:506403 guard_name_pattern_list = [
6404 # Anything with the right suffix (maybe with an extra _).
6405 r'\w+_H__?',
Daniel Bratell8ba52722018-03-02 16:06:146406
Sam Maiera6e76d72022-02-11 21:43:506407 # To cover include guards with old Blink style.
6408 r'\w+_h',
Daniel Bratell8ba52722018-03-02 16:06:146409
Sam Maiera6e76d72022-02-11 21:43:506410 # Anything including the uppercase name of the file.
6411 r'\w*' + input_api.re.escape(
6412 replace_special_with_underscore(upper_base_file_name)) +
6413 r'\w*',
6414 ]
6415 guard_name_pattern = '|'.join(guard_name_pattern_list)
6416 guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
6417 guard_name_pattern + ')')
Daniel Bratell8ba52722018-03-02 16:06:146418
Sam Maiera6e76d72022-02-11 21:43:506419 for line_number, line in enumerate(f.NewContents()):
Bruce Dawson4a5579a2022-04-08 17:11:366420 if ('no-include-guard-because-multiply-included' in line
6421 or 'no-include-guard-because-pch-file' in line):
Lei Zhangd84f9512024-05-28 19:43:306422 bypass_checks_at_end_of_file = True
Sam Maiera6e76d72022-02-11 21:43:506423 break
Daniel Bratell8ba52722018-03-02 16:06:146424
Sam Maiera6e76d72022-02-11 21:43:506425 if guard_name is None:
6426 match = guard_pattern.match(line)
6427 if match:
6428 guard_name = match.group(1)
6429 guard_line_number = line_number
Daniel Bratell8ba52722018-03-02 16:06:146430
Sam Maiera6e76d72022-02-11 21:43:506431 # We allow existing files to use include guards whose names
6432 # don't match the chromium style guide, but new files should
6433 # get it right.
Bruce Dawson6cc154e2022-04-12 20:39:496434 if guard_name != expected_guard:
Bruce Dawson95eb7562022-09-14 15:27:166435 if f.Action() == 'A': # If file was just 'A'dded
Sam Maiera6e76d72022-02-11 21:43:506436 errors.append(
6437 output_api.PresubmitPromptWarning(
6438 'Header using the wrong include guard name %s'
6439 % guard_name, [
6440 '%s:%d' %
6441 (f.LocalPath(), line_number + 1)
6442 ], 'Expected: %r\nFound: %r' %
6443 (expected_guard, guard_name)))
6444 else:
6445 # The line after #ifndef should have a #define of the same name.
6446 if line_number == guard_line_number + 1:
6447 expected_line = '#define %s' % guard_name
6448 if line != expected_line:
6449 errors.append(
6450 output_api.PresubmitPromptWarning(
6451 'Missing "%s" for include guard' %
6452 expected_line,
6453 ['%s:%d' % (f.LocalPath(), line_number + 1)],
6454 'Expected: %r\nGot: %r' %
6455 (expected_line, line)))
Daniel Bratell8ba52722018-03-02 16:06:146456
Sam Maiera6e76d72022-02-11 21:43:506457 if not seen_guard_end and line == '#endif // %s' % guard_name:
6458 seen_guard_end = True
6459 elif seen_guard_end:
6460 if line.strip() != '':
6461 errors.append(
6462 output_api.PresubmitPromptWarning(
6463 'Include guard %s not covering the whole file'
6464 % (guard_name), [f.LocalPath()]))
6465 break # Nothing else to check and enough to warn once.
Daniel Bratell8ba52722018-03-02 16:06:146466
Lei Zhangd84f9512024-05-28 19:43:306467 if bypass_checks_at_end_of_file:
6468 continue
6469
Sam Maiera6e76d72022-02-11 21:43:506470 if guard_name is None:
6471 errors.append(
6472 output_api.PresubmitPromptWarning(
Bruce Dawson32114b62022-04-11 16:45:496473 'Missing include guard in %s\n'
Sam Maiera6e76d72022-02-11 21:43:506474 'Recommended name: %s\n'
6475 'This check can be disabled by having the string\n'
Bruce Dawson4a5579a2022-04-08 17:11:366476 '"no-include-guard-because-multiply-included" or\n'
6477 '"no-include-guard-because-pch-file" in the header.'
Sam Maiera6e76d72022-02-11 21:43:506478 % (f.LocalPath(), expected_guard)))
Lei Zhangd84f9512024-05-28 19:43:306479 elif not seen_guard_end:
6480 errors.append(
6481 output_api.PresubmitPromptWarning(
6482 'Incorrect or missing include guard #endif in %s\n'
6483 'Recommended #endif comment: // %s'
6484 % (f.LocalPath(), expected_guard)))
Sam Maiera6e76d72022-02-11 21:43:506485
6486 return errors
Daniel Bratell8ba52722018-03-02 16:06:146487
6488
Saagar Sanghavifceeaae2020-08-12 16:40:366489def CheckForWindowsLineEndings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506490 """Check source code and known ascii text files for Windows style line
6491 endings.
6492 """
Bruce Dawson5efbdc652022-04-11 19:29:516493 known_text_files = r'.*\.(txt|html|htm|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:236494
Sam Maiera6e76d72022-02-11 21:43:506495 file_inclusion_pattern = (known_text_files,
6496 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
6497 r'.+%s' % _HEADER_EXTENSIONS)
mostynbb639aca52015-01-07 20:31:236498
Sam Maiera6e76d72022-02-11 21:43:506499 problems = []
6500 source_file_filter = lambda f: input_api.FilterSourceFile(
6501 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
6502 for f in input_api.AffectedSourceFiles(source_file_filter):
Bruce Dawson5efbdc652022-04-11 19:29:516503 # Ignore test files that contain crlf intentionally.
6504 if f.LocalPath().endswith('crlf.txt'):
Daniel Chenga37c03db2022-05-12 17:20:346505 continue
Sam Maiera6e76d72022-02-11 21:43:506506 include_file = False
6507 for line in input_api.ReadFile(f, 'r').splitlines(True):
6508 if line.endswith('\r\n'):
6509 include_file = True
6510 if include_file:
6511 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:236512
Sam Maiera6e76d72022-02-11 21:43:506513 if problems:
6514 return [
6515 output_api.PresubmitPromptWarning(
6516 'Are you sure that you want '
6517 'these files to contain Windows style line endings?\n' +
6518 '\n'.join(problems))
6519 ]
mostynbb639aca52015-01-07 20:31:236520
Sam Maiera6e76d72022-02-11 21:43:506521 return []
6522
mostynbb639aca52015-01-07 20:31:236523
Evan Stade6cfc964c12021-05-18 20:21:166524def CheckIconFilesForLicenseHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506525 """Check that .icon files (which are fragments of C++) have license headers.
6526 """
Evan Stade6cfc964c12021-05-18 20:21:166527
Sam Maiera6e76d72022-02-11 21:43:506528 icon_files = (r'.*\.icon$', )
Evan Stade6cfc964c12021-05-18 20:21:166529
Sam Maiera6e76d72022-02-11 21:43:506530 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
6531 return input_api.canned_checks.CheckLicense(input_api,
6532 output_api,
6533 source_file_filter=icons)
6534
Evan Stade6cfc964c12021-05-18 20:21:166535
Jose Magana2b456f22021-03-09 23:26:406536def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506537 """Check source code for use of Chrome App technologies being
6538 deprecated.
6539 """
Jose Magana2b456f22021-03-09 23:26:406540
Sam Maiera6e76d72022-02-11 21:43:506541 def _CheckForDeprecatedTech(input_api,
6542 output_api,
6543 detection_list,
6544 files_to_check=None,
6545 files_to_skip=None):
Jose Magana2b456f22021-03-09 23:26:406546
Sam Maiera6e76d72022-02-11 21:43:506547 if (files_to_check or files_to_skip):
6548 source_file_filter = lambda f: input_api.FilterSourceFile(
6549 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
6550 else:
6551 source_file_filter = None
6552
6553 problems = []
6554
6555 for f in input_api.AffectedSourceFiles(source_file_filter):
6556 if f.Action() == 'D':
6557 continue
6558 for _, line in f.ChangedContents():
6559 if any(detect in line for detect in detection_list):
6560 problems.append(f.LocalPath())
6561
6562 return problems
6563
6564 # to avoid this presubmit script triggering warnings
6565 files_to_skip = ['PRESUBMIT.py', 'PRESUBMIT_test.py']
Jose Magana2b456f22021-03-09 23:26:406566
6567 problems = []
6568
Sam Maiera6e76d72022-02-11 21:43:506569 # NMF: any files with extensions .nmf or NMF
6570 _NMF_FILES = r'\.(nmf|NMF)$'
6571 problems += _CheckForDeprecatedTech(
6572 input_api,
6573 output_api,
6574 detection_list=[''], # any change to the file will trigger warning
6575 files_to_check=[r'.+%s' % _NMF_FILES])
Jose Magana2b456f22021-03-09 23:26:406576
Sam Maiera6e76d72022-02-11 21:43:506577 # MANIFEST: any manifest.json that in its diff includes "app":
6578 _MANIFEST_FILES = r'(manifest\.json)$'
6579 problems += _CheckForDeprecatedTech(
6580 input_api,
6581 output_api,
6582 detection_list=['"app":'],
6583 files_to_check=[r'.*%s' % _MANIFEST_FILES])
Jose Magana2b456f22021-03-09 23:26:406584
Sam Maiera6e76d72022-02-11 21:43:506585 # NaCl / PNaCl: any file that in its diff contains the strings in the list
6586 problems += _CheckForDeprecatedTech(
6587 input_api,
6588 output_api,
6589 detection_list=['config=nacl', 'enable-nacl', 'cpu=pnacl', 'nacl_io'],
Bruce Dawson40fece62022-09-16 19:58:316590 files_to_skip=files_to_skip + [r"^native_client_sdk/"])
Jose Magana2b456f22021-03-09 23:26:406591
Gao Shenga79ebd42022-08-08 17:25:596592 # PPAPI: any C/C++ file that in its diff includes a ppapi library
Sam Maiera6e76d72022-02-11 21:43:506593 problems += _CheckForDeprecatedTech(
6594 input_api,
6595 output_api,
6596 detection_list=['#include "ppapi', '#include <ppapi'],
6597 files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,
6598 r'.+%s' % _IMPLEMENTATION_EXTENSIONS),
Bruce Dawson40fece62022-09-16 19:58:316599 files_to_skip=[r"^ppapi/"])
Jose Magana2b456f22021-03-09 23:26:406600
Sam Maiera6e76d72022-02-11 21:43:506601 if problems:
6602 return [
6603 output_api.PresubmitPromptWarning(
6604 'You are adding/modifying code'
6605 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
6606 ' PNaCl, PPAPI). See this blog post for more details:\n'
6607 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
6608 'and this documentation for options to replace these technologies:\n'
6609 'https://developer.chrome.com/docs/apps/migration/\n' +
6610 '\n'.join(problems))
6611 ]
Jose Magana2b456f22021-03-09 23:26:406612
Sam Maiera6e76d72022-02-11 21:43:506613 return []
Jose Magana2b456f22021-03-09 23:26:406614
mostynbb639aca52015-01-07 20:31:236615
Saagar Sanghavifceeaae2020-08-12 16:40:366616def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
Sam Maiera6e76d72022-02-11 21:43:506617 """Checks that all source files use SYSLOG properly."""
6618 syslog_files = []
6619 for f in input_api.AffectedSourceFiles(src_file_filter):
6620 for line_number, line in f.ChangedContents():
6621 if 'SYSLOG' in line:
6622 syslog_files.append(f.LocalPath() + ':' + str(line_number))
pastarmovj032ba5bc2017-01-12 10:41:566623
Sam Maiera6e76d72022-02-11 21:43:506624 if syslog_files:
6625 return [
6626 output_api.PresubmitPromptWarning(
6627 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
6628 ' calls.\nFiles to check:\n',
6629 items=syslog_files)
6630 ]
6631 return []
pastarmovj89f7ee12016-09-20 14:58:136632
6633
[email protected]1f7b4172010-01-28 01:17:346634def CheckChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506635 if input_api.version < [2, 0, 0]:
6636 return [
6637 output_api.PresubmitError(
6638 "Your depot_tools is out of date. "
6639 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
6640 "but your version is %d.%d.%d" % tuple(input_api.version))
6641 ]
6642 results = []
6643 results.extend(
6644 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
6645 return results
[email protected]ca8d19842009-02-19 16:33:126646
6647
6648def CheckChangeOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506649 if input_api.version < [2, 0, 0]:
6650 return [
6651 output_api.PresubmitError(
6652 "Your depot_tools is out of date. "
6653 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
6654 "but your version is %d.%d.%d" % tuple(input_api.version))
6655 ]
Saagar Sanghavifceeaae2020-08-12 16:40:366656
Sam Maiera6e76d72022-02-11 21:43:506657 results = []
6658 # Make sure the tree is 'open'.
6659 results.extend(
6660 input_api.canned_checks.CheckTreeIsOpen(
6661 input_api,
6662 output_api,
6663 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:276664
Sam Maiera6e76d72022-02-11 21:43:506665 results.extend(
6666 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
6667 results.extend(
6668 input_api.canned_checks.CheckChangeHasBugField(input_api, output_api))
6669 results.extend(
6670 input_api.canned_checks.CheckChangeHasNoUnwantedTags(
6671 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:506672 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146673
6674
Saagar Sanghavifceeaae2020-08-12 16:40:366675def CheckStrings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506676 """Check string ICU syntax validity and if translation screenshots exist."""
6677 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
6678 # footer is set to true.
6679 git_footers = input_api.change.GitFootersFromDescription()
6680 skip_screenshot_check_footer = [
6681 footer.lower() for footer in git_footers.get(
6682 u'Skip-Translation-Screenshots-Check', [])
6683 ]
6684 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:026685
Sam Maiera6e76d72022-02-11 21:43:506686 import os
6687 import re
6688 import sys
6689 from io import StringIO
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146690
Sam Maiera6e76d72022-02-11 21:43:506691 new_or_added_paths = set(f.LocalPath() for f in input_api.AffectedFiles()
6692 if (f.Action() == 'A' or f.Action() == 'M'))
6693 removed_paths = set(f.LocalPath()
6694 for f in input_api.AffectedFiles(include_deletes=True)
6695 if f.Action() == 'D')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146696
Sam Maiera6e76d72022-02-11 21:43:506697 affected_grds = [
6698 f for f in input_api.AffectedFiles()
6699 if f.LocalPath().endswith(('.grd', '.grdp'))
6700 ]
6701 affected_grds = [
6702 f for f in affected_grds if not 'testdata' in f.LocalPath()
6703 ]
6704 if not affected_grds:
6705 return []
meacer8c0d3832019-12-26 21:46:166706
Sam Maiera6e76d72022-02-11 21:43:506707 affected_png_paths = [
Andrew Grieve713b89b2024-10-15 20:20:086708 f.LocalPath() for f in input_api.AffectedFiles()
6709 if f.LocalPath().endswith('.png')
Sam Maiera6e76d72022-02-11 21:43:506710 ]
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146711
Sam Maiera6e76d72022-02-11 21:43:506712 # Check for screenshots. Developers can upload screenshots using
6713 # tools/translation/upload_screenshots.py which finds and uploads
6714 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
6715 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
6716 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
6717 #
6718 # The logic here is as follows:
6719 #
6720 # - If the CL has a .png file under the screenshots directory for a grd
6721 # file, warn the developer. Actual images should never be checked into the
6722 # Chrome repo.
6723 #
6724 # - If the CL contains modified or new messages in grd files and doesn't
6725 # contain the corresponding .sha1 files, warn the developer to add images
6726 # and upload them via tools/translation/upload_screenshots.py.
6727 #
6728 # - If the CL contains modified or new messages in grd files and the
6729 # corresponding .sha1 files, everything looks good.
6730 #
6731 # - If the CL contains removed messages in grd files but the corresponding
6732 # .sha1 files aren't removed, warn the developer to remove them.
6733 unnecessary_screenshots = []
Jens Mueller054652c2023-05-10 15:12:306734 invalid_sha1 = []
Sam Maiera6e76d72022-02-11 21:43:506735 missing_sha1 = []
Bruce Dawson55776c42022-12-09 17:23:476736 missing_sha1_modified = []
Sam Maiera6e76d72022-02-11 21:43:506737 unnecessary_sha1_files = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146738
Sam Maiera6e76d72022-02-11 21:43:506739 # This checks verifies that the ICU syntax of messages this CL touched is
6740 # valid, and reports any found syntax errors.
6741 # Without this presubmit check, ICU syntax errors in Chromium strings can land
6742 # without developers being aware of them. Later on, such ICU syntax errors
6743 # break message extraction for translation, hence would block Chromium
6744 # translations until they are fixed.
6745 icu_syntax_errors = []
Jens Mueller054652c2023-05-10 15:12:306746 sha1_pattern = input_api.re.compile(r'^[a-fA-F0-9]{40}$',
6747 input_api.re.MULTILINE)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146748
Sam Maiera6e76d72022-02-11 21:43:506749 def _CheckScreenshotAdded(screenshots_dir, message_id):
6750 sha1_path = input_api.os_path.join(screenshots_dir,
6751 message_id + '.png.sha1')
6752 if sha1_path not in new_or_added_paths:
6753 missing_sha1.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306754 elif not _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256755 invalid_sha1.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146756
Bruce Dawson55776c42022-12-09 17:23:476757 def _CheckScreenshotModified(screenshots_dir, message_id):
6758 sha1_path = input_api.os_path.join(screenshots_dir,
6759 message_id + '.png.sha1')
6760 if sha1_path not in new_or_added_paths:
6761 missing_sha1_modified.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306762 elif not _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256763 invalid_sha1.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306764
6765 def _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256766 return sha1_pattern.search(
6767 next("\n".join(f.NewContents()) for f in input_api.AffectedFiles()
6768 if f.LocalPath() == sha1_path))
Bruce Dawson55776c42022-12-09 17:23:476769
Sam Maiera6e76d72022-02-11 21:43:506770 def _CheckScreenshotRemoved(screenshots_dir, message_id):
6771 sha1_path = input_api.os_path.join(screenshots_dir,
6772 message_id + '.png.sha1')
6773 if input_api.os_path.exists(
6774 sha1_path) and sha1_path not in removed_paths:
6775 unnecessary_sha1_files.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146776
Sam Maiera6e76d72022-02-11 21:43:506777 def _ValidateIcuSyntax(text, level, signatures):
6778 """Validates ICU syntax of a text string.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146779
Sam Maiera6e76d72022-02-11 21:43:506780 Check if text looks similar to ICU and checks for ICU syntax correctness
6781 in this case. Reports various issues with ICU syntax and values of
6782 variants. Supports checking of nested messages. Accumulate information of
6783 each ICU messages found in the text for further checking.
Rainhard Findlingfc31844c52020-05-15 09:58:266784
Sam Maiera6e76d72022-02-11 21:43:506785 Args:
6786 text: a string to check.
6787 level: a number of current nesting level.
6788 signatures: an accumulator, a list of tuple of (level, variable,
6789 kind, variants).
Rainhard Findlingfc31844c52020-05-15 09:58:266790
Sam Maiera6e76d72022-02-11 21:43:506791 Returns:
6792 None if a string is not ICU or no issue detected.
6793 A tuple of (message, start index, end index) if an issue detected.
6794 """
6795 valid_types = {
6796 'plural': (frozenset(
Rainhard Findling3cde3ef02024-02-05 18:40:326797 ['=0', '=1', '=2', '=3', 'zero', 'one', 'two', 'few', 'many',
Sam Maiera6e76d72022-02-11 21:43:506798 'other']), frozenset(['=1', 'other'])),
6799 'selectordinal': (frozenset(
Rainhard Findling3cde3ef02024-02-05 18:40:326800 ['=0', '=1', '=2', '=3', 'zero', 'one', 'two', 'few', 'many',
Sam Maiera6e76d72022-02-11 21:43:506801 'other']), frozenset(['one', 'other'])),
6802 'select': (frozenset(), frozenset(['other'])),
6803 }
Rainhard Findlingfc31844c52020-05-15 09:58:266804
Sam Maiera6e76d72022-02-11 21:43:506805 # Check if the message looks like an attempt to use ICU
6806 # plural. If yes - check if its syntax strictly matches ICU format.
6807 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b',
6808 text)
6809 if not like:
6810 signatures.append((level, None, None, None))
6811 return
Rainhard Findlingfc31844c52020-05-15 09:58:266812
Sam Maiera6e76d72022-02-11 21:43:506813 # Check for valid prefix and suffix
6814 m = re.match(
6815 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
6816 r'(plural|selectordinal|select),\s*'
6817 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
6818 if not m:
6819 return (('This message looks like an ICU plural, '
6820 'but does not follow ICU syntax.'), like.start(),
6821 like.end())
6822 starting, variable, kind, variant_pairs = m.groups()
6823 variants, depth, last_pos = _ParseIcuVariants(variant_pairs,
6824 m.start(4))
6825 if depth:
6826 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
6827 len(text))
6828 first = text[0]
6829 ending = text[last_pos:]
6830 if not starting:
6831 return ('Invalid ICU format. No initial opening bracket',
6832 last_pos - 1, last_pos)
6833 if not ending or '}' not in ending:
6834 return ('Invalid ICU format. No final closing bracket',
6835 last_pos - 1, last_pos)
6836 elif first != '{':
6837 return ((
6838 'Invalid ICU format. Extra characters at the start of a complex '
6839 'message (go/icu-message-migration): "%s"') % starting, 0,
6840 len(starting))
6841 elif ending != '}':
6842 return ((
6843 'Invalid ICU format. Extra characters at the end of a complex '
6844 'message (go/icu-message-migration): "%s"') % ending,
6845 last_pos - 1, len(text) - 1)
6846 if kind not in valid_types:
6847 return (('Unknown ICU message type %s. '
6848 'Valid types are: plural, select, selectordinal') % kind,
6849 0, 0)
6850 known, required = valid_types[kind]
6851 defined_variants = set()
6852 for variant, variant_range, value, value_range in variants:
6853 start, end = variant_range
6854 if variant in defined_variants:
6855 return ('Variant "%s" is defined more than once' % variant,
6856 start, end)
6857 elif known and variant not in known:
6858 return ('Variant "%s" is not valid for %s message' %
6859 (variant, kind), start, end)
6860 defined_variants.add(variant)
6861 # Check for nested structure
6862 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
6863 if res:
6864 return (res[0], res[1] + value_range[0] + 1,
6865 res[2] + value_range[0] + 1)
6866 missing = required - defined_variants
6867 if missing:
6868 return ('Required variants missing: %s' % ', '.join(missing), 0,
6869 len(text))
6870 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:266871
Sam Maiera6e76d72022-02-11 21:43:506872 def _ParseIcuVariants(text, offset=0):
6873 """Parse variants part of ICU complex message.
Rainhard Findlingfc31844c52020-05-15 09:58:266874
Sam Maiera6e76d72022-02-11 21:43:506875 Builds a tuple of variant names and values, as well as
6876 their offsets in the input string.
Rainhard Findlingfc31844c52020-05-15 09:58:266877
Sam Maiera6e76d72022-02-11 21:43:506878 Args:
6879 text: a string to parse
6880 offset: additional offset to add to positions in the text to get correct
6881 position in the complete ICU string.
Rainhard Findlingfc31844c52020-05-15 09:58:266882
Sam Maiera6e76d72022-02-11 21:43:506883 Returns:
6884 List of tuples, each tuple consist of four fields: variant name,
6885 variant name span (tuple of two integers), variant value, value
6886 span (tuple of two integers).
6887 """
6888 depth, start, end = 0, -1, -1
6889 variants = []
6890 key = None
6891 for idx, char in enumerate(text):
6892 if char == '{':
6893 if not depth:
6894 start = idx
6895 chunk = text[end + 1:start]
6896 key = chunk.strip()
6897 pos = offset + end + 1 + chunk.find(key)
6898 span = (pos, pos + len(key))
6899 depth += 1
6900 elif char == '}':
6901 if not depth:
6902 return variants, depth, offset + idx
6903 depth -= 1
6904 if not depth:
6905 end = idx
6906 variants.append((key, span, text[start:end + 1],
6907 (offset + start, offset + end + 1)))
6908 return variants, depth, offset + end + 1
Rainhard Findlingfc31844c52020-05-15 09:58:266909
Sam Maiera6e76d72022-02-11 21:43:506910 try:
6911 old_sys_path = sys.path
6912 sys.path = sys.path + [
6913 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
6914 'translation')
6915 ]
6916 from helper import grd_helper
6917 finally:
6918 sys.path = old_sys_path
Rainhard Findlingfc31844c52020-05-15 09:58:266919
Sam Maiera6e76d72022-02-11 21:43:506920 for f in affected_grds:
6921 file_path = f.LocalPath()
6922 old_id_to_msg_map = {}
6923 new_id_to_msg_map = {}
6924 # Note that this code doesn't check if the file has been deleted. This is
6925 # OK because it only uses the old and new file contents and doesn't load
6926 # the file via its path.
6927 # It's also possible that a file's content refers to a renamed or deleted
6928 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
6929 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
6930 # .grdp files.
6931 if file_path.endswith('.grdp'):
6932 if f.OldContents():
6933 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6934 '\n'.join(f.OldContents()))
6935 if f.NewContents():
6936 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6937 '\n'.join(f.NewContents()))
6938 else:
6939 file_dir = input_api.os_path.dirname(file_path) or '.'
6940 if f.OldContents():
6941 old_id_to_msg_map = grd_helper.GetGrdMessages(
6942 StringIO('\n'.join(f.OldContents())), file_dir)
6943 if f.NewContents():
6944 new_id_to_msg_map = grd_helper.GetGrdMessages(
6945 StringIO('\n'.join(f.NewContents())), file_dir)
Rainhard Findlingfc31844c52020-05-15 09:58:266946
Sam Maiera6e76d72022-02-11 21:43:506947 grd_name, ext = input_api.os_path.splitext(
6948 input_api.os_path.basename(file_path))
6949 screenshots_dir = input_api.os_path.join(
6950 input_api.os_path.dirname(file_path),
6951 grd_name + ext.replace('.', '_'))
Rainhard Findlingfc31844c52020-05-15 09:58:266952
Sam Maiera6e76d72022-02-11 21:43:506953 # Compute added, removed and modified message IDs.
6954 old_ids = set(old_id_to_msg_map)
6955 new_ids = set(new_id_to_msg_map)
6956 added_ids = new_ids - old_ids
6957 removed_ids = old_ids - new_ids
6958 modified_ids = set([])
6959 for key in old_ids.intersection(new_ids):
6960 if (old_id_to_msg_map[key].ContentsAsXml('', True) !=
6961 new_id_to_msg_map[key].ContentsAsXml('', True)):
6962 # The message content itself changed. Require an updated screenshot.
6963 modified_ids.add(key)
6964 elif old_id_to_msg_map[key].attrs['meaning'] != \
6965 new_id_to_msg_map[key].attrs['meaning']:
Jens Mueller054652c2023-05-10 15:12:306966 # The message meaning changed. We later check for a screenshot.
6967 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146968
Sam Maiera6e76d72022-02-11 21:43:506969 if run_screenshot_check:
6970 # Check the screenshot directory for .png files. Warn if there is any.
6971 for png_path in affected_png_paths:
6972 if png_path.startswith(screenshots_dir):
6973 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146974
Sam Maiera6e76d72022-02-11 21:43:506975 for added_id in added_ids:
6976 _CheckScreenshotAdded(screenshots_dir, added_id)
Rainhard Findlingd8d04372020-08-13 13:30:096977
Sam Maiera6e76d72022-02-11 21:43:506978 for modified_id in modified_ids:
Bruce Dawson55776c42022-12-09 17:23:476979 _CheckScreenshotModified(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146980
Sam Maiera6e76d72022-02-11 21:43:506981 for removed_id in removed_ids:
6982 _CheckScreenshotRemoved(screenshots_dir, removed_id)
6983
6984 # Check new and changed strings for ICU syntax errors.
6985 for key in added_ids.union(modified_ids):
6986 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
6987 err = _ValidateIcuSyntax(msg, 0, [])
6988 if err is not None:
6989 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
6990
6991 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:266992 if run_screenshot_check:
Sam Maiera6e76d72022-02-11 21:43:506993 if unnecessary_screenshots:
6994 results.append(
6995 output_api.PresubmitError(
6996 'Do not include actual screenshots in the changelist. Run '
6997 'tools/translate/upload_screenshots.py to upload them instead:',
6998 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146999
Sam Maiera6e76d72022-02-11 21:43:507000 if missing_sha1:
7001 results.append(
7002 output_api.PresubmitError(
Bruce Dawson55776c42022-12-09 17:23:477003 'You are adding UI strings.\n'
Sam Maiera6e76d72022-02-11 21:43:507004 'To ensure the best translations, take screenshots of the relevant UI '
7005 '(https://g.co/chrome/translation) and add these files to your '
7006 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147007
Jens Mueller054652c2023-05-10 15:12:307008 if invalid_sha1:
7009 results.append(
7010 output_api.PresubmitError(
7011 'The following files do not seem to contain valid sha1 hashes. '
7012 'Make sure they contain hashes created by '
7013 'tools/translate/upload_screenshots.py:', sorted(invalid_sha1)))
7014
Bruce Dawson55776c42022-12-09 17:23:477015 if missing_sha1_modified:
7016 results.append(
7017 output_api.PresubmitError(
7018 'You are modifying UI strings or their meanings.\n'
7019 'To ensure the best translations, take screenshots of the relevant UI '
7020 '(https://g.co/chrome/translation) and add these files to your '
7021 'changelist:', sorted(missing_sha1_modified)))
7022
Sam Maiera6e76d72022-02-11 21:43:507023 if unnecessary_sha1_files:
7024 results.append(
7025 output_api.PresubmitError(
7026 'You removed strings associated with these files. Remove:',
7027 sorted(unnecessary_sha1_files)))
7028 else:
7029 results.append(
7030 output_api.PresubmitPromptOrNotify('Skipping translation '
7031 'screenshots check.'))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147032
Sam Maiera6e76d72022-02-11 21:43:507033 if icu_syntax_errors:
7034 results.append(
7035 output_api.PresubmitPromptWarning(
7036 'ICU syntax errors were found in the following strings (problems or '
7037 'feedback? Contact [email protected]):',
7038 items=icu_syntax_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:267039
Sam Maiera6e76d72022-02-11 21:43:507040 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:127041
7042
Saagar Sanghavifceeaae2020-08-12 16:40:367043def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:127044 repo_root=None,
7045 translation_expectations_path=None,
7046 grd_files=None):
Sam Maiera6e76d72022-02-11 21:43:507047 import sys
7048 affected_grds = [
7049 f for f in input_api.AffectedFiles()
7050 if (f.LocalPath().endswith('.grd') or f.LocalPath().endswith('.grdp'))
7051 ]
7052 if not affected_grds:
7053 return []
7054
7055 try:
7056 old_sys_path = sys.path
7057 sys.path = sys.path + [
7058 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
7059 'translation')
7060 ]
7061 from helper import git_helper
7062 from helper import translation_helper
7063 finally:
7064 sys.path = old_sys_path
7065
7066 # Check that translation expectations can be parsed and we can get a list of
7067 # translatable grd files. |repo_root| and |translation_expectations_path| are
7068 # only passed by tests.
7069 if not repo_root:
7070 repo_root = input_api.PresubmitLocalPath()
7071 if not translation_expectations_path:
7072 translation_expectations_path = input_api.os_path.join(
7073 repo_root, 'tools', 'gritsettings', 'translation_expectations.pyl')
7074 if not grd_files:
7075 grd_files = git_helper.list_grds_in_repository(repo_root)
7076
7077 # Ignore bogus grd files used only for testing
Gao Shenga79ebd42022-08-08 17:25:597078 # ui/webui/resources/tools/generate_grd.py.
Sam Maiera6e76d72022-02-11 21:43:507079 ignore_path = input_api.os_path.join('ui', 'webui', 'resources', 'tools',
7080 'tests')
7081 grd_files = [p for p in grd_files if ignore_path not in p]
7082
7083 try:
7084 translation_helper.get_translatable_grds(
7085 repo_root, grd_files, translation_expectations_path)
7086 except Exception as e:
7087 return [
7088 output_api.PresubmitNotifyResult(
7089 'Failed to get a list of translatable grd files. This happens when:\n'
7090 ' - One of the modified grd or grdp files cannot be parsed or\n'
7091 ' - %s is not updated.\n'
7092 'Stack:\n%s' % (translation_expectations_path, str(e)))
7093 ]
Mustafa Emre Acer51f2f742020-03-09 19:41:127094 return []
7095
Ken Rockotc31f4832020-05-29 18:58:517096
Saagar Sanghavifceeaae2020-08-12 16:40:367097def CheckStableMojomChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507098 """Changes to [Stable] mojom types must preserve backward-compatibility."""
7099 changed_mojoms = input_api.AffectedFiles(
7100 include_deletes=True,
7101 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:527102
Bruce Dawson344ab262022-06-04 11:35:107103 if not changed_mojoms or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:507104 return []
7105
7106 delta = []
7107 for mojom in changed_mojoms:
Sam Maiera6e76d72022-02-11 21:43:507108 delta.append({
7109 'filename': mojom.LocalPath(),
7110 'old': '\n'.join(mojom.OldContents()) or None,
7111 'new': '\n'.join(mojom.NewContents()) or None,
7112 })
7113
7114 process = input_api.subprocess.Popen([
Takuto Ikutadca10222022-04-13 02:51:217115 input_api.python3_executable,
Sam Maiera6e76d72022-02-11 21:43:507116 input_api.os_path.join(
7117 input_api.PresubmitLocalPath(), 'mojo', 'public', 'tools', 'mojom',
7118 'check_stable_mojom_compatibility.py'), '--src-root',
7119 input_api.PresubmitLocalPath()
7120 ],
7121 stdin=input_api.subprocess.PIPE,
7122 stdout=input_api.subprocess.PIPE,
7123 stderr=input_api.subprocess.PIPE,
7124 universal_newlines=True)
7125 (x, error) = process.communicate(input=input_api.json.dumps(delta))
7126 if process.returncode:
7127 return [
7128 output_api.PresubmitError(
7129 'One or more [Stable] mojom definitions appears to have been changed '
Alex Goughc99921652024-02-15 22:59:127130 'in a way that is not backward-compatible. See '
7131 'https://chromium.googlesource.com/chromium/src/+/HEAD/mojo/public/tools/bindings/README.md#versioning'
7132 ' for details.',
Sam Maiera6e76d72022-02-11 21:43:507133 long_text=error)
7134 ]
Erik Staabc734cd7a2021-11-23 03:11:527135 return []
7136
Dominic Battre645d42342020-12-04 16:14:107137def CheckDeprecationOfPreferences(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507138 """Removing a preference should come with a deprecation."""
Dominic Battre645d42342020-12-04 16:14:107139
Sam Maiera6e76d72022-02-11 21:43:507140 def FilterFile(affected_file):
7141 """Accept only .cc files and the like."""
7142 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
7143 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
7144 input_api.DEFAULT_FILES_TO_SKIP)
7145 return input_api.FilterSourceFile(
7146 affected_file,
7147 files_to_check=file_inclusion_pattern,
7148 files_to_skip=files_to_skip)
Dominic Battre645d42342020-12-04 16:14:107149
Sam Maiera6e76d72022-02-11 21:43:507150 def ModifiedLines(affected_file):
7151 """Returns a list of tuples (line number, line text) of added and removed
7152 lines.
Dominic Battre645d42342020-12-04 16:14:107153
Sam Maiera6e76d72022-02-11 21:43:507154 Deleted lines share the same line number as the previous line.
Dominic Battre645d42342020-12-04 16:14:107155
Sam Maiera6e76d72022-02-11 21:43:507156 This relies on the scm diff output describing each changed code section
7157 with a line of the form
Dominic Battre645d42342020-12-04 16:14:107158
Sam Maiera6e76d72022-02-11 21:43:507159 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
7160 """
7161 line_num = 0
7162 modified_lines = []
7163 for line in affected_file.GenerateScmDiff().splitlines():
7164 # Extract <new line num> of the patch fragment (see format above).
7165 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@',
7166 line)
7167 if m:
7168 line_num = int(m.groups(1)[0])
7169 continue
7170 if ((line.startswith('+') and not line.startswith('++'))
7171 or (line.startswith('-') and not line.startswith('--'))):
7172 modified_lines.append((line_num, line))
Dominic Battre645d42342020-12-04 16:14:107173
Sam Maiera6e76d72022-02-11 21:43:507174 if not line.startswith('-'):
7175 line_num += 1
7176 return modified_lines
Dominic Battre645d42342020-12-04 16:14:107177
Sam Maiera6e76d72022-02-11 21:43:507178 def FindLineWith(lines, needle):
7179 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
Dominic Battre645d42342020-12-04 16:14:107180
Sam Maiera6e76d72022-02-11 21:43:507181 If 0 or >1 lines contain `needle`, -1 is returned.
7182 """
7183 matching_line_numbers = [
7184 # + 1 for 1-based counting of line numbers.
7185 i + 1 for i, line in enumerate(lines) if needle in line
7186 ]
7187 return matching_line_numbers[0] if len(
7188 matching_line_numbers) == 1 else -1
Dominic Battre645d42342020-12-04 16:14:107189
Sam Maiera6e76d72022-02-11 21:43:507190 def ModifiedPrefMigration(affected_file):
7191 """Returns whether the MigrateObsolete.*Pref functions were modified."""
7192 # Determine first and last lines of MigrateObsolete.*Pref functions.
7193 new_contents = affected_file.NewContents()
7194 range_1 = (FindLineWith(new_contents,
7195 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
7196 FindLineWith(new_contents,
7197 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
7198 range_2 = (FindLineWith(new_contents,
7199 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
7200 FindLineWith(new_contents,
7201 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
7202 if (-1 in range_1 + range_2):
7203 raise Exception(
7204 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.'
7205 )
Dominic Battre645d42342020-12-04 16:14:107206
Sam Maiera6e76d72022-02-11 21:43:507207 # Check whether any of the modified lines are part of the
7208 # MigrateObsolete.*Pref functions.
7209 for line_nr, line in ModifiedLines(affected_file):
7210 if (range_1[0] <= line_nr <= range_1[1]
7211 or range_2[0] <= line_nr <= range_2[1]):
7212 return True
7213 return False
Dominic Battre645d42342020-12-04 16:14:107214
Sam Maiera6e76d72022-02-11 21:43:507215 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
7216 browser_prefs_file_pattern = input_api.re.compile(
7217 r'chrome/browser/prefs/browser_prefs.cc')
Dominic Battre645d42342020-12-04 16:14:107218
Sam Maiera6e76d72022-02-11 21:43:507219 changes = input_api.AffectedFiles(include_deletes=True,
7220 file_filter=FilterFile)
7221 potential_problems = []
7222 for f in changes:
7223 for line in f.GenerateScmDiff().splitlines():
7224 # Check deleted lines for pref registrations.
7225 if (line.startswith('-') and not line.startswith('--')
7226 and register_pref_pattern.search(line)):
7227 potential_problems.append('%s: %s' % (f.LocalPath(), line))
Dominic Battre645d42342020-12-04 16:14:107228
Sam Maiera6e76d72022-02-11 21:43:507229 if browser_prefs_file_pattern.search(f.LocalPath()):
7230 # If the developer modified the MigrateObsolete.*Prefs() functions, we
7231 # assume that they knew that they have to deprecate preferences and don't
7232 # warn.
7233 try:
7234 if ModifiedPrefMigration(f):
7235 return []
7236 except Exception as e:
7237 return [output_api.PresubmitError(str(e))]
Dominic Battre645d42342020-12-04 16:14:107238
Sam Maiera6e76d72022-02-11 21:43:507239 if potential_problems:
7240 return [
7241 output_api.PresubmitPromptWarning(
7242 'Discovered possible removal of preference registrations.\n\n'
7243 'Please make sure to properly deprecate preferences by clearing their\n'
7244 'value for a couple of milestones before finally removing the code.\n'
7245 'Otherwise data may stay in the preferences files forever. See\n'
7246 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
7247 'chrome/browser/prefs/README.md for examples.\n'
7248 'This may be a false positive warning (e.g. if you move preference\n'
7249 'registrations to a different place).\n', potential_problems)
7250 ]
7251 return []
7252
Matt Stark6ef08872021-07-29 01:21:467253
7254def CheckConsistentGrdChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507255 """Changes to GRD files must be consistent for tools to read them."""
7256 changed_grds = input_api.AffectedFiles(
7257 include_deletes=False,
7258 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
7259 errors = []
7260 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
7261 for matcher, msg in _INVALID_GRD_FILE_LINE]
7262 for grd in changed_grds:
7263 for i, line in enumerate(grd.NewContents()):
7264 for matcher, msg in invalid_file_regexes:
7265 if matcher.search(line):
7266 errors.append(
7267 output_api.PresubmitError(
7268 'Problem on {grd}:{i} - {msg}'.format(
7269 grd=grd.LocalPath(), i=i + 1, msg=msg)))
7270 return errors
7271
Kevin McNee967dd2d22021-11-15 16:09:297272
Henrique Ferreiro2a4b55942021-11-29 23:45:367273def CheckAssertAshOnlyCode(input_api, output_api):
7274 """Errors if a BUILD.gn file in an ash/ directory doesn't include
Georg Neis94f87f02024-10-22 08:20:137275 assert(is_chromeos).
7276 For a transition period, assert(is_chromeos_ash) is also accepted.
Henrique Ferreiro2a4b55942021-11-29 23:45:367277 """
7278
7279 def FileFilter(affected_file):
7280 """Includes directories known to be Ash only."""
7281 return input_api.FilterSourceFile(
7282 affected_file,
7283 files_to_check=(
7284 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
7285 r'.*/ash/.*BUILD\.gn'), # Any path component.
7286 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
7287
7288 errors = []
Georg Neis94f87f02024-10-22 08:20:137289 pattern = input_api.re.compile(r'assert\(is_chromeos(_ash)?\b')
Jameson Thies0ce669f2021-12-09 15:56:567290 for f in input_api.AffectedFiles(include_deletes=False,
7291 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:367292 if (not pattern.search(input_api.ReadFile(f))):
7293 errors.append(
7294 output_api.PresubmitError(
Georg Neis94f87f02024-10-22 08:20:137295 'Please add assert(is_chromeos) to %s. If that\'s not '
7296 'possible, please create an issue and add a comment such '
Alison Galed6b25fe2024-04-17 13:59:047297 'as:\n # TODO(crbug.com/XXX): add '
Georg Neis94f87f02024-10-22 08:20:137298 'assert(is_chromeos) when ...' % f.LocalPath()))
Henrique Ferreiro2a4b55942021-11-29 23:45:367299 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:277300
7301
Kalvin Lee84ad17a2023-09-25 11:14:417302def _IsMiraclePtrDisallowed(input_api, affected_file):
Sam Maiera6e76d72022-02-11 21:43:507303 path = affected_file.LocalPath()
7304 if not _IsCPlusPlusFile(input_api, path):
7305 return False
7306
Bartek Nowierski49b1a452024-06-08 00:24:357307 # Renderer-only code is generally allowed to use MiraclePtr. These
7308 # directories, however, are specifically disallowed, for perf reasons.
Kalvin Lee84ad17a2023-09-25 11:14:417309 if ("third_party/blink/renderer/core/" in path
7310 or "third_party/blink/renderer/platform/heap/" in path
Bartek Nowierski49b1a452024-06-08 00:24:357311 or "third_party/blink/renderer/platform/wtf/" in path
7312 or "third_party/blink/renderer/platform/fonts/" in path):
7313 return True
7314
7315 # The below paths are an explicitly listed subset of Renderer-only code,
7316 # because the plan is to Oilpanize it.
7317 # TODO(crbug.com/330759291): Remove once Oilpanization is completed or
7318 # abandoned.
7319 if ("third_party/blink/renderer/core/paint/" in path
7320 or "third_party/blink/renderer/platform/graphics/compositing/" in path
7321 or "third_party/blink/renderer/platform/graphics/paint/" in path):
Sam Maiera6e76d72022-02-11 21:43:507322 return True
7323
Sam Maiera6e76d72022-02-11 21:43:507324 # We assume that everything else may be used outside of Renderer processes.
Lukasz Anforowicz7016d05e2021-11-30 03:56:277325 return False
7326
Alison Galed6b25fe2024-04-17 13:59:047327# TODO(crbug.com/40206238): Remove these checks, once they are replaced
Lukasz Anforowicz7016d05e2021-11-30 03:56:277328# by the Chromium Clang Plugin (which will be preferable because it will
7329# 1) report errors earlier - at compile-time and 2) cover more rules).
7330def CheckRawPtrUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507331 """Rough checks that raw_ptr<T> usage guidelines are followed."""
7332 errors = []
7333 # The regex below matches "raw_ptr<" following a word boundary, but not in a
7334 # C++ comment.
7335 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
Kalvin Lee84ad17a2023-09-25 11:14:417336 file_filter = lambda f: _IsMiraclePtrDisallowed(input_api, f)
Sam Maiera6e76d72022-02-11 21:43:507337 for f, line_num, line in input_api.RightHandSideLines(file_filter):
7338 if raw_ptr_matcher.search(line):
7339 errors.append(
7340 output_api.PresubmitError(
7341 'Problem on {path}:{line} - '\
Kalvin Lee84ad17a2023-09-25 11:14:417342 'raw_ptr<T> should not be used in this renderer code '\
Sam Maiera6e76d72022-02-11 21:43:507343 '(as documented in the "Pointers to unprotected memory" '\
7344 'section in //base/memory/raw_ptr.md)'.format(
7345 path=f.LocalPath(), line=line_num)))
7346 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:567347
mikt9337567c2023-09-08 18:38:177348def CheckAdvancedMemorySafetyChecksUsage(input_api, output_api):
7349 """Checks that ADVANCED_MEMORY_SAFETY_CHECKS() macro is neither added nor
7350 removed as it is managed by the memory safety team internally.
7351 Do not add / remove it manually."""
7352 paths = set([])
7353 # The regex below matches "ADVANCED_MEMORY_SAFETY_CHECKS(" following a word
7354 # boundary, but not in a C++ comment.
7355 macro_matcher = input_api.re.compile(
7356 r'^((?!//).)*\bADVANCED_MEMORY_SAFETY_CHECKS\(', input_api.re.MULTILINE)
7357 for f in input_api.AffectedFiles():
7358 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
7359 continue
7360 if macro_matcher.search(f.GenerateScmDiff()):
7361 paths.add(f.LocalPath())
7362 if not paths:
7363 return []
7364 return [output_api.PresubmitPromptWarning(
7365 'ADVANCED_MEMORY_SAFETY_CHECKS() macro is managed by ' \
7366 'the memory safety team (chrome-memory-safety@). ' \
7367 'Please contact us to add/delete the uses of the macro.',
7368 paths)]
Henrique Ferreirof9819f2e32021-11-30 13:31:567369
7370def CheckPythonShebang(input_api, output_api):
7371 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
7372 system-wide python.
7373 """
7374 errors = []
7375 sources = lambda affected_file: input_api.FilterSourceFile(
7376 affected_file,
7377 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
7378 r'third_party/blink/web_tests/external/') + input_api.
7379 DEFAULT_FILES_TO_SKIP),
7380 files_to_check=[r'.*\.py$'])
7381 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:277382 for line_num, line in f.ChangedContents():
7383 if line_num == 1 and line.startswith('#!/usr/bin/python'):
7384 errors.append(f.LocalPath())
7385 break
Henrique Ferreirof9819f2e32021-11-30 13:31:567386
7387 result = []
7388 for file in errors:
7389 result.append(
7390 output_api.PresubmitError(
7391 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
7392 file))
7393 return result
James Shen81cc0e22022-06-15 21:10:457394
7395
7396def CheckBatchAnnotation(input_api, output_api):
7397 """Checks that tests have either @Batch or @DoNotBatch annotation. If this
7398 is not an instrumentation test, disregard."""
7399
7400 batch_annotation = input_api.re.compile(r'^\s*@Batch')
7401 do_not_batch_annotation = input_api.re.compile(r'^\s*@DoNotBatch')
7402 robolectric_test = input_api.re.compile(r'[rR]obolectric')
7403 test_class_declaration = input_api.re.compile(r'^\s*public\sclass.*Test')
7404 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
Mark Schillaci8ef0d872023-07-18 22:07:597405 test_annotation_declaration = input_api.re.compile(r'^\s*public\s@interface\s.*{')
James Shen81cc0e22022-06-15 21:10:457406
ckitagawae8fd23b2022-06-17 15:29:387407 missing_annotation_errors = []
7408 extra_annotation_errors = []
James Shen81cc0e22022-06-15 21:10:457409
7410 def _FilterFile(affected_file):
7411 return input_api.FilterSourceFile(
7412 affected_file,
7413 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
7414 files_to_check=[r'.*Test\.java$'])
7415
7416 for f in input_api.AffectedSourceFiles(_FilterFile):
7417 batch_matched = None
7418 do_not_batch_matched = None
7419 is_instrumentation_test = True
Mark Schillaci8ef0d872023-07-18 22:07:597420 test_annotation_declaration_matched = None
James Shen81cc0e22022-06-15 21:10:457421 for line in f.NewContents():
7422 if robolectric_test.search(line) or uiautomator_test.search(line):
7423 # Skip Robolectric and UiAutomator tests.
7424 is_instrumentation_test = False
7425 break
7426 if not batch_matched:
7427 batch_matched = batch_annotation.search(line)
7428 if not do_not_batch_matched:
7429 do_not_batch_matched = do_not_batch_annotation.search(line)
7430 test_class_declaration_matched = test_class_declaration.search(
7431 line)
Mark Schillaci8ef0d872023-07-18 22:07:597432 test_annotation_declaration_matched = test_annotation_declaration.search(line)
7433 if test_class_declaration_matched or test_annotation_declaration_matched:
James Shen81cc0e22022-06-15 21:10:457434 break
Mark Schillaci8ef0d872023-07-18 22:07:597435 if test_annotation_declaration_matched:
7436 continue
James Shen81cc0e22022-06-15 21:10:457437 if (is_instrumentation_test and
7438 not batch_matched and
7439 not do_not_batch_matched):
Sam Maier4cef9242022-10-03 14:21:247440 missing_annotation_errors.append(str(f.LocalPath()))
ckitagawae8fd23b2022-06-17 15:29:387441 if (not is_instrumentation_test and
7442 (batch_matched or
7443 do_not_batch_matched)):
Sam Maier4cef9242022-10-03 14:21:247444 extra_annotation_errors.append(str(f.LocalPath()))
James Shen81cc0e22022-06-15 21:10:457445
7446 results = []
7447
ckitagawae8fd23b2022-06-17 15:29:387448 if missing_annotation_errors:
James Shen81cc0e22022-06-15 21:10:457449 results.append(
7450 output_api.PresubmitPromptWarning(
7451 """
Andrew Grieve43a5cf82023-09-08 15:09:467452A change was made to an on-device test that has neither been annotated with
7453@Batch nor @DoNotBatch. If this is a new test, please add the annotation. If
7454this is an existing test, please consider adding it if you are sufficiently
7455familiar with the test (but do so as a separate change).
7456
Jens Mueller2085ff82023-02-27 11:54:497457See https://source.chromium.org/chromium/chromium/src/+/main:docs/testing/batching_instrumentation_tests.md
ckitagawae8fd23b2022-06-17 15:29:387458""", missing_annotation_errors))
7459 if extra_annotation_errors:
7460 results.append(
7461 output_api.PresubmitPromptWarning(
7462 """
7463Robolectric tests do not need a @Batch or @DoNotBatch annotations.
7464""", extra_annotation_errors))
James Shen81cc0e22022-06-15 21:10:457465
7466 return results
Sam Maier4cef9242022-10-03 14:21:247467
7468
7469def CheckMockAnnotation(input_api, output_api):
7470 """Checks that we have annotated all Mockito.mock()-ed or Mockito.spy()-ed
7471 classes with @Mock or @Spy. If this is not an instrumentation test,
7472 disregard."""
7473
7474 # This is just trying to be approximately correct. We are not writing a
7475 # Java parser, so special cases like statically importing mock() then
7476 # calling an unrelated non-mockito spy() function will cause a false
7477 # positive.
7478 package_name = input_api.re.compile(r'^package\s+(\w+(?:\.\w+)+);')
7479 mock_static_import = input_api.re.compile(
7480 r'^import\s+static\s+org.mockito.Mockito.(?:mock|spy);')
7481 import_class = input_api.re.compile(r'import\s+((?:\w+\.)+)(\w+);')
7482 mock_annotation = input_api.re.compile(r'^\s*@(?:Mock|Spy)')
7483 field_type = input_api.re.compile(r'(\w+)(?:<\w+>)?\s+\w+\s*(?:;|=)')
7484 mock_or_spy_function_call = r'(?:mock|spy)\(\s*(?:new\s*)?(\w+)(?:\.class|\()'
7485 fully_qualified_mock_function = input_api.re.compile(
7486 r'Mockito\.' + mock_or_spy_function_call)
7487 statically_imported_mock_function = input_api.re.compile(
7488 r'\W' + mock_or_spy_function_call)
7489 robolectric_test = input_api.re.compile(r'[rR]obolectric')
7490 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
7491
7492 def _DoClassLookup(class_name, class_name_map, package):
7493 found = class_name_map.get(class_name)
7494 if found is not None:
7495 return found
7496 else:
7497 return package + '.' + class_name
7498
7499 def _FilterFile(affected_file):
7500 return input_api.FilterSourceFile(
7501 affected_file,
7502 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
7503 files_to_check=[r'.*Test\.java$'])
7504
7505 mocked_by_function_classes = set()
7506 mocked_by_annotation_classes = set()
7507 class_to_filename = {}
7508 for f in input_api.AffectedSourceFiles(_FilterFile):
7509 mock_function_regex = fully_qualified_mock_function
7510 next_line_is_annotated = False
7511 fully_qualified_class_map = {}
7512 package = None
7513
7514 for line in f.NewContents():
7515 if robolectric_test.search(line) or uiautomator_test.search(line):
7516 # Skip Robolectric and UiAutomator tests.
7517 break
7518
7519 m = package_name.search(line)
7520 if m:
7521 package = m.group(1)
7522 continue
7523
7524 if mock_static_import.search(line):
7525 mock_function_regex = statically_imported_mock_function
7526 continue
7527
7528 m = import_class.search(line)
7529 if m:
7530 fully_qualified_class_map[m.group(2)] = m.group(1) + m.group(2)
7531 continue
7532
7533 if next_line_is_annotated:
7534 next_line_is_annotated = False
7535 fully_qualified_class = _DoClassLookup(
7536 field_type.search(line).group(1), fully_qualified_class_map,
7537 package)
7538 mocked_by_annotation_classes.add(fully_qualified_class)
7539 continue
7540
7541 if mock_annotation.search(line):
Sam Maierb8a66a02023-10-10 13:50:557542 field_type_search = field_type.search(line)
7543 if field_type_search:
7544 fully_qualified_class = _DoClassLookup(
7545 field_type_search.group(1), fully_qualified_class_map,
7546 package)
7547 mocked_by_annotation_classes.add(fully_qualified_class)
7548 else:
7549 next_line_is_annotated = True
Sam Maier4cef9242022-10-03 14:21:247550 continue
7551
7552 m = mock_function_regex.search(line)
7553 if m:
7554 fully_qualified_class = _DoClassLookup(m.group(1),
7555 fully_qualified_class_map, package)
7556 # Skipping builtin classes, since they don't get optimized.
7557 if fully_qualified_class.startswith(
7558 'android.') or fully_qualified_class.startswith(
7559 'java.'):
7560 continue
7561 class_to_filename[fully_qualified_class] = str(f.LocalPath())
7562 mocked_by_function_classes.add(fully_qualified_class)
7563
7564 results = []
7565 missed_classes = mocked_by_function_classes - mocked_by_annotation_classes
7566 if missed_classes:
7567 error_locations = []
7568 for c in missed_classes:
7569 error_locations.append(c + ' in ' + class_to_filename[c])
7570 results.append(
7571 output_api.PresubmitPromptWarning(
7572 """
7573Mockito.mock()/spy() cause issues with our Java optimizer. You have 3 options:
75741) If the mocked variable can be a class member, annotate the member with
7575 @Mock/@Spy.
75762) If the mocked variable cannot be a class member, create a dummy member
7577 variable of that type, annotated with @Mock/@Spy. This dummy does not need
7578 to be used or initialized in any way.
75793) If the mocked type is definitely not going to be optimized, whether it's a
7580 builtin type which we don't ship, or a class you know R8 will treat
7581 specially, you can ignore this warning.
7582""", error_locations))
7583
7584 return results
Mike Dougherty1b8be712022-10-20 00:15:137585
7586def CheckNoJsInIos(input_api, output_api):
7587 """Checks to make sure that JavaScript files are not used on iOS."""
7588
7589 def _FilterFile(affected_file):
7590 return input_api.FilterSourceFile(
7591 affected_file,
7592 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP +
Daniel White44b8bd02023-08-22 16:20:367593 (r'^ios/third_party/*', r'^ios/tools/*', r'^third_party/*',
7594 r'^components/autofill/ios/form_util/resources/*'),
Mike Dougherty1b8be712022-10-20 00:15:137595 files_to_check=[r'^ios/.*\.js$', r'.*/ios/.*\.js$'])
7596
Mike Dougherty4d1050b2023-03-14 15:59:537597 deleted_files = []
7598
7599 # Collect filenames of all removed JS files.
Arthur Sonzognic66e9c82024-04-23 07:53:047600 for f in input_api.AffectedFiles(file_filter=_FilterFile):
Mike Dougherty4d1050b2023-03-14 15:59:537601 local_path = f.LocalPath()
7602
7603 if input_api.os_path.splitext(local_path)[1] == '.js' and f.Action() == 'D':
7604 deleted_files.append(input_api.os_path.basename(local_path))
7605
Mike Dougherty1b8be712022-10-20 00:15:137606 error_paths = []
Mike Dougherty4d1050b2023-03-14 15:59:537607 moved_paths = []
Mike Dougherty1b8be712022-10-20 00:15:137608 warning_paths = []
7609
7610 for f in input_api.AffectedSourceFiles(_FilterFile):
7611 local_path = f.LocalPath()
7612
7613 if input_api.os_path.splitext(local_path)[1] == '.js':
7614 if f.Action() == 'A':
Mike Dougherty4d1050b2023-03-14 15:59:537615 if input_api.os_path.basename(local_path) in deleted_files:
7616 # This script was probably moved rather than newly created.
7617 # Present a warning instead of an error for these cases.
7618 moved_paths.append(local_path)
7619 else:
7620 error_paths.append(local_path)
Mike Dougherty1b8be712022-10-20 00:15:137621 elif f.Action() != 'D':
7622 warning_paths.append(local_path)
7623
7624 results = []
7625
7626 if warning_paths:
7627 results.append(output_api.PresubmitPromptWarning(
7628 'TypeScript is now fully supported for iOS feature scripts. '
7629 'Consider converting JavaScript files to TypeScript. See '
7630 '//ios/web/public/js_messaging/README.md for more details.',
7631 warning_paths))
7632
Mike Dougherty4d1050b2023-03-14 15:59:537633 if moved_paths:
7634 results.append(output_api.PresubmitPromptWarning(
7635 'Do not use JavaScript on iOS for new files as TypeScript is '
7636 'fully supported. (If this is a moved file, you may leave the '
7637 'script unconverted.) See //ios/web/public/js_messaging/README.md '
7638 'for help using scripts on iOS.', moved_paths))
7639
Mike Dougherty1b8be712022-10-20 00:15:137640 if error_paths:
7641 results.append(output_api.PresubmitError(
7642 'Do not use JavaScript on iOS as TypeScript is fully supported. '
7643 'See //ios/web/public/js_messaging/README.md for help using '
7644 'scripts on iOS.', error_paths))
7645
7646 return results
Hans Wennborg23a81d52023-03-24 16:38:137647
7648def CheckLibcxxRevisionsMatch(input_api, output_api):
7649 """Check to make sure the libc++ version matches across deps files."""
Andrew Grieve21bb6792023-03-27 19:06:487650 # Disable check for changes to sub-repositories.
7651 if input_api.PresubmitLocalPath() != input_api.change.RepositoryRoot():
Sam Maierb926c58c2023-08-08 19:58:257652 return []
Hans Wennborg23a81d52023-03-24 16:38:137653
7654 DEPS_FILES = [ 'DEPS', 'buildtools/deps_revisions.gni' ]
7655
7656 file_filter = lambda f: f.LocalPath().replace(
7657 input_api.os_path.sep, '/') in DEPS_FILES
7658 changed_deps_files = input_api.AffectedFiles(file_filter=file_filter)
7659 if not changed_deps_files:
7660 return []
7661
7662 def LibcxxRevision(file):
7663 file = input_api.os_path.join(input_api.PresubmitLocalPath(),
7664 *file.split('/'))
7665 return input_api.re.search(
7666 r'libcxx_revision.*[:=].*[\'"](\w+)[\'"]',
7667 input_api.ReadFile(file)).group(1)
7668
7669 if len(set([LibcxxRevision(f) for f in DEPS_FILES])) == 1:
7670 return []
7671
7672 return [output_api.PresubmitError(
7673 'libcxx_revision not equal across %s' % ', '.join(DEPS_FILES),
7674 changed_deps_files)]
Arthur Sonzogni7109bd32023-10-03 10:34:427675
7676
7677def CheckDanglingUntriaged(input_api, output_api):
7678 """Warn developers adding DanglingUntriaged raw_ptr."""
7679
7680 # Ignore during git presubmit --all.
7681 #
7682 # This would be too costly, because this would check every lines of every
7683 # C++ files. Check from _BANNED_CPP_FUNCTIONS are also reading the whole
7684 # source code, but only once to apply every checks. It seems the bots like
7685 # `win-presubmit` are particularly sensitive to reading the files. Adding
7686 # this check caused the bot to run 2x longer. See https://crbug.com/1486612.
7687 if input_api.no_diffs:
Arthur Sonzogni9eafd222023-11-10 08:50:397688 return []
Arthur Sonzogni7109bd32023-10-03 10:34:427689
7690 def FilterFile(file):
7691 return input_api.FilterSourceFile(
7692 file,
7693 files_to_check=[r".*\.(h|cc|cpp|cxx|m|mm)$"],
7694 files_to_skip=[r"^base/allocator.*"],
7695 )
7696
7697 count = 0
Arthur Sonzognic66e9c82024-04-23 07:53:047698 for f in input_api.AffectedFiles(file_filter=FilterFile):
Arthur Sonzogni9eafd222023-11-10 08:50:397699 count -= sum([l.count("DanglingUntriaged") for l in f.OldContents()])
7700 count += sum([l.count("DanglingUntriaged") for l in f.NewContents()])
Arthur Sonzogni7109bd32023-10-03 10:34:427701
7702 # Most likely, nothing changed:
7703 if count == 0:
7704 return []
7705
7706 # Congrats developers for improving it:
7707 if count < 0:
Arthur Sonzogni9eafd222023-11-10 08:50:397708 message = f"DanglingUntriaged pointers removed: {-count}\nThank you!"
Arthur Sonzogni7109bd32023-10-03 10:34:427709 return [output_api.PresubmitNotifyResult(message)]
7710
7711 # Check for 'DanglingUntriaged-notes' in the description:
7712 notes_regex = input_api.re.compile("DanglingUntriaged-notes[:=]")
7713 if any(
7714 notes_regex.match(line)
7715 for line in input_api.change.DescriptionText().splitlines()):
7716 return []
7717
7718 # Check for DanglingUntriaged-notes in the git footer:
7719 if input_api.change.GitFootersFromDescription().get(
7720 "DanglingUntriaged-notes", []):
7721 return []
7722
7723 message = (
Arthur Sonzogni9eafd222023-11-10 08:50:397724 "Unexpected new occurrences of `DanglingUntriaged` detected. Please\n" +
7725 "avoid adding new ones\n" +
7726 "\n" +
7727 "See documentation:\n" +
7728 "https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr.md\n" +
7729 "\n" +
7730 "See also the guide to fix dangling pointers:\n" +
7731 "https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr_guide.md\n" +
7732 "\n" +
7733 "To disable this warning, please add in the commit description:\n" +
Alex Gough26dcd852023-12-22 16:47:197734 "DanglingUntriaged-notes: <rationale for new untriaged dangling " +
Arthur Sonzogni9eafd222023-11-10 08:50:397735 "pointers>"
Arthur Sonzogni7109bd32023-10-03 10:34:427736 )
7737 return [output_api.PresubmitPromptWarning(message)]
Jan Keitel77be7522023-10-12 20:40:497738
7739def CheckInlineConstexprDefinitionsInHeaders(input_api, output_api):
7740 """Checks that non-static constexpr definitions in headers are inline."""
7741 # In a properly formatted file, constexpr definitions inside classes or
7742 # structs will have additional whitespace at the beginning of the line.
7743 # The pattern looks for variables initialized as constexpr kVar = ...; or
7744 # constexpr kVar{...};
7745 # The pattern does not match expressions that have braces in kVar to avoid
7746 # matching constexpr functions.
7747 pattern = input_api.re.compile(r'^constexpr (?!inline )[^\(\)]*[={]')
7748 attribute_pattern = input_api.re.compile(r'(\[\[[a-zA-Z_:]+\]\]|[A-Z]+[A-Z_]+) ')
7749 problems = []
7750 for f in input_api.AffectedFiles():
7751 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
7752 continue
7753
7754 for line_number, line in f.ChangedContents():
7755 line = attribute_pattern.sub('', line)
7756 if pattern.search(line):
7757 problems.append(
7758 f"{f.LocalPath()}: {line_number}\n {line}")
7759
7760 if problems:
7761 return [
7762 output_api.PresubmitPromptWarning(
7763 'Consider inlining constexpr variable definitions in headers '
7764 'outside of classes to avoid unnecessary copies of the '
7765 'constant. See https://abseil.io/tips/168 for more details.',
7766 problems)
7767 ]
7768 else:
7769 return []
Alison Galed6b25fe2024-04-17 13:59:047770
7771def CheckTodoBugReferences(input_api, output_api):
7772 """Checks that bugs in TODOs use updated issue tracker IDs."""
7773
7774 files_to_skip = ['PRESUBMIT_test.py']
7775
7776 def _FilterFile(affected_file):
7777 return input_api.FilterSourceFile(
7778 affected_file,
7779 files_to_skip=files_to_skip)
7780
7781 # Monorail bug IDs are all less than or equal to 1524553 so check that all
7782 # bugs in TODOs are greater than that value.
7783 pattern = input_api.re.compile(r'.*TODO\([^\)0-9]*([0-9]+)\).*')
7784 problems = []
7785 for f in input_api.AffectedSourceFiles(_FilterFile):
7786 for line_number, line in f.ChangedContents():
7787 match = pattern.match(line)
7788 if match and int(match.group(1)) <= 1524553:
7789 problems.append(
7790 f"{f.LocalPath()}: {line_number}\n {line}")
7791
7792 if problems:
7793 return [
7794 output_api.PresubmitPromptWarning(
Alison Galecb598de52024-04-26 17:03:257795 'TODOs should use the new Chromium Issue Tracker IDs which can '
7796 'be found by navigating to the bug. See '
7797 'https://crbug.com/336778624 for more details.',
Alison Galed6b25fe2024-04-17 13:59:047798 problems)
7799 ]
7800 else:
7801 return []