blob: fada61c7cbeb83f02a00c013bb8d00a522b6427b [file] [log] [blame]
Avi Drissman24976592022-09-12 15:24:311# Copyright 2012 The Chromium Authors
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
Daniel Chengd88244472022-05-16 09:08:477See https://www.chromium.org/developers/how-tos/depottools/presubmit-scripts/
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d1982009-02-19 16:33:129"""
Daniel Chenga44a1bcd2022-03-15 20:00:1510
Daniel Chenga37c03db2022-05-12 17:20:3411from typing import Callable
Daniel Chenga44a1bcd2022-03-15 20:00:1512from typing import Optional
13from typing import Sequence
mikt19226ff22024-08-27 05:28:2114from typing import Tuple
Daniel Chenga44a1bcd2022-03-15 20:00:1515from dataclasses import dataclass
16
Saagar Sanghavifceeaae2020-08-12 16:40:3617PRESUBMIT_VERSION = '2.0.0'
[email protected]eea609a2011-11-18 13:10:1218
Dirk Prankee3c9c62d2021-05-18 18:35:5919
[email protected]379e7dd2010-01-28 17:39:2120_EXCLUDED_PATHS = (
Bruce Dawson7f8566b2022-05-06 16:22:1821 # Generated file
Bruce Dawson40fece62022-09-16 19:58:3122 (r"chrome/android/webapk/shell_apk/src/org/chromium"
23 r"/webapk/lib/runtime_library/IWebApkApi.java"),
Mila Greene3aa7222021-09-07 16:34:0824 # File needs to write to stdout to emulate a tool it's replacing.
Bruce Dawson40fece62022-09-16 19:58:3125 r"chrome/updater/mac/keystone/ksadmin.mm",
Ilya Shermane8a7d2d2020-07-25 04:33:4726 # Generated file.
Bruce Dawson40fece62022-09-16 19:58:3127 (r"^components/variations/proto/devtools/"
Ilya Shermanc167a962020-08-18 18:40:2628 r"client_variations.js"),
Bruce Dawson3bd976c2022-05-06 22:47:5229 # These are video files, not typescript.
Bruce Dawson40fece62022-09-16 19:58:3130 r"^media/test/data/.*.ts",
31 r"^native_client_sdksrc/build_tools/make_rules.py",
32 r"^native_client_sdk/src/build_tools/make_simple.py",
33 r"^native_client_sdk/src/tools/.*.mk",
34 r"^net/tools/spdyshark/.*",
35 r"^skia/.*",
36 r"^third_party/blink/.*",
37 r"^third_party/breakpad/.*",
Darwin Huangd74a9d32019-07-17 17:58:4638 # sqlite is an imported third party dependency.
Bruce Dawson40fece62022-09-16 19:58:3139 r"^third_party/sqlite/.*",
40 r"^v8/.*",
[email protected]3e4eb112011-01-18 03:29:5441 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5342 r".+_autogen\.h$",
Yue Shecf1380552022-08-23 20:59:2043 r".+_pb2(_grpc)?\.py$",
Bruce Dawson40fece62022-09-16 19:58:3144 r".+/pnacl_shim\.c$",
45 r"^gpu/config/.*_list_json\.cc$",
46 r"tools/md_browser/.*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1447 # Test pages for Maps telemetry tests.
Bruce Dawson40fece62022-09-16 19:58:3148 r"tools/perf/page_sets/maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5449 # Test pages for WebRTC telemetry tests.
Bruce Dawson40fece62022-09-16 19:58:3150 r"tools/perf/page_sets/webrtc_cases.*",
dpapad2efd4452023-04-06 01:43:4551 # Test file compared with generated output.
52 r"tools/polymer/tests/html_to_wrapper/.*.html.ts$",
dpapada45be36c2024-08-07 20:19:3553 # Third-party dependency frozen at a fixed version.
54 r"chrome/test/data/webui/chromeos/chai_v4.js$",
[email protected]4306417642009-06-11 00:33:4055)
[email protected]ca8d1982009-02-19 16:33:1256
John Abd-El-Malek759fea62021-03-13 03:41:1457_EXCLUDED_SET_NO_PARENT_PATHS = (
58 # It's for historical reasons that blink isn't a top level directory, where
59 # it would be allowed to have "set noparent" to avoid top level owners
60 # accidentally +1ing changes.
61 'third_party/blink/OWNERS',
62)
63
wnwenbdc444e2016-05-25 13:44:1564
[email protected]06e6d0ff2012-12-11 01:36:4465# Fragment of a regular expression that matches C++ and Objective-C++
66# implementation files.
67_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
68
wnwenbdc444e2016-05-25 13:44:1569
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1970# Fragment of a regular expression that matches C++ and Objective-C++
71# header files.
72_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
73
74
Aleksey Khoroshilov9b28c032022-06-03 16:35:3275# Paths with sources that don't use //base.
76_NON_BASE_DEPENDENT_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:3177 r"^chrome/browser/browser_switcher/bho/",
78 r"^tools/win/",
Aleksey Khoroshilov9b28c032022-06-03 16:35:3279)
80
81
[email protected]06e6d0ff2012-12-11 01:36:4482# Regular expression that matches code only used for test binaries
83# (best effort).
84_TEST_CODE_EXCLUDED_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:3185 r'.*/(fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
Marijn Kruisselbrink2a2d5fc2024-05-15 15:23:4986 # Test support files, like:
87 # foo_test_support.cc
88 # bar_test_util_linux.cc (suffix)
89 # baz_test_base.cc
90 r'.+_test_(base|support|util)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
James Cook1b4dc132021-03-09 22:45:1391 # Test suite files, like:
92 # foo_browsertest.cc
93 # bar_unittest_mac.cc (suffix)
94 # baz_unittests.cc (plural)
95 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(s)?(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1296 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1897 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
Victor Hugo Vianna Silvac22e0202021-06-09 19:46:2198 r'.+sync_service_impl_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Bruce Dawson40fece62022-09-16 19:58:3199 r'.*/(test|tool(s)?)/.*',
danakj89f47082020-09-02 17:53:43100 # content_shell is used for running content_browsertests.
Bruce Dawson40fece62022-09-16 19:58:31101 r'content/shell/.*',
danakj89f47082020-09-02 17:53:43102 # Web test harness.
Bruce Dawson40fece62022-09-16 19:58:31103 r'content/web_test/.*',
[email protected]7b054982013-11-27 00:44:47104 # Non-production example code.
Bruce Dawson40fece62022-09-16 19:58:31105 r'mojo/examples/.*',
[email protected]8176de12014-06-20 19:07:08106 # Launcher for running iOS tests on the simulator.
Bruce Dawson40fece62022-09-16 19:58:31107 r'testing/iossim/iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:41108 # EarlGrey app side code for tests.
Bruce Dawson40fece62022-09-16 19:58:31109 r'ios/.*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:17110 # Views Examples code
Bruce Dawson40fece62022-09-16 19:58:31111 r'ui/views/examples/.*',
Austin Sullivan33da70a2020-10-07 15:39:41112 # Chromium Codelab
Bruce Dawson40fece62022-09-16 19:58:31113 r'codelabs/*'
[email protected]06e6d0ff2012-12-11 01:36:44114)
[email protected]ca8d1982009-02-19 16:33:12115
Daniel Bratell609102be2019-03-27 20:53:21116_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:15117
[email protected]eea609a2011-11-18 13:10:12118_TEST_ONLY_WARNING = (
119 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:55120 'production code. If you are doing this from inside another method\n'
121 'named as *ForTesting(), then consider exposing things to have tests\n'
122 'make that same call directly.\n'
123 'If that is not possible, you may put a comment on the same line with\n'
124 ' // IN-TEST \n'
125 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
126 'method and can be ignored. Do not do this inside production code.\n'
127 'The android-binary-size trybot will block if the method exists in the\n'
Yulun Zeng08d7d8c2024-02-01 18:46:54128 'release apk.\n'
129 'Note: this warning might be a false positive (crbug.com/1196548).')
[email protected]eea609a2011-11-18 13:10:12130
131
Daniel Chenga44a1bcd2022-03-15 20:00:15132@dataclass
133class BanRule:
Daniel Chenga37c03db2022-05-12 17:20:34134 # String pattern. If the pattern begins with a slash, the pattern will be
135 # treated as a regular expression instead.
136 pattern: str
137 # Explanation as a sequence of strings. Each string in the sequence will be
138 # printed on its own line.
mikt19226ff22024-08-27 05:28:21139 explanation: Tuple[str, ...]
Daniel Chenga37c03db2022-05-12 17:20:34140 # Whether or not to treat this ban as a fatal error. If unspecified,
141 # defaults to true.
142 treat_as_error: Optional[bool] = None
143 # Paths that should be excluded from the ban check. Each string is a regular
144 # expression that will be matched against the path of the file being checked
145 # relative to the root of the source tree.
146 excluded_paths: Optional[Sequence[str]] = None
[email protected]cf9b78f2012-11-14 11:40:28147
Daniel Chenga44a1bcd2022-03-15 20:00:15148
Daniel Cheng917ce542022-03-15 20:46:57149_BANNED_JAVA_IMPORTS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15150 BanRule(
151 'import java.net.URI;',
152 (
153 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
154 ),
155 excluded_paths=(
156 (r'net/android/javatests/src/org/chromium/net/'
157 'AndroidProxySelectorTest\.java'),
158 r'components/cronet/',
159 r'third_party/robolectric/local/',
160 ),
Michael Thiessen44457642020-02-06 00:24:15161 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15162 BanRule(
163 'import android.annotation.TargetApi;',
164 (
165 'Do not use TargetApi, use @androidx.annotation.RequiresApi instead. '
166 'RequiresApi ensures that any calls are guarded by the appropriate '
167 'SDK_INT check. See https://crbug.com/1116486.',
168 ),
169 ),
170 BanRule(
Mohamed Heikal3d7a94c2023-03-28 16:55:24171 'import androidx.test.rule.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 Newsoneb6f5ce2022-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",
756 "chrome/services/file_util/public/cpp/zip_file_creator_browsertest.cc",
757 "chrome/test/chromedriver/chrome/web_view_impl.cc",
758 "chrome/test/chromedriver/log_replay/log_replay_socket.cc",
759 "chromecast/crash/linux/dump_info.cc",
760 "chromeos/ash/components/dbus/biod/fake_biod_client.cc",
761 "chromeos/ash/components/dbus/biod/fake_biod_client_unittest.cc",
762 "chromeos/ash/components/report/utils/time_utils.cc",
763 "chromeos/ash/services/device_sync/cryptauth_device_manager_impl.cc",
764 "chromeos/ash/services/device_sync/cryptauth_device_manager_impl_unittest.cc",
765 "chromeos/ash/services/secure_channel/ble_weave_packet_receiver.cc",
766 "chromeos/ash/services/secure_channel/bluetooth_helper_impl_unittest.cc",
767 "chromeos/process_proxy/process_proxy.cc",
768 "components/chromeos_camera/jpeg_encode_accelerator_unittest.cc",
769 "components/cronet/native/perftest/perf_test.cc",
770 "components/download/internal/common/download_item_impl_unittest.cc",
771 "components/gcm_driver/gcm_client_impl_unittest.cc",
772 "components/history/core/test/fake_web_history_service.cc",
773 "components/history_clusters/core/clustering_test_utils.cc",
774 "components/language/content/browser/ulp_language_code_locator/s2langquadtree_datatest.cc",
775 "components/live_caption/views/caption_bubble_controller_views.cc",
776 "components/offline_pages/core/offline_event_logger_unittest.cc",
777 "components/offline_pages/core/offline_page_model_event_logger.cc",
778 "components/omnibox/browser/history_quick_provider_performance_unittest.cc",
779 "components/omnibox/browser/in_memory_url_index_unittest.cc",
780 "components/payments/content/payment_method_manifest_table_unittest.cc",
781 "components/policy/core/common/cloud/device_management_service_unittest.cc",
782 "components/policy/core/common/schema.cc",
783 "components/sync_bookmarks/bookmark_model_observer_impl_unittest.cc",
784 "components/tracing/test/trace_event_perftest.cc",
785 "components/ui_devtools/views/overlay_agent_views.cc",
786 "components/url_pattern_index/closed_hash_map_unittest.cc",
787 "components/url_pattern_index/url_pattern_index_unittest.cc",
788 "content/browser/accessibility/accessibility_tree_formatter_blink.cc",
789 "content/browser/background_fetch/mock_background_fetch_delegate.cc",
790 "content/browser/background_fetch/storage/database_helpers.cc",
791 "content/browser/background_sync/background_sync_launcher_unittest.cc",
792 "content/browser/browser_child_process_host_impl.cc",
793 "content/browser/devtools/protocol/security_handler.cc",
794 "content/browser/notifications/platform_notification_context_trigger_unittest.cc",
795 "content/browser/renderer_host/input/touch_action_browsertest.cc",
796 "content/browser/renderer_host/render_process_host_impl.cc",
797 "content/browser/renderer_host/text_input_manager.cc",
798 "content/browser/sandbox_parameters_mac.mm",
799 "device/fido/mock_fido_device.cc",
800 "gpu/command_buffer/tests/gl_webgl_multi_draw_test.cc",
801 "gpu/config/gpu_control_list.cc",
802 "media/audio/win/core_audio_util_win.cc",
803 "media/gpu/android/media_codec_video_decoder.cc",
804 "media/gpu/vaapi/vaapi_wrapper.cc",
805 "remoting/host/linux/certificate_watcher_unittest.cc",
806 "testing/libfuzzer/fuzzers/url_parse_proto_fuzzer.cc",
807 "testing/libfuzzer/proto/url_proto_converter.cc",
808 "third_party/blink/renderer/core/css/parser/css_proto_converter.cc",
809 "third_party/blink/renderer/core/editing/ime/edit_context.cc",
810 "third_party/blink/renderer/platform/graphics/bitmap_image_test.cc",
811 "tools/binary_size/libsupersize/viewer/caspian/diff_test.cc",
812 "tools/binary_size/libsupersize/viewer/caspian/tree_builder_test.cc",
813 "ui/base/ime/win/tsf_text_store.cc",
814 "ui/ozone/platform/drm/gpu/hardware_display_plane.cc",
815 _THIRD_PARTY_EXCEPT_BLINK
816 ],
Daniel Bratell69334cc2019-03-26 11:07:45817 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15818 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53819 r'/#include <(cctype|ctype\.h|cwctype|wctype.h)>',
820 (
821 '<cctype>/<ctype.h>/<cwctype>/<wctype.h> are banned. Use',
822 '"third_party/abseil-cpp/absl/strings/ascii.h" instead.',
823 ),
824 True,
825 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting6f79b202023-08-09 21:25:41826 ),
827 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53828 r'/\bstd::shared_ptr\b',
829 ('std::shared_ptr is banned. Use scoped_refptr instead.', ),
830 True,
831 [
832 # Needed for interop with third-party library.
833 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
834 'array_buffer_contents\.(cc|h)',
835 '^third_party/blink/renderer/core/typed_arrays/dom_array_buffer\.cc',
836 '^third_party/blink/renderer/bindings/core/v8/' +
837 'v8_wasm_response_extensions.cc',
838 '^gin/array_buffer\.(cc|h)',
839 '^gin/per_isolate_data\.(cc|h)',
840 '^chrome/services/sharing/nearby/',
841 # Needed for interop with third-party library libunwindstack.
842 '^base/profiler/libunwindstack_unwinder_android\.(cc|h)',
843 '^base/profiler/native_unwinder_android_memory_regions_map_impl.(cc|h)',
844 # Needed for interop with third-party boringssl cert verifier
845 '^third_party/boringssl/',
846 '^net/cert/',
847 '^net/tools/cert_verify_tool/',
848 '^services/cert_verifier/',
849 '^components/certificate_transparency/',
850 '^components/media_router/common/providers/cast/certificate/',
851 # gRPC provides some C++ libraries that use std::shared_ptr<>.
852 '^chromeos/ash/services/libassistant/grpc/',
853 '^chromecast/cast_core/grpc',
854 '^chromecast/cast_core/runtime/browser',
855 '^ios/chrome/test/earl_grey/chrome_egtest_plugin_client\.(mm|h)',
856 # Fuchsia provides C++ libraries that use std::shared_ptr<>.
857 '^base/fuchsia/.*\.(cc|h)',
858 '.*fuchsia.*test\.(cc|h)',
859 # Clang plugins have different build config.
860 '^tools/clang/plugins/',
861 _THIRD_PARTY_EXCEPT_BLINK
862 ], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21863 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15864 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53865 r'/\bstd::weak_ptr\b',
866 ('std::weak_ptr is banned. Use base::WeakPtr instead.', ),
867 True,
868 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting991618a62019-06-17 22:00:09869 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15870 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53871 r'/\blong long\b',
872 ('long long is banned. Use [u]int64_t instead.', ),
873 False, # Only a warning since it is already used.
874 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21875 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15876 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53877 r'/\b(absl|std)::any\b',
878 (
879 '{absl,std}::any are banned due to incompatibility with the component ',
880 'build.',
881 ),
882 True,
883 # Not an error in third party folders, though it probably should be :)
884 [_THIRD_PARTY_EXCEPT_BLINK],
Daniel Chengc05fcc62022-01-12 16:54:29885 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15886 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53887 r'/\bstd::bind\b',
888 (
889 'std::bind() is banned because of lifetime risks. Use ',
890 'base::Bind{Once,Repeating}() instead.',
891 ),
892 True,
893 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21894 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15895 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53896 (r'/\bstd::(?:'
897 r'linear_congruential_engine|mersenne_twister_engine|'
898 r'subtract_with_carry_engine|discard_block_engine|'
899 r'independent_bits_engine|shuffle_order_engine|'
900 r'minstd_rand0?|mt19937(_64)?|ranlux(24|48)(_base)?|knuth_b|'
901 r'default_random_engine|'
902 r'random_device|'
903 r'seed_seq'
904 r')\b'),
905 (
906 'STL random number engines and generators are banned. Use the ',
907 'helpers in base/rand_util.h instead, e.g. base::RandBytes() or ',
908 'base::RandomBitGenerator.'
909 '',
910 'Please reach out to [email protected] if the base APIs are ',
911 'insufficient for your needs.',
912 ),
913 True,
914 [
915 # Not an error in third_party folders.
916 _THIRD_PARTY_EXCEPT_BLINK,
917 # Various tools which build outside of Chrome.
918 r'testing/libfuzzer',
Steinar H. Gundersone5689e42024-08-07 18:17:19919 r'testing/perf/confidence',
Daniel Cheng566634ff2024-06-29 14:56:53920 r'tools/android/io_benchmark/',
921 # Fuzzers are allowed to use standard library random number generators
922 # since fuzzing speed + reproducibility is important.
923 r'tools/ipc_fuzzer/',
924 r'.+_fuzzer\.cc$',
925 r'.+_fuzzertest\.cc$',
926 # TODO(https://crbug.com/1380528): These are all unsanctioned uses of
927 # the standard library's random number generators, and should be
928 # migrated to the //base equivalent.
929 r'ash/ambient/model/ambient_topic_queue\.cc',
930 r'base/allocator/partition_allocator/src/partition_alloc/partition_alloc_unittest\.cc',
931 r'base/ranges/algorithm_unittest\.cc',
932 r'base/test/launcher/test_launcher\.cc',
933 r'cc/metrics/video_playback_roughness_reporter_unittest\.cc',
934 r'chrome/browser/apps/app_service/metrics/website_metrics\.cc',
935 r'chrome/browser/ash/power/auto_screen_brightness/monotone_cubic_spline_unittest\.cc',
936 r'chrome/browser/ash/printing/zeroconf_printer_detector_unittest\.cc',
937 r'chrome/browser/nearby_sharing/contacts/nearby_share_contact_manager_impl_unittest\.cc',
938 r'chrome/browser/nearby_sharing/contacts/nearby_share_contacts_sorter_unittest\.cc',
939 r'chrome/browser/privacy_budget/mesa_distribution_unittest\.cc',
940 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
941 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
942 r'chrome/browser/win/conflicts/module_blocklist_cache_util_unittest\.cc',
943 r'chromeos/ash/components/memory/userspace_swap/swap_storage_unittest\.cc',
944 r'chromeos/ash/components/memory/userspace_swap/userspace_swap\.cc',
945 r'components/metrics/metrics_state_manager\.cc',
946 r'components/omnibox/browser/history_quick_provider_performance_unittest\.cc',
947 r'components/zucchini/disassembler_elf_unittest\.cc',
948 r'content/browser/webid/federated_auth_request_impl\.cc',
949 r'content/browser/webid/federated_auth_request_impl\.cc',
950 r'media/cast/test/utility/udp_proxy\.h',
951 r'sql/recover_module/module_unittest\.cc',
952 r'components/search_engines/template_url_prepopulate_data.cc',
953 # Do not add new entries to this list. If you have a use case which is
954 # not satisfied by the current APIs (i.e. you need an explicitly-seeded
955 # sequence, or stability of some sort is required), please contact
956 # [email protected].
957 ],
Daniel Cheng192683f2022-11-01 20:52:44958 ),
959 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53960 r'/\b(absl,std)::bind_front\b',
961 ('{absl,std}::bind_front() are banned. Use base::Bind{Once,Repeating}() '
962 'instead.', ),
963 True,
964 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12965 ),
966 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53967 r'/\bABSL_FLAG\b',
968 ('ABSL_FLAG is banned. Use base::CommandLine instead.', ),
969 True,
970 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12971 ),
972 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53973 r'/\babsl::c_',
974 (
975 'Abseil container utilities are banned. Use base/ranges/algorithm.h ',
976 'instead.',
977 ),
978 True,
979 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12980 ),
981 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53982 r'/\babsl::FixedArray\b',
983 ('absl::FixedArray is banned. Use base::FixedArray instead.', ),
984 True,
985 [
986 # base::FixedArray provides canonical access.
987 r'^base/types/fixed_array.h',
988 # Not an error in third_party folders.
989 _THIRD_PARTY_EXCEPT_BLINK,
990 ],
Peter Kasting431239a2023-09-29 03:11:44991 ),
992 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53993 r'/\babsl::FunctionRef\b',
994 ('absl::FunctionRef is banned. Use base::FunctionRef instead.', ),
995 True,
996 [
997 # base::Bind{Once,Repeating} references absl::FunctionRef to disallow
998 # interoperability.
999 r'^base/functional/bind_internal\.h',
1000 # base::FunctionRef is implemented on top of absl::FunctionRef.
1001 r'^base/functional/function_ref.*\..+',
1002 # Not an error in third_party folders.
1003 _THIRD_PARTY_EXCEPT_BLINK,
1004 ],
Peter Kasting4f35bfc2022-10-18 18:39:121005 ),
1006 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531007 r'/\babsl::(Insecure)?BitGen\b',
1008 ('absl random number generators are banned. Use the helpers in '
1009 'base/rand_util.h instead, e.g. base::RandBytes() or ',
1010 'base::RandomBitGenerator.'),
1011 True,
1012 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:121013 ),
1014 BanRule(
Peter Kasting3b77a0c2024-08-22 00:22:261015 pattern=
1016 r'/\babsl::(optional|nullopt|make_optional)\b',
1017 explanation=('absl::optional is banned. Use std::optional instead.', ),
1018 treat_as_error=True,
1019 excluded_paths=[
1020 _THIRD_PARTY_EXCEPT_BLINK,
1021 ]),
1022 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531023 r'/(\babsl::Span\b|#include <span>|\bstd::span\b)',
1024 (
1025 'absl::Span and std::span are not allowed ',
1026 '(https://crbug.com/1414652). Use base::span instead.',
1027 ),
1028 True,
1029 [
1030 # Included for conversions between base and std.
1031 r'base/containers/span.h',
1032 # Test base::span<> compatibility against std::span<>.
1033 r'base/containers/span_unittest.cc',
1034 # //base/numerics can't use base or absl. So it uses std.
1035 r'base/numerics/.*'
Lei Zhang1f9d9ec42024-06-20 18:42:271036
Daniel Cheng566634ff2024-06-29 14:56:531037 # Needed to use QUICHE API.
Ciara McMullinc029c8e2024-08-21 14:22:321038 r'android_webview/browser/ip_protection/.*',
Daniel Cheng566634ff2024-06-29 14:56:531039 r'chrome/browser/ip_protection/.*',
1040 r'components/ip_protection/.*',
1041 r'net/third_party/quiche/overrides/quiche_platform_impl/quiche_stack_trace_impl\.*',
1042 r'services/network/web_transport\.cc',
Lei Zhang1f9d9ec42024-06-20 18:42:271043
Daniel Cheng566634ff2024-06-29 14:56:531044 # Not an error in third_party folders.
1045 _THIRD_PARTY_EXCEPT_BLINK,
1046 ],
Peter Kasting4f35bfc2022-10-18 18:39:121047 ),
1048 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531049 r'/\babsl::StatusOr\b',
1050 ('absl::StatusOr is banned. Use base::expected instead.', ),
1051 True,
1052 [
1053 # Needed to use liburlpattern API.
1054 r'components/url_pattern/.*',
1055 r'services/network/shared_dictionary/simple_url_pattern_matcher\.cc',
1056 r'third_party/blink/renderer/core/url_pattern/.*',
1057 r'third_party/blink/renderer/modules/manifest/manifest_parser\.cc',
Lei Zhang1f9d9ec42024-06-20 18:42:271058
Daniel Cheng566634ff2024-06-29 14:56:531059 # Needed to use QUICHE API.
Ciara McMullinc029c8e2024-08-21 14:22:321060 r'android_webview/browser/ip_protection/.*',
Daniel Cheng566634ff2024-06-29 14:56:531061 r'chrome/browser/ip_protection/.*',
1062 r'components/ip_protection/.*',
Lei Zhang1f9d9ec42024-06-20 18:42:271063
Daniel Cheng566634ff2024-06-29 14:56:531064 # Needed to use MediaPipe API.
1065 r'components/media_effects/.*\.cc',
1066 # Not an error in third_party folders.
1067 _THIRD_PARTY_EXCEPT_BLINK
1068 ],
Peter Kasting4f35bfc2022-10-18 18:39:121069 ),
1070 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531071 r'/\babsl::StrFormat\b',
1072 (
1073 'absl::StrFormat() is not allowed yet (https://crbug.com/1371963). ',
1074 'Use base::StringPrintf() instead.',
1075 ),
1076 True,
1077 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:121078 ),
1079 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531080 r'/\babsl::(StrSplit|StrJoin|StrCat|StrAppend|Substitute|StrContains)\b',
1081 ('Abseil string utilities are banned. Use base/strings instead.', ),
1082 True,
1083 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:121084 ),
1085 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531086 r'/\babsl::(Mutex|CondVar|Notification|Barrier|BlockingCounter)\b',
1087 (
1088 'Abseil synchronization primitives are banned. Use',
1089 'base/synchronization instead.',
1090 ),
1091 True,
1092 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:121093 ),
1094 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531095 r'/\babsl::(Duration|Time|TimeZone|CivilDay)\b',
1096 ('Abseil\'s time library is banned. Use base/time instead.', ),
1097 True,
1098 [
1099 # Needed to use QUICHE API.
Ciara McMullinc029c8e2024-08-21 14:22:321100 r'android_webview/browser/ip_protection/.*',
Daniel Cheng566634ff2024-06-29 14:56:531101 r'chrome/browser/ip_protection/.*',
1102 r'components/ip_protection/.*',
Lei Zhang1f9d9ec42024-06-20 18:42:271103
Daniel Cheng566634ff2024-06-29 14:56:531104 # Needed to integrate with //third_party/nearby
1105 r'components/cross_device/nearby/system_clock.cc',
1106 _THIRD_PARTY_EXCEPT_BLINK # Not an error in third_party folders.
1107 ],
1108 ),
1109 BanRule(
1110 r'/#include <chrono>',
1111 ('<chrono> is banned. Use base/time instead.', ),
1112 True,
1113 [
1114 # Not an error in third_party folders:
1115 _THIRD_PARTY_EXCEPT_BLINK,
Daniel Cheng566634ff2024-06-29 14:56:531116 # This uses openscreen API depending on std::chrono.
1117 "components/openscreen_platform/task_runner.cc",
1118 ]),
1119 BanRule(
1120 r'/#include <exception>',
1121 ('Exceptions are banned and disabled in Chromium.', ),
1122 True,
1123 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1124 ),
1125 BanRule(
1126 r'/\bstd::function\b',
1127 ('std::function is banned. Use base::{Once,Repeating}Callback instead.',
1128 ),
1129 True,
1130 [
1131 # Has tests that template trait helpers don't unintentionally match
1132 # std::function.
1133 r'base/functional/callback_helpers_unittest\.cc',
1134 # Required to implement interfaces from the third-party perfetto
1135 # library.
1136 r'base/tracing/perfetto_task_runner\.cc',
1137 r'base/tracing/perfetto_task_runner\.h',
1138 # Needed for interop with the third-party nearby library type
1139 # location::nearby::connections::ResultCallback.
1140 'chrome/services/sharing/nearby/nearby_connections_conversions\.cc'
1141 # Needed for interop with the internal libassistant library.
1142 'chromeos/ash/services/libassistant/callback_utils\.h',
1143 # Needed for interop with Fuchsia fidl APIs.
1144 'fuchsia_web/webengine/browser/context_impl_browsertest\.cc',
1145 'fuchsia_web/webengine/browser/cookie_manager_impl_unittest\.cc',
1146 'fuchsia_web/webengine/browser/media_player_impl_unittest\.cc',
1147 # Required to interop with interfaces from the third-party ChromeML
1148 # library API.
1149 'services/on_device_model/ml/chrome_ml_api\.h',
1150 'services/on_device_model/ml/on_device_model_executor\.cc',
1151 'services/on_device_model/ml/on_device_model_executor\.h',
1152 # Required to interop with interfaces from the third-party perfetto
1153 # library.
1154 'services/tracing/public/cpp/perfetto/custom_event_recorder\.cc',
1155 'services/tracing/public/cpp/perfetto/perfetto_traced_process\.cc',
1156 'services/tracing/public/cpp/perfetto/perfetto_traced_process\.h',
1157 'services/tracing/public/cpp/perfetto/perfetto_tracing_backend\.cc',
1158 'services/tracing/public/cpp/perfetto/producer_client\.cc',
1159 'services/tracing/public/cpp/perfetto/producer_client\.h',
1160 'services/tracing/public/cpp/perfetto/producer_test_utils\.cc',
1161 'services/tracing/public/cpp/perfetto/producer_test_utils\.h',
1162 # Required for interop with the third-party webrtc library.
1163 'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.cc',
1164 'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.h',
1165 # TODO(https://crbug.com/1364577): Various uses that should be
1166 # migrated to something else.
1167 # Should use base::OnceCallback or base::RepeatingCallback.
1168 'base/allocator/dispatcher/initializer_unittest\.cc',
1169 'chrome/browser/ash/accessibility/speech_monitor\.cc',
1170 'chrome/browser/ash/accessibility/speech_monitor\.h',
1171 'chrome/browser/ash/login/ash_hud_login_browsertest\.cc',
1172 'chromecast/base/observer_unittest\.cc',
1173 'chromecast/browser/cast_web_view\.h',
1174 'chromecast/public/cast_media_shlib\.h',
1175 'device/bluetooth/floss/exported_callback_manager\.h',
1176 'device/bluetooth/floss/floss_dbus_client\.h',
1177 'device/fido/cable/v2_handshake_unittest\.cc',
1178 'device/fido/pin\.cc',
1179 'services/tracing/perfetto/test_utils\.h',
1180 # Should use base::FunctionRef.
1181 'chrome/browser/media/webrtc/test_stats_dictionary\.cc',
1182 'chrome/browser/media/webrtc/test_stats_dictionary\.h',
1183 'chromeos/ash/services/libassistant/device_settings_controller\.cc',
1184 'components/browser_ui/client_certificate/android/ssl_client_certificate_request\.cc',
1185 'components/gwp_asan/client/sampling_malloc_shims_unittest\.cc',
1186 'content/browser/font_unique_name_lookup/font_unique_name_lookup_unittest\.cc',
1187 # Does not need std::function at all.
1188 'components/omnibox/browser/autocomplete_result\.cc',
1189 'device/fido/win/webauthn_api\.cc',
1190 'media/audio/alsa/alsa_util\.cc',
1191 'media/remoting/stream_provider\.h',
1192 'sql/vfs_wrapper\.cc',
1193 # TODO(https://crbug.com/1364585): Remove usage and exception list
1194 # entries.
1195 'extensions/renderer/api/automation/automation_internal_custom_bindings\.cc',
1196 'extensions/renderer/api/automation/automation_internal_custom_bindings\.h',
1197 # TODO(https://crbug.com/1364579): Remove usage and exception list
1198 # entry.
1199 'ui/views/controls/focus_ring\.h',
Lei Zhang1f9d9ec42024-06-20 18:42:271200
Daniel Cheng566634ff2024-06-29 14:56:531201 # Various pre-existing uses in //tools that is low-priority to fix.
1202 'tools/binary_size/libsupersize/viewer/caspian/diff\.cc',
1203 'tools/binary_size/libsupersize/viewer/caspian/model\.cc',
1204 'tools/binary_size/libsupersize/viewer/caspian/model\.h',
1205 'tools/binary_size/libsupersize/viewer/caspian/tree_builder\.h',
1206 'tools/clang/base_bind_rewriters/BaseBindRewriters\.cpp',
Daniel Chenge5583e3c2022-09-22 00:19:411207
Daniel Cheng566634ff2024-06-29 14:56:531208 # Not an error in third_party folders.
1209 _THIRD_PARTY_EXCEPT_BLINK
1210 ],
Daniel Bratell609102be2019-03-27 20:53:211211 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151212 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531213 r'/#include <X11/',
1214 ('Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.', ),
1215 True,
1216 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Tom Andersona95e12042020-09-09 23:08:001217 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151218 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531219 r'/\bstd::ratio\b',
1220 ('std::ratio is banned by the Google Style Guide.', ),
1221 True,
1222 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:451223 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151224 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531225 r'/\bstd::aligned_alloc\b',
1226 (
1227 'std::aligned_alloc() is not yet allowed (crbug.com/1412818). Use ',
1228 'base::AlignedAlloc() instead.',
1229 ),
1230 True,
1231 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181232 ),
1233 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531234 r'/#include <(barrier|latch|semaphore|stop_token)>',
1235 ('The thread support library is banned. Use base/synchronization '
1236 'instead.', ),
1237 True,
1238 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181239 ),
1240 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531241 r'/\bstd::execution::(par|seq)\b',
1242 ('std::execution::(par|seq) is banned; they do not fit into '
1243 ' Chrome\'s threading model, and libc++ doesn\'t have full '
mikt19226ff22024-08-27 05:28:211244 'support.', ),
Daniel Cheng566634ff2024-06-29 14:56:531245 True,
1246 [_THIRD_PARTY_EXCEPT_BLINK],
Helmut Januschka7cc8a84f2024-02-07 22:50:411247 ),
1248 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531249 r'/\bstd::bit_cast\b',
1250 ('std::bit_cast is banned; use base::bit_cast instead for values and '
1251 'standard C++ casting when pointers are involved.', ),
1252 True,
1253 [
1254 # Don't warn in third_party folders.
1255 _THIRD_PARTY_EXCEPT_BLINK,
1256 # //base/numerics can't use base or absl.
1257 r'base/numerics/.*'
1258 ],
Avi Drissman70cb7f72023-12-12 17:44:371259 ),
1260 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531261 r'/\bstd::(c8rtomb|mbrtoc8)\b',
1262 ('std::c8rtomb() and std::mbrtoc8() are banned.', ),
1263 True,
1264 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181265 ),
1266 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531267 r'/\bchar8_t|std::u8string\b',
1268 (
1269 'char8_t and std::u8string are not yet allowed. Can you use [unsigned]',
1270 ' char and std::string instead?',
1271 ),
1272 True,
1273 [
1274 # The demangler does not use this type but needs to know about it.
1275 'base/third_party/symbolize/demangle\.cc',
1276 # Don't warn in third_party folders.
1277 _THIRD_PARTY_EXCEPT_BLINK
1278 ],
Peter Kastinge2c5ee82023-02-15 17:23:081279 ),
1280 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531281 r'/(\b(co_await|co_return|co_yield)\b|#include <coroutine>)',
1282 ('Coroutines are not yet allowed (https://crbug.com/1403840).', ),
1283 True,
1284 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081285 ),
1286 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531287 r'/^\s*(export\s|import\s+["<:\w]|module(;|\s+[:\w]))',
1288 ('Modules are disallowed for now due to lack of toolchain support.', ),
1289 True,
1290 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting69357dc2023-03-14 01:34:291291 ),
1292 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531293 r'/\[\[(\w*::)?no_unique_address\]\]',
1294 (
1295 '[[no_unique_address]] does not work as expected on Windows ',
1296 '(https://crbug.com/1414621). Use NO_UNIQUE_ADDRESS instead.',
1297 ),
1298 True,
1299 [
1300 # NO_UNIQUE_ADDRESS / PA_NO_UNIQUE_ADDRESS provide canonical access.
1301 r'^base/compiler_specific\.h',
1302 r'^base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/compiler_specific\.h',
1303 # Not an error in third_party folders.
1304 _THIRD_PARTY_EXCEPT_BLINK,
1305 ],
Peter Kasting8bc046d22023-11-14 00:38:031306 ),
1307 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531308 r'/#include <format>',
1309 ('<format> is not yet allowed. Use base::StringPrintf() instead.', ),
1310 True,
1311 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081312 ),
1313 BanRule(
Daniel Cheng89719222024-07-04 04:59:291314 pattern='std::views',
1315 explanation=(
1316 'Use of std::views is banned in Chrome. If you need this '
1317 'functionality, please contact [email protected].',
1318 ),
1319 treat_as_error=True,
1320 excluded_paths=[
1321 # Don't warn in third_party folders.
1322 _THIRD_PARTY_EXCEPT_BLINK
1323 ],
1324 ),
1325 BanRule(
1326 # Ban everything except specifically allowlisted constructs.
1327 pattern=r'/std::ranges::(?!' + '|'.join((
1328 # From https://en.cppreference.com/w/cpp/ranges:
1329 # Range access
1330 'begin',
1331 'end',
1332 'cbegin',
1333 'cend',
1334 'rbegin',
1335 'rend',
1336 'crbegin',
1337 'crend',
1338 'size',
1339 'ssize',
1340 'empty',
1341 'data',
1342 'cdata',
1343 # Range primitives
1344 'iterator_t',
1345 'const_iterator_t',
1346 'sentinel_t',
1347 'const_sentinel_t',
1348 'range_difference_t',
1349 'range_size_t',
1350 'range_value_t',
1351 'range_reference_t',
1352 'range_const_reference_t',
1353 'range_rvalue_reference_t',
1354 'range_common_reference_t',
1355 # Dangling iterator handling
1356 'dangling',
1357 'borrowed_iterator_t',
1358 # Banned: borrowed_subrange_t
1359 # Range concepts
1360 'range',
1361 'borrowed_range',
1362 'sized_range',
1363 'view',
1364 'input_range',
1365 'output_range',
1366 'forward_range',
1367 'bidirectional_range',
1368 'random_access_range',
1369 'contiguous_range',
1370 'common_range',
1371 'viewable_range',
1372 'constant_range',
1373 # Banned: Views
1374 # Banned: Range factories
1375 # Banned: Range adaptors
1376 # From https://en.cppreference.com/w/cpp/algorithm/ranges:
1377 # Constrained algorithms: non-modifying sequence operations
1378 'all_of',
1379 'any_of',
1380 'none_of',
1381 'for_each',
1382 'for_each_n',
1383 'count',
1384 'count_if',
1385 'mismatch',
1386 'equal',
1387 'lexicographical_compare',
1388 'find',
1389 'find_if',
1390 'find_if_not',
1391 'find_end',
1392 'find_first_of',
1393 'adjacent_find',
1394 'search',
1395 'search_n',
1396 # Constrained algorithms: modifying sequence operations
1397 'copy',
1398 'copy_if',
1399 'copy_n',
1400 'copy_backward',
1401 'move',
1402 'move_backward',
1403 'fill',
1404 'fill_n',
1405 'transform',
1406 'generate',
1407 'generate_n',
1408 'remove',
1409 'remove_if',
1410 'remove_copy',
1411 'remove_copy_if',
1412 'replace',
1413 'replace_if',
1414 'replace_copy',
1415 'replace_copy_if',
1416 'swap_ranges',
1417 'reverse',
1418 'reverse_copy',
1419 'rotate',
1420 'rotate_copy',
1421 'shuffle',
1422 'sample',
1423 'unique',
1424 'unique_copy',
1425 # Constrained algorithms: partitioning operations
1426 'is_partitioned',
1427 'partition',
1428 'partition_copy',
1429 'stable_partition',
1430 'partition_point',
1431 # Constrained algorithms: sorting operations
1432 'is_sorted',
1433 'is_sorted_until',
1434 'sort',
1435 'partial_sort',
1436 'partial_sort_copy',
1437 'stable_sort',
1438 'nth_element',
1439 # Constrained algorithms: binary search operations (on sorted ranges)
1440 'lower_bound',
1441 'upper_bound',
1442 'binary_search',
1443 'equal_range',
1444 # Constrained algorithms: set operations (on sorted ranges)
1445 'merge',
1446 'inplace_merge',
1447 'includes',
1448 'set_difference',
1449 'set_intersection',
1450 'set_symmetric_difference',
1451 'set_union',
1452 # Constrained algorithms: heap operations
1453 'is_heap',
1454 'is_heap_until',
1455 'make_heap',
1456 'push_heap',
1457 'pop_heap',
1458 'sort_heap',
1459 # Constrained algorithms: minimum/maximum operations
1460 'max',
1461 'max_element',
1462 'min',
1463 'min_element',
1464 'minmax',
1465 'minmax_element',
1466 'clamp',
1467 # Constrained algorithms: permutation operations
1468 'is_permutation',
1469 'next_permutation',
1470 'prev_premutation',
1471 # Constrained uninitialized memory algorithms
1472 'uninitialized_copy',
1473 'uninitialized_copy_n',
1474 'uninitialized_fill',
1475 'uninitialized_fill_n',
1476 'uninitialized_move',
1477 'uninitialized_move_n',
1478 'uninitialized_default_construct',
1479 'uninitialized_default_construct_n',
1480 'uninitialized_value_construct',
1481 'uninitialized_value_construct_n',
1482 'destroy',
1483 'destroy_n',
1484 'destroy_at',
1485 'construct_at',
1486 # Return types
1487 'in_fun_result',
1488 'in_in_result',
1489 'in_out_result',
1490 'in_in_out_result',
1491 'in_out_out_result',
1492 'min_max_result',
1493 'in_found_result',
danakj91c715b2024-07-10 13:24:261494 # From https://en.cppreference.com/w/cpp/iterator
1495 'advance',
1496 'distance',
1497 'next',
1498 'prev',
Daniel Cheng89719222024-07-04 04:59:291499 )) + r')\w+',
1500 explanation=(
1501 'Use of range views and associated helpers is banned in Chrome. '
1502 'If you need this functionality, please contact [email protected].',
1503 ),
1504 treat_as_error=True,
1505 excluded_paths=[
1506 # Don't warn in third_party folders.
1507 _THIRD_PARTY_EXCEPT_BLINK
1508 ],
Peter Kastinge2c5ee82023-02-15 17:23:081509 ),
1510 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531511 r'/#include <source_location>',
1512 ('<source_location> is not yet allowed. Use base/location.h instead.',
1513 ),
1514 True,
1515 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081516 ),
1517 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531518 r'/\bstd::to_address\b',
1519 (
1520 'std::to_address is banned because it is not guaranteed to be',
1521 'SFINAE-compatible. Use base::to_address from base/types/to_address.h',
1522 'instead.',
1523 ),
1524 True,
1525 [
1526 # Needed in base::to_address implementation.
1527 r'base/types/to_address.h',
1528 _THIRD_PARTY_EXCEPT_BLINK
1529 ], # Not an error in third_party folders.
Nick Diego Yamanee522ae82024-02-27 04:23:221530 ),
1531 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531532 r'/#include <syncstream>',
1533 ('<syncstream> is banned.', ),
1534 True,
1535 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181536 ),
1537 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531538 r'/\bRunMessageLoop\b',
1539 ('RunMessageLoop is deprecated, use RunLoop instead.', ),
1540 False,
1541 (),
Gabriel Charette147335ea2018-03-22 15:59:191542 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151543 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531544 'RunAllPendingInMessageLoop()',
1545 (
1546 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
1547 "if you're convinced you need this.",
1548 ),
1549 False,
1550 (),
Gabriel Charette147335ea2018-03-22 15:59:191551 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151552 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531553 'RunAllPendingInMessageLoop(BrowserThread',
1554 (
1555 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
1556 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
1557 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
1558 'async events instead of flushing threads.',
1559 ),
1560 False,
1561 (),
Gabriel Charette147335ea2018-03-22 15:59:191562 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151563 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531564 r'MessageLoopRunner',
1565 ('MessageLoopRunner is deprecated, use RunLoop instead.', ),
1566 False,
1567 (),
Gabriel Charette147335ea2018-03-22 15:59:191568 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151569 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531570 'GetDeferredQuitTaskForRunLoop',
1571 (
1572 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
1573 "gab@ if you found a use case where this is the only solution.",
1574 ),
1575 False,
1576 (),
Gabriel Charette147335ea2018-03-22 15:59:191577 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151578 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531579 'sqlite3_initialize(',
1580 (
1581 'Instead of calling sqlite3_initialize(), depend on //sql, ',
1582 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
1583 ),
1584 True,
1585 (
1586 r'^sql/initialization\.(cc|h)$',
1587 r'^third_party/sqlite/.*\.(c|cc|h)$',
1588 ),
Victor Costan3653df62018-02-08 21:38:161589 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151590 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531591 'CREATE VIEW',
1592 (
1593 'SQL views are disabled in Chromium feature code',
1594 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-views',
1595 ),
1596 True,
1597 (
1598 _THIRD_PARTY_EXCEPT_BLINK,
1599 # sql/ itself uses views when using memory-mapped IO.
1600 r'^sql/.*',
1601 # Various performance tools that do not build as part of Chrome.
1602 r'^infra/.*',
1603 r'^tools/perf.*',
1604 r'.*perfetto.*',
1605 ),
Austin Sullivand661ab52022-11-16 08:55:151606 ),
1607 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531608 'CREATE VIRTUAL TABLE',
1609 (
1610 'SQL virtual tables are disabled in Chromium feature code',
1611 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-virtual-tables',
1612 ),
1613 True,
1614 (
1615 _THIRD_PARTY_EXCEPT_BLINK,
1616 # sql/ itself uses virtual tables in the recovery module and tests.
1617 r'^sql/.*',
1618 # TODO(https://crbug.com/695592): Remove once WebSQL is deprecated.
1619 r'third_party/blink/web_tests/storage/websql/.*'
1620 # Various performance tools that do not build as part of Chrome.
1621 r'^tools/perf.*',
1622 r'.*perfetto.*',
1623 ),
Austin Sullivand661ab52022-11-16 08:55:151624 ),
1625 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531626 'std::random_shuffle',
1627 ('std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
1628 'base::RandomShuffle instead.'),
1629 True,
1630 (),
tzik5de2157f2018-05-08 03:42:471631 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151632 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531633 'ios/web/public/test/http_server',
1634 ('web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
1635 ),
1636 False,
1637 (),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:241638 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151639 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531640 'GetAddressOf',
1641 ('Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
1642 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
1643 'operator& is generally recommended. So always use operator& instead. ',
1644 'See http://crbug.com/914910 for more conversion guidance.'),
1645 True,
1646 (),
Robert Liao764c9492019-01-24 18:46:281647 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151648 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531649 'SHFileOperation',
1650 ('SHFileOperation was deprecated in Windows Vista, and there are less ',
1651 'complex functions to achieve the same goals. Use IFileOperation for ',
1652 'any esoteric actions instead.'),
1653 True,
1654 (),
Ben Lewisa9514602019-04-29 17:53:051655 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151656 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531657 'StringFromGUID2',
1658 ('StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
1659 'Use base::win::WStringFromGUID instead.'),
1660 True,
1661 (r'/base/win/win_util_unittest.cc', ),
Cliff Smolinsky81951642019-04-30 21:39:511662 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151663 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531664 'StringFromCLSID',
1665 ('StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
1666 'Use base::win::WStringFromGUID instead.'),
1667 True,
1668 (r'/base/win/win_util_unittest.cc', ),
Cliff Smolinsky81951642019-04-30 21:39:511669 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151670 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531671 'kCFAllocatorNull',
1672 (
1673 'The use of kCFAllocatorNull with the NoCopy creation of ',
1674 'CoreFoundation types is prohibited.',
1675 ),
1676 True,
1677 (),
Avi Drissman7382afa02019-04-29 23:27:131678 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151679 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531680 'mojo::ConvertTo',
1681 ('mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1682 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1683 'StringTraits if you would like to convert between custom types and',
1684 'the wire format of mojom types.'),
1685 False,
1686 (
1687 r'^fuchsia_web/webengine/browser/url_request_rewrite_rules_manager\.cc$',
1688 r'^fuchsia_web/webengine/url_request_rewrite_type_converters\.cc$',
1689 r'^third_party/blink/.*\.(cc|h)$',
1690 r'^content/renderer/.*\.(cc|h)$',
1691 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291692 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151693 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531694 'GetInterfaceProvider',
1695 ('InterfaceProvider is deprecated.',
1696 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1697 'or Platform::GetBrowserInterfaceBroker.'),
1698 False,
1699 (),
Oksana Zhuravlovac8222d22019-12-19 19:21:161700 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151701 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531702 'CComPtr',
1703 ('New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1704 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1705 'details.'),
1706 False,
1707 (),
Robert Liao1d78df52019-11-11 20:02:011708 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151709 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531710 r'/\b(IFACE|STD)METHOD_?\(',
1711 ('IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1712 'Instead, always use IFACEMETHODIMP in the declaration.'),
1713 False,
1714 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Xiaohan Wang72bd2ba2020-02-18 21:38:201715 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151716 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531717 'set_owned_by_client',
1718 ('set_owned_by_client is deprecated.',
1719 'views::View already owns the child views by default. This introduces ',
1720 'a competing ownership model which makes the code difficult to reason ',
1721 'about. See http://crbug.com/1044687 for more details.'),
1722 False,
1723 (),
Allen Bauer53b43fb12020-03-12 17:21:471724 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151725 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531726 'RemoveAllChildViewsWithoutDeleting',
1727 ('RemoveAllChildViewsWithoutDeleting is deprecated.',
1728 'This method is deemed dangerous as, unless raw pointers are re-added,',
1729 'calls to this method introduce memory leaks.'),
1730 False,
1731 (),
Peter Boström7ff41522021-07-29 03:43:271732 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151733 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531734 r'/\bTRACE_EVENT_ASYNC_',
1735 (
1736 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1737 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1738 ),
1739 False,
1740 (
1741 r'^base/trace_event/.*',
1742 r'^base/tracing/.*',
1743 ),
Eric Secklerbe6f48d2020-05-06 18:09:121744 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151745 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531746 r'/\bbase::debug::DumpWithoutCrashingUnthrottled[(][)]',
1747 (
1748 'base::debug::DumpWithoutCrashingUnthrottled() does not throttle',
1749 'dumps and may spam crash reports. Consider if the throttled',
1750 'variants suffice instead.',
1751 ),
1752 False,
1753 (),
Aditya Kushwah5a286b72022-02-10 04:54:431754 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151755 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531756 'RoInitialize',
1757 ('Improper use of [base::win]::RoInitialize() has been implicated in a ',
1758 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
1759 'instead. See http://crbug.com/1197722 for more information.'),
1760 True,
1761 (
1762 r'^base/win/scoped_winrt_initializer\.cc$',
1763 r'^third_party/abseil-cpp/absl/.*',
1764 ),
Robert Liao22f66a52021-04-10 00:57:521765 ),
Patrick Monettec343bb982022-06-01 17:18:451766 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531767 r'base::Watchdog',
1768 (
1769 'base::Watchdog is deprecated because it creates its own thread.',
1770 'Instead, manually start a timer on a SequencedTaskRunner.',
1771 ),
1772 False,
1773 (),
Patrick Monettec343bb982022-06-01 17:18:451774 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091775 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531776 'base::Passed',
1777 ('Do not use base::Passed. It is a legacy helper for capturing ',
1778 'move-only types with base::BindRepeating, but invoking the ',
1779 'resulting RepeatingCallback moves the captured value out of ',
1780 'the callback storage, and subsequent invocations may pass the ',
1781 'value in a valid but undefined state. Prefer base::BindOnce().',
1782 'See http://crbug.com/1326449 for context.'),
1783 False,
1784 (
1785 # False positive, but it is also fine to let bind internals reference
1786 # base::Passed.
1787 r'^base[\\/]functional[\\/]bind\.h',
1788 r'^base[\\/]functional[\\/]bind_internal\.h',
1789 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091790 ),
Daniel Cheng2248b332022-07-27 06:16:591791 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531792 r'base::Feature k',
1793 ('Please use BASE_DECLARE_FEATURE() or BASE_FEATURE() instead of ',
1794 'directly declaring/defining features.'),
1795 True,
1796 [
1797 # Implements BASE_DECLARE_FEATURE().
1798 r'^base/feature_list\.h',
1799 ],
Daniel Chengba3bc2e2022-10-03 02:45:431800 ),
Robert Ogden92101dcb2022-10-19 23:49:361801 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531802 r'/\bchartorune\b',
1803 ('chartorune is not memory-safe, unless you can guarantee the input ',
1804 'string is always null-terminated. Otherwise, please use charntorune ',
1805 'from libphonenumber instead.'),
1806 True,
1807 [
1808 _THIRD_PARTY_EXCEPT_BLINK,
1809 # Exceptions to this rule should have a fuzzer.
1810 ],
Robert Ogden92101dcb2022-10-19 23:49:361811 ),
Arthur Sonzogni1da65fa2023-03-27 16:01:521812 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531813 r'/\b#include "base/atomicops\.h"\b',
1814 ('Do not use base::subtle atomics, but std::atomic, which are simpler '
1815 'to use, have better understood, clearer and richer semantics, and are '
1816 'harder to mis-use. See details in base/atomicops.h.', ),
1817 False,
1818 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Benoit Lize79cf0592023-01-27 10:01:571819 ),
Daniel Cheng566634ff2024-06-29 14:56:531820 BanRule(r'CrossThreadPersistent<', (
Arthur Sonzogni60348572e2023-04-07 10:22:521821 'Do not use blink::CrossThreadPersistent, but '
Daniel Cheng566634ff2024-06-29 14:56:531822 'blink::CrossThreadHandle. It is harder to mis-use.', 'More info: '
Arthur Sonzogni60348572e2023-04-07 10:22:521823 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1824 'Please contact platform-architecture-dev@ before adding new instances.'
Daniel Cheng566634ff2024-06-29 14:56:531825 ), False, []),
1826 BanRule(r'CrossThreadWeakPersistent<', (
Arthur Sonzogni60348572e2023-04-07 10:22:521827 'Do not use blink::CrossThreadWeakPersistent, but '
Daniel Cheng566634ff2024-06-29 14:56:531828 'blink::CrossThreadWeakHandle. It is harder to mis-use.', 'More info: '
Arthur Sonzogni60348572e2023-04-07 10:22:521829 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1830 'Please contact platform-architecture-dev@ before adding new instances.'
Daniel Cheng566634ff2024-06-29 14:56:531831 ), False, []),
1832 BanRule(r'objc/objc.h', (
Avi Drissman491617c2023-04-13 17:33:151833 'Do not include <objc/objc.h>. It defines away ARC lifetime '
1834 'annotations, and is thus dangerous.',
1835 'Please use the pimpl pattern; search for `ObjCStorage` for examples.',
1836 'For further reading on how to safely mix C++ and Obj-C, see',
1837 'https://chromium.googlesource.com/chromium/src/+/main/docs/mac/mixing_cpp_and_objc.md'
Daniel Cheng566634ff2024-06-29 14:56:531838 ), True, []),
1839 BanRule(
1840 r'/#include <filesystem>',
1841 ('libc++ <filesystem> is banned per the Google C++ styleguide.', ),
1842 True,
1843 # This fuzzing framework is a standalone open source project and
1844 # cannot rely on Chromium base.
1845 (r'third_party/centipede'),
Avi Drissman491617c2023-04-13 17:33:151846 ),
Grace Park8d59b54b2023-04-26 17:53:351847 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531848 r'TopDocument()',
1849 ('TopDocument() does not work correctly with out-of-process iframes. '
1850 'Please do not introduce new uses.', ),
1851 True,
1852 (
1853 # TODO(crbug.com/617677): Remove all remaining uses.
1854 r'^third_party/blink/renderer/core/dom/document\.cc',
1855 r'^third_party/blink/renderer/core/dom/document\.h',
1856 r'^third_party/blink/renderer/core/dom/element\.cc',
1857 r'^third_party/blink/renderer/core/exported/web_disallow_transition_scope_test\.cc',
1858 r'^third_party/blink/renderer/core/exported/web_document_test\.cc',
1859 r'^third_party/blink/renderer/core/html/html_anchor_element\.cc',
1860 r'^third_party/blink/renderer/core/html/html_dialog_element\.cc',
1861 r'^third_party/blink/renderer/core/html/html_element\.cc',
1862 r'^third_party/blink/renderer/core/html/html_frame_owner_element\.cc',
1863 r'^third_party/blink/renderer/core/html/media/video_wake_lock\.cc',
1864 r'^third_party/blink/renderer/core/loader/anchor_element_interaction_tracker\.cc',
1865 r'^third_party/blink/renderer/core/page/scrolling/root_scroller_controller\.cc',
1866 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.cc',
1867 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.h',
1868 r'^third_party/blink/renderer/core/script/classic_pending_script\.cc',
1869 r'^third_party/blink/renderer/core/script/script_loader\.cc',
1870 ),
Grace Park8d59b54b2023-04-26 17:53:351871 ),
Daniel Cheng72153e02023-05-18 21:18:141872 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531873 pattern=r'base::raw_ptr<',
1874 explanation=('Do not use base::raw_ptr, use raw_ptr.', ),
1875 treat_as_error=True,
1876 excluded_paths=(
1877 '^base/',
1878 '^tools/',
1879 ),
Daniel Cheng72153e02023-05-18 21:18:141880 ),
Arthur Sonzognif0eea302023-08-18 19:20:311881 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531882 pattern=r'base:raw_ref<',
1883 explanation=('Do not use base::raw_ref, use raw_ref.', ),
1884 treat_as_error=True,
1885 excluded_paths=(
1886 '^base/',
1887 '^tools/',
1888 ),
Arthur Sonzognif0eea302023-08-18 19:20:311889 ),
1890 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531891 pattern=r'/raw_ptr<[^;}]*\w{};',
1892 explanation=(
1893 'Do not use {} for raw_ptr initialization, use = nullptr instead.',
1894 ),
1895 treat_as_error=True,
1896 excluded_paths=(
1897 '^base/',
1898 '^tools/',
1899 ),
Arthur Sonzognif0eea302023-08-18 19:20:311900 ),
Anton Maliev66751812023-08-24 16:28:131901 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531902 pattern=r'/#include "base/allocator/.*/raw_'
1903 r'(ptr|ptr_cast|ptr_exclusion|ref).h"',
1904 explanation=(
1905 'Please include the corresponding facade headers:',
1906 '- #include "base/memory/raw_ptr.h"',
1907 '- #include "base/memory/raw_ptr_cast.h"',
1908 '- #include "base/memory/raw_ptr_exclusion.h"',
1909 '- #include "base/memory/raw_ref.h"',
1910 ),
1911 treat_as_error=True,
1912 excluded_paths=(
1913 '^base/',
1914 '^tools/',
1915 ),
Tom Sepez41eb158d2023-09-12 16:16:221916 ),
1917 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531918 pattern=r'ContentSettingsType::COOKIES',
1919 explanation=
1920 ('Do not use ContentSettingsType::COOKIES to check whether cookies are '
1921 'supported in the provided context. Instead rely on the '
1922 'content_settings::CookieSettings API. If you are using '
1923 'ContentSettingsType::COOKIES to check the user preference setting '
1924 'specifically, disregard this warning.', ),
1925 treat_as_error=False,
1926 excluded_paths=(
1927 '^chrome/browser/ui/content_settings/',
1928 '^components/content_settings/',
1929 '^services/network/cookie_settings.cc',
1930 '.*test.cc',
1931 ),
Arthur Sonzogni48c6aea22023-09-04 22:25:201932 ),
1933 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531934 pattern=r'ContentSettingsType::TRACKING_PROTECTION',
1935 explanation=
1936 ('Do not directly use ContentSettingsType::TRACKING_PROTECTION to check '
1937 'for tracking protection exceptions. Instead rely on the '
1938 'privacy_sandbox::TrackingProtectionSettings API.', ),
1939 treat_as_error=False,
1940 excluded_paths=(
1941 '^chrome/browser/ui/content_settings/',
1942 '^components/content_settings/',
1943 '^components/privacy_sandbox/tracking_protection_settings.cc',
1944 '.*test.cc',
1945 ),
Anton Maliev66751812023-08-24 16:28:131946 ),
Tom Andersoncd522072023-10-03 00:52:351947 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531948 pattern=r'/\bg_signal_connect',
1949 explanation=('Use ScopedGSignal instead of g_signal_connect*()', ),
1950 treat_as_error=True,
1951 excluded_paths=('^ui/base/glib/scoped_gsignal.h', ),
Michelle Abreo6b7437822024-04-26 17:29:041952 ),
1953 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531954 pattern=r'features::kIsolatedWebApps',
1955 explanation=(
1956 'Do not use `features::kIsolatedWebApps` directly to guard Isolated ',
1957 'Web App code. ',
1958 'Use `content::IsolatedWebAppsPolicy::AreIsolatedWebAppsEnabled()` in ',
1959 'the browser process or check the `kEnableIsolatedWebAppsInRenderer` ',
1960 'command line flag in the renderer process.',
1961 ),
1962 treat_as_error=True,
1963 excluded_paths=_TEST_CODE_EXCLUDED_PATHS +
1964 ('^chrome/browser/about_flags.cc',
1965 '^chrome/browser/web_applications/isolated_web_apps/chrome_content_browser_client_isolated_web_apps_part.cc',
1966 '^chrome/browser/ui/startup/bad_flags_prompt.cc',
1967 '^content/shell/browser/shell_content_browser_client.cc')),
1968 BanRule(
1969 pattern=r'features::kIsolatedWebAppDevMode',
1970 explanation=(
1971 'Do not use `features::kIsolatedWebAppDevMode` directly to guard code ',
1972 'related to Isolated Web App Developer Mode. ',
1973 'Use `web_app::IsIwaDevModeEnabled()` instead.',
1974 ),
1975 treat_as_error=True,
1976 excluded_paths=_TEST_CODE_EXCLUDED_PATHS + (
1977 '^chrome/browser/about_flags.cc',
1978 '^chrome/browser/web_applications/isolated_web_apps/isolated_web_app_features.cc',
1979 '^chrome/browser/ui/startup/bad_flags_prompt.cc',
1980 )),
1981 BanRule(
1982 pattern=r'features::kIsolatedWebAppUnmanagedInstall',
1983 explanation=(
1984 'Do not use `features::kIsolatedWebAppUnmanagedInstall` directly to ',
1985 'guard code related to unmanaged install flow for Isolated Web Apps. ',
1986 'Use `web_app::IsIwaUnmanagedInstallEnabled()` instead.',
1987 ),
1988 treat_as_error=True,
1989 excluded_paths=_TEST_CODE_EXCLUDED_PATHS + (
1990 '^chrome/browser/about_flags.cc',
1991 '^chrome/browser/web_applications/isolated_web_apps/isolated_web_app_features.cc',
1992 )),
1993 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531994 pattern='/(CUIAutomation|AccessibleObjectFromWindow)',
1995 explanation=
1996 ('Direct usage of UIAutomation or IAccessible2 in client code is '
1997 'discouraged in Chromium, as it is not an assistive technology and '
1998 'should not rely on accessibility APIs directly. These APIs can '
1999 'introduce significant performance overhead. However, if you believe '
2000 'your use case warrants an exception, please discuss it with an '
2001 'accessibility owner before proceeding. For more information on the '
2002 'performance implications, see https://docs.google.com/document/d/1jN4itpCe_bDXF0BhFaYwv4xVLsCWkL9eULdzjmLzkuk/edit#heading=h.pwth3nbwdub0.',
2003 ),
2004 treat_as_error=False,
Andrew Rayskiycdd45e732024-03-20 14:32:392005 ),
2006 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:532007 pattern=r'/WIDGET_OWNS_NATIVE_WIDGET|'
2008 r'NATIVE_WIDGET_OWNS_WIDGET',
2009 explanation=
2010 ('WIDGET_OWNS_NATIVE_WIDGET and NATIVE_WIDGET_OWNS_WIDGET are in the '
2011 'process of being deprecated. Consider using the new '
2012 'CLIENT_OWNS_WIDGET ownership model. Eventually, this will be the only '
2013 'available ownership model available and the associated enumeration'
2014 'will be removed.', ),
2015 treat_as_error=False,
Andrew Rayskiycdd45e732024-03-20 14:32:392016 ),
2017 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:532018 pattern='ProfileManager::GetLastUsedProfile',
2019 explanation=
2020 ('Most code should already be scoped to a Profile. Pass in a Profile* '
2021 'or retreive from an existing entity with a reference to the Profile '
2022 '(e.g. WebContents).', ),
2023 treat_as_error=False,
Arthur Sonzogni5cbd3e32024-02-08 17:51:322024 ),
Helmut Januschkab3f71ab52024-03-12 02:48:052025 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:532026 pattern=(r'/FindBrowserWithUiElementContext|'
2027 r'FindBrowserWithTab|'
2028 r'FindBrowserWithGroup|'
2029 r'FindTabbedBrowser|'
2030 r'FindAnyBrowser|'
2031 r'FindBrowserWithProfile|'
Erik Chen5f02eb4c2024-08-23 06:30:442032 r'FindLastActive|'
Daniel Cheng566634ff2024-06-29 14:56:532033 r'FindBrowserWithActiveWindow'),
2034 explanation=
2035 ('Most code should already be scoped to a Browser. Pass in a Browser* '
2036 'or retreive from an existing entity with a reference to the Browser.',
2037 ),
2038 treat_as_error=False,
Helmut Januschkab3f71ab52024-03-12 02:48:052039 ),
2040 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:532041 pattern='BrowserUserData',
2042 explanation=
2043 ('Do not use BrowserUserData to store state on a Browser instance. '
2044 'Instead use BrowserWindowFeatures. BrowserWindowFeatures is '
2045 'functionally identical but has two benefits: it does not force a '
2046 'dependency onto class Browser, and lifetime semantics are explicit '
2047 'rather than implicit. See BrowserUserData header file for more '
2048 'details.', ),
2049 treat_as_error=False,
Mike Doughertyab1bdec2024-08-06 16:39:012050 excluded_paths=(
2051 # Exclude iOS as the iOS implementation of BrowserUserData is separate
2052 # and still in use.
2053 '^ios/',
2054 ),
Erik Chen87358e82024-06-04 02:13:122055 ),
Tom Sepezea67b6e2024-08-08 18:17:272056 BanRule(
2057 pattern=r'UNSAFE_TODO(',
2058 explanation=
2059 ('Do not use UNSAFE_TODO() to write new unsafe code. Use only when '
Tom Sepeza90f92b2024-08-15 16:01:352060 'removing a pre-existing file-wide allow_unsafe_buffers pragma, or '
2061 'when incrementally converting code off of unsafe interfaces',
Tom Sepezea67b6e2024-08-08 18:17:272062 ),
2063 treat_as_error=False,
2064 ),
2065 BanRule(
2066 pattern=r'UNSAFE_BUFFERS(',
2067 explanation=
Tom Sepeza90f92b2024-08-15 16:01:352068 ('Try to avoid using UNSAFE_BUFFERS() if at all possible. Otherwise, '
2069 'be sure to justify in a // SAFETY comment why other options are not '
2070 'available, and why the code is safe.',
Tom Sepezea67b6e2024-08-08 18:17:272071 ),
2072 treat_as_error=False,
2073 ),
Erik Chend086ae02024-08-20 22:53:332074 BanRule(
2075 pattern='BrowserWithTestWindowTest',
2076 explanation=
2077 ('Do not use BrowserWithTestWindowTest. By instantiating an instance '
2078 'of class Browser, the test is no longer a unit test but is instead a '
2079 'browser test. The class BrowserWithTestWindowTest forces production '
2080 'logic to take on test-only conditionals, which is an anti-pattern. '
2081 'Features should be performing dependency injection rather than '
2082 'directly using class Browser. See '
mikt19226ff22024-08-27 05:28:212083 'docs/chrome_browser_design_principles.md for more details.',
Erik Chend086ae02024-08-20 22:53:332084 ),
2085 treat_as_error=False,
2086 ),
Erik Chen8cf3a652024-08-23 17:13:302087 BanRule(
Erik Chen959cdd72024-08-29 02:11:212088 pattern='TestWithBrowserView',
2089 explanation=
2090 ('Do not use TestWithBrowserView. See '
2091 'docs/chrome_browser_design_principles.md for details. If you want '
2092 'to write a test that has both a Browser and a BrowserView, create '
2093 'a browser_test. If you want to write a unit_test, your code must '
2094 'not reference Browser*.'
2095 ),
2096 treat_as_error=False,
2097 ),
2098 BanRule(
Erik Chen8cf3a652024-08-23 17:13:302099 pattern='RunUntilIdle',
2100 explanation=
2101 ('Do not RunUntilIdle. If possible, explicitly quit the run loop using '
2102 'run_loop.Quit() or run_loop.QuitClosure() if completion can be '
2103 'observed using a lambda or callback. Otherwise, wait for the '
mikt19226ff22024-08-27 05:28:212104 'condition to be true via base::test::RunUntil().',
Erik Chen8cf3a652024-08-23 17:13:302105 ),
2106 treat_as_error=False,
2107 ),
Daniel Chengddde13a2024-09-05 21:39:282108 BanRule(
2109 pattern=r'/\bstd::(literals|string_literals|string_view_literals)\b',
2110 explanation = (
2111 'User-defined literals are banned by the Google C++ style guide. '
2112 'Exceptions are provided in Chrome for string and string_view '
2113 'literals that embed \\0.',
2114 ),
2115 treat_as_error=True,
2116 excluded_paths=(
2117 # Various tests or test helpers that embed NUL in strings or
2118 # string_views.
2119 r'^ash/components/arc/session/serial_number_util_unittest\.cc',
2120 r'^base/strings/string_util_unittest\.cc',
2121 r'^base/strings/utf_string_conversions_unittest\.cc',
2122 r'^chrome/browser/ash/crosapi/browser_data_back_migrator_unittest\.cc',
2123 r'^chrome/browser/ash/crosapi/browser_data_migrator_util_unittest\.cc',
2124 r'^chrome/browser/ash/crosapi/move_migrator_unittest\.cc',
2125 r'^components/history/core/browser/visit_annotations_database\.cc',
2126 r'^components/history/core/browser/visit_annotations_database_unittest\.cc',
2127 r'^components/os_crypt/sync/os_crypt_unittest\.cc',
2128 r'^components/password_manager/core/browser/credentials_cleaner_unittest\.cc',
2129 r'^content/browser/file_system_access/file_system_access_file_writer_impl_unittest\.cc',
2130 r'^net/cookies/parsed_cookie_unittest\.cc',
2131 r'^third_party/blink/renderer/modules/webcodecs/test_helpers\.cc',
2132 r'^third_party/blink/renderer/modules/websockets/websocket_channel_impl_test\.cc',
2133 ),
2134 )
[email protected]127f18ec2012-06-16 05:05:592135)
2136
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152137_DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING = (
2138 'Used a predicate related to signin::ConsentLevel::kSync which will always '
2139 'return false in the future (crbug.com/40066949). Prefer using a predicate '
2140 'that also supports signin::ConsentLevel::kSignin when appropriate. It is '
2141 'safe to ignore this warning if you are just moving an existing call, or if '
2142 'you want special handling for users in the legacy state. In doubt, reach '
Victor Hugo Vianna Silvae2292972024-06-04 17:11:552143 'out to //components/sync/OWNERS.',
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152144)
2145
2146# C++ functions related to signin::ConsentLevel::kSync which are deprecated.
2147_DEPRECATED_SYNC_CONSENT_CPP_FUNCTIONS : Sequence[BanRule] = (
2148 BanRule(
2149 'HasSyncConsent',
2150 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2151 False,
2152 ),
2153 BanRule(
2154 'CanSyncFeatureStart',
2155 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2156 False,
2157 ),
2158 BanRule(
2159 'IsSyncFeatureEnabled',
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152160 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152161 False,
2162 ),
2163 BanRule(
2164 'IsSyncFeatureActive',
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152165 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152166 False,
2167 ),
2168)
2169
2170# Java functions related to signin::ConsentLevel::kSync which are deprecated.
2171_DEPRECATED_SYNC_CONSENT_JAVA_FUNCTIONS : Sequence[BanRule] = (
2172 BanRule(
2173 'hasSyncConsent',
2174 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2175 False,
2176 ),
2177 BanRule(
2178 'canSyncFeatureStart',
2179 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2180 False,
2181 ),
2182 BanRule(
2183 'isSyncFeatureEnabled',
2184 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2185 False,
2186 ),
2187 BanRule(
2188 'isSyncFeatureActive',
2189 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2190 False,
2191 ),
2192)
2193
Daniel Cheng92c15e32022-03-16 17:48:222194_BANNED_MOJOM_PATTERNS : Sequence[BanRule] = (
2195 BanRule(
2196 'handle<shared_buffer>',
2197 (
2198 'Please use one of the more specific shared memory types instead:',
2199 ' mojo_base.mojom.ReadOnlySharedMemoryRegion',
2200 ' mojo_base.mojom.WritableSharedMemoryRegion',
2201 ' mojo_base.mojom.UnsafeSharedMemoryRegion',
2202 ),
2203 True,
2204 ),
2205)
2206
mlamouria82272622014-09-16 18:45:042207_IPC_ENUM_TRAITS_DEPRECATED = (
2208 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:502209 'See http://www.chromium.org/Home/chromium-security/education/'
2210 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:042211
Stephen Martinis97a394142018-06-07 23:06:052212_LONG_PATH_ERROR = (
2213 'Some files included in this CL have file names that are too long (> 200'
2214 ' characters). If committed, these files will cause issues on Windows. See'
2215 ' https://crbug.com/612667 for more details.'
2216)
2217
Shenghua Zhangbfaa38b82017-11-16 21:58:022218_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Bruce Dawson40fece62022-09-16 19:58:312219 r".*/AppHooksImpl\.java",
2220 r".*/BuildHooksAndroidImpl\.java",
2221 r".*/LicenseContentProvider\.java",
2222 r".*/PlatformServiceBridgeImpl.java",
2223 r".*chrome/android/feed/dummy/.*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:022224]
[email protected]127f18ec2012-06-16 05:05:592225
Mohamed Heikald048240a2019-11-12 16:57:372226# List of image extensions that are used as resources in chromium.
2227_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
2228
Sean Kau46e29bc2017-08-28 16:31:162229# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:402230_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Bruce Dawson40fece62022-09-16 19:58:312231 r'test/data/',
2232 r'testing/buildbot/',
2233 r'^components/policy/resources/policy_templates\.json$',
2234 r'^third_party/protobuf/',
Camillo Bruni1411a352023-05-24 12:39:032235 r'^third_party/blink/perf_tests/speedometer.*/resources/todomvc/learn\.json',
Bruce Dawson40fece62022-09-16 19:58:312236 r'^third_party/blink/renderer/devtools/protocol\.json$',
2237 r'^third_party/blink/web_tests/external/wpt/',
2238 r'^tools/perf/',
2239 r'^tools/traceline/svgui/startup-release.json',
Daniel Cheng2d4c2d192022-07-01 01:38:312240 # vscode configuration files allow comments
Bruce Dawson40fece62022-09-16 19:58:312241 r'^tools/vscode/',
Sean Kau46e29bc2017-08-28 16:31:162242]
2243
Andrew Grieveb773bad2020-06-05 18:00:382244# These are not checked on the public chromium-presubmit trybot.
2245# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:042246# checkouts.
agrievef32bcc72016-04-04 14:57:402247_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:382248 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382249]
2250
2251
2252_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:042253 'android_webview/tools/run_cts.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:362254 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042255 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362256 'build/android/gyp/aar.pydeps',
2257 'build/android/gyp/aidl.pydeps',
2258 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:382259 'build/android/gyp/assert_static_initializers.pydeps',
Mohamed Heikal133e1f22023-04-18 20:04:372260 'build/android/gyp/binary_baseline_profile.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362261 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:022262 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:222263 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:112264 'build/android/gyp/compile_java.pydeps',
Peter Weneaa963f2023-01-20 19:40:302265 'build/android/gyp/compile_kt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362266 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362267 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362268 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:112269 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042270 'build/android/gyp/create_app_bundle_apks.pydeps',
2271 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362272 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:122273 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:092274 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:222275 'build/android/gyp/create_size_info_files.pydeps',
Peter Wene6e017e2022-07-27 21:40:402276 'build/android/gyp/create_test_apk_wrapper_script.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002277 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362278 'build/android/gyp/dex.pydeps',
2279 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362280 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:212281 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362282 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:362283 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362284 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:582285 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362286 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:142287 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:262288 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:472289 'build/android/gyp/java_google_api_keys.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042290 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362291 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362292 'build/android/gyp/merge_manifest.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:102293 'build/android/gyp/optimize_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362294 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:222295 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362296 'build/android/gyp/proguard.pydeps',
Mohamed Heikaldd52b452024-09-10 17:10:502297 'build/android/gyp/rename_java_classes.pydeps',
Andrew Grievee3a775ab2022-05-16 15:59:222298 'build/android/gyp/system_image_apks.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:102299 'build/android/gyp/trace_event_bytecode_rewriter.pydeps',
Peter Wen578730b2020-03-19 19:55:462300 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:302301 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:242302 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362303 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:462304 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:562305 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362306 'build/android/incremental_install/generate_android_manifest.pydeps',
2307 'build/android/incremental_install/write_installer_json.pydeps',
Stephanie Kim392913b452022-06-15 17:25:322308 'build/android/pylib/results/presentation/test_results_presentation.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042309 'build/android/resource_sizes.pydeps',
2310 'build/android/test_runner.pydeps',
2311 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:362312 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362313 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:322314 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:272315 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
2316 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:042317 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Mohannad Farrag19102742023-12-01 01:16:302318 'components/cronet/tools/check_combined_proguard_file.pydeps',
2319 'components/cronet/tools/generate_proguard_file.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002320 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382321 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002322 'content/public/android/generate_child_service.pydeps',
Hzj_jie77bdb802024-07-22 18:14:512323 'fuchsia_web/av_testing/av_sync_tests.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382324 'net/tools/testserver/testserver.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:182325 'testing/scripts/run_isolated_script_test.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:412326 'testing/merge_scripts/standard_isolated_script_merge.pydeps',
2327 'testing/merge_scripts/standard_gtest_merge.pydeps',
2328 'testing/merge_scripts/code_coverage/merge_results.pydeps',
2329 'testing/merge_scripts/code_coverage/merge_steps.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042330 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:422331 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
Yuki Shiino38eeaad12022-08-11 06:40:252332 'third_party/blink/renderer/bindings/scripts/check_generated_file_list.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:422333 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:132334 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Yuki Shiinoea477d32023-08-21 06:24:342335 'third_party/blink/renderer/bindings/scripts/generate_event_interface_names.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:502336 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:412337 'third_party/blink/tools/blinkpy/web_tests/merge_results.pydeps',
2338 'third_party/blink/tools/merge_web_test_results.pydeps',
John Budorickbc3571aa2019-04-25 02:20:062339 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:222340 'tools/binary_size/supersize.pydeps',
Ben Pastene028104a2022-08-10 19:17:452341 'tools/perf/process_perf_results.pydeps',
agrievef32bcc72016-04-04 14:57:402342]
2343
wnwenbdc444e2016-05-25 13:44:152344
agrievef32bcc72016-04-04 14:57:402345_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
2346
2347
Eric Boren6fd2b932018-01-25 15:05:082348# Bypass the AUTHORS check for these accounts.
2349_KNOWN_ROBOTS = set(
nqmtuan918b2232024-04-11 23:09:552350 ) | set('%[email protected]' % s for s in ('findit-for-me', 'luci-bisection')
Achuith Bhandarkar35905562018-07-25 19:28:452351 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:592352 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:522353 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:232354 'wpt-autoroller', 'chrome-weblayer-builder',
Garrett Beaty4d4fcf62021-11-24 17:57:472355 'lacros-version-skew-roller', 'skylab-test-cros-roller',
Sven Zheng722960ba2022-07-18 16:40:462356 'infra-try-recipes-tester', 'lacros-tracking-roller',
Brian Sheedy1c951e62022-10-27 01:16:182357 'lacros-sdk-version-roller', 'chrome-automated-expectation',
Stephanie Kimb49bdd242023-04-28 16:46:042358 'chromium-automated-expectation', 'chrome-branch-day',
2359 'chromium-autosharder')
Eric Boren835d71f2018-09-07 21:09:042360 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:272361 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:042362 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:162363 for s in ('chromium-internal-autoroll',)
Kyungjun Lee3b7c9352024-04-02 23:59:142364 ) | set('%[email protected]' % s
2365 for s in ('chrome-screen-ai-releaser',)
Yulan Lineb0cfba2021-04-09 18:43:162366 ) | set('%[email protected]' % s
Chong Gub277e342022-10-15 03:30:552367 for s in ('swarming-tasks',)
2368 ) | set('%[email protected]' % s
2369 for s in ('global-integration-try-builder',
Joey Scarr1103c5d2023-09-14 01:17:552370 'global-integration-ci-builder')
Suma Kasa3b9cf7a2023-09-21 22:05:542371 ) | set('%[email protected]' % s
2372 for s in ('chops-security-borg',
2373 'chops-security-cronjobs-cpesuggest'))
Eric Boren6fd2b932018-01-25 15:05:082374
Matt Stark6ef08872021-07-29 01:21:462375_INVALID_GRD_FILE_LINE = [
2376 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
2377]
Eric Boren6fd2b932018-01-25 15:05:082378
Daniel Bratell65b033262019-04-23 08:17:062379def _IsCPlusPlusFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502380 """Returns True if this file contains C++-like code (and not Python,
2381 Go, Java, MarkDown, ...)"""
Daniel Bratell65b033262019-04-23 08:17:062382
Sam Maiera6e76d72022-02-11 21:43:502383 ext = input_api.os_path.splitext(file_path)[1]
2384 # This list is compatible with CppChecker.IsCppFile but we should
2385 # consider adding ".c" to it. If we do that we can use this function
2386 # at more places in the code.
2387 return ext in (
2388 '.h',
2389 '.cc',
2390 '.cpp',
2391 '.m',
2392 '.mm',
2393 )
2394
Daniel Bratell65b033262019-04-23 08:17:062395
2396def _IsCPlusPlusHeaderFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502397 return input_api.os_path.splitext(file_path)[1] == ".h"
Daniel Bratell65b033262019-04-23 08:17:062398
2399
2400def _IsJavaFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502401 return input_api.os_path.splitext(file_path)[1] == ".java"
Daniel Bratell65b033262019-04-23 08:17:062402
2403
2404def _IsProtoFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502405 return input_api.os_path.splitext(file_path)[1] == ".proto"
Daniel Bratell65b033262019-04-23 08:17:062406
Mohamed Heikal5e5b7922020-10-29 18:57:592407
Erik Staabc734cd7a2021-11-23 03:11:522408def _IsXmlOrGrdFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502409 ext = input_api.os_path.splitext(file_path)[1]
2410 return ext in ('.grd', '.xml')
Erik Staabc734cd7a2021-11-23 03:11:522411
2412
Sven Zheng76a79ea2022-12-21 21:25:242413def _IsMojomFile(input_api, file_path):
2414 return input_api.os_path.splitext(file_path)[1] == ".mojom"
2415
2416
Mohamed Heikal5e5b7922020-10-29 18:57:592417def CheckNoUpstreamDepsOnClank(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502418 """Prevent additions of dependencies from the upstream repo on //clank."""
2419 # clank can depend on clank
2420 if input_api.change.RepositoryRoot().endswith('clank'):
2421 return []
2422 build_file_patterns = [
2423 r'(.+/)?BUILD\.gn',
2424 r'.+\.gni',
2425 ]
2426 excluded_files = [r'build[/\\]config[/\\]android[/\\]config\.gni']
2427 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
Mohamed Heikal5e5b7922020-10-29 18:57:592428
Sam Maiera6e76d72022-02-11 21:43:502429 error_message = 'Disallowed import on //clank in an upstream build file:'
Mohamed Heikal5e5b7922020-10-29 18:57:592430
Sam Maiera6e76d72022-02-11 21:43:502431 def FilterFile(affected_file):
2432 return input_api.FilterSourceFile(affected_file,
2433 files_to_check=build_file_patterns,
2434 files_to_skip=excluded_files)
Mohamed Heikal5e5b7922020-10-29 18:57:592435
Sam Maiera6e76d72022-02-11 21:43:502436 problems = []
2437 for f in input_api.AffectedSourceFiles(FilterFile):
2438 local_path = f.LocalPath()
2439 for line_number, line in f.ChangedContents():
2440 if (bad_pattern.search(line)):
2441 problems.append('%s:%d\n %s' %
2442 (local_path, line_number, line.strip()))
2443 if problems:
2444 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
2445 else:
2446 return []
Mohamed Heikal5e5b7922020-10-29 18:57:592447
2448
Saagar Sanghavifceeaae2020-08-12 16:40:362449def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502450 """Attempts to prevent use of functions intended only for testing in
2451 non-testing code. For now this is just a best-effort implementation
2452 that ignores header files and may have some false positives. A
2453 better implementation would probably need a proper C++ parser.
2454 """
2455 # We only scan .cc files and the like, as the declaration of
2456 # for-testing functions in header files are hard to distinguish from
2457 # calls to such functions without a proper C++ parser.
2458 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:192459
Sam Maiera6e76d72022-02-11 21:43:502460 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
2461 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' %
2462 base_function_pattern)
2463 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
2464 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
2465 exclusion_pattern = input_api.re.compile(
2466 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' %
2467 (base_function_pattern, base_function_pattern))
2468 # Avoid a false positive in this case, where the method name, the ::, and
2469 # the closing { are all on different lines due to line wrapping.
2470 # HelperClassForTesting::
2471 # HelperClassForTesting(
2472 # args)
2473 # : member(0) {}
2474 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:192475
Sam Maiera6e76d72022-02-11 21:43:502476 def FilterFile(affected_file):
2477 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2478 input_api.DEFAULT_FILES_TO_SKIP)
2479 return input_api.FilterSourceFile(
2480 affected_file,
2481 files_to_check=file_inclusion_pattern,
2482 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:192483
Sam Maiera6e76d72022-02-11 21:43:502484 problems = []
2485 for f in input_api.AffectedSourceFiles(FilterFile):
2486 local_path = f.LocalPath()
2487 in_method_defn = False
2488 for line_number, line in f.ChangedContents():
2489 if (inclusion_pattern.search(line)
2490 and not comment_pattern.search(line)
2491 and not exclusion_pattern.search(line)
2492 and not allowlist_pattern.search(line)
2493 and not in_method_defn):
2494 problems.append('%s:%d\n %s' %
2495 (local_path, line_number, line.strip()))
2496 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:192497
Sam Maiera6e76d72022-02-11 21:43:502498 if problems:
2499 return [
2500 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
2501 ]
2502 else:
2503 return []
[email protected]55459852011-08-10 15:17:192504
2505
Saagar Sanghavifceeaae2020-08-12 16:40:362506def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502507 """This is a simplified version of
2508 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
2509 """
2510 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
2511 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
2512 name_pattern = r'ForTest(s|ing)?'
2513 # Describes an occurrence of "ForTest*" inside a // comment.
2514 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
2515 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
2516 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
2517 # Catch calls.
2518 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
2519 # Ignore definitions. (Comments are ignored separately.)
2520 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
Andrew Grieve40f451d2023-07-06 19:46:512521 allowlist_re = input_api.re.compile(r'// IN-TEST$')
Vaclav Brozek7dbc28c2018-03-27 08:35:232522
Sam Maiera6e76d72022-02-11 21:43:502523 problems = []
2524 sources = lambda x: input_api.FilterSourceFile(
2525 x,
2526 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
2527 DEFAULT_FILES_TO_SKIP),
2528 files_to_check=[r'.*\.java$'])
2529 for f in input_api.AffectedFiles(include_deletes=False,
2530 file_filter=sources):
2531 local_path = f.LocalPath()
Vaclav Brozek7dbc28c2018-03-27 08:35:232532 is_inside_javadoc = False
Sam Maiera6e76d72022-02-11 21:43:502533 for line_number, line in f.ChangedContents():
2534 if is_inside_javadoc and javadoc_end_re.search(line):
2535 is_inside_javadoc = False
2536 if not is_inside_javadoc and javadoc_start_re.search(line):
2537 is_inside_javadoc = True
2538 if is_inside_javadoc:
2539 continue
2540 if (inclusion_re.search(line) and not comment_re.search(line)
2541 and not annotation_re.search(line)
Andrew Grieve40f451d2023-07-06 19:46:512542 and not allowlist_re.search(line)
Sam Maiera6e76d72022-02-11 21:43:502543 and not exclusion_re.search(line)):
2544 problems.append('%s:%d\n %s' %
2545 (local_path, line_number, line.strip()))
Vaclav Brozek7dbc28c2018-03-27 08:35:232546
Sam Maiera6e76d72022-02-11 21:43:502547 if problems:
2548 return [
2549 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
2550 ]
2551 else:
2552 return []
Vaclav Brozek7dbc28c2018-03-27 08:35:232553
2554
Saagar Sanghavifceeaae2020-08-12 16:40:362555def CheckNoIOStreamInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502556 """Checks to make sure no .h files include <iostream>."""
2557 files = []
2558 pattern = input_api.re.compile(r'^#include\s*<iostream>',
2559 input_api.re.MULTILINE)
2560 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2561 if not f.LocalPath().endswith('.h'):
2562 continue
2563 contents = input_api.ReadFile(f)
2564 if pattern.search(contents):
2565 files.append(f)
[email protected]10689ca2011-09-02 02:31:542566
Sam Maiera6e76d72022-02-11 21:43:502567 if len(files):
2568 return [
2569 output_api.PresubmitError(
2570 'Do not #include <iostream> in header files, since it inserts static '
2571 'initialization into every file including the header. Instead, '
2572 '#include <ostream>. See http://crbug.com/94794', files)
2573 ]
2574 return []
2575
[email protected]10689ca2011-09-02 02:31:542576
Aleksey Khoroshilov9b28c032022-06-03 16:35:322577def CheckNoStrCatRedefines(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502578 """Checks no windows headers with StrCat redefined are included directly."""
2579 files = []
Aleksey Khoroshilov9b28c032022-06-03 16:35:322580 files_to_check = (r'.+%s' % _HEADER_EXTENSIONS,
2581 r'.+%s' % _IMPLEMENTATION_EXTENSIONS)
2582 files_to_skip = (input_api.DEFAULT_FILES_TO_SKIP +
2583 _NON_BASE_DEPENDENT_PATHS)
2584 sources_filter = lambda f: input_api.FilterSourceFile(
2585 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
2586
Sam Maiera6e76d72022-02-11 21:43:502587 pattern_deny = input_api.re.compile(
2588 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
2589 input_api.re.MULTILINE)
2590 pattern_allow = input_api.re.compile(
2591 r'^#include\s"base/win/windows_defines.inc"', input_api.re.MULTILINE)
Aleksey Khoroshilov9b28c032022-06-03 16:35:322592 for f in input_api.AffectedSourceFiles(sources_filter):
Sam Maiera6e76d72022-02-11 21:43:502593 contents = input_api.ReadFile(f)
2594 if pattern_deny.search(
2595 contents) and not pattern_allow.search(contents):
2596 files.append(f.LocalPath())
Danil Chapovalov3518f362018-08-11 16:13:432597
Sam Maiera6e76d72022-02-11 21:43:502598 if len(files):
2599 return [
2600 output_api.PresubmitError(
2601 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
2602 'directly since they pollute code with StrCat macro. Instead, '
2603 'include matching header from base/win. See http://crbug.com/856536',
2604 files)
2605 ]
2606 return []
Danil Chapovalov3518f362018-08-11 16:13:432607
[email protected]10689ca2011-09-02 02:31:542608
Andrew Williamsc9f69b482023-07-10 16:07:362609def _CheckNoUNIT_TESTInSourceFiles(input_api, f):
2610 problems = []
2611
2612 unit_test_macro = input_api.re.compile(
2613 '^\s*#.*(?:ifn?def\s+UNIT_TEST|defined\s*\(?\s*UNIT_TEST\s*\)?)(?:$|\s+)')
2614 for line_num, line in f.ChangedContents():
2615 if unit_test_macro.match(line):
2616 problems.append(' %s:%d' % (f.LocalPath(), line_num))
2617
2618 return problems
2619
2620
Saagar Sanghavifceeaae2020-08-12 16:40:362621def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502622 """Checks to make sure no source files use UNIT_TEST."""
2623 problems = []
2624 for f in input_api.AffectedFiles():
2625 if (not f.LocalPath().endswith(('.cc', '.mm'))):
2626 continue
Andrew Williamsc9f69b482023-07-10 16:07:362627 problems.extend(
2628 _CheckNoUNIT_TESTInSourceFiles(input_api, f))
[email protected]72df4e782012-06-21 16:28:182629
Sam Maiera6e76d72022-02-11 21:43:502630 if not problems:
2631 return []
2632 return [
2633 output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
2634 '\n'.join(problems))
2635 ]
2636
[email protected]72df4e782012-06-21 16:28:182637
Saagar Sanghavifceeaae2020-08-12 16:40:362638def CheckNoDISABLETypoInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502639 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
Dominic Battre033531052018-09-24 15:45:342640
Sam Maiera6e76d72022-02-11 21:43:502641 This test warns if somebody tries to disable a test with the DISABLE_ prefix
2642 instead of DISABLED_. To filter false positives, reports are only generated
2643 if a corresponding MAYBE_ line exists.
2644 """
2645 problems = []
Dominic Battre033531052018-09-24 15:45:342646
Sam Maiera6e76d72022-02-11 21:43:502647 # The following two patterns are looked for in tandem - is a test labeled
2648 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
2649 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
2650 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
Dominic Battre033531052018-09-24 15:45:342651
Sam Maiera6e76d72022-02-11 21:43:502652 # This is for the case that a test is disabled on all platforms.
2653 full_disable_pattern = input_api.re.compile(
2654 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
2655 input_api.re.MULTILINE)
Dominic Battre033531052018-09-24 15:45:342656
Arthur Sonzognic66e9c82024-04-23 07:53:042657 for f in input_api.AffectedFiles(include_deletes=False):
Sam Maiera6e76d72022-02-11 21:43:502658 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2659 continue
Dominic Battre033531052018-09-24 15:45:342660
Arthur Sonzognic66e9c82024-04-23 07:53:042661 # Search for MAYBE_, DISABLE_ pairs.
Sam Maiera6e76d72022-02-11 21:43:502662 disable_lines = {} # Maps of test name to line number.
2663 maybe_lines = {}
2664 for line_num, line in f.ChangedContents():
2665 disable_match = disable_pattern.search(line)
2666 if disable_match:
2667 disable_lines[disable_match.group(1)] = line_num
2668 maybe_match = maybe_pattern.search(line)
2669 if maybe_match:
2670 maybe_lines[maybe_match.group(1)] = line_num
Dominic Battre033531052018-09-24 15:45:342671
Sam Maiera6e76d72022-02-11 21:43:502672 # Search for DISABLE_ occurrences within a TEST() macro.
2673 disable_tests = set(disable_lines.keys())
2674 maybe_tests = set(maybe_lines.keys())
2675 for test in disable_tests.intersection(maybe_tests):
2676 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
Dominic Battre033531052018-09-24 15:45:342677
Sam Maiera6e76d72022-02-11 21:43:502678 contents = input_api.ReadFile(f)
2679 full_disable_match = full_disable_pattern.search(contents)
2680 if full_disable_match:
2681 problems.append(' %s' % f.LocalPath())
Dominic Battre033531052018-09-24 15:45:342682
Sam Maiera6e76d72022-02-11 21:43:502683 if not problems:
2684 return []
2685 return [
2686 output_api.PresubmitPromptWarning(
2687 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
2688 '\n'.join(problems))
2689 ]
2690
Dominic Battre033531052018-09-24 15:45:342691
Nina Satragnof7660532021-09-20 18:03:352692def CheckForgettingMAYBEInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502693 """Checks to make sure tests disabled conditionally are not missing a
2694 corresponding MAYBE_ prefix.
2695 """
2696 # Expect at least a lowercase character in the test name. This helps rule out
2697 # false positives with macros wrapping the actual tests name.
2698 define_maybe_pattern = input_api.re.compile(
2699 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
Bruce Dawsonffc55292022-04-20 04:18:192700 # The test_maybe_pattern needs to handle all of these forms. The standard:
2701 # IN_PROC_TEST_F(SyncTest, MAYBE_Start) {
2702 # With a wrapper macro around the test name:
2703 # IN_PROC_TEST_F(SyncTest, E2E_ENABLED(MAYBE_Start)) {
2704 # And the odd-ball NACL_BROWSER_TEST_f format:
2705 # NACL_BROWSER_TEST_F(NaClBrowserTest, SimpleLoad, {
2706 # The optional E2E_ENABLED-style is handled with (\w*\()?
2707 # The NACL_BROWSER_TEST_F pattern is handled by allowing a trailing comma or
2708 # trailing ')'.
2709 test_maybe_pattern = (
2710 r'^\s*\w*TEST[^(]*\(\s*\w+,\s*(\w*\()?MAYBE_{test_name}[\),]')
Sam Maiera6e76d72022-02-11 21:43:502711 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
2712 warnings = []
Nina Satragnof7660532021-09-20 18:03:352713
Sam Maiera6e76d72022-02-11 21:43:502714 # Read the entire files. We can't just read the affected lines, forgetting to
2715 # add MAYBE_ on a change would not show up otherwise.
Arthur Sonzognic66e9c82024-04-23 07:53:042716 for f in input_api.AffectedFiles(include_deletes=False):
Sam Maiera6e76d72022-02-11 21:43:502717 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2718 continue
2719 contents = input_api.ReadFile(f)
2720 lines = contents.splitlines(True)
2721 current_position = 0
2722 warning_test_names = set()
2723 for line_num, line in enumerate(lines, start=1):
2724 current_position += len(line)
2725 maybe_match = define_maybe_pattern.search(line)
2726 if maybe_match:
2727 test_name = maybe_match.group('test_name')
2728 # Do not warn twice for the same test.
2729 if (test_name in warning_test_names):
2730 continue
2731 warning_test_names.add(test_name)
Nina Satragnof7660532021-09-20 18:03:352732
Sam Maiera6e76d72022-02-11 21:43:502733 # Attempt to find the corresponding MAYBE_ test or suite, starting from
2734 # the current position.
2735 test_match = input_api.re.compile(
2736 test_maybe_pattern.format(test_name=test_name),
2737 input_api.re.MULTILINE).search(contents, current_position)
2738 suite_match = input_api.re.compile(
2739 suite_maybe_pattern.format(test_name=test_name),
2740 input_api.re.MULTILINE).search(contents, current_position)
2741 if not test_match and not suite_match:
2742 warnings.append(
2743 output_api.PresubmitPromptWarning(
2744 '%s:%d found MAYBE_ defined without corresponding test %s'
2745 % (f.LocalPath(), line_num, test_name)))
2746 return warnings
2747
[email protected]72df4e782012-06-21 16:28:182748
Saagar Sanghavifceeaae2020-08-12 16:40:362749def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502750 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
2751 errors = []
Kalvin Lee4a3b79de2022-05-26 16:00:162752 pattern = input_api.re.compile(r'\bDCHECK_IS_ON\b(?!\(\))',
Sam Maiera6e76d72022-02-11 21:43:502753 input_api.re.MULTILINE)
2754 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2755 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
2756 continue
2757 for lnum, line in f.ChangedContents():
2758 if input_api.re.search(pattern, line):
2759 errors.append(
2760 output_api.PresubmitError((
2761 '%s:%d: Use of DCHECK_IS_ON() must be written as "#if '
2762 + 'DCHECK_IS_ON()", not forgetting the parentheses.') %
2763 (f.LocalPath(), lnum)))
2764 return errors
danakj61c1aa22015-10-26 19:55:522765
2766
Weilun Shia487fad2020-10-28 00:10:342767# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
2768# more reliable way. See
2769# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:192770
wnwenbdc444e2016-05-25 13:44:152771
Saagar Sanghavifceeaae2020-08-12 16:40:362772def CheckFlakyTestUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502773 """Check that FlakyTest annotation is our own instead of the android one"""
2774 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
2775 files = []
2776 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2777 if f.LocalPath().endswith('Test.java'):
2778 if pattern.search(input_api.ReadFile(f)):
2779 files.append(f)
2780 if len(files):
2781 return [
2782 output_api.PresubmitError(
2783 'Use org.chromium.base.test.util.FlakyTest instead of '
2784 'android.test.FlakyTest', files)
2785 ]
2786 return []
mcasasb7440c282015-02-04 14:52:192787
wnwenbdc444e2016-05-25 13:44:152788
Saagar Sanghavifceeaae2020-08-12 16:40:362789def CheckNoDEPSGIT(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502790 """Make sure .DEPS.git is never modified manually."""
2791 if any(f.LocalPath().endswith('.DEPS.git')
2792 for f in input_api.AffectedFiles()):
2793 return [
2794 output_api.PresubmitError(
2795 'Never commit changes to .DEPS.git. This file is maintained by an\n'
2796 'automated system based on what\'s in DEPS and your changes will be\n'
2797 'overwritten.\n'
2798 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
2799 'get-the-code#Rolling_DEPS\n'
2800 'for more information')
2801 ]
2802 return []
[email protected]2a8ac9c2011-10-19 17:20:442803
2804
Sven Zheng76a79ea2022-12-21 21:25:242805def CheckCrosApiNeedBrowserTest(input_api, output_api):
2806 """Check new crosapi should add browser test."""
2807 has_new_crosapi = False
2808 has_browser_test = False
2809 for f in input_api.AffectedFiles():
2810 path = f.LocalPath()
2811 if (path.startswith('chromeos/crosapi/mojom') and
2812 _IsMojomFile(input_api, path) and f.Action() == 'A'):
2813 has_new_crosapi = True
2814 if path.endswith('browsertest.cc') or path.endswith('browser_test.cc'):
2815 has_browser_test = True
2816 if has_new_crosapi and not has_browser_test:
2817 return [
2818 output_api.PresubmitPromptWarning(
2819 'You are adding a new crosapi, but there is no file ends with '
2820 'browsertest.cc file being added or modified. It is important '
2821 'to add crosapi browser test coverage to avoid version '
2822 ' skew issues.\n'
2823 'Check //docs/lacros/test_instructions.md for more information.'
2824 )
2825 ]
2826 return []
2827
2828
Saagar Sanghavifceeaae2020-08-12 16:40:362829def CheckValidHostsInDEPSOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502830 """Checks that DEPS file deps are from allowed_hosts."""
2831 # Run only if DEPS file has been modified to annoy fewer bystanders.
2832 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
2833 return []
2834 # Outsource work to gclient verify
2835 try:
2836 gclient_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
2837 'third_party', 'depot_tools',
2838 'gclient.py')
2839 input_api.subprocess.check_output(
Bruce Dawson8a43cf72022-05-13 17:10:322840 [input_api.python3_executable, gclient_path, 'verify'],
Sam Maiera6e76d72022-02-11 21:43:502841 stderr=input_api.subprocess.STDOUT)
2842 return []
2843 except input_api.subprocess.CalledProcessError as error:
2844 return [
2845 output_api.PresubmitError(
2846 'DEPS file must have only git dependencies.',
2847 long_text=error.output)
2848 ]
tandriief664692014-09-23 14:51:472849
2850
Mario Sanchez Prada2472cab2019-09-18 10:58:312851def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152852 ban_rule):
Allen Bauer84778682022-09-22 16:28:562853 """Helper method for checking for banned constructs.
Mario Sanchez Prada2472cab2019-09-18 10:58:312854
Sam Maiera6e76d72022-02-11 21:43:502855 Returns an string composed of the name of the file, the line number where the
2856 match has been found and the additional text passed as |message| in case the
2857 target type name matches the text inside the line passed as parameter.
2858 """
2859 result = []
Peng Huang9c5949a02020-06-11 19:20:542860
Daniel Chenga44a1bcd2022-03-15 20:00:152861 # Ignore comments about banned types.
2862 if input_api.re.search(r"^ *//", line):
Sam Maiera6e76d72022-02-11 21:43:502863 return result
Daniel Chenga44a1bcd2022-03-15 20:00:152864 # A // nocheck comment will bypass this error.
2865 if line.endswith(" nocheck"):
Sam Maiera6e76d72022-02-11 21:43:502866 return result
2867
2868 matched = False
Daniel Chenga44a1bcd2022-03-15 20:00:152869 if ban_rule.pattern[0:1] == '/':
2870 regex = ban_rule.pattern[1:]
Sam Maiera6e76d72022-02-11 21:43:502871 if input_api.re.search(regex, line):
2872 matched = True
Daniel Chenga44a1bcd2022-03-15 20:00:152873 elif ban_rule.pattern in line:
Sam Maiera6e76d72022-02-11 21:43:502874 matched = True
2875
2876 if matched:
2877 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
Daniel Chenga44a1bcd2022-03-15 20:00:152878 for line in ban_rule.explanation:
2879 result.append(' %s' % line)
Sam Maiera6e76d72022-02-11 21:43:502880
danakjd18e8892020-12-17 17:42:012881 return result
Mario Sanchez Prada2472cab2019-09-18 10:58:312882
2883
Saagar Sanghavifceeaae2020-08-12 16:40:362884def CheckNoBannedFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502885 """Make sure that banned functions are not used."""
2886 warnings = []
2887 errors = []
[email protected]127f18ec2012-06-16 05:05:592888
Sam Maiera6e76d72022-02-11 21:43:502889 def IsExcludedFile(affected_file, excluded_paths):
Daniel Chenga44a1bcd2022-03-15 20:00:152890 if not excluded_paths:
2891 return False
2892
Sam Maiera6e76d72022-02-11 21:43:502893 local_path = affected_file.LocalPath()
Bruce Dawson40fece62022-09-16 19:58:312894 # Consistently use / as path separator to simplify the writing of regex
2895 # expressions.
2896 local_path = local_path.replace(input_api.os_path.sep, '/')
Sam Maiera6e76d72022-02-11 21:43:502897 for item in excluded_paths:
2898 if input_api.re.match(item, local_path):
2899 return True
2900 return False
wnwenbdc444e2016-05-25 13:44:152901
Sam Maiera6e76d72022-02-11 21:43:502902 def IsIosObjcFile(affected_file):
2903 local_path = affected_file.LocalPath()
2904 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m',
2905 '.h'):
2906 return False
2907 basename = input_api.os_path.basename(local_path)
2908 if 'ios' in basename.split('_'):
2909 return True
2910 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
2911 if sep and 'ios' in local_path.split(sep):
2912 return True
2913 return False
Sylvain Defresnea8b73d252018-02-28 15:45:542914
Daniel Chenga44a1bcd2022-03-15 20:00:152915 def CheckForMatch(affected_file, line_num: int, line: str,
2916 ban_rule: BanRule):
2917 if IsExcludedFile(affected_file, ban_rule.excluded_paths):
2918 return
2919
Sam Maiera6e76d72022-02-11 21:43:502920 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152921 ban_rule)
Sam Maiera6e76d72022-02-11 21:43:502922 if problems:
Daniel Chenga44a1bcd2022-03-15 20:00:152923 if ban_rule.treat_as_error is not None and ban_rule.treat_as_error:
Sam Maiera6e76d72022-02-11 21:43:502924 errors.extend(problems)
2925 else:
2926 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:152927
Sam Maiera6e76d72022-02-11 21:43:502928 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2929 for f in input_api.AffectedFiles(file_filter=file_filter):
2930 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152931 for ban_rule in _BANNED_JAVA_FUNCTIONS:
2932 CheckForMatch(f, line_num, line, ban_rule)
Eric Stevensona9a980972017-09-23 00:04:412933
Clement Yan9b330cb2022-11-17 05:25:292934 file_filter = lambda f: f.LocalPath().endswith(('.js', '.ts'))
2935 for f in input_api.AffectedFiles(file_filter=file_filter):
2936 for line_num, line in f.ChangedContents():
2937 for ban_rule in _BANNED_JAVASCRIPT_FUNCTIONS:
2938 CheckForMatch(f, line_num, line, ban_rule)
2939
Sam Maiera6e76d72022-02-11 21:43:502940 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
2941 for f in input_api.AffectedFiles(file_filter=file_filter):
2942 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152943 for ban_rule in _BANNED_OBJC_FUNCTIONS:
2944 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:592945
Sam Maiera6e76d72022-02-11 21:43:502946 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
2947 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152948 for ban_rule in _BANNED_IOS_OBJC_FUNCTIONS:
2949 CheckForMatch(f, line_num, line, ban_rule)
Sylvain Defresnea8b73d252018-02-28 15:45:542950
Sam Maiera6e76d72022-02-11 21:43:502951 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
2952 for f in input_api.AffectedFiles(file_filter=egtest_filter):
2953 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152954 for ban_rule in _BANNED_IOS_EGTEST_FUNCTIONS:
2955 CheckForMatch(f, line_num, line, ban_rule)
Peter K. Lee6c03ccff2019-07-15 14:40:052956
Sam Maiera6e76d72022-02-11 21:43:502957 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
2958 for f in input_api.AffectedFiles(file_filter=file_filter):
2959 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152960 for ban_rule in _BANNED_CPP_FUNCTIONS:
2961 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:592962
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152963 # As of 05/2024, iOS fully migrated ConsentLevel::kSync to kSignin, and
2964 # Android is in the process of preventing new users from entering kSync.
2965 # So the warning is restricted to those platforms.
2966 ios_pattern = input_api.re.compile('(^|[\W_])ios[\W_]')
2967 file_filter = lambda f: (f.LocalPath().endswith(('.cc', '.mm', '.h')) and
2968 ('android' in f.LocalPath() or
2969 # Simply checking for an 'ios' substring would
2970 # catch unrelated cases, use a regex.
2971 ios_pattern.search(f.LocalPath())))
2972 for f in input_api.AffectedFiles(file_filter=file_filter):
2973 for line_num, line in f.ChangedContents():
2974 for ban_rule in _DEPRECATED_SYNC_CONSENT_CPP_FUNCTIONS:
2975 CheckForMatch(f, line_num, line, ban_rule)
2976
2977 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2978 for f in input_api.AffectedFiles(file_filter=file_filter):
2979 for line_num, line in f.ChangedContents():
2980 for ban_rule in _DEPRECATED_SYNC_CONSENT_JAVA_FUNCTIONS:
2981 CheckForMatch(f, line_num, line, ban_rule)
2982
Daniel Cheng92c15e32022-03-16 17:48:222983 file_filter = lambda f: f.LocalPath().endswith(('.mojom'))
2984 for f in input_api.AffectedFiles(file_filter=file_filter):
2985 for line_num, line in f.ChangedContents():
2986 for ban_rule in _BANNED_MOJOM_PATTERNS:
2987 CheckForMatch(f, line_num, line, ban_rule)
2988
2989
Sam Maiera6e76d72022-02-11 21:43:502990 result = []
2991 if (warnings):
2992 result.append(
2993 output_api.PresubmitPromptWarning('Banned functions were used.\n' +
2994 '\n'.join(warnings)))
2995 if (errors):
2996 result.append(
2997 output_api.PresubmitError('Banned functions were used.\n' +
2998 '\n'.join(errors)))
2999 return result
[email protected]127f18ec2012-06-16 05:05:593000
Michael Thiessen44457642020-02-06 00:24:153001def _CheckAndroidNoBannedImports(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503002 """Make sure that banned java imports are not used."""
3003 errors = []
Michael Thiessen44457642020-02-06 00:24:153004
Sam Maiera6e76d72022-02-11 21:43:503005 file_filter = lambda f: f.LocalPath().endswith(('.java'))
3006 for f in input_api.AffectedFiles(file_filter=file_filter):
3007 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:153008 for ban_rule in _BANNED_JAVA_IMPORTS:
3009 # Consider merging this into the above function. There is no
3010 # real difference anymore other than helping with a little
3011 # bit of boilerplate text. Doing so means things like
3012 # `treat_as_error` will also be uniformly handled.
Sam Maiera6e76d72022-02-11 21:43:503013 problems = _GetMessageForMatchingType(input_api, f, line_num,
Daniel Chenga44a1bcd2022-03-15 20:00:153014 line, ban_rule)
Sam Maiera6e76d72022-02-11 21:43:503015 if problems:
3016 errors.extend(problems)
3017 result = []
3018 if (errors):
3019 result.append(
3020 output_api.PresubmitError('Banned imports were used.\n' +
3021 '\n'.join(errors)))
3022 return result
Michael Thiessen44457642020-02-06 00:24:153023
3024
Saagar Sanghavifceeaae2020-08-12 16:40:363025def CheckNoPragmaOnce(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503026 """Make sure that banned functions are not used."""
3027 files = []
3028 pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
3029 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
3030 if not f.LocalPath().endswith('.h'):
3031 continue
Bruce Dawson4c4c2922022-05-02 18:07:333032 if f.LocalPath().endswith('com_imported_mstscax.h'):
3033 continue
Sam Maiera6e76d72022-02-11 21:43:503034 contents = input_api.ReadFile(f)
3035 if pattern.search(contents):
3036 files.append(f)
[email protected]6c063c62012-07-11 19:11:063037
Sam Maiera6e76d72022-02-11 21:43:503038 if files:
3039 return [
3040 output_api.PresubmitError(
3041 'Do not use #pragma once in header files.\n'
3042 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
3043 files)
3044 ]
3045 return []
[email protected]6c063c62012-07-11 19:11:063046
[email protected]127f18ec2012-06-16 05:05:593047
Saagar Sanghavifceeaae2020-08-12 16:40:363048def CheckNoTrinaryTrueFalse(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503049 """Checks to make sure we don't introduce use of foo ? true : false."""
3050 problems = []
3051 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
3052 for f in input_api.AffectedFiles():
3053 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
3054 continue
[email protected]e7479052012-09-19 00:26:123055
Sam Maiera6e76d72022-02-11 21:43:503056 for line_num, line in f.ChangedContents():
3057 if pattern.match(line):
3058 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]e7479052012-09-19 00:26:123059
Sam Maiera6e76d72022-02-11 21:43:503060 if not problems:
3061 return []
3062 return [
3063 output_api.PresubmitPromptWarning(
3064 'Please consider avoiding the "? true : false" pattern if possible.\n'
3065 + '\n'.join(problems))
3066 ]
[email protected]e7479052012-09-19 00:26:123067
3068
Saagar Sanghavifceeaae2020-08-12 16:40:363069def CheckUnwantedDependencies(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503070 """Runs checkdeps on #include and import statements added in this
3071 change. Breaking - rules is an error, breaking ! rules is a
3072 warning.
3073 """
3074 # Return early if no relevant file types were modified.
3075 for f in input_api.AffectedFiles():
3076 path = f.LocalPath()
3077 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path)
3078 or _IsJavaFile(input_api, path)):
3079 break
[email protected]55f9f382012-07-31 11:02:183080 else:
Sam Maiera6e76d72022-02-11 21:43:503081 return []
rhalavati08acd232017-04-03 07:23:283082
Sam Maiera6e76d72022-02-11 21:43:503083 import sys
3084 # We need to wait until we have an input_api object and use this
3085 # roundabout construct to import checkdeps because this file is
3086 # eval-ed and thus doesn't have __file__.
3087 original_sys_path = sys.path
3088 try:
3089 sys.path = sys.path + [
3090 input_api.os_path.join(input_api.PresubmitLocalPath(),
3091 'buildtools', 'checkdeps')
3092 ]
3093 import checkdeps
3094 from rules import Rule
3095 finally:
3096 # Restore sys.path to what it was before.
3097 sys.path = original_sys_path
[email protected]55f9f382012-07-31 11:02:183098
Sam Maiera6e76d72022-02-11 21:43:503099 added_includes = []
3100 added_imports = []
3101 added_java_imports = []
3102 for f in input_api.AffectedFiles():
3103 if _IsCPlusPlusFile(input_api, f.LocalPath()):
3104 changed_lines = [line for _, line in f.ChangedContents()]
3105 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
3106 elif _IsProtoFile(input_api, f.LocalPath()):
3107 changed_lines = [line for _, line in f.ChangedContents()]
3108 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
3109 elif _IsJavaFile(input_api, f.LocalPath()):
3110 changed_lines = [line for _, line in f.ChangedContents()]
3111 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:243112
Sam Maiera6e76d72022-02-11 21:43:503113 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
3114
3115 error_descriptions = []
3116 warning_descriptions = []
3117 error_subjects = set()
3118 warning_subjects = set()
3119
3120 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
3121 added_includes):
3122 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3123 description_with_path = '%s\n %s' % (path, rule_description)
3124 if rule_type == Rule.DISALLOW:
3125 error_descriptions.append(description_with_path)
3126 error_subjects.add("#includes")
3127 else:
3128 warning_descriptions.append(description_with_path)
3129 warning_subjects.add("#includes")
3130
3131 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
3132 added_imports):
3133 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3134 description_with_path = '%s\n %s' % (path, rule_description)
3135 if rule_type == Rule.DISALLOW:
3136 error_descriptions.append(description_with_path)
3137 error_subjects.add("imports")
3138 else:
3139 warning_descriptions.append(description_with_path)
3140 warning_subjects.add("imports")
3141
3142 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
3143 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
3144 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3145 description_with_path = '%s\n %s' % (path, rule_description)
3146 if rule_type == Rule.DISALLOW:
3147 error_descriptions.append(description_with_path)
3148 error_subjects.add("imports")
3149 else:
3150 warning_descriptions.append(description_with_path)
3151 warning_subjects.add("imports")
3152
3153 results = []
3154 if error_descriptions:
3155 results.append(
3156 output_api.PresubmitError(
3157 'You added one or more %s that violate checkdeps rules.' %
3158 " and ".join(error_subjects), error_descriptions))
3159 if warning_descriptions:
3160 results.append(
3161 output_api.PresubmitPromptOrNotify(
3162 'You added one or more %s of files that are temporarily\n'
3163 'allowed but being removed. Can you avoid introducing the\n'
3164 '%s? See relevant DEPS file(s) for details and contacts.' %
3165 (" and ".join(warning_subjects), "/".join(warning_subjects)),
3166 warning_descriptions))
3167 return results
[email protected]55f9f382012-07-31 11:02:183168
3169
Saagar Sanghavifceeaae2020-08-12 16:40:363170def CheckFilePermissions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503171 """Check that all files have their permissions properly set."""
3172 if input_api.platform == 'win32':
3173 return []
3174 checkperms_tool = input_api.os_path.join(input_api.PresubmitLocalPath(),
3175 'tools', 'checkperms',
3176 'checkperms.py')
3177 args = [
Bruce Dawson8a43cf72022-05-13 17:10:323178 input_api.python3_executable, checkperms_tool, '--root',
Sam Maiera6e76d72022-02-11 21:43:503179 input_api.change.RepositoryRoot()
3180 ]
3181 with input_api.CreateTemporaryFile() as file_list:
3182 for f in input_api.AffectedFiles():
3183 # checkperms.py file/directory arguments must be relative to the
3184 # repository.
3185 file_list.write((f.LocalPath() + '\n').encode('utf8'))
3186 file_list.close()
3187 args += ['--file-list', file_list.name]
3188 try:
3189 input_api.subprocess.check_output(args)
3190 return []
3191 except input_api.subprocess.CalledProcessError as error:
3192 return [
3193 output_api.PresubmitError('checkperms.py failed:',
3194 long_text=error.output.decode(
3195 'utf-8', 'ignore'))
3196 ]
[email protected]fbcafe5a2012-08-08 15:31:223197
3198
Saagar Sanghavifceeaae2020-08-12 16:40:363199def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503200 """Makes sure we don't include ui/aura/window_property.h
3201 in header files.
3202 """
3203 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
3204 errors = []
3205 for f in input_api.AffectedFiles():
3206 if not f.LocalPath().endswith('.h'):
3207 continue
3208 for line_num, line in f.ChangedContents():
3209 if pattern.match(line):
3210 errors.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]c8278b32012-10-30 20:35:493211
Sam Maiera6e76d72022-02-11 21:43:503212 results = []
3213 if errors:
3214 results.append(
3215 output_api.PresubmitError(
3216 'Header files should not include ui/aura/window_property.h',
3217 errors))
3218 return results
[email protected]c8278b32012-10-30 20:35:493219
3220
Omer Katzcc77ea92021-04-26 10:23:283221def CheckNoInternalHeapIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503222 """Makes sure we don't include any headers from
3223 third_party/blink/renderer/platform/heap/impl or
3224 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
3225 third_party/blink/renderer/platform/heap
3226 """
3227 impl_pattern = input_api.re.compile(
3228 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
3229 v8_wrapper_pattern = input_api.re.compile(
3230 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"'
3231 )
Bruce Dawson40fece62022-09-16 19:58:313232 # Consistently use / as path separator to simplify the writing of regex
3233 # expressions.
Sam Maiera6e76d72022-02-11 21:43:503234 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:313235 r"^third_party/blink/renderer/platform/heap/.*",
3236 f.LocalPath().replace(input_api.os_path.sep, '/'))
Sam Maiera6e76d72022-02-11 21:43:503237 errors = []
Omer Katzcc77ea92021-04-26 10:23:283238
Sam Maiera6e76d72022-02-11 21:43:503239 for f in input_api.AffectedFiles(file_filter=file_filter):
3240 for line_num, line in f.ChangedContents():
3241 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
3242 errors.append(' %s:%d' % (f.LocalPath(), line_num))
Omer Katzcc77ea92021-04-26 10:23:283243
Sam Maiera6e76d72022-02-11 21:43:503244 results = []
3245 if errors:
3246 results.append(
3247 output_api.PresubmitError(
3248 'Do not include files from third_party/blink/renderer/platform/heap/impl'
3249 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
3250 'relevant counterparts from third_party/blink/renderer/platform/heap',
3251 errors))
3252 return results
Omer Katzcc77ea92021-04-26 10:23:283253
3254
[email protected]70ca77752012-11-20 03:45:033255def _CheckForVersionControlConflictsInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:503256 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
3257 errors = []
3258 for line_num, line in f.ChangedContents():
3259 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
3260 # First-level headers in markdown look a lot like version control
3261 # conflict markers. http://daringfireball.net/projects/markdown/basics
3262 continue
3263 if pattern.match(line):
3264 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
3265 return errors
[email protected]70ca77752012-11-20 03:45:033266
3267
Saagar Sanghavifceeaae2020-08-12 16:40:363268def CheckForVersionControlConflicts(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503269 """Usually this is not intentional and will cause a compile failure."""
3270 errors = []
3271 for f in input_api.AffectedFiles():
3272 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
[email protected]70ca77752012-11-20 03:45:033273
Sam Maiera6e76d72022-02-11 21:43:503274 results = []
3275 if errors:
3276 results.append(
3277 output_api.PresubmitError(
3278 'Version control conflict markers found, please resolve.',
3279 errors))
3280 return results
[email protected]70ca77752012-11-20 03:45:033281
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203282
Saagar Sanghavifceeaae2020-08-12 16:40:363283def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503284 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
3285 errors = []
3286 for f in input_api.AffectedFiles():
3287 for line_num, line in f.ChangedContents():
3288 if pattern.search(line):
3289 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
estadee17314a02017-01-12 16:22:163290
Sam Maiera6e76d72022-02-11 21:43:503291 results = []
3292 if errors:
3293 results.append(
3294 output_api.PresubmitPromptWarning(
3295 'Found Google support URL addressed by answer number. Please replace '
3296 'with a p= identifier instead. See crbug.com/679462\n',
3297 errors))
3298 return results
estadee17314a02017-01-12 16:22:163299
[email protected]70ca77752012-11-20 03:45:033300
Saagar Sanghavifceeaae2020-08-12 16:40:363301def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503302 def FilterFile(affected_file):
3303 """Filter function for use with input_api.AffectedSourceFiles,
3304 below. This filters out everything except non-test files from
3305 top-level directories that generally speaking should not hard-code
3306 service URLs (e.g. src/android_webview/, src/content/ and others).
3307 """
3308 return input_api.FilterSourceFile(
3309 affected_file,
Bruce Dawson40fece62022-09-16 19:58:313310 files_to_check=[r'^(android_webview|base|content|net)/.*'],
Sam Maiera6e76d72022-02-11 21:43:503311 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3312 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:443313
Sam Maiera6e76d72022-02-11 21:43:503314 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
3315 '\.(com|net)[^"]*"')
3316 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
3317 pattern = input_api.re.compile(base_pattern)
3318 problems = [] # items are (filename, line_number, line)
3319 for f in input_api.AffectedSourceFiles(FilterFile):
3320 for line_num, line in f.ChangedContents():
3321 if not comment_pattern.search(line) and pattern.search(line):
3322 problems.append((f.LocalPath(), line_num, line))
[email protected]06e6d0ff2012-12-11 01:36:443323
Sam Maiera6e76d72022-02-11 21:43:503324 if problems:
3325 return [
3326 output_api.PresubmitPromptOrNotify(
3327 'Most layers below src/chrome/ should not hardcode service URLs.\n'
3328 'Are you sure this is correct?', [
3329 ' %s:%d: %s' % (problem[0], problem[1], problem[2])
3330 for problem in problems
3331 ])
3332 ]
3333 else:
3334 return []
[email protected]06e6d0ff2012-12-11 01:36:443335
3336
Saagar Sanghavifceeaae2020-08-12 16:40:363337def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503338 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
James Cook6b6597c2019-11-06 22:05:293339
Sam Maiera6e76d72022-02-11 21:43:503340 def FileFilter(affected_file):
3341 """Includes directories known to be Chrome OS only."""
3342 return input_api.FilterSourceFile(
3343 affected_file,
3344 files_to_check=(
3345 '^ash/',
3346 '^chromeos/', # Top-level src/chromeos.
3347 '.*/chromeos/', # Any path component.
3348 '^components/arc',
3349 '^components/exo'),
3350 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:293351
Sam Maiera6e76d72022-02-11 21:43:503352 prefs = []
3353 priority_prefs = []
3354 for f in input_api.AffectedFiles(file_filter=FileFilter):
3355 for line_num, line in f.ChangedContents():
3356 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF',
3357 line):
3358 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
3359 prefs.append(' %s' % line)
3360 if input_api.re.search(
3361 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
3362 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
3363 priority_prefs.append(' %s' % line)
3364
3365 results = []
3366 if (prefs):
3367 results.append(
3368 output_api.PresubmitPromptWarning(
3369 'Preferences were registered as SYNCABLE_PREF and will be controlled '
3370 'by browser sync settings. If these prefs should be controlled by OS '
3371 'sync settings use SYNCABLE_OS_PREF instead.\n' +
3372 '\n'.join(prefs)))
3373 if (priority_prefs):
3374 results.append(
3375 output_api.PresubmitPromptWarning(
3376 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
3377 'controlled by browser sync settings. If these prefs should be '
3378 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
3379 'instead.\n' + '\n'.join(prefs)))
3380 return results
James Cook6b6597c2019-11-06 22:05:293381
3382
Saagar Sanghavifceeaae2020-08-12 16:40:363383def CheckNoAbbreviationInPngFileName(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503384 """Makes sure there are no abbreviations in the name of PNG files.
3385 The native_client_sdk directory is excluded because it has auto-generated PNG
3386 files for documentation.
3387 """
3388 errors = []
Yuanqing Zhu9eef02832022-12-04 14:42:173389 files_to_check = [r'.*\.png$']
Bruce Dawson40fece62022-09-16 19:58:313390 files_to_skip = [r'^native_client_sdk/',
3391 r'^services/test/',
3392 r'^third_party/blink/web_tests/',
Bruce Dawson3db456212022-05-02 05:34:183393 ]
Sam Maiera6e76d72022-02-11 21:43:503394 file_filter = lambda f: input_api.FilterSourceFile(
3395 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Yuanqing Zhu9eef02832022-12-04 14:42:173396 abbreviation = input_api.re.compile('.+_[a-z]\.png|.+_[a-z]_.*\.png')
Sam Maiera6e76d72022-02-11 21:43:503397 for f in input_api.AffectedFiles(include_deletes=False,
3398 file_filter=file_filter):
Yuanqing Zhu9eef02832022-12-04 14:42:173399 file_name = input_api.os_path.split(f.LocalPath())[1]
3400 if abbreviation.search(file_name):
3401 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:273402
Sam Maiera6e76d72022-02-11 21:43:503403 results = []
3404 if errors:
3405 results.append(
3406 output_api.PresubmitError(
3407 'The name of PNG files should not have abbreviations. \n'
3408 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
3409 'Contact [email protected] if you have questions.', errors))
3410 return results
[email protected]d2530012013-01-25 16:39:273411
Evan Stade7cd4a2c2022-08-04 23:37:253412def CheckNoProductIconsAddedToPublicRepo(input_api, output_api):
3413 """Heuristically identifies product icons based on their file name and reminds
3414 contributors not to add them to the Chromium repository.
3415 """
3416 errors = []
3417 files_to_check = [r'.*google.*\.png$|.*google.*\.svg$|.*google.*\.icon$']
3418 file_filter = lambda f: input_api.FilterSourceFile(
3419 f, files_to_check=files_to_check)
3420 for f in input_api.AffectedFiles(include_deletes=False,
3421 file_filter=file_filter):
3422 errors.append(' %s' % f.LocalPath())
3423
3424 results = []
3425 if errors:
Bruce Dawson3bcf0c92022-08-12 00:03:083426 # Give warnings instead of errors on presubmit --all and presubmit
3427 # --files.
3428 message_type = (output_api.PresubmitNotifyResult if input_api.no_diffs
3429 else output_api.PresubmitError)
Evan Stade7cd4a2c2022-08-04 23:37:253430 results.append(
Bruce Dawson3bcf0c92022-08-12 00:03:083431 message_type(
Evan Stade7cd4a2c2022-08-04 23:37:253432 'Trademarked images should not be added to the public repo. '
3433 'See crbug.com/944754', errors))
3434 return results
3435
[email protected]d2530012013-01-25 16:39:273436
Daniel Cheng4dcdb6b2017-04-13 08:30:173437def _ExtractAddRulesFromParsedDeps(parsed_deps):
Sam Maiera6e76d72022-02-11 21:43:503438 """Extract the rules that add dependencies from a parsed DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:173439
Sam Maiera6e76d72022-02-11 21:43:503440 Args:
3441 parsed_deps: the locals dictionary from evaluating the DEPS file."""
3442 add_rules = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:173443 add_rules.update([
Sam Maiera6e76d72022-02-11 21:43:503444 rule[1:] for rule in parsed_deps.get('include_rules', [])
Daniel Cheng4dcdb6b2017-04-13 08:30:173445 if rule.startswith('+') or rule.startswith('!')
3446 ])
Sam Maiera6e76d72022-02-11 21:43:503447 for _, rules in parsed_deps.get('specific_include_rules', {}).items():
3448 add_rules.update([
3449 rule[1:] for rule in rules
3450 if rule.startswith('+') or rule.startswith('!')
3451 ])
3452 return add_rules
Daniel Cheng4dcdb6b2017-04-13 08:30:173453
3454
3455def _ParseDeps(contents):
Sam Maiera6e76d72022-02-11 21:43:503456 """Simple helper for parsing DEPS files."""
Daniel Cheng4dcdb6b2017-04-13 08:30:173457
Sam Maiera6e76d72022-02-11 21:43:503458 # Stubs for handling special syntax in the root DEPS file.
3459 class _VarImpl:
3460 def __init__(self, local_scope):
3461 self._local_scope = local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:173462
Sam Maiera6e76d72022-02-11 21:43:503463 def Lookup(self, var_name):
3464 """Implements the Var syntax."""
3465 try:
3466 return self._local_scope['vars'][var_name]
3467 except KeyError:
3468 raise Exception('Var is not defined: %s' % var_name)
Daniel Cheng4dcdb6b2017-04-13 08:30:173469
Sam Maiera6e76d72022-02-11 21:43:503470 local_scope = {}
3471 global_scope = {
3472 'Var': _VarImpl(local_scope).Lookup,
3473 'Str': str,
3474 }
Dirk Pranke1b9e06382021-05-14 01:16:223475
Sam Maiera6e76d72022-02-11 21:43:503476 exec(contents, global_scope, local_scope)
3477 return local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:173478
3479
3480def _CalculateAddedDeps(os_path, old_contents, new_contents):
Sam Maiera6e76d72022-02-11 21:43:503481 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
3482 a set of DEPS entries that we should look up.
[email protected]14a6131c2014-01-08 01:15:413483
Sam Maiera6e76d72022-02-11 21:43:503484 For a directory (rather than a specific filename) we fake a path to
3485 a specific filename by adding /DEPS. This is chosen as a file that
3486 will seldom or never be subject to per-file include_rules.
3487 """
3488 # We ignore deps entries on auto-generated directories.
3489 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:083490
Sam Maiera6e76d72022-02-11 21:43:503491 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
3492 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
Daniel Cheng4dcdb6b2017-04-13 08:30:173493
Sam Maiera6e76d72022-02-11 21:43:503494 added_deps = new_deps.difference(old_deps)
Daniel Cheng4dcdb6b2017-04-13 08:30:173495
Sam Maiera6e76d72022-02-11 21:43:503496 results = set()
3497 for added_dep in added_deps:
3498 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
3499 continue
3500 # Assume that a rule that ends in .h is a rule for a specific file.
3501 if added_dep.endswith('.h'):
3502 results.add(added_dep)
3503 else:
3504 results.add(os_path.join(added_dep, 'DEPS'))
3505 return results
[email protected]f32e2d1e2013-07-26 21:39:083506
Stephanie Kimec4f55a2024-04-24 16:54:023507def CheckForNewDEPSDownloadFromGoogleStorageHooks(input_api, output_api):
3508 """Checks that there are no new download_from_google_storage hooks"""
3509 for f in input_api.AffectedFiles(include_deletes=False):
3510 if f.LocalPath() == 'DEPS':
3511 old_hooks = _ParseDeps('\n'.join(f.OldContents()))['hooks']
3512 new_hooks = _ParseDeps('\n'.join(f.NewContents()))['hooks']
3513 old_name_to_hook = {hook['name']: hook for hook in old_hooks}
3514 new_name_to_hook = {hook['name']: hook for hook in new_hooks}
3515 added_hook_names = set(new_name_to_hook.keys()) - set(
3516 old_name_to_hook.keys())
3517 if not added_hook_names:
3518 return []
3519 new_download_from_google_storage_hooks = []
3520 for new_hook in added_hook_names:
3521 hook = new_name_to_hook[new_hook]
3522 action_cmd = hook['action']
3523 if any('download_from_google_storage' in arg
3524 for arg in action_cmd):
3525 new_download_from_google_storage_hooks.append(new_hook)
3526 if new_download_from_google_storage_hooks:
3527 return [
3528 output_api.PresubmitError(
3529 'Please do not add new download_from_google_storage '
3530 'hooks. Instead, add a `gcs` dep_type entry to `deps`. '
3531 'See https://chromium.googlesource.com/chromium/src.git'
3532 '/+/refs/heads/main/docs/gcs_dependencies.md for more '
3533 'info. Added hooks:',
3534 items=new_download_from_google_storage_hooks)
3535 ]
3536 return []
3537
[email protected]f32e2d1e2013-07-26 21:39:083538
Rasika Navarangec2d33d22024-05-23 15:19:023539def CheckEachPerfettoTestDataFileHasDepsEntry(input_api, output_api):
3540 test_data_filter = lambda f: input_api.FilterSourceFile(
Rasika Navarange08e542162024-05-31 13:31:263541 f, files_to_check=[r'^base/tracing/test/data_sha256/.*\.sha256'])
Rasika Navarangec2d33d22024-05-23 15:19:023542 if not any(input_api.AffectedFiles(file_filter=test_data_filter)):
3543 return []
3544
3545 # Find DEPS entry
3546 deps_entry = []
Rasika Navarange277cd662024-06-04 10:14:593547 old_deps_entry = []
Rasika Navarangec2d33d22024-05-23 15:19:023548 for f in input_api.AffectedFiles(include_deletes=False):
3549 if f.LocalPath() == 'DEPS':
3550 new_deps = _ParseDeps('\n'.join(f.NewContents()))['deps']
3551 deps_entry = new_deps['src/base/tracing/test/data']
Rasika Navarange277cd662024-06-04 10:14:593552 old_deps = _ParseDeps('\n'.join(f.OldContents()))['deps']
3553 old_deps_entry = old_deps['src/base/tracing/test/data']
Rasika Navarangec2d33d22024-05-23 15:19:023554 if not deps_entry:
Rasika Navarange08e542162024-05-31 13:31:263555 # TODO(312895063):Add back error when .sha256 files have been moved.
Rasika Navaranged977df342024-06-05 10:01:273556 return [output_api.PresubmitError(
Rasika Navarangec2d33d22024-05-23 15:19:023557 'You must update the DEPS file when you update a '
Rasika Navarange08e542162024-05-31 13:31:263558 '.sha256 file in base/tracing/test/data_sha256'
Rasika Navarangec2d33d22024-05-23 15:19:023559 )]
3560
3561 output = []
3562 for f in input_api.AffectedFiles(file_filter=test_data_filter):
3563 objects = deps_entry['objects']
3564 if not f.NewContents():
3565 # Deleted file so check that DEPS entry removed
3566 sha256_from_file = f.OldContents()[0]
3567 object_entry = next(
3568 (item for item in objects if item["sha256sum"] == sha256_from_file),
3569 None)
Rasika Navarange277cd662024-06-04 10:14:593570 old_entry = next(
3571 (item for item in old_deps_entry['objects'] if item["sha256sum"] == sha256_from_file),
3572 None)
Rasika Navarangec2d33d22024-05-23 15:19:023573 if object_entry:
Rasika Navarange277cd662024-06-04 10:14:593574 # Allow renaming of objects with the same hash
3575 if object_entry['object_name'] != old_entry['object_name']:
3576 continue
Rasika Navarangec2d33d22024-05-23 15:19:023577 output.append(output_api.PresubmitError(
3578 'You deleted %s so you must also remove the corresponding DEPS entry.'
3579 % f.LocalPath()
3580 ))
3581 continue
3582
3583 sha256_from_file = f.NewContents()[0]
3584 object_entry = next(
3585 (item for item in objects if item["sha256sum"] == sha256_from_file),
3586 None)
3587 if not object_entry:
3588 output.append(output_api.PresubmitError(
3589 'No corresponding DEPS entry found for %s. '
3590 'Run `base/tracing/test/test_data.py get_deps --filepath %s` '
3591 'to generate the DEPS entry.'
3592 % (f.LocalPath(), f.LocalPath())
3593 ))
3594
3595 if output:
3596 output.append(output_api.PresubmitError(
3597 'The DEPS entry for `src/base/tracing/test/data` in the DEPS file has not been '
3598 'updated properly. Run `base/tracing/test/test_data.py get_all_deps` to see what '
3599 'the DEPS entry should look like.'
3600 ))
3601 return output
3602
3603
Saagar Sanghavifceeaae2020-08-12 16:40:363604def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503605 """When a dependency prefixed with + is added to a DEPS file, we
3606 want to make sure that the change is reviewed by an OWNER of the
3607 target file or directory, to avoid layering violations from being
3608 introduced. This check verifies that this happens.
3609 """
3610 # We rely on Gerrit's code-owners to check approvals.
3611 # input_api.gerrit is always set for Chromium, but other projects
3612 # might not use Gerrit.
Bruce Dawson344ab262022-06-04 11:35:103613 if not input_api.gerrit or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:503614 return []
Bruce Dawsonb357aeb2022-08-09 15:38:303615 if 'PRESUBMIT_SKIP_NETWORK' in input_api.environ:
Sam Maiera6e76d72022-02-11 21:43:503616 return []
Bruce Dawsonb357aeb2022-08-09 15:38:303617 try:
3618 if (input_api.change.issue and
3619 input_api.gerrit.IsOwnersOverrideApproved(
3620 input_api.change.issue)):
3621 # Skip OWNERS check when Owners-Override label is approved. This is
3622 # intended for global owners, trusted bots, and on-call sheriffs.
3623 # Review is still required for these changes.
3624 return []
3625 except Exception as e:
Sam Maier4cef9242022-10-03 14:21:243626 return [output_api.PresubmitPromptWarning(
3627 'Failed to retrieve owner override status - %s' % str(e))]
Edward Lesmes6fba51082021-01-20 04:20:233628
Sam Maiera6e76d72022-02-11 21:43:503629 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:243630
Bruce Dawson40fece62022-09-16 19:58:313631 # Consistently use / as path separator to simplify the writing of regex
3632 # expressions.
Sam Maiera6e76d72022-02-11 21:43:503633 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:313634 r"^third_party/blink/.*",
3635 f.LocalPath().replace(input_api.os_path.sep, '/'))
Sam Maiera6e76d72022-02-11 21:43:503636 for f in input_api.AffectedFiles(include_deletes=False,
3637 file_filter=file_filter):
3638 filename = input_api.os_path.basename(f.LocalPath())
3639 if filename == 'DEPS':
3640 virtual_depended_on_files.update(
3641 _CalculateAddedDeps(input_api.os_path,
3642 '\n'.join(f.OldContents()),
3643 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:553644
Sam Maiera6e76d72022-02-11 21:43:503645 if not virtual_depended_on_files:
3646 return []
[email protected]e871964c2013-05-13 14:14:553647
Sam Maiera6e76d72022-02-11 21:43:503648 if input_api.is_committing:
3649 if input_api.tbr:
3650 return [
3651 output_api.PresubmitNotifyResult(
3652 '--tbr was specified, skipping OWNERS check for DEPS additions'
3653 )
3654 ]
Daniel Cheng3008dc12022-05-13 04:02:113655 # TODO(dcheng): Make this generate an error on dry runs if the reviewer
3656 # is not added, to prevent review serialization.
Sam Maiera6e76d72022-02-11 21:43:503657 if input_api.dry_run:
3658 return [
3659 output_api.PresubmitNotifyResult(
3660 'This is a dry run, skipping OWNERS check for DEPS additions'
3661 )
3662 ]
3663 if not input_api.change.issue:
3664 return [
3665 output_api.PresubmitError(
3666 "DEPS approval by OWNERS check failed: this change has "
3667 "no change number, so we can't check it for approvals.")
3668 ]
3669 output = output_api.PresubmitError
[email protected]14a6131c2014-01-08 01:15:413670 else:
Sam Maiera6e76d72022-02-11 21:43:503671 output = output_api.PresubmitNotifyResult
[email protected]e871964c2013-05-13 14:14:553672
Sam Maiera6e76d72022-02-11 21:43:503673 owner_email, reviewers = (
3674 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3675 input_api, None, approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:553676
Sam Maiera6e76d72022-02-11 21:43:503677 owner_email = owner_email or input_api.change.author_email
3678
3679 approval_status = input_api.owners_client.GetFilesApprovalStatus(
3680 virtual_depended_on_files, reviewers.union([owner_email]), [])
3681 missing_files = [
3682 f for f in virtual_depended_on_files
3683 if approval_status[f] != input_api.owners_client.APPROVED
3684 ]
3685
3686 # We strip the /DEPS part that was added by
3687 # _FilesToCheckForIncomingDeps to fake a path to a file in a
3688 # directory.
3689 def StripDeps(path):
3690 start_deps = path.rfind('/DEPS')
3691 if start_deps != -1:
3692 return path[:start_deps]
3693 else:
3694 return path
3695
Scott Leebf6a0942024-06-26 22:59:393696 submodule_paths = set(input_api.ListSubmodules())
3697 def is_from_submodules(path, submodule_paths):
3698 path = input_api.os_path.normpath(path)
3699 while path:
3700 if path in submodule_paths:
3701 return True
3702
3703 # All deps should be a relative path from the checkout.
3704 # i.e., shouldn't start with "/" or "c:\", for example.
3705 #
3706 # That said, this is to prevent an infinite loop, just in case
3707 # an input dep path starts with "/", because
3708 # os.path.dirname("/") => "/"
3709 parent = input_api.os_path.dirname(path)
3710 if parent == path:
3711 break
3712 path = parent
3713
3714 return False
3715
Sam Maiera6e76d72022-02-11 21:43:503716 unapproved_dependencies = [
3717 "'+%s'," % StripDeps(path) for path in missing_files
Scott Leebf6a0942024-06-26 22:59:393718 # if a newly added dep is from a submodule, it becomes trickier
3719 # to get suggested owners, especially it is from a different host.
3720 #
3721 # skip the review enforcement for cross-repo deps.
3722 if not is_from_submodules(path, submodule_paths)
Sam Maiera6e76d72022-02-11 21:43:503723 ]
3724
3725 if unapproved_dependencies:
3726 output_list = [
3727 output(
3728 'You need LGTM from owners of depends-on paths in DEPS that were '
3729 'modified in this CL:\n %s' %
3730 '\n '.join(sorted(unapproved_dependencies)))
3731 ]
3732 suggested_owners = input_api.owners_client.SuggestOwners(
3733 missing_files, exclude=[owner_email])
3734 output_list.append(
3735 output('Suggested missing target path OWNERS:\n %s' %
3736 '\n '.join(suggested_owners or [])))
3737 return output_list
3738
3739 return []
[email protected]e871964c2013-05-13 14:14:553740
3741
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493742# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:363743def CheckSpamLogging(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503744 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3745 files_to_skip = (
3746 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3747 input_api.DEFAULT_FILES_TO_SKIP + (
Jaewon Jung2f323bb2022-12-07 23:55:013748 r"^base/fuchsia/scoped_fx_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313749 r"^base/logging\.h$",
3750 r"^base/logging\.cc$",
3751 r"^base/task/thread_pool/task_tracker\.cc$",
3752 r"^chrome/app/chrome_main_delegate\.cc$",
Yao Li359937b2023-02-15 23:43:033753 r"^chrome/browser/ash/arc/enterprise/cert_store/arc_cert_installer\.cc$",
3754 r"^chrome/browser/ash/policy/remote_commands/user_command_arc_job\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313755 r"^chrome/browser/chrome_browser_main\.cc$",
3756 r"^chrome/browser/ui/startup/startup_browser_creator\.cc$",
3757 r"^chrome/browser/browser_switcher/bho/.*",
3758 r"^chrome/browser/diagnostics/diagnostics_writer\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313759 r"^chrome/chrome_elf/dll_hash/dll_hash_main\.cc$",
3760 r"^chrome/installer/setup/.*",
Daniel Ruberyad36eea2024-08-01 01:38:323761 # crdmg runs as a separate binary which intentionally does
3762 # not depend on base logging.
3763 r"^chrome/utility/safe_browsing/mac/crdmg\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313764 r"^chromecast/",
Vigen Issahhanjane2d93822023-06-30 15:57:203765 r"^components/cast",
Bruce Dawson40fece62022-09-16 19:58:313766 r"^components/media_control/renderer/media_playback_options\.cc$",
Salma Elmahallawy52976452023-01-27 17:04:493767 r"^components/policy/core/common/policy_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313768 r"^components/viz/service/display/"
Sam Maiera6e76d72022-02-11 21:43:503769 r"overlay_strategy_underlay_cast\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313770 r"^components/zucchini/.*",
Sam Maiera6e76d72022-02-11 21:43:503771 # TODO(peter): Remove exception. https://crbug.com/534537
Bruce Dawson40fece62022-09-16 19:58:313772 r"^content/browser/notifications/"
Sam Maiera6e76d72022-02-11 21:43:503773 r"notification_event_dispatcher_impl\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313774 r"^content/common/gpu/client/gl_helper_benchmark\.cc$",
3775 r"^courgette/courgette_minimal_tool\.cc$",
3776 r"^courgette/courgette_tool\.cc$",
3777 r"^extensions/renderer/logging_native_handler\.cc$",
3778 r"^fuchsia_web/common/init_logging\.cc$",
3779 r"^fuchsia_web/runners/common/web_component\.cc$",
Caroline Liua7050132023-02-13 22:23:153780 r"^fuchsia_web/shell/.*\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313781 r"^headless/app/headless_shell\.cc$",
3782 r"^ipc/ipc_logging\.cc$",
3783 r"^native_client_sdk/",
3784 r"^remoting/base/logging\.h$",
3785 r"^remoting/host/.*",
3786 r"^sandbox/linux/.*",
Austin Sullivana6054e02024-05-20 16:31:293787 r"^services/webnn/tflite/graph_impl_tflite\.cc$",
3788 r"^services/webnn/coreml/graph_impl_coreml\.mm$",
Bruce Dawson40fece62022-09-16 19:58:313789 r"^storage/browser/file_system/dump_file_system\.cc$",
Steinar H. Gundersone5689e42024-08-07 18:17:193790 r"^testing/perf/",
Bruce Dawson40fece62022-09-16 19:58:313791 r"^tools/",
3792 r"^ui/base/resource/data_pack\.cc$",
3793 r"^ui/aura/bench/bench_main\.cc$",
3794 r"^ui/ozone/platform/cast/",
3795 r"^ui/base/x/xwmstartupcheck/"
Sam Maiera6e76d72022-02-11 21:43:503796 r"xwmstartupcheck\.cc$"))
3797 source_file_filter = lambda x: input_api.FilterSourceFile(
3798 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:403799
Sam Maiera6e76d72022-02-11 21:43:503800 log_info = set([])
3801 printf = set([])
[email protected]85218562013-11-22 07:41:403802
Sam Maiera6e76d72022-02-11 21:43:503803 for f in input_api.AffectedSourceFiles(source_file_filter):
3804 for _, line in f.ChangedContents():
3805 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
3806 log_info.add(f.LocalPath())
3807 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
3808 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:373809
Sam Maiera6e76d72022-02-11 21:43:503810 if input_api.re.search(r"\bprintf\(", line):
3811 printf.add(f.LocalPath())
3812 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
3813 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:403814
Sam Maiera6e76d72022-02-11 21:43:503815 if log_info:
3816 return [
3817 output_api.PresubmitError(
3818 'These files spam the console log with LOG(INFO):',
3819 items=log_info)
3820 ]
3821 if printf:
3822 return [
3823 output_api.PresubmitError(
3824 'These files spam the console log with printf/fprintf:',
3825 items=printf)
3826 ]
3827 return []
[email protected]85218562013-11-22 07:41:403828
3829
Saagar Sanghavifceeaae2020-08-12 16:40:363830def CheckForAnonymousVariables(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503831 """These types are all expected to hold locks while in scope and
3832 so should never be anonymous (which causes them to be immediately
3833 destroyed)."""
3834 they_who_must_be_named = [
3835 'base::AutoLock',
3836 'base::AutoReset',
3837 'base::AutoUnlock',
3838 'SkAutoAlphaRestore',
3839 'SkAutoBitmapShaderInstall',
3840 'SkAutoBlitterChoose',
3841 'SkAutoBounderCommit',
3842 'SkAutoCallProc',
3843 'SkAutoCanvasRestore',
3844 'SkAutoCommentBlock',
3845 'SkAutoDescriptor',
3846 'SkAutoDisableDirectionCheck',
3847 'SkAutoDisableOvalCheck',
3848 'SkAutoFree',
3849 'SkAutoGlyphCache',
3850 'SkAutoHDC',
3851 'SkAutoLockColors',
3852 'SkAutoLockPixels',
3853 'SkAutoMalloc',
3854 'SkAutoMaskFreeImage',
3855 'SkAutoMutexAcquire',
3856 'SkAutoPathBoundsUpdate',
3857 'SkAutoPDFRelease',
3858 'SkAutoRasterClipValidate',
3859 'SkAutoRef',
3860 'SkAutoTime',
3861 'SkAutoTrace',
3862 'SkAutoUnref',
3863 ]
3864 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
3865 # bad: base::AutoLock(lock.get());
3866 # not bad: base::AutoLock lock(lock.get());
3867 bad_pattern = input_api.re.compile(anonymous)
3868 # good: new base::AutoLock(lock.get())
3869 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
3870 errors = []
[email protected]49aa76a2013-12-04 06:59:163871
Sam Maiera6e76d72022-02-11 21:43:503872 for f in input_api.AffectedFiles():
3873 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
3874 continue
3875 for linenum, line in f.ChangedContents():
3876 if bad_pattern.search(line) and not good_pattern.search(line):
3877 errors.append('%s:%d' % (f.LocalPath(), linenum))
[email protected]49aa76a2013-12-04 06:59:163878
Sam Maiera6e76d72022-02-11 21:43:503879 if errors:
3880 return [
3881 output_api.PresubmitError(
3882 'These lines create anonymous variables that need to be named:',
3883 items=errors)
3884 ]
3885 return []
[email protected]49aa76a2013-12-04 06:59:163886
3887
Saagar Sanghavifceeaae2020-08-12 16:40:363888def CheckUniquePtrOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503889 # Returns whether |template_str| is of the form <T, U...> for some types T
Glen Robertson9142ffd72024-05-16 01:37:473890 # and U, or is invalid due to mismatched angle bracket pairs. Assumes that
3891 # |template_str| is already in the form <...>.
3892 def HasMoreThanOneArgOrInvalid(template_str):
Sam Maiera6e76d72022-02-11 21:43:503893 # Level of <...> nesting.
3894 nesting = 0
3895 for c in template_str:
3896 if c == '<':
3897 nesting += 1
3898 elif c == '>':
3899 nesting -= 1
3900 elif c == ',' and nesting == 1:
3901 return True
Glen Robertson9142ffd72024-05-16 01:37:473902 if nesting != 0:
Daniel Cheng566634ff2024-06-29 14:56:533903 # Invalid.
3904 return True
Sam Maiera6e76d72022-02-11 21:43:503905 return False
Vaclav Brozekb7fadb692018-08-30 06:39:533906
Sam Maiera6e76d72022-02-11 21:43:503907 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3908 sources = lambda affected_file: input_api.FilterSourceFile(
3909 affected_file,
3910 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3911 DEFAULT_FILES_TO_SKIP),
3912 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:553913
Sam Maiera6e76d72022-02-11 21:43:503914 # Pattern to capture a single "<...>" block of template arguments. It can
3915 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
3916 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
3917 # latter would likely require counting that < and > match, which is not
3918 # expressible in regular languages. Should the need arise, one can introduce
3919 # limited counting (matching up to a total number of nesting depth), which
3920 # should cover all practical cases for already a low nesting limit.
3921 template_arg_pattern = (
3922 r'<[^>]*' # Opening block of <.
3923 r'>([^<]*>)?') # Closing block of >.
3924 # Prefix expressing that whatever follows is not already inside a <...>
3925 # block.
3926 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
3927 null_construct_pattern = input_api.re.compile(
3928 not_inside_template_arg_pattern + r'\bstd::unique_ptr' +
3929 template_arg_pattern + r'\(\)')
Vaclav Brozeka54c528b2018-04-06 19:23:553930
Sam Maiera6e76d72022-02-11 21:43:503931 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
3932 template_arg_no_array_pattern = (
3933 r'<[^>]*[^]]' # Opening block of <.
3934 r'>([^(<]*[^]]>)?') # Closing block of >.
3935 # Prefix saying that what follows is the start of an expression.
3936 start_of_expr_pattern = r'(=|\breturn|^)\s*'
3937 # Suffix saying that what follows are call parentheses with a non-empty list
3938 # of arguments.
3939 nonempty_arg_list_pattern = r'\(([^)]|$)'
3940 # Put the template argument into a capture group for deeper examination later.
3941 return_construct_pattern = input_api.re.compile(
3942 start_of_expr_pattern + r'std::unique_ptr' + '(?P<template_arg>' +
3943 template_arg_no_array_pattern + ')' + nonempty_arg_list_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:553944
Sam Maiera6e76d72022-02-11 21:43:503945 problems_constructor = []
3946 problems_nullptr = []
3947 for f in input_api.AffectedSourceFiles(sources):
3948 for line_number, line in f.ChangedContents():
3949 # Disallow:
3950 # return std::unique_ptr<T>(foo);
3951 # bar = std::unique_ptr<T>(foo);
3952 # But allow:
3953 # return std::unique_ptr<T[]>(foo);
3954 # bar = std::unique_ptr<T[]>(foo);
3955 # And also allow cases when the second template argument is present. Those
3956 # cases cannot be handled by std::make_unique:
3957 # return std::unique_ptr<T, U>(foo);
3958 # bar = std::unique_ptr<T, U>(foo);
3959 local_path = f.LocalPath()
3960 return_construct_result = return_construct_pattern.search(line)
Glen Robertson9142ffd72024-05-16 01:37:473961 if return_construct_result and not HasMoreThanOneArgOrInvalid(
Sam Maiera6e76d72022-02-11 21:43:503962 return_construct_result.group('template_arg')):
3963 problems_constructor.append(
3964 '%s:%d\n %s' % (local_path, line_number, line.strip()))
3965 # Disallow:
3966 # std::unique_ptr<T>()
3967 if null_construct_pattern.search(line):
3968 problems_nullptr.append(
3969 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Vaclav Brozek851d9602018-04-04 16:13:053970
Sam Maiera6e76d72022-02-11 21:43:503971 errors = []
3972 if problems_nullptr:
3973 errors.append(
3974 output_api.PresubmitPromptWarning(
3975 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
3976 problems_nullptr))
3977 if problems_constructor:
3978 errors.append(
3979 output_api.PresubmitError(
3980 'The following files use explicit std::unique_ptr constructor. '
3981 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
3982 'std::make_unique is not an option.', problems_constructor))
3983 return errors
Peter Kasting4844e46e2018-02-23 07:27:103984
3985
Saagar Sanghavifceeaae2020-08-12 16:40:363986def CheckUserActionUpdate(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503987 """Checks if any new user action has been added."""
3988 if any('actions.xml' == input_api.os_path.basename(f)
3989 for f in input_api.LocalPaths()):
3990 # If actions.xml is already included in the changelist, the PRESUBMIT
3991 # for actions.xml will do a more complete presubmit check.
3992 return []
3993
3994 file_inclusion_pattern = [r'.*\.(cc|mm)$']
3995 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3996 input_api.DEFAULT_FILES_TO_SKIP)
3997 file_filter = lambda f: input_api.FilterSourceFile(
3998 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
3999
4000 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
4001 current_actions = None
4002 for f in input_api.AffectedFiles(file_filter=file_filter):
4003 for line_num, line in f.ChangedContents():
4004 match = input_api.re.search(action_re, line)
4005 if match:
4006 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
4007 # loaded only once.
4008 if not current_actions:
Bruce Dawson6cb2d4d2023-03-01 21:35:094009 with open('tools/metrics/actions/actions.xml',
4010 encoding='utf-8') as actions_f:
Sam Maiera6e76d72022-02-11 21:43:504011 current_actions = actions_f.read()
4012 # Search for the matched user action name in |current_actions|.
4013 for action_name in match.groups():
4014 action = 'name="{0}"'.format(action_name)
4015 if action not in current_actions:
4016 return [
4017 output_api.PresubmitPromptWarning(
4018 'File %s line %d: %s is missing in '
4019 'tools/metrics/actions/actions.xml. Please run '
4020 'tools/metrics/actions/extract_actions.py to update.'
4021 % (f.LocalPath(), line_num, action_name))
4022 ]
[email protected]999261d2014-03-03 20:08:084023 return []
4024
[email protected]999261d2014-03-03 20:08:084025
Daniel Cheng13ca61a882017-08-25 15:11:254026def _ImportJSONCommentEater(input_api):
Sam Maiera6e76d72022-02-11 21:43:504027 import sys
4028 sys.path = sys.path + [
4029 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4030 'json_comment_eater')
4031 ]
4032 import json_comment_eater
4033 return json_comment_eater
Daniel Cheng13ca61a882017-08-25 15:11:254034
4035
[email protected]99171a92014-06-03 08:44:474036def _GetJSONParseError(input_api, filename, eat_comments=True):
dchenge07de812016-06-20 19:27:174037 try:
Sam Maiera6e76d72022-02-11 21:43:504038 contents = input_api.ReadFile(filename)
4039 if eat_comments:
4040 json_comment_eater = _ImportJSONCommentEater(input_api)
4041 contents = json_comment_eater.Nom(contents)
dchenge07de812016-06-20 19:27:174042
Sam Maiera6e76d72022-02-11 21:43:504043 input_api.json.loads(contents)
4044 except ValueError as e:
4045 return e
Andrew Grieve4deedb12022-02-03 21:34:504046 return None
4047
4048
Sam Maiera6e76d72022-02-11 21:43:504049def _GetIDLParseError(input_api, filename):
4050 try:
4051 contents = input_api.ReadFile(filename)
Devlin Croninf7582a12022-04-21 21:14:284052 for i, char in enumerate(contents):
Daniel Chenga37c03db2022-05-12 17:20:344053 if not char.isascii():
4054 return (
4055 'Non-ascii character "%s" (ord %d) found at offset %d.' %
4056 (char, ord(char), i))
Sam Maiera6e76d72022-02-11 21:43:504057 idl_schema = input_api.os_path.join(input_api.PresubmitLocalPath(),
4058 'tools', 'json_schema_compiler',
4059 'idl_schema.py')
4060 process = input_api.subprocess.Popen(
Bruce Dawson679fb082022-04-14 00:47:284061 [input_api.python3_executable, idl_schema],
Sam Maiera6e76d72022-02-11 21:43:504062 stdin=input_api.subprocess.PIPE,
4063 stdout=input_api.subprocess.PIPE,
4064 stderr=input_api.subprocess.PIPE,
4065 universal_newlines=True)
4066 (_, error) = process.communicate(input=contents)
4067 return error or None
4068 except ValueError as e:
4069 return e
agrievef32bcc72016-04-04 14:57:404070
agrievef32bcc72016-04-04 14:57:404071
Sam Maiera6e76d72022-02-11 21:43:504072def CheckParseErrors(input_api, output_api):
4073 """Check that IDL and JSON files do not contain syntax errors."""
4074 actions = {
4075 '.idl': _GetIDLParseError,
4076 '.json': _GetJSONParseError,
4077 }
4078 # Most JSON files are preprocessed and support comments, but these do not.
4079 json_no_comments_patterns = [
Bruce Dawson40fece62022-09-16 19:58:314080 r'^testing/',
Sam Maiera6e76d72022-02-11 21:43:504081 ]
4082 # Only run IDL checker on files in these directories.
4083 idl_included_patterns = [
Bruce Dawson40fece62022-09-16 19:58:314084 r'^chrome/common/extensions/api/',
4085 r'^extensions/common/api/',
Sam Maiera6e76d72022-02-11 21:43:504086 ]
agrievef32bcc72016-04-04 14:57:404087
Sam Maiera6e76d72022-02-11 21:43:504088 def get_action(affected_file):
4089 filename = affected_file.LocalPath()
4090 return actions.get(input_api.os_path.splitext(filename)[1])
agrievef32bcc72016-04-04 14:57:404091
Sam Maiera6e76d72022-02-11 21:43:504092 def FilterFile(affected_file):
4093 action = get_action(affected_file)
4094 if not action:
4095 return False
4096 path = affected_file.LocalPath()
agrievef32bcc72016-04-04 14:57:404097
Sam Maiera6e76d72022-02-11 21:43:504098 if _MatchesFile(input_api,
4099 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS, path):
4100 return False
4101
4102 if (action == _GetIDLParseError
4103 and not _MatchesFile(input_api, idl_included_patterns, path)):
4104 return False
4105 return True
4106
4107 results = []
4108 for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
4109 include_deletes=False):
4110 action = get_action(affected_file)
4111 kwargs = {}
4112 if (action == _GetJSONParseError
4113 and _MatchesFile(input_api, json_no_comments_patterns,
4114 affected_file.LocalPath())):
4115 kwargs['eat_comments'] = False
4116 parse_error = action(input_api, affected_file.AbsoluteLocalPath(),
4117 **kwargs)
4118 if parse_error:
4119 results.append(
4120 output_api.PresubmitError(
4121 '%s could not be parsed: %s' %
4122 (affected_file.LocalPath(), parse_error)))
4123 return results
4124
4125
4126def CheckJavaStyle(input_api, output_api):
4127 """Runs checkstyle on changed java files and returns errors if any exist."""
4128
4129 # Return early if no java files were modified.
4130 if not any(
4131 _IsJavaFile(input_api, f.LocalPath())
4132 for f in input_api.AffectedFiles()):
4133 return []
4134
4135 import sys
4136 original_sys_path = sys.path
4137 try:
4138 sys.path = sys.path + [
4139 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4140 'android', 'checkstyle')
4141 ]
4142 import checkstyle
4143 finally:
4144 # Restore sys.path to what it was before.
4145 sys.path = original_sys_path
4146
Andrew Grieve4f88e3ca2022-11-22 19:09:204147 return checkstyle.run_presubmit(
Sam Maiera6e76d72022-02-11 21:43:504148 input_api,
4149 output_api,
Sam Maiera6e76d72022-02-11 21:43:504150 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
4151
4152
4153def CheckPythonDevilInit(input_api, output_api):
4154 """Checks to make sure devil is initialized correctly in python scripts."""
4155 script_common_initialize_pattern = input_api.re.compile(
4156 r'script_common\.InitializeEnvironment\(')
4157 devil_env_config_initialize = input_api.re.compile(
4158 r'devil_env\.config\.Initialize\(')
4159
4160 errors = []
4161
4162 sources = lambda affected_file: input_api.FilterSourceFile(
4163 affected_file,
4164 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314165 r'^build/android/devil_chromium\.py',
Sven Zheng8e079562024-05-10 20:11:064166 r'^tools/bisect-builds\.py',
Bruce Dawson40fece62022-09-16 19:58:314167 r'^third_party/.*',
Sam Maiera6e76d72022-02-11 21:43:504168 )),
4169 files_to_check=[r'.*\.py$'])
4170
4171 for f in input_api.AffectedSourceFiles(sources):
4172 for line_num, line in f.ChangedContents():
4173 if (script_common_initialize_pattern.search(line)
4174 or devil_env_config_initialize.search(line)):
4175 errors.append("%s:%d" % (f.LocalPath(), line_num))
4176
4177 results = []
4178
4179 if errors:
4180 results.append(
4181 output_api.PresubmitError(
4182 'Devil initialization should always be done using '
4183 'devil_chromium.Initialize() in the chromium project, to use better '
4184 'defaults for dependencies (ex. up-to-date version of adb).',
4185 errors))
4186
4187 return results
4188
4189
4190def _MatchesFile(input_api, patterns, path):
Bruce Dawson40fece62022-09-16 19:58:314191 # Consistently use / as path separator to simplify the writing of regex
4192 # expressions.
4193 path = path.replace(input_api.os_path.sep, '/')
Sam Maiera6e76d72022-02-11 21:43:504194 for pattern in patterns:
4195 if input_api.re.search(pattern, path):
4196 return True
4197 return False
4198
4199
Daniel Chenga37c03db2022-05-12 17:20:344200def _ChangeHasSecurityReviewer(input_api, owners_file):
4201 """Returns True iff the CL has a reviewer from SECURITY_OWNERS.
Sam Maiera6e76d72022-02-11 21:43:504202
Daniel Chenga37c03db2022-05-12 17:20:344203 Args:
4204 input_api: The presubmit input API.
4205 owners_file: OWNERS file with required reviewers. Typically, this is
4206 something like ipc/SECURITY_OWNERS.
4207
4208 Note: if the presubmit is running for commit rather than for upload, this
4209 only returns True if a security reviewer has also approved the CL.
Sam Maiera6e76d72022-02-11 21:43:504210 """
Daniel Chengd88244472022-05-16 09:08:474211 # Owners-Override should bypass all additional OWNERS enforcement checks.
4212 # A CR+1 vote will still be required to land this change.
4213 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
4214 input_api.change.issue)):
4215 return True
4216
Daniel Chenga37c03db2022-05-12 17:20:344217 owner_email, reviewers = (
4218 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
Daniel Cheng3008dc12022-05-13 04:02:114219 input_api,
4220 None,
4221 approval_needed=input_api.is_committing and not input_api.dry_run))
Sam Maiera6e76d72022-02-11 21:43:504222
Daniel Chenga37c03db2022-05-12 17:20:344223 security_owners = input_api.owners_client.ListOwners(owners_file)
4224 return any(owner in reviewers for owner in security_owners)
Sam Maiera6e76d72022-02-11 21:43:504225
Daniel Chenga37c03db2022-05-12 17:20:344226
4227@dataclass
Daniel Cheng171dad8d2022-05-21 00:40:254228class _SecurityProblemWithItems:
4229 problem: str
4230 items: Sequence[str]
4231
4232
4233@dataclass
Daniel Chenga37c03db2022-05-12 17:20:344234class _MissingSecurityOwnersResult:
Daniel Cheng171dad8d2022-05-21 00:40:254235 owners_file_problems: Sequence[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:344236 has_security_sensitive_files: bool
Daniel Cheng171dad8d2022-05-21 00:40:254237 missing_reviewer_problem: Optional[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:344238
4239
4240def _FindMissingSecurityOwners(input_api,
4241 output_api,
4242 file_patterns: Sequence[str],
4243 excluded_patterns: Sequence[str],
4244 required_owners_file: str,
4245 custom_rule_function: Optional[Callable] = None
4246 ) -> _MissingSecurityOwnersResult:
4247 """Find OWNERS files missing per-file rules for security-sensitive files.
4248
4249 Args:
4250 input_api: the PRESUBMIT input API object.
4251 output_api: the PRESUBMIT output API object.
4252 file_patterns: basename patterns that require a corresponding per-file
4253 security restriction.
4254 excluded_patterns: path patterns that should be exempted from
4255 requiring a security restriction.
4256 required_owners_file: path to the required OWNERS file, e.g.
4257 ipc/SECURITY_OWNERS
4258 cc_alias: If not None, email that will be CCed automatically if the
4259 change contains security-sensitive files, as determined by
4260 `file_patterns` and `excluded_patterns`.
4261 custom_rule_function: If not None, will be called with `input_api` and
4262 the current file under consideration. Returning True will add an
4263 exact match per-file rule check for the current file.
4264 """
4265
4266 # `to_check` is a mapping of an OWNERS file path to Patterns.
4267 #
4268 # Patterns is a dictionary mapping glob patterns (suitable for use in
4269 # per-file rules) to a PatternEntry.
4270 #
Sam Maiera6e76d72022-02-11 21:43:504271 # PatternEntry is a dictionary with two keys:
4272 # - 'files': the files that are matched by this pattern
4273 # - 'rules': the per-file rules needed for this pattern
Daniel Chenga37c03db2022-05-12 17:20:344274 #
Sam Maiera6e76d72022-02-11 21:43:504275 # For example, if we expect OWNERS file to contain rules for *.mojom and
4276 # *_struct_traits*.*, Patterns might look like this:
4277 # {
4278 # '*.mojom': {
4279 # 'files': ...,
4280 # 'rules': [
4281 # 'per-file *.mojom=set noparent',
4282 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
4283 # ],
4284 # },
4285 # '*_struct_traits*.*': {
4286 # 'files': ...,
4287 # 'rules': [
4288 # 'per-file *_struct_traits*.*=set noparent',
4289 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
4290 # ],
4291 # },
4292 # }
4293 to_check = {}
Daniel Chenga37c03db2022-05-12 17:20:344294 files_to_review = []
Sam Maiera6e76d72022-02-11 21:43:504295
Daniel Chenga37c03db2022-05-12 17:20:344296 def AddPatternToCheck(file, pattern):
Sam Maiera6e76d72022-02-11 21:43:504297 owners_file = input_api.os_path.join(
Daniel Chengd88244472022-05-16 09:08:474298 input_api.os_path.dirname(file.LocalPath()), 'OWNERS')
Sam Maiera6e76d72022-02-11 21:43:504299 if owners_file not in to_check:
4300 to_check[owners_file] = {}
4301 if pattern not in to_check[owners_file]:
4302 to_check[owners_file][pattern] = {
4303 'files': [],
4304 'rules': [
Daniel Chenga37c03db2022-05-12 17:20:344305 f'per-file {pattern}=set noparent',
4306 f'per-file {pattern}=file://{required_owners_file}',
Sam Maiera6e76d72022-02-11 21:43:504307 ]
4308 }
Daniel Chenged57a162022-05-25 02:56:344309 to_check[owners_file][pattern]['files'].append(file.LocalPath())
Daniel Chenga37c03db2022-05-12 17:20:344310 files_to_review.append(file.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:504311
Daniel Chenga37c03db2022-05-12 17:20:344312 # Only enforce security OWNERS rules for a directory if that directory has a
4313 # file that matches `file_patterns`. For example, if a directory only
4314 # contains *.mojom files and no *_messages*.h files, the check should only
4315 # ensure that rules for *.mojom files are present.
4316 for file in input_api.AffectedFiles(include_deletes=False):
4317 file_basename = input_api.os_path.basename(file.LocalPath())
4318 if custom_rule_function is not None and custom_rule_function(
4319 input_api, file):
4320 AddPatternToCheck(file, file_basename)
4321 continue
Sam Maiera6e76d72022-02-11 21:43:504322
Daniel Chenga37c03db2022-05-12 17:20:344323 if any(
4324 input_api.fnmatch.fnmatch(file.LocalPath(), pattern)
4325 for pattern in excluded_patterns):
Sam Maiera6e76d72022-02-11 21:43:504326 continue
4327
4328 for pattern in file_patterns:
Daniel Chenga37c03db2022-05-12 17:20:344329 # Unlike `excluded_patterns`, `file_patterns` is checked only against the
4330 # file's basename.
4331 if input_api.fnmatch.fnmatch(file_basename, pattern):
4332 AddPatternToCheck(file, pattern)
Sam Maiera6e76d72022-02-11 21:43:504333 break
4334
Daniel Chenga37c03db2022-05-12 17:20:344335 has_security_sensitive_files = bool(to_check)
Daniel Cheng171dad8d2022-05-21 00:40:254336
4337 # Check if any newly added lines in OWNERS files intersect with required
4338 # per-file OWNERS lines. If so, ensure that a security reviewer is included.
4339 # This is a hack, but is needed because the OWNERS check (by design) ignores
4340 # new OWNERS entries; otherwise, a non-owner could add someone as a new
4341 # OWNER and have that newly-added OWNER self-approve their own addition.
4342 newly_covered_files = []
4343 for file in input_api.AffectedFiles(include_deletes=False):
4344 if not file.LocalPath() in to_check:
4345 continue
4346 for _, line in file.ChangedContents():
4347 for _, entry in to_check[file.LocalPath()].items():
4348 if line in entry['rules']:
4349 newly_covered_files.extend(entry['files'])
4350
4351 missing_reviewer_problems = None
4352 if newly_covered_files and not _ChangeHasSecurityReviewer(
Daniel Chenga37c03db2022-05-12 17:20:344353 input_api, required_owners_file):
Daniel Cheng171dad8d2022-05-21 00:40:254354 missing_reviewer_problems = _SecurityProblemWithItems(
4355 f'Review from an owner in {required_owners_file} is required for '
4356 'the following newly-added files:',
4357 [f'{file}' for file in sorted(set(newly_covered_files))])
Sam Maiera6e76d72022-02-11 21:43:504358
4359 # Go through the OWNERS files to check, filtering out rules that are already
4360 # present in that OWNERS file.
4361 for owners_file, patterns in to_check.items():
4362 try:
Daniel Cheng171dad8d2022-05-21 00:40:254363 lines = set(
4364 input_api.ReadFile(
4365 input_api.os_path.join(input_api.change.RepositoryRoot(),
4366 owners_file)).splitlines())
4367 for entry in patterns.values():
4368 entry['rules'] = [
4369 rule for rule in entry['rules'] if rule not in lines
4370 ]
Sam Maiera6e76d72022-02-11 21:43:504371 except IOError:
4372 # No OWNERS file, so all the rules are definitely missing.
4373 continue
4374
4375 # All the remaining lines weren't found in OWNERS files, so emit an error.
Daniel Cheng171dad8d2022-05-21 00:40:254376 owners_file_problems = []
Daniel Chenga37c03db2022-05-12 17:20:344377
Sam Maiera6e76d72022-02-11 21:43:504378 for owners_file, patterns in to_check.items():
4379 missing_lines = []
4380 files = []
4381 for _, entry in patterns.items():
Daniel Chenged57a162022-05-25 02:56:344382 files.extend(entry['files'])
Sam Maiera6e76d72022-02-11 21:43:504383 missing_lines.extend(entry['rules'])
Sam Maiera6e76d72022-02-11 21:43:504384 if missing_lines:
Daniel Cheng171dad8d2022-05-21 00:40:254385 joined_missing_lines = '\n'.join(line for line in missing_lines)
4386 owners_file_problems.append(
4387 _SecurityProblemWithItems(
4388 'Found missing OWNERS lines for security-sensitive files. '
4389 f'Please add the following lines to {owners_file}:\n'
4390 f'{joined_missing_lines}\n\nTo ensure security review for:',
4391 files))
Daniel Chenga37c03db2022-05-12 17:20:344392
Daniel Cheng171dad8d2022-05-21 00:40:254393 return _MissingSecurityOwnersResult(owners_file_problems,
Daniel Chenga37c03db2022-05-12 17:20:344394 has_security_sensitive_files,
Daniel Cheng171dad8d2022-05-21 00:40:254395 missing_reviewer_problems)
Daniel Chenga37c03db2022-05-12 17:20:344396
4397
4398def _CheckChangeForIpcSecurityOwners(input_api, output_api):
4399 # Whether or not a file affects IPC is (mostly) determined by a simple list
4400 # of filename patterns.
4401 file_patterns = [
4402 # Legacy IPC:
4403 '*_messages.cc',
4404 '*_messages*.h',
4405 '*_param_traits*.*',
4406 # Mojo IPC:
4407 '*.mojom',
4408 '*_mojom_traits*.*',
4409 '*_type_converter*.*',
4410 # Android native IPC:
4411 '*.aidl',
4412 ]
4413
Daniel Chenga37c03db2022-05-12 17:20:344414 excluded_patterns = [
Daniel Cheng518943f2022-05-12 22:15:464415 # These third_party directories do not contain IPCs, but contain files
4416 # matching the above patterns, which trigger false positives.
Daniel Chenga37c03db2022-05-12 17:20:344417 'third_party/crashpad/*',
4418 'third_party/blink/renderer/platform/bindings/*',
4419 'third_party/protobuf/benchmarks/python/*',
4420 'third_party/win_build_output/*',
Daniel Chengd88244472022-05-16 09:08:474421 # Enum-only mojoms used for web metrics, so no security review needed.
4422 'third_party/blink/public/mojom/use_counter/metrics/*',
Daniel Chenga37c03db2022-05-12 17:20:344423 # These files are just used to communicate between class loaders running
4424 # in the same process.
4425 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
4426 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
4427 ]
4428
4429 def IsMojoServiceManifestFile(input_api, file):
4430 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
4431 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
4432 if not manifest_pattern.search(file.LocalPath()):
4433 return False
4434
4435 if test_manifest_pattern.search(file.LocalPath()):
4436 return False
4437
4438 # All actual service manifest files should contain at least one
4439 # qualified reference to service_manager::Manifest.
4440 return any('service_manager::Manifest' in line
4441 for line in file.NewContents())
4442
4443 return _FindMissingSecurityOwners(
4444 input_api,
4445 output_api,
4446 file_patterns,
4447 excluded_patterns,
4448 'ipc/SECURITY_OWNERS',
4449 custom_rule_function=IsMojoServiceManifestFile)
4450
4451
4452def _CheckChangeForFuchsiaSecurityOwners(input_api, output_api):
4453 file_patterns = [
4454 # Component specifications.
4455 '*.cml', # Component Framework v2.
4456 '*.cmx', # Component Framework v1.
4457
4458 # Fuchsia IDL protocol specifications.
4459 '*.fidl',
4460 ]
4461
4462 # Don't check for owners files for changes in these directories.
4463 excluded_patterns = [
4464 'third_party/crashpad/*',
4465 ]
4466
4467 return _FindMissingSecurityOwners(input_api, output_api, file_patterns,
4468 excluded_patterns,
4469 'build/fuchsia/SECURITY_OWNERS')
4470
4471
4472def CheckSecurityOwners(input_api, output_api):
4473 """Checks that various security-sensitive files have an IPC OWNERS rule."""
4474 ipc_results = _CheckChangeForIpcSecurityOwners(input_api, output_api)
4475 fuchsia_results = _CheckChangeForFuchsiaSecurityOwners(
4476 input_api, output_api)
4477
4478 if ipc_results.has_security_sensitive_files:
4479 output_api.AppendCC('[email protected]')
Sam Maiera6e76d72022-02-11 21:43:504480
4481 results = []
Daniel Chenga37c03db2022-05-12 17:20:344482
Daniel Cheng171dad8d2022-05-21 00:40:254483 missing_reviewer_problems = []
4484 if ipc_results.missing_reviewer_problem:
4485 missing_reviewer_problems.append(ipc_results.missing_reviewer_problem)
4486 if fuchsia_results.missing_reviewer_problem:
4487 missing_reviewer_problems.append(
4488 fuchsia_results.missing_reviewer_problem)
Daniel Chenga37c03db2022-05-12 17:20:344489
Daniel Cheng171dad8d2022-05-21 00:40:254490 # Missing reviewers are an error unless there's no issue number
4491 # associated with this branch; in that case, the presubmit is being run
4492 # with --all or --files.
4493 #
4494 # Note that upload should never be an error; otherwise, it would be
4495 # impossible to upload changes at all.
4496 if input_api.is_committing and input_api.change.issue:
4497 make_presubmit_message = output_api.PresubmitError
4498 else:
4499 make_presubmit_message = output_api.PresubmitNotifyResult
4500 for problem in missing_reviewer_problems:
Sam Maiera6e76d72022-02-11 21:43:504501 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:254502 make_presubmit_message(problem.problem, items=problem.items))
Daniel Chenga37c03db2022-05-12 17:20:344503
Daniel Cheng171dad8d2022-05-21 00:40:254504 owners_file_problems = []
4505 owners_file_problems.extend(ipc_results.owners_file_problems)
4506 owners_file_problems.extend(fuchsia_results.owners_file_problems)
Daniel Chenga37c03db2022-05-12 17:20:344507
Daniel Cheng171dad8d2022-05-21 00:40:254508 for problem in owners_file_problems:
Daniel Cheng3008dc12022-05-13 04:02:114509 # Missing per-file rules are always an error. While swarming and caching
4510 # means that uploading a patchset with updated OWNERS files and sending
4511 # it to the CQ again should not have a large incremental cost, it is
4512 # still frustrating to discover the error only after the change has
4513 # already been uploaded.
Daniel Chenga37c03db2022-05-12 17:20:344514 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:254515 output_api.PresubmitError(problem.problem, items=problem.items))
Sam Maiera6e76d72022-02-11 21:43:504516
4517 return results
4518
4519
4520def _GetFilesUsingSecurityCriticalFunctions(input_api):
4521 """Checks affected files for changes to security-critical calls. This
4522 function checks the full change diff, to catch both additions/changes
4523 and removals.
4524
4525 Returns a dict keyed by file name, and the value is a set of detected
4526 functions.
4527 """
4528 # Map of function pretty name (displayed in an error) to the pattern to
4529 # match it with.
4530 _PATTERNS_TO_CHECK = {
4531 'content::GetServiceSandboxType<>()': 'GetServiceSandboxType\\<'
4532 }
4533 _PATTERNS_TO_CHECK = {
4534 k: input_api.re.compile(v)
4535 for k, v in _PATTERNS_TO_CHECK.items()
4536 }
4537
Sam Maiera6e76d72022-02-11 21:43:504538 # We don't want to trigger on strings within this file.
4539 def presubmit_file_filter(f):
Daniel Chenga37c03db2022-05-12 17:20:344540 return 'PRESUBMIT.py' != input_api.os_path.split(f.LocalPath())[1]
Sam Maiera6e76d72022-02-11 21:43:504541
4542 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
4543 files_to_functions = {}
4544 for f in input_api.AffectedFiles(file_filter=presubmit_file_filter):
4545 diff = f.GenerateScmDiff()
4546 for line in diff.split('\n'):
4547 # Not using just RightHandSideLines() because removing a
4548 # call to a security-critical function can be just as important
4549 # as adding or changing the arguments.
4550 if line.startswith('-') or (line.startswith('+')
4551 and not line.startswith('++')):
4552 for name, pattern in _PATTERNS_TO_CHECK.items():
4553 if pattern.search(line):
4554 path = f.LocalPath()
4555 if not path in files_to_functions:
4556 files_to_functions[path] = set()
4557 files_to_functions[path].add(name)
4558 return files_to_functions
4559
4560
4561def CheckSecurityChanges(input_api, output_api):
4562 """Checks that changes involving security-critical functions are reviewed
4563 by the security team.
4564 """
4565 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
4566 if not len(files_to_functions):
4567 return []
4568
Sam Maiera6e76d72022-02-11 21:43:504569 owners_file = 'ipc/SECURITY_OWNERS'
Daniel Chenga37c03db2022-05-12 17:20:344570 if _ChangeHasSecurityReviewer(input_api, owners_file):
Sam Maiera6e76d72022-02-11 21:43:504571 return []
4572
Daniel Chenga37c03db2022-05-12 17:20:344573 msg = 'The following files change calls to security-sensitive functions\n' \
Sam Maiera6e76d72022-02-11 21:43:504574 'that need to be reviewed by {}.\n'.format(owners_file)
4575 for path, names in files_to_functions.items():
4576 msg += ' {}\n'.format(path)
4577 for name in names:
4578 msg += ' {}\n'.format(name)
4579 msg += '\n'
4580
4581 if input_api.is_committing:
4582 output = output_api.PresubmitError
Mohamed Heikale217fc852020-07-06 19:44:034583 else:
Sam Maiera6e76d72022-02-11 21:43:504584 output = output_api.PresubmitNotifyResult
4585 return [output(msg)]
4586
4587
4588def CheckSetNoParent(input_api, output_api):
4589 """Checks that set noparent is only used together with an OWNERS file in
4590 //build/OWNERS.setnoparent (see also
4591 //docs/code_reviews.md#owners-files-details)
4592 """
4593 # Return early if no OWNERS files were modified.
4594 if not any(f.LocalPath().endswith('OWNERS')
4595 for f in input_api.AffectedFiles(include_deletes=False)):
4596 return []
4597
4598 errors = []
4599
4600 allowed_owners_files_file = 'build/OWNERS.setnoparent'
4601 allowed_owners_files = set()
Bruce Dawson58a45d22023-02-27 11:24:164602 with open(allowed_owners_files_file, 'r', encoding='utf-8') as f:
Sam Maiera6e76d72022-02-11 21:43:504603 for line in f:
4604 line = line.strip()
4605 if not line or line.startswith('#'):
4606 continue
4607 allowed_owners_files.add(line)
4608
4609 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
4610
4611 for f in input_api.AffectedFiles(include_deletes=False):
4612 if not f.LocalPath().endswith('OWNERS'):
4613 continue
4614
4615 found_owners_files = set()
4616 found_set_noparent_lines = dict()
4617
4618 # Parse the OWNERS file.
4619 for lineno, line in enumerate(f.NewContents(), 1):
4620 line = line.strip()
4621 if line.startswith('set noparent'):
4622 found_set_noparent_lines[''] = lineno
4623 if line.startswith('file://'):
4624 if line in allowed_owners_files:
4625 found_owners_files.add('')
4626 if line.startswith('per-file'):
4627 match = per_file_pattern.match(line)
4628 if match:
4629 glob = match.group(1).strip()
4630 directive = match.group(2).strip()
4631 if directive == 'set noparent':
4632 found_set_noparent_lines[glob] = lineno
4633 if directive.startswith('file://'):
4634 if directive in allowed_owners_files:
4635 found_owners_files.add(glob)
4636
4637 # Check that every set noparent line has a corresponding file:// line
4638 # listed in build/OWNERS.setnoparent. An exception is made for top level
4639 # directories since src/OWNERS shouldn't review them.
Bruce Dawson6bb0d672022-04-06 15:13:494640 linux_path = f.LocalPath().replace(input_api.os_path.sep, '/')
4641 if (linux_path.count('/') != 1
4642 and (not linux_path in _EXCLUDED_SET_NO_PARENT_PATHS)):
Sam Maiera6e76d72022-02-11 21:43:504643 for set_noparent_line in found_set_noparent_lines:
4644 if set_noparent_line in found_owners_files:
4645 continue
4646 errors.append(' %s:%d' %
Bruce Dawson6bb0d672022-04-06 15:13:494647 (linux_path,
Sam Maiera6e76d72022-02-11 21:43:504648 found_set_noparent_lines[set_noparent_line]))
4649
4650 results = []
4651 if errors:
4652 if input_api.is_committing:
4653 output = output_api.PresubmitError
4654 else:
4655 output = output_api.PresubmitPromptWarning
4656 results.append(
4657 output(
4658 'Found the following "set noparent" restrictions in OWNERS files that '
4659 'do not include owners from build/OWNERS.setnoparent:',
4660 long_text='\n\n'.join(errors)))
4661 return results
4662
4663
4664def CheckUselessForwardDeclarations(input_api, output_api):
4665 """Checks that added or removed lines in non third party affected
4666 header files do not lead to new useless class or struct forward
4667 declaration.
4668 """
4669 results = []
4670 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
4671 input_api.re.MULTILINE)
4672 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
4673 input_api.re.MULTILINE)
4674 for f in input_api.AffectedFiles(include_deletes=False):
4675 if (f.LocalPath().startswith('third_party')
4676 and not f.LocalPath().startswith('third_party/blink')
4677 and not f.LocalPath().startswith('third_party\\blink')):
4678 continue
4679
4680 if not f.LocalPath().endswith('.h'):
4681 continue
4682
4683 contents = input_api.ReadFile(f)
4684 fwd_decls = input_api.re.findall(class_pattern, contents)
4685 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
4686
4687 useless_fwd_decls = []
4688 for decl in fwd_decls:
4689 count = sum(1 for _ in input_api.re.finditer(
4690 r'\b%s\b' % input_api.re.escape(decl), contents))
4691 if count == 1:
4692 useless_fwd_decls.append(decl)
4693
4694 if not useless_fwd_decls:
4695 continue
4696
4697 for line in f.GenerateScmDiff().splitlines():
4698 if (line.startswith('-') and not line.startswith('--')
4699 or line.startswith('+') and not line.startswith('++')):
4700 for decl in useless_fwd_decls:
4701 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
4702 results.append(
4703 output_api.PresubmitPromptWarning(
4704 '%s: %s forward declaration is no longer needed'
4705 % (f.LocalPath(), decl)))
4706 useless_fwd_decls.remove(decl)
4707
4708 return results
4709
4710
4711def _CheckAndroidDebuggableBuild(input_api, output_api):
4712 """Checks that code uses BuildInfo.isDebugAndroid() instead of
4713 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
4714 this is a debuggable build of Android.
4715 """
4716 build_type_check_pattern = input_api.re.compile(
4717 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
4718
4719 errors = []
4720
4721 sources = lambda affected_file: input_api.FilterSourceFile(
4722 affected_file,
4723 files_to_skip=(
4724 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4725 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314726 r"^android_webview/support_library/boundary_interfaces/",
4727 r"^chrome/android/webapk/.*",
4728 r'^third_party/.*',
4729 r"tools/android/customtabs_benchmark/.*",
4730 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504731 )),
4732 files_to_check=[r'.*\.java$'])
4733
4734 for f in input_api.AffectedSourceFiles(sources):
4735 for line_num, line in f.ChangedContents():
4736 if build_type_check_pattern.search(line):
4737 errors.append("%s:%d" % (f.LocalPath(), line_num))
4738
4739 results = []
4740
4741 if errors:
4742 results.append(
4743 output_api.PresubmitPromptWarning(
4744 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
4745 ' Please use BuildInfo.isDebugAndroid() instead.', errors))
4746
4747 return results
4748
4749# TODO: add unit tests
4750def _CheckAndroidToastUsage(input_api, output_api):
4751 """Checks that code uses org.chromium.ui.widget.Toast instead of
4752 android.widget.Toast (Chromium Toast doesn't force hardware
4753 acceleration on low-end devices, saving memory).
4754 """
4755 toast_import_pattern = input_api.re.compile(
4756 r'^import android\.widget\.Toast;$')
4757
4758 errors = []
4759
4760 sources = lambda affected_file: input_api.FilterSourceFile(
4761 affected_file,
4762 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
Bruce Dawson40fece62022-09-16 19:58:314763 DEFAULT_FILES_TO_SKIP + (r'^chromecast/.*',
4764 r'^remoting/.*')),
Sam Maiera6e76d72022-02-11 21:43:504765 files_to_check=[r'.*\.java$'])
4766
4767 for f in input_api.AffectedSourceFiles(sources):
4768 for line_num, line in f.ChangedContents():
4769 if toast_import_pattern.search(line):
4770 errors.append("%s:%d" % (f.LocalPath(), line_num))
4771
4772 results = []
4773
4774 if errors:
4775 results.append(
4776 output_api.PresubmitError(
4777 'android.widget.Toast usage is detected. Android toasts use hardware'
4778 ' acceleration, and can be\ncostly on low-end devices. Please use'
4779 ' org.chromium.ui.widget.Toast instead.\n'
4780 'Contact [email protected] if you have any questions.',
4781 errors))
4782
4783 return results
4784
4785
4786def _CheckAndroidCrLogUsage(input_api, output_api):
4787 """Checks that new logs using org.chromium.base.Log:
4788 - Are using 'TAG' as variable name for the tags (warn)
4789 - Are using a tag that is shorter than 20 characters (error)
4790 """
4791
4792 # Do not check format of logs in the given files
4793 cr_log_check_excluded_paths = [
4794 # //chrome/android/webapk cannot depend on //base
Bruce Dawson40fece62022-09-16 19:58:314795 r"^chrome/android/webapk/.*",
Sam Maiera6e76d72022-02-11 21:43:504796 # WebView license viewer code cannot depend on //base; used in stub APK.
Bruce Dawson40fece62022-09-16 19:58:314797 r"^android_webview/glue/java/src/com/android/"
4798 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504799 # The customtabs_benchmark is a small app that does not depend on Chromium
4800 # java pieces.
Bruce Dawson40fece62022-09-16 19:58:314801 r"tools/android/customtabs_benchmark/.*",
Sam Maiera6e76d72022-02-11 21:43:504802 ]
4803
4804 cr_log_import_pattern = input_api.re.compile(
4805 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
4806 class_in_base_pattern = input_api.re.compile(
4807 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
4808 has_some_log_import_pattern = input_api.re.compile(r'^import .*\.Log;$',
4809 input_api.re.MULTILINE)
4810 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
4811 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
4812 log_decl_pattern = input_api.re.compile(
4813 r'static final String TAG = "(?P<name>(.*))"')
4814 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
4815
4816 REF_MSG = ('See docs/android_logging.md for more info.')
4817 sources = lambda x: input_api.FilterSourceFile(
4818 x,
4819 files_to_check=[r'.*\.java$'],
4820 files_to_skip=cr_log_check_excluded_paths)
4821
4822 tag_decl_errors = []
Andrew Grieved3a35d82024-01-02 21:24:384823 tag_length_errors = []
Sam Maiera6e76d72022-02-11 21:43:504824 tag_errors = []
4825 tag_with_dot_errors = []
4826 util_log_errors = []
4827
4828 for f in input_api.AffectedSourceFiles(sources):
4829 file_content = input_api.ReadFile(f)
4830 has_modified_logs = False
4831 # Per line checks
4832 if (cr_log_import_pattern.search(file_content)
4833 or (class_in_base_pattern.search(file_content)
4834 and not has_some_log_import_pattern.search(file_content))):
4835 # Checks to run for files using cr log
4836 for line_num, line in f.ChangedContents():
4837 if rough_log_decl_pattern.search(line):
4838 has_modified_logs = True
4839
4840 # Check if the new line is doing some logging
4841 match = log_call_pattern.search(line)
4842 if match:
4843 has_modified_logs = True
4844
4845 # Make sure it uses "TAG"
4846 if not match.group('tag') == 'TAG':
4847 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
4848 else:
4849 # Report non cr Log function calls in changed lines
4850 for line_num, line in f.ChangedContents():
4851 if log_call_pattern.search(line):
4852 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
4853
4854 # Per file checks
4855 if has_modified_logs:
4856 # Make sure the tag is using the "cr" prefix and is not too long
4857 match = log_decl_pattern.search(file_content)
4858 tag_name = match.group('name') if match else None
4859 if not tag_name:
4860 tag_decl_errors.append(f.LocalPath())
Andrew Grieved3a35d82024-01-02 21:24:384861 elif len(tag_name) > 20:
4862 tag_length_errors.append(f.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:504863 elif '.' in tag_name:
4864 tag_with_dot_errors.append(f.LocalPath())
4865
4866 results = []
4867 if tag_decl_errors:
4868 results.append(
4869 output_api.PresubmitPromptWarning(
4870 'Please define your tags using the suggested format: .\n'
4871 '"private static final String TAG = "<package tag>".\n'
4872 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
4873 tag_decl_errors))
4874
Andrew Grieved3a35d82024-01-02 21:24:384875 if tag_length_errors:
4876 results.append(
4877 output_api.PresubmitError(
4878 'The tag length is restricted by the system to be at most '
4879 '20 characters.\n' + REF_MSG, tag_length_errors))
4880
Sam Maiera6e76d72022-02-11 21:43:504881 if tag_errors:
4882 results.append(
4883 output_api.PresubmitPromptWarning(
4884 'Please use a variable named "TAG" for your log tags.\n' +
4885 REF_MSG, tag_errors))
4886
4887 if util_log_errors:
4888 results.append(
4889 output_api.PresubmitPromptWarning(
4890 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
4891 util_log_errors))
4892
4893 if tag_with_dot_errors:
4894 results.append(
4895 output_api.PresubmitPromptWarning(
4896 'Dot in log tags cause them to be elided in crash reports.\n' +
4897 REF_MSG, tag_with_dot_errors))
4898
4899 return results
4900
4901
Sam Maiera6e76d72022-02-11 21:43:504902def _CheckAndroidTestAnnotationUsage(input_api, output_api):
4903 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
4904 deprecated_annotation_import_pattern = input_api.re.compile(
4905 r'^import android\.test\.suitebuilder\.annotation\..*;',
4906 input_api.re.MULTILINE)
4907 sources = lambda x: input_api.FilterSourceFile(
4908 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
4909 errors = []
4910 for f in input_api.AffectedFiles(file_filter=sources):
4911 for line_num, line in f.ChangedContents():
4912 if deprecated_annotation_import_pattern.search(line):
4913 errors.append("%s:%d" % (f.LocalPath(), line_num))
4914
4915 results = []
4916 if errors:
4917 results.append(
4918 output_api.PresubmitError(
4919 'Annotations in android.test.suitebuilder.annotation have been'
Mohamed Heikal3d7a94c2023-03-28 16:55:244920 ' deprecated since API level 24. Please use androidx.test.filters'
4921 ' from //third_party/androidx:androidx_test_runner_java instead.'
Sam Maiera6e76d72022-02-11 21:43:504922 ' Contact [email protected] if you have any questions.',
4923 errors))
4924 return results
4925
4926
4927def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
4928 """Checks if MDPI assets are placed in a correct directory."""
Bruce Dawson6c05e852022-07-21 15:48:514929 file_filter = lambda f: (f.LocalPath().endswith(
4930 '.png') and ('/res/drawable/'.replace('/', input_api.os_path.sep) in f.
4931 LocalPath() or '/res/drawable-ldrtl/'.replace(
4932 '/', input_api.os_path.sep) in f.LocalPath()))
Sam Maiera6e76d72022-02-11 21:43:504933 errors = []
4934 for f in input_api.AffectedFiles(include_deletes=False,
4935 file_filter=file_filter):
4936 errors.append(' %s' % f.LocalPath())
4937
4938 results = []
4939 if errors:
4940 results.append(
4941 output_api.PresubmitError(
4942 'MDPI assets should be placed in /res/drawable-mdpi/ or '
4943 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
4944 '/res/drawable-ldrtl/.\n'
4945 'Contact [email protected] if you have questions.', errors))
4946 return results
4947
4948
4949def _CheckAndroidWebkitImports(input_api, output_api):
4950 """Checks that code uses org.chromium.base.Callback instead of
4951 android.webview.ValueCallback except in the WebView glue layer
4952 and WebLayer.
4953 """
4954 valuecallback_import_pattern = input_api.re.compile(
4955 r'^import android\.webkit\.ValueCallback;$')
4956
4957 errors = []
4958
4959 sources = lambda affected_file: input_api.FilterSourceFile(
4960 affected_file,
4961 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4962 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314963 r'^android_webview/glue/.*',
elabadysayedcbbaea72024-08-01 16:10:424964 r'^android_webview/support_library/.*',
Bruce Dawson40fece62022-09-16 19:58:314965 r'^weblayer/.*',
Sam Maiera6e76d72022-02-11 21:43:504966 )),
4967 files_to_check=[r'.*\.java$'])
4968
4969 for f in input_api.AffectedSourceFiles(sources):
4970 for line_num, line in f.ChangedContents():
4971 if valuecallback_import_pattern.search(line):
4972 errors.append("%s:%d" % (f.LocalPath(), line_num))
4973
4974 results = []
4975
4976 if errors:
4977 results.append(
4978 output_api.PresubmitError(
4979 'android.webkit.ValueCallback usage is detected outside of the glue'
4980 ' layer. To stay compatible with the support library, android.webkit.*'
4981 ' classes should only be used inside the glue layer and'
4982 ' org.chromium.base.Callback should be used instead.', errors))
4983
4984 return results
4985
4986
4987def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
4988 """Checks Android XML styles """
4989
4990 # Return early if no relevant files were modified.
4991 if not any(
4992 _IsXmlOrGrdFile(input_api, f.LocalPath())
4993 for f in input_api.AffectedFiles(include_deletes=False)):
4994 return []
4995
4996 import sys
4997 original_sys_path = sys.path
4998 try:
4999 sys.path = sys.path + [
5000 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5001 'android', 'checkxmlstyle')
5002 ]
5003 import checkxmlstyle
5004 finally:
5005 # Restore sys.path to what it was before.
5006 sys.path = original_sys_path
5007
5008 if is_check_on_upload:
5009 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
5010 else:
5011 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
5012
5013
5014def _CheckAndroidInfoBarDeprecation(input_api, output_api):
5015 """Checks Android Infobar Deprecation """
5016
5017 import sys
5018 original_sys_path = sys.path
5019 try:
5020 sys.path = sys.path + [
5021 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5022 'android', 'infobar_deprecation')
5023 ]
5024 import infobar_deprecation
5025 finally:
5026 # Restore sys.path to what it was before.
5027 sys.path = original_sys_path
5028
5029 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
5030
5031
5032class _PydepsCheckerResult:
5033 def __init__(self, cmd, pydeps_path, process, old_contents):
5034 self._cmd = cmd
5035 self._pydeps_path = pydeps_path
5036 self._process = process
5037 self._old_contents = old_contents
5038
5039 def GetError(self):
5040 """Returns an error message, or None."""
5041 import difflib
Andrew Grieved27620b62023-07-13 16:35:075042 new_contents = self._process.stdout.read().splitlines()[2:]
Sam Maiera6e76d72022-02-11 21:43:505043 if self._process.wait() != 0:
5044 # STDERR should already be printed.
5045 return 'Command failed: ' + self._cmd
Sam Maiera6e76d72022-02-11 21:43:505046 if self._old_contents != new_contents:
5047 diff = '\n'.join(
5048 difflib.context_diff(self._old_contents, new_contents))
5049 return ('File is stale: {}\n'
5050 'Diff (apply to fix):\n'
5051 '{}\n'
5052 'To regenerate, run:\n\n'
5053 ' {}').format(self._pydeps_path, diff, self._cmd)
5054 return None
5055
5056
5057class PydepsChecker:
5058 def __init__(self, input_api, pydeps_files):
5059 self._file_cache = {}
5060 self._input_api = input_api
5061 self._pydeps_files = pydeps_files
5062
5063 def _LoadFile(self, path):
5064 """Returns the list of paths within a .pydeps file relative to //."""
5065 if path not in self._file_cache:
5066 with open(path, encoding='utf-8') as f:
5067 self._file_cache[path] = f.read()
5068 return self._file_cache[path]
5069
5070 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
Gao Shenga79ebd42022-08-08 17:25:595071 """Returns an iterable of paths within the .pydep, relativized to //."""
Sam Maiera6e76d72022-02-11 21:43:505072 pydeps_data = self._LoadFile(pydeps_path)
5073 uses_gn_paths = '--gn-paths' in pydeps_data
5074 entries = (l for l in pydeps_data.splitlines()
5075 if not l.startswith('#'))
5076 if uses_gn_paths:
5077 # Paths look like: //foo/bar/baz
5078 return (e[2:] for e in entries)
5079 else:
5080 # Paths look like: path/relative/to/file.pydeps
5081 os_path = self._input_api.os_path
5082 pydeps_dir = os_path.dirname(pydeps_path)
5083 return (os_path.normpath(os_path.join(pydeps_dir, e))
5084 for e in entries)
5085
5086 def _CreateFilesToPydepsMap(self):
5087 """Returns a map of local_path -> list_of_pydeps."""
5088 ret = {}
5089 for pydep_local_path in self._pydeps_files:
5090 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
5091 ret.setdefault(path, []).append(pydep_local_path)
5092 return ret
5093
5094 def ComputeAffectedPydeps(self):
5095 """Returns an iterable of .pydeps files that might need regenerating."""
5096 affected_pydeps = set()
5097 file_to_pydeps_map = None
5098 for f in self._input_api.AffectedFiles(include_deletes=True):
5099 local_path = f.LocalPath()
5100 # Changes to DEPS can lead to .pydeps changes if any .py files are in
5101 # subrepositories. We can't figure out which files change, so re-check
5102 # all files.
5103 # Changes to print_python_deps.py affect all .pydeps.
5104 if local_path in ('DEPS', 'PRESUBMIT.py'
5105 ) or local_path.endswith('print_python_deps.py'):
5106 return self._pydeps_files
5107 elif local_path.endswith('.pydeps'):
5108 if local_path in self._pydeps_files:
5109 affected_pydeps.add(local_path)
5110 elif local_path.endswith('.py'):
5111 if file_to_pydeps_map is None:
5112 file_to_pydeps_map = self._CreateFilesToPydepsMap()
5113 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
5114 return affected_pydeps
5115
5116 def DetermineIfStaleAsync(self, pydeps_path):
5117 """Runs print_python_deps.py to see if the files is stale."""
5118 import os
5119
5120 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
5121 if old_pydeps_data:
5122 cmd = old_pydeps_data[1][1:].strip()
5123 if '--output' not in cmd:
5124 cmd += ' --output ' + pydeps_path
5125 old_contents = old_pydeps_data[2:]
5126 else:
5127 # A default cmd that should work in most cases (as long as pydeps filename
5128 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
5129 # file is empty/new.
5130 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
5131 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
5132 old_contents = []
5133 env = dict(os.environ)
5134 env['PYTHONDONTWRITEBYTECODE'] = '1'
5135 process = self._input_api.subprocess.Popen(
5136 cmd + ' --output ""',
5137 shell=True,
5138 env=env,
5139 stdout=self._input_api.subprocess.PIPE,
5140 encoding='utf-8')
5141 return _PydepsCheckerResult(cmd, pydeps_path, process, old_contents)
agrievef32bcc72016-04-04 14:57:405142
5143
Tibor Goldschwendt360793f72019-06-25 18:23:495144def _ParseGclientArgs():
Sam Maiera6e76d72022-02-11 21:43:505145 args = {}
5146 with open('build/config/gclient_args.gni', 'r') as f:
5147 for line in f:
5148 line = line.strip()
5149 if not line or line.startswith('#'):
5150 continue
5151 attribute, value = line.split('=')
5152 args[attribute.strip()] = value.strip()
5153 return args
Tibor Goldschwendt360793f72019-06-25 18:23:495154
5155
Saagar Sanghavifceeaae2020-08-12 16:40:365156def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
Sam Maiera6e76d72022-02-11 21:43:505157 """Checks if a .pydeps file needs to be regenerated."""
5158 # This check is for Python dependency lists (.pydeps files), and involves
5159 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
5160 # doesn't work on Windows and Mac, so skip it on other platforms.
5161 if not input_api.platform.startswith('linux'):
5162 return []
Erik Staabc734cd7a2021-11-23 03:11:525163
Sam Maiera6e76d72022-02-11 21:43:505164 results = []
5165 # First, check for new / deleted .pydeps.
5166 for f in input_api.AffectedFiles(include_deletes=True):
5167 # Check whether we are running the presubmit check for a file in src.
5168 # f.LocalPath is relative to repo (src, or internal repo).
5169 # os_path.exists is relative to src repo.
5170 # Therefore if os_path.exists is true, it means f.LocalPath is relative
5171 # to src and we can conclude that the pydeps is in src.
5172 if f.LocalPath().endswith('.pydeps'):
5173 if input_api.os_path.exists(f.LocalPath()):
5174 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
5175 results.append(
5176 output_api.PresubmitError(
5177 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
5178 'remove %s' % f.LocalPath()))
5179 elif f.Action() != 'D' and f.LocalPath(
5180 ) not in _ALL_PYDEPS_FILES:
5181 results.append(
5182 output_api.PresubmitError(
5183 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
5184 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:405185
Sam Maiera6e76d72022-02-11 21:43:505186 if results:
5187 return results
5188
Gavin Mak23884402024-07-25 20:39:265189 try:
5190 parsed_args = _ParseGclientArgs()
5191 except FileNotFoundError:
5192 message = (
5193 'build/config/gclient_args.gni not found. Please make sure your '
5194 'workspace has been initialized with gclient sync.'
5195 )
5196 import sys
5197 original_sys_path = sys.path
5198 try:
5199 sys.path = sys.path + [
5200 input_api.os_path.join(input_api.PresubmitLocalPath(),
5201 'third_party', 'depot_tools')
5202 ]
5203 import gclient_utils
5204 if gclient_utils.IsEnvCog():
5205 # Users will always hit this when they run presubmits before cog
5206 # workspace initialization finishes. The check shouldn't fail in
5207 # this case. This is an unavoidable workaround that's needed for
5208 # good presubmit UX for cog.
5209 results.append(output_api.PresubmitPromptWarning(message))
5210 else:
5211 results.append(output_api.PresubmitError(message))
5212 return results
5213 finally:
5214 # Restore sys.path to what it was before.
5215 sys.path = original_sys_path
5216
5217 is_android = parsed_args.get('checkout_android', 'false') == 'true'
Sam Maiera6e76d72022-02-11 21:43:505218 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
5219 affected_pydeps = set(checker.ComputeAffectedPydeps())
5220 affected_android_pydeps = affected_pydeps.intersection(
5221 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
5222 if affected_android_pydeps and not is_android:
5223 results.append(
5224 output_api.PresubmitPromptOrNotify(
5225 'You have changed python files that may affect pydeps for android\n'
Gao Shenga79ebd42022-08-08 17:25:595226 'specific scripts. However, the relevant presubmit check cannot be\n'
Sam Maiera6e76d72022-02-11 21:43:505227 'run because you are not using an Android checkout. To validate that\n'
5228 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
5229 'use the android-internal-presubmit optional trybot.\n'
5230 'Possibly stale pydeps files:\n{}'.format(
5231 '\n'.join(affected_android_pydeps))))
5232
5233 all_pydeps = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
5234 pydeps_to_check = affected_pydeps.intersection(all_pydeps)
5235 # Process these concurrently, as each one takes 1-2 seconds.
5236 pydep_results = [checker.DetermineIfStaleAsync(p) for p in pydeps_to_check]
5237 for result in pydep_results:
5238 error_msg = result.GetError()
5239 if error_msg:
5240 results.append(output_api.PresubmitError(error_msg))
5241
agrievef32bcc72016-04-04 14:57:405242 return results
5243
agrievef32bcc72016-04-04 14:57:405244
Saagar Sanghavifceeaae2020-08-12 16:40:365245def CheckSingletonInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505246 """Checks to make sure no header files have |Singleton<|."""
5247
5248 def FileFilter(affected_file):
5249 # It's ok for base/memory/singleton.h to have |Singleton<|.
5250 files_to_skip = (_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
Bruce Dawson40fece62022-09-16 19:58:315251 (r"^base/memory/singleton\.h$",
5252 r"^net/quic/platform/impl/quic_singleton_impl\.h$"))
Sam Maiera6e76d72022-02-11 21:43:505253 return input_api.FilterSourceFile(affected_file,
5254 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:435255
Sam Maiera6e76d72022-02-11 21:43:505256 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
5257 files = []
5258 for f in input_api.AffectedSourceFiles(FileFilter):
5259 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx')
5260 or f.LocalPath().endswith('.hpp')
5261 or f.LocalPath().endswith('.inl')):
5262 contents = input_api.ReadFile(f)
5263 for line in contents.splitlines(False):
5264 if (not line.lstrip().startswith('//')
5265 and # Strip C++ comment.
5266 pattern.search(line)):
5267 files.append(f)
5268 break
glidere61efad2015-02-18 17:39:435269
Sam Maiera6e76d72022-02-11 21:43:505270 if files:
5271 return [
5272 output_api.PresubmitError(
5273 'Found base::Singleton<T> in the following header files.\n' +
5274 'Please move them to an appropriate source file so that the ' +
5275 'template gets instantiated in a single compilation unit.',
5276 files)
5277 ]
5278 return []
glidere61efad2015-02-18 17:39:435279
5280
[email protected]fd20b902014-05-09 02:14:535281_DEPRECATED_CSS = [
5282 # Values
5283 ( "-webkit-box", "flex" ),
5284 ( "-webkit-inline-box", "inline-flex" ),
5285 ( "-webkit-flex", "flex" ),
5286 ( "-webkit-inline-flex", "inline-flex" ),
5287 ( "-webkit-min-content", "min-content" ),
5288 ( "-webkit-max-content", "max-content" ),
5289
5290 # Properties
5291 ( "-webkit-background-clip", "background-clip" ),
5292 ( "-webkit-background-origin", "background-origin" ),
5293 ( "-webkit-background-size", "background-size" ),
5294 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:445295 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:535296
5297 # Functions
5298 ( "-webkit-gradient", "gradient" ),
5299 ( "-webkit-repeating-gradient", "repeating-gradient" ),
5300 ( "-webkit-linear-gradient", "linear-gradient" ),
5301 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
5302 ( "-webkit-radial-gradient", "radial-gradient" ),
5303 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
5304]
5305
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:205306
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:495307# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:365308def CheckNoDeprecatedCss(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505309 """ Make sure that we don't use deprecated CSS
5310 properties, functions or values. Our external
5311 documentation and iOS CSS for dom distiller
5312 (reader mode) are ignored by the hooks as it
5313 needs to be consumed by WebKit. """
5314 results = []
5315 file_inclusion_pattern = [r".+\.css$"]
5316 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
5317 input_api.DEFAULT_FILES_TO_SKIP +
5318 (r"^chrome/common/extensions/docs", r"^chrome/docs",
Teresa Mao1d910882024-04-26 21:06:255319 r"^native_client_sdk",
5320 # The NTP team prefers reserving -webkit-line-clamp for
5321 # ellipsis effect which can only be used with -webkit-box.
5322 r"ui/webui/resources/cr_components/most_visited/.*\.css$"))
Sam Maiera6e76d72022-02-11 21:43:505323 file_filter = lambda f: input_api.FilterSourceFile(
5324 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
5325 for fpath in input_api.AffectedFiles(file_filter=file_filter):
5326 for line_num, line in fpath.ChangedContents():
5327 for (deprecated_value, value) in _DEPRECATED_CSS:
5328 if deprecated_value in line:
5329 results.append(
5330 output_api.PresubmitError(
5331 "%s:%d: Use of deprecated CSS %s, use %s instead" %
5332 (fpath.LocalPath(), line_num, deprecated_value,
5333 value)))
5334 return results
[email protected]fd20b902014-05-09 02:14:535335
mohan.reddyf21db962014-10-16 12:26:475336
Saagar Sanghavifceeaae2020-08-12 16:40:365337def CheckForRelativeIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505338 bad_files = {}
5339 for f in input_api.AffectedFiles(include_deletes=False):
5340 if (f.LocalPath().startswith('third_party')
5341 and not f.LocalPath().startswith('third_party/blink')
5342 and not f.LocalPath().startswith('third_party\\blink')):
5343 continue
rlanday6802cf632017-05-30 17:48:365344
Sam Maiera6e76d72022-02-11 21:43:505345 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
5346 continue
rlanday6802cf632017-05-30 17:48:365347
Sam Maiera6e76d72022-02-11 21:43:505348 relative_includes = [
5349 line for _, line in f.ChangedContents()
5350 if "#include" in line and "../" in line
5351 ]
5352 if not relative_includes:
5353 continue
5354 bad_files[f.LocalPath()] = relative_includes
rlanday6802cf632017-05-30 17:48:365355
Sam Maiera6e76d72022-02-11 21:43:505356 if not bad_files:
5357 return []
rlanday6802cf632017-05-30 17:48:365358
Sam Maiera6e76d72022-02-11 21:43:505359 error_descriptions = []
5360 for file_path, bad_lines in bad_files.items():
5361 error_description = file_path
5362 for line in bad_lines:
5363 error_description += '\n ' + line
5364 error_descriptions.append(error_description)
rlanday6802cf632017-05-30 17:48:365365
Sam Maiera6e76d72022-02-11 21:43:505366 results = []
5367 results.append(
5368 output_api.PresubmitError(
5369 'You added one or more relative #include paths (including "../").\n'
5370 'These shouldn\'t be used because they can be used to include headers\n'
5371 'from code that\'s not correctly specified as a dependency in the\n'
5372 'relevant BUILD.gn file(s).', error_descriptions))
rlanday6802cf632017-05-30 17:48:365373
Sam Maiera6e76d72022-02-11 21:43:505374 return results
rlanday6802cf632017-05-30 17:48:365375
Takeshi Yoshinoe387aa32017-08-02 13:16:135376
Saagar Sanghavifceeaae2020-08-12 16:40:365377def CheckForCcIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505378 """Check that nobody tries to include a cc file. It's a relatively
5379 common error which results in duplicate symbols in object
5380 files. This may not always break the build until someone later gets
5381 very confusing linking errors."""
5382 results = []
5383 for f in input_api.AffectedFiles(include_deletes=False):
5384 # We let third_party code do whatever it wants
5385 if (f.LocalPath().startswith('third_party')
5386 and not f.LocalPath().startswith('third_party/blink')
5387 and not f.LocalPath().startswith('third_party\\blink')):
5388 continue
Daniel Bratell65b033262019-04-23 08:17:065389
Sam Maiera6e76d72022-02-11 21:43:505390 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
5391 continue
Daniel Bratell65b033262019-04-23 08:17:065392
Sam Maiera6e76d72022-02-11 21:43:505393 for _, line in f.ChangedContents():
5394 if line.startswith('#include "'):
5395 included_file = line.split('"')[1]
5396 if _IsCPlusPlusFile(input_api, included_file):
5397 # The most common naming for external files with C++ code,
5398 # apart from standard headers, is to call them foo.inc, but
5399 # Chromium sometimes uses foo-inc.cc so allow that as well.
5400 if not included_file.endswith(('.h', '-inc.cc')):
5401 results.append(
5402 output_api.PresubmitError(
5403 'Only header files or .inc files should be included in other\n'
5404 'C++ files. Compiling the contents of a cc file more than once\n'
5405 'will cause duplicate information in the build which may later\n'
5406 'result in strange link_errors.\n' +
5407 f.LocalPath() + ':\n ' + line))
Daniel Bratell65b033262019-04-23 08:17:065408
Sam Maiera6e76d72022-02-11 21:43:505409 return results
Daniel Bratell65b033262019-04-23 08:17:065410
5411
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205412def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
Sam Maiera6e76d72022-02-11 21:43:505413 if not isinstance(key, ast.Str):
5414 return 'Key at line %d must be a string literal' % key.lineno
5415 if not isinstance(value, ast.Dict):
5416 return 'Value at line %d must be a dict' % value.lineno
5417 if len(value.keys) != 1:
5418 return 'Dict at line %d must have single entry' % value.lineno
5419 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
5420 return (
5421 'Entry at line %d must have a string literal \'filepath\' as key' %
5422 value.lineno)
5423 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:135424
Takeshi Yoshinoe387aa32017-08-02 13:16:135425
Sergey Ulanov4af16052018-11-08 02:41:465426def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Sam Maiera6e76d72022-02-11 21:43:505427 if not isinstance(key, ast.Str):
5428 return 'Key at line %d must be a string literal' % key.lineno
5429 if not isinstance(value, ast.List):
5430 return 'Value at line %d must be a list' % value.lineno
5431 for element in value.elts:
5432 if not isinstance(element, ast.Str):
5433 return 'Watchlist elements on line %d is not a string' % key.lineno
5434 if not email_regex.match(element.s):
5435 return ('Watchlist element on line %d doesn\'t look like a valid '
5436 + 'email: %s') % (key.lineno, element.s)
5437 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:135438
Takeshi Yoshinoe387aa32017-08-02 13:16:135439
Sergey Ulanov4af16052018-11-08 02:41:465440def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Sam Maiera6e76d72022-02-11 21:43:505441 mismatch_template = (
5442 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
5443 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:135444
Sam Maiera6e76d72022-02-11 21:43:505445 email_regex = input_api.re.compile(
5446 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
Sergey Ulanov4af16052018-11-08 02:41:465447
Sam Maiera6e76d72022-02-11 21:43:505448 ast = input_api.ast
5449 i = 0
5450 last_key = ''
5451 while True:
5452 if i >= len(wd_dict.keys):
5453 if i >= len(w_dict.keys):
5454 return None
5455 return mismatch_template % ('missing',
5456 'line %d' % w_dict.keys[i].lineno)
5457 elif i >= len(w_dict.keys):
5458 return (mismatch_template %
5459 ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:135460
Sam Maiera6e76d72022-02-11 21:43:505461 wd_key = wd_dict.keys[i]
5462 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:135463
Sam Maiera6e76d72022-02-11 21:43:505464 result = _CheckWatchlistDefinitionsEntrySyntax(wd_key,
5465 wd_dict.values[i], ast)
5466 if result is not None:
5467 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:135468
Sam Maiera6e76d72022-02-11 21:43:505469 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast,
5470 email_regex)
5471 if result is not None:
5472 return 'Bad entry in WATCHLISTS dict: %s' % result
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205473
Sam Maiera6e76d72022-02-11 21:43:505474 if wd_key.s != w_key.s:
5475 return mismatch_template % ('%s at line %d' %
5476 (wd_key.s, wd_key.lineno),
5477 '%s at line %d' %
5478 (w_key.s, w_key.lineno))
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205479
Sam Maiera6e76d72022-02-11 21:43:505480 if wd_key.s < last_key:
5481 return (
5482 'WATCHLISTS dict is not sorted lexicographically at line %d and %d'
5483 % (wd_key.lineno, w_key.lineno))
5484 last_key = wd_key.s
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205485
Sam Maiera6e76d72022-02-11 21:43:505486 i = i + 1
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205487
5488
Sergey Ulanov4af16052018-11-08 02:41:465489def _CheckWATCHLISTSSyntax(expression, input_api):
Sam Maiera6e76d72022-02-11 21:43:505490 ast = input_api.ast
5491 if not isinstance(expression, ast.Expression):
5492 return 'WATCHLISTS file must contain a valid expression'
5493 dictionary = expression.body
5494 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
5495 return 'WATCHLISTS file must have single dict with exactly two entries'
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205496
Sam Maiera6e76d72022-02-11 21:43:505497 first_key = dictionary.keys[0]
5498 first_value = dictionary.values[0]
5499 second_key = dictionary.keys[1]
5500 second_value = dictionary.values[1]
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205501
Sam Maiera6e76d72022-02-11 21:43:505502 if (not isinstance(first_key, ast.Str)
5503 or first_key.s != 'WATCHLIST_DEFINITIONS'
5504 or not isinstance(first_value, ast.Dict)):
5505 return ('The first entry of the dict in WATCHLISTS file must be '
5506 'WATCHLIST_DEFINITIONS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205507
Sam Maiera6e76d72022-02-11 21:43:505508 if (not isinstance(second_key, ast.Str) or second_key.s != 'WATCHLISTS'
5509 or not isinstance(second_value, ast.Dict)):
5510 return ('The second entry of the dict in WATCHLISTS file must be '
5511 'WATCHLISTS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205512
Sam Maiera6e76d72022-02-11 21:43:505513 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:135514
5515
Saagar Sanghavifceeaae2020-08-12 16:40:365516def CheckWATCHLISTS(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505517 for f in input_api.AffectedFiles(include_deletes=False):
5518 if f.LocalPath() == 'WATCHLISTS':
5519 contents = input_api.ReadFile(f, 'r')
Takeshi Yoshinoe387aa32017-08-02 13:16:135520
Sam Maiera6e76d72022-02-11 21:43:505521 try:
5522 # First, make sure that it can be evaluated.
5523 input_api.ast.literal_eval(contents)
5524 # Get an AST tree for it and scan the tree for detailed style checking.
5525 expression = input_api.ast.parse(contents,
5526 filename='WATCHLISTS',
5527 mode='eval')
5528 except ValueError as e:
5529 return [
5530 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5531 long_text=repr(e))
5532 ]
5533 except SyntaxError as e:
5534 return [
5535 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5536 long_text=repr(e))
5537 ]
5538 except TypeError as e:
5539 return [
5540 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5541 long_text=repr(e))
5542 ]
Takeshi Yoshinoe387aa32017-08-02 13:16:135543
Sam Maiera6e76d72022-02-11 21:43:505544 result = _CheckWATCHLISTSSyntax(expression, input_api)
5545 if result is not None:
5546 return [output_api.PresubmitError(result)]
5547 break
Takeshi Yoshinoe387aa32017-08-02 13:16:135548
Sam Maiera6e76d72022-02-11 21:43:505549 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:135550
Sean Kaucb7c9b32022-10-25 21:25:525551def CheckGnRebasePath(input_api, output_api):
5552 """Checks that target_gen_dir is not used wtih "//" in rebase_path().
5553
5554 Developers should use root_build_dir instead of "//" when using target_gen_dir because
5555 Chromium is sometimes built outside of the source tree.
5556 """
5557
5558 def gn_files(f):
5559 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
5560
5561 rebase_path_regex = input_api.re.compile(r'rebase_path\(("\$target_gen_dir"|target_gen_dir), ("/"|"//")\)')
5562 problems = []
5563 for f in input_api.AffectedSourceFiles(gn_files):
5564 for line_num, line in f.ChangedContents():
5565 if rebase_path_regex.search(line):
5566 problems.append(
5567 'Absolute path in rebase_path() in %s:%d' %
5568 (f.LocalPath(), line_num))
5569
5570 if problems:
5571 return [
5572 output_api.PresubmitPromptWarning(
5573 'Using an absolute path in rebase_path()',
5574 items=sorted(problems),
5575 long_text=(
5576 'rebase_path() should use root_build_dir instead of "/" ',
5577 'since builds can be initiated from outside of the source ',
5578 'root.'))
5579 ]
5580 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:135581
Andrew Grieve1b290e4a22020-11-24 20:07:015582def CheckGnGlobForward(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505583 """Checks that forward_variables_from(invoker, "*") follows best practices.
Andrew Grieve1b290e4a22020-11-24 20:07:015584
Sam Maiera6e76d72022-02-11 21:43:505585 As documented at //build/docs/writing_gn_templates.md
5586 """
Andrew Grieve1b290e4a22020-11-24 20:07:015587
Sam Maiera6e76d72022-02-11 21:43:505588 def gn_files(f):
5589 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
Andrew Grieve1b290e4a22020-11-24 20:07:015590
Sam Maiera6e76d72022-02-11 21:43:505591 problems = []
5592 for f in input_api.AffectedSourceFiles(gn_files):
5593 for line_num, line in f.ChangedContents():
5594 if 'forward_variables_from(invoker, "*")' in line:
5595 problems.append(
5596 'Bare forward_variables_from(invoker, "*") in %s:%d' %
5597 (f.LocalPath(), line_num))
5598
5599 if problems:
5600 return [
5601 output_api.PresubmitPromptWarning(
5602 'forward_variables_from("*") without exclusions',
5603 items=sorted(problems),
5604 long_text=(
Gao Shenga79ebd42022-08-08 17:25:595605 'The variables "visibility" and "test_only" should be '
Sam Maiera6e76d72022-02-11 21:43:505606 'explicitly listed in forward_variables_from(). For more '
5607 'details, see:\n'
5608 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
5609 'build/docs/writing_gn_templates.md'
5610 '#Using-forward_variables_from'))
5611 ]
5612 return []
Andrew Grieve1b290e4a22020-11-24 20:07:015613
Saagar Sanghavifceeaae2020-08-12 16:40:365614def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505615 """Checks that newly added header files have corresponding GN changes.
5616 Note that this is only a heuristic. To be precise, run script:
5617 build/check_gn_headers.py.
5618 """
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195619
Sam Maiera6e76d72022-02-11 21:43:505620 def headers(f):
5621 return input_api.FilterSourceFile(
5622 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195623
Sam Maiera6e76d72022-02-11 21:43:505624 new_headers = []
5625 for f in input_api.AffectedSourceFiles(headers):
5626 if f.Action() != 'A':
5627 continue
5628 new_headers.append(f.LocalPath())
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195629
Sam Maiera6e76d72022-02-11 21:43:505630 def gn_files(f):
5631 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195632
Sam Maiera6e76d72022-02-11 21:43:505633 all_gn_changed_contents = ''
5634 for f in input_api.AffectedSourceFiles(gn_files):
5635 for _, line in f.ChangedContents():
5636 all_gn_changed_contents += line
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195637
Sam Maiera6e76d72022-02-11 21:43:505638 problems = []
5639 for header in new_headers:
5640 basename = input_api.os_path.basename(header)
5641 if basename not in all_gn_changed_contents:
5642 problems.append(header)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195643
Sam Maiera6e76d72022-02-11 21:43:505644 if problems:
5645 return [
5646 output_api.PresubmitPromptWarning(
5647 'Missing GN changes for new header files',
5648 items=sorted(problems),
5649 long_text=
5650 'Please double check whether newly added header files need '
5651 'corresponding changes in gn or gni files.\nThis checking is only a '
5652 'heuristic. Run build/check_gn_headers.py to be precise.\n'
5653 'Read https://crbug.com/661774 for more info.')
5654 ]
5655 return []
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195656
5657
Saagar Sanghavifceeaae2020-08-12 16:40:365658def CheckCorrectProductNameInMessages(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505659 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
Michael Giuffridad3bc8672018-10-25 22:48:025660
Sam Maiera6e76d72022-02-11 21:43:505661 This assumes we won't intentionally reference one product from the other
5662 product.
5663 """
5664 all_problems = []
5665 test_cases = [{
5666 "filename_postfix": "google_chrome_strings.grd",
5667 "correct_name": "Chrome",
5668 "incorrect_name": "Chromium",
5669 }, {
Thiago Perrotta099034f2023-06-05 18:10:205670 "filename_postfix": "google_chrome_strings.grd",
5671 "correct_name": "Chrome",
5672 "incorrect_name": "Chrome for Testing",
5673 }, {
Sam Maiera6e76d72022-02-11 21:43:505674 "filename_postfix": "chromium_strings.grd",
5675 "correct_name": "Chromium",
5676 "incorrect_name": "Chrome",
5677 }]
Michael Giuffridad3bc8672018-10-25 22:48:025678
Sam Maiera6e76d72022-02-11 21:43:505679 for test_case in test_cases:
5680 problems = []
5681 filename_filter = lambda x: x.LocalPath().endswith(test_case[
5682 "filename_postfix"])
Michael Giuffridad3bc8672018-10-25 22:48:025683
Sam Maiera6e76d72022-02-11 21:43:505684 # Check each new line. Can yield false positives in multiline comments, but
5685 # easier than trying to parse the XML because messages can have nested
5686 # children, and associating message elements with affected lines is hard.
5687 for f in input_api.AffectedSourceFiles(filename_filter):
5688 for line_num, line in f.ChangedContents():
5689 if "<message" in line or "<!--" in line or "-->" in line:
5690 continue
5691 if test_case["incorrect_name"] in line:
Thiago Perrotta099034f2023-06-05 18:10:205692 # Chrome for Testing is a special edge case: https://goo.gle/chrome-for-testing#bookmark=id.n1rat320av91
5693 if (test_case["correct_name"] == "Chromium" and line.count("Chrome") == line.count("Chrome for Testing")):
5694 continue
Sam Maiera6e76d72022-02-11 21:43:505695 problems.append("Incorrect product name in %s:%d" %
5696 (f.LocalPath(), line_num))
Michael Giuffridad3bc8672018-10-25 22:48:025697
Sam Maiera6e76d72022-02-11 21:43:505698 if problems:
5699 message = (
5700 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
5701 % (test_case["correct_name"], test_case["correct_name"],
5702 test_case["incorrect_name"]))
5703 all_problems.append(
5704 output_api.PresubmitPromptWarning(message, items=problems))
Michael Giuffridad3bc8672018-10-25 22:48:025705
Sam Maiera6e76d72022-02-11 21:43:505706 return all_problems
Michael Giuffridad3bc8672018-10-25 22:48:025707
5708
Saagar Sanghavifceeaae2020-08-12 16:40:365709def CheckForTooLargeFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505710 """Avoid large files, especially binary files, in the repository since
5711 git doesn't scale well for those. They will be in everyone's repo
5712 clones forever, forever making Chromium slower to clone and work
5713 with."""
Daniel Bratell93eb6c62019-04-29 20:13:365714
Sam Maiera6e76d72022-02-11 21:43:505715 # Uploading files to cloud storage is not trivial so we don't want
5716 # to set the limit too low, but the upper limit for "normal" large
5717 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
5718 # anything over 20 MB is exceptional.
Bruce Dawsonbb414db2022-12-27 20:21:255719 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024
Daniel Bratell93eb6c62019-04-29 20:13:365720
Sam Maiera6e76d72022-02-11 21:43:505721 too_large_files = []
5722 for f in input_api.AffectedFiles():
5723 # Check both added and modified files (but not deleted files).
5724 if f.Action() in ('A', 'M'):
5725 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Joe DeBlasio10a832f2023-04-21 20:20:185726 if size > TOO_LARGE_FILE_SIZE_LIMIT:
Sam Maiera6e76d72022-02-11 21:43:505727 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
Daniel Bratell93eb6c62019-04-29 20:13:365728
Sam Maiera6e76d72022-02-11 21:43:505729 if too_large_files:
5730 message = (
5731 'Do not commit large files to git since git scales badly for those.\n'
5732 +
5733 'Instead put the large files in cloud storage and use DEPS to\n' +
5734 'fetch them.\n' + '\n'.join(too_large_files))
5735 return [
5736 output_api.PresubmitError('Too large files found in commit',
5737 long_text=message + '\n')
5738 ]
5739 else:
5740 return []
Daniel Bratell93eb6c62019-04-29 20:13:365741
Max Morozb47503b2019-08-08 21:03:275742
Saagar Sanghavifceeaae2020-08-12 16:40:365743def CheckFuzzTargetsOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505744 """Checks specific for fuzz target sources."""
5745 EXPORTED_SYMBOLS = [
5746 'LLVMFuzzerInitialize',
5747 'LLVMFuzzerCustomMutator',
5748 'LLVMFuzzerCustomCrossOver',
5749 'LLVMFuzzerMutate',
5750 ]
Max Morozb47503b2019-08-08 21:03:275751
Sam Maiera6e76d72022-02-11 21:43:505752 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
Max Morozb47503b2019-08-08 21:03:275753
Sam Maiera6e76d72022-02-11 21:43:505754 def FilterFile(affected_file):
5755 """Ignore libFuzzer source code."""
5756 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
Bruce Dawson40fece62022-09-16 19:58:315757 files_to_skip = r"^third_party/libFuzzer"
Max Morozb47503b2019-08-08 21:03:275758
Sam Maiera6e76d72022-02-11 21:43:505759 return input_api.FilterSourceFile(affected_file,
5760 files_to_check=[files_to_check],
5761 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:275762
Sam Maiera6e76d72022-02-11 21:43:505763 files_with_missing_header = []
5764 for f in input_api.AffectedSourceFiles(FilterFile):
5765 contents = input_api.ReadFile(f, 'r')
5766 if REQUIRED_HEADER in contents:
5767 continue
Max Morozb47503b2019-08-08 21:03:275768
Sam Maiera6e76d72022-02-11 21:43:505769 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
5770 files_with_missing_header.append(f.LocalPath())
Max Morozb47503b2019-08-08 21:03:275771
Sam Maiera6e76d72022-02-11 21:43:505772 if not files_with_missing_header:
5773 return []
Max Morozb47503b2019-08-08 21:03:275774
Sam Maiera6e76d72022-02-11 21:43:505775 long_text = (
5776 'If you define any of the libFuzzer optional functions (%s), it is '
5777 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
5778 'work incorrectly on Mac (crbug.com/687076).\nNote that '
5779 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
5780 'to access command line arguments passed to the fuzzer. Instead, prefer '
5781 'static initialization and shared resources as documented in '
5782 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
5783 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n'
5784 % (', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER))
Max Morozb47503b2019-08-08 21:03:275785
Sam Maiera6e76d72022-02-11 21:43:505786 return [
5787 output_api.PresubmitPromptWarning(message="Missing '%s' in:" %
5788 REQUIRED_HEADER,
5789 items=files_with_missing_header,
5790 long_text=long_text)
5791 ]
Max Morozb47503b2019-08-08 21:03:275792
5793
Mohamed Heikald048240a2019-11-12 16:57:375794def _CheckNewImagesWarning(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505795 """
5796 Warns authors who add images into the repo to make sure their images are
5797 optimized before committing.
5798 """
5799 images_added = False
5800 image_paths = []
5801 errors = []
5802 filter_lambda = lambda x: input_api.FilterSourceFile(
5803 x,
5804 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
5805 DEFAULT_FILES_TO_SKIP),
5806 files_to_check=[r'.*\/(drawable|mipmap)'])
5807 for f in input_api.AffectedFiles(include_deletes=False,
5808 file_filter=filter_lambda):
5809 local_path = f.LocalPath().lower()
5810 if any(
5811 local_path.endswith(extension)
5812 for extension in _IMAGE_EXTENSIONS):
5813 images_added = True
5814 image_paths.append(f)
5815 if images_added:
5816 errors.append(
5817 output_api.PresubmitPromptWarning(
5818 'It looks like you are trying to commit some images. If these are '
5819 'non-test-only images, please make sure to read and apply the tips in '
5820 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
5821 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
5822 'FYI only and will not block your CL on the CQ.', image_paths))
5823 return errors
Mohamed Heikald048240a2019-11-12 16:57:375824
5825
Saagar Sanghavifceeaae2020-08-12 16:40:365826def ChecksAndroidSpecificOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505827 """Groups upload checks that target android code."""
5828 results = []
5829 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
5830 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
5831 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
5832 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505833 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
5834 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
5835 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
5836 results.extend(_CheckNewImagesWarning(input_api, output_api))
5837 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
5838 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
5839 return results
5840
Becky Zhou7c69b50992018-12-10 19:37:575841
Saagar Sanghavifceeaae2020-08-12 16:40:365842def ChecksAndroidSpecificOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505843 """Groups commit checks that target android code."""
5844 results = []
5845 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
5846 return results
dgnaa68d5e2015-06-10 10:08:225847
Chris Hall59f8d0c72020-05-01 07:31:195848# TODO(chrishall): could we additionally match on any path owned by
5849# ui/accessibility/OWNERS ?
5850_ACCESSIBILITY_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:315851 r"^chrome/browser.*/accessibility/",
5852 r"^chrome/browser/extensions/api/automation.*/",
5853 r"^chrome/renderer/extensions/accessibility_.*",
5854 r"^chrome/tests/data/accessibility/",
5855 r"^content/browser/accessibility/",
5856 r"^content/renderer/accessibility/",
5857 r"^content/tests/data/accessibility/",
5858 r"^extensions/renderer/api/automation/",
Katie Dektar58ef07b2022-09-27 13:19:175859 r"^services/accessibility/",
Abigail Klein7a63c572024-02-28 20:45:095860 r"^services/screen_ai/",
Bruce Dawson40fece62022-09-16 19:58:315861 r"^ui/accessibility/",
5862 r"^ui/views/accessibility/",
Chris Hall59f8d0c72020-05-01 07:31:195863)
5864
Saagar Sanghavifceeaae2020-08-12 16:40:365865def CheckAccessibilityRelnotesField(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505866 """Checks that commits to accessibility code contain an AX-Relnotes field in
5867 their commit message."""
Chris Hall59f8d0c72020-05-01 07:31:195868
Sam Maiera6e76d72022-02-11 21:43:505869 def FileFilter(affected_file):
5870 paths = _ACCESSIBILITY_PATHS
5871 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:195872
Sam Maiera6e76d72022-02-11 21:43:505873 # Only consider changes affecting accessibility paths.
5874 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
5875 return []
Akihiro Ota08108e542020-05-20 15:30:535876
Sam Maiera6e76d72022-02-11 21:43:505877 # AX-Relnotes can appear in either the description or the footer.
5878 # When searching the description, require 'AX-Relnotes:' to appear at the
5879 # beginning of a line.
5880 ax_regex = input_api.re.compile('ax-relnotes[:=]')
5881 description_has_relnotes = any(
5882 ax_regex.match(line)
5883 for line in input_api.change.DescriptionText().lower().splitlines())
Chris Hall59f8d0c72020-05-01 07:31:195884
Sam Maiera6e76d72022-02-11 21:43:505885 footer_relnotes = input_api.change.GitFootersFromDescription().get(
5886 'AX-Relnotes', [])
5887 if description_has_relnotes or footer_relnotes:
5888 return []
Chris Hall59f8d0c72020-05-01 07:31:195889
Sam Maiera6e76d72022-02-11 21:43:505890 # TODO(chrishall): link to Relnotes documentation in message.
5891 message = (
5892 "Missing 'AX-Relnotes:' field required for accessibility changes"
5893 "\n please add 'AX-Relnotes: [release notes].' to describe any "
5894 "user-facing changes"
5895 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
5896 "user-facing effects"
5897 "\n if this is confusing or annoying then please contact members "
5898 "of ui/accessibility/OWNERS.")
5899
5900 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:225901
Mark Schillacie5a0be22022-01-19 00:38:395902
5903_ACCESSIBILITY_EVENTS_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315904 r"^content/test/data/accessibility/event/.*\.html",
Mark Schillacie5a0be22022-01-19 00:38:395905)
5906
5907_ACCESSIBILITY_TREE_TEST_PATH = (
Aaron Leventhal267119f2023-08-18 22:45:345908 r"^content/test/data/accessibility/accname/"
5909 ".*-expected-(mac|win|uia-win|auralinux).txt",
5910 r"^content/test/data/accessibility/aria/"
5911 ".*-expected-(mac|win|uia-win|auralinux).txt",
5912 r"^content/test/data/accessibility/css/"
5913 ".*-expected-(mac|win|uia-win|auralinux).txt",
5914 r"^content/test/data/accessibility/event/"
5915 ".*-expected-(mac|win|uia-win|auralinux).txt",
5916 r"^content/test/data/accessibility/html/"
5917 ".*-expected-(mac|win|uia-win|auralinux).txt",
Mark Schillacie5a0be22022-01-19 00:38:395918)
5919
5920_ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315921 r"^.*/WebContentsAccessibilityEventsTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:395922)
5923
5924_ACCESSIBILITY_ANDROID_TREE_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315925 r"^.*/WebContentsAccessibilityTreeTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:395926)
5927
5928def CheckAccessibilityEventsTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505929 """Checks that commits that include a newly added, renamed/moved, or deleted
5930 test in the DumpAccessibilityEventsTest suite also includes a corresponding
5931 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:395932
Sam Maiera6e76d72022-02-11 21:43:505933 def FilePathFilter(affected_file):
5934 paths = _ACCESSIBILITY_EVENTS_TEST_PATH
5935 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395936
Sam Maiera6e76d72022-02-11 21:43:505937 def AndroidFilePathFilter(affected_file):
5938 paths = _ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH
5939 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395940
Sam Maiera6e76d72022-02-11 21:43:505941 # Only consider changes in the events test data path with html type.
5942 if not any(
5943 input_api.AffectedFiles(include_deletes=True,
5944 file_filter=FilePathFilter)):
5945 return []
Mark Schillacie5a0be22022-01-19 00:38:395946
Sam Maiera6e76d72022-02-11 21:43:505947 # If the commit contains any change to the Android test file, ignore.
5948 if any(
5949 input_api.AffectedFiles(include_deletes=True,
5950 file_filter=AndroidFilePathFilter)):
5951 return []
Mark Schillacie5a0be22022-01-19 00:38:395952
Sam Maiera6e76d72022-02-11 21:43:505953 # Only consider changes that are adding/renaming or deleting a file
5954 message = []
5955 for f in input_api.AffectedFiles(include_deletes=True,
5956 file_filter=FilePathFilter):
Aaron Leventhal267119f2023-08-18 22:45:345957 if f.Action() == 'A':
Sam Maiera6e76d72022-02-11 21:43:505958 message = (
Aaron Leventhal267119f2023-08-18 22:45:345959 "It appears that you are adding platform expectations for a"
Aaron Leventhal0de81072023-08-21 21:26:525960 "\ndump_accessibility_events* test, but have not included"
Sam Maiera6e76d72022-02-11 21:43:505961 "\na corresponding change for Android."
Aaron Leventhal267119f2023-08-18 22:45:345962 "\nPlease include the test from:"
Sam Maiera6e76d72022-02-11 21:43:505963 "\n content/public/android/javatests/src/org/chromium/"
5964 "content/browser/accessibility/"
5965 "WebContentsAccessibilityEventsTest.java"
5966 "\nIf this message is confusing or annoying, please contact"
5967 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:395968
Sam Maiera6e76d72022-02-11 21:43:505969 # If no message was set, return empty.
5970 if not len(message):
5971 return []
5972
5973 return [output_api.PresubmitPromptWarning(message)]
5974
Mark Schillacie5a0be22022-01-19 00:38:395975
5976def CheckAccessibilityTreeTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505977 """Checks that commits that include a newly added, renamed/moved, or deleted
5978 test in the DumpAccessibilityTreeTest suite also includes a corresponding
5979 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:395980
Sam Maiera6e76d72022-02-11 21:43:505981 def FilePathFilter(affected_file):
5982 paths = _ACCESSIBILITY_TREE_TEST_PATH
5983 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395984
Sam Maiera6e76d72022-02-11 21:43:505985 def AndroidFilePathFilter(affected_file):
5986 paths = _ACCESSIBILITY_ANDROID_TREE_TEST_PATH
5987 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395988
Sam Maiera6e76d72022-02-11 21:43:505989 # Only consider changes in the various tree test data paths with html type.
5990 if not any(
5991 input_api.AffectedFiles(include_deletes=True,
5992 file_filter=FilePathFilter)):
5993 return []
Mark Schillacie5a0be22022-01-19 00:38:395994
Sam Maiera6e76d72022-02-11 21:43:505995 # If the commit contains any change to the Android test file, ignore.
5996 if any(
5997 input_api.AffectedFiles(include_deletes=True,
5998 file_filter=AndroidFilePathFilter)):
5999 return []
Mark Schillacie5a0be22022-01-19 00:38:396000
Sam Maiera6e76d72022-02-11 21:43:506001 # Only consider changes that are adding/renaming or deleting a file
6002 message = []
6003 for f in input_api.AffectedFiles(include_deletes=True,
6004 file_filter=FilePathFilter):
Aaron Leventhal0de81072023-08-21 21:26:526005 if f.Action() == 'A':
Sam Maiera6e76d72022-02-11 21:43:506006 message = (
Aaron Leventhal0de81072023-08-21 21:26:526007 "It appears that you are adding platform expectations for a"
6008 "\ndump_accessibility_tree* test, but have not included"
Sam Maiera6e76d72022-02-11 21:43:506009 "\na corresponding change for Android."
6010 "\nPlease include (or remove) the test from:"
6011 "\n content/public/android/javatests/src/org/chromium/"
6012 "content/browser/accessibility/"
6013 "WebContentsAccessibilityTreeTest.java"
6014 "\nIf this message is confusing or annoying, please contact"
6015 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:396016
Sam Maiera6e76d72022-02-11 21:43:506017 # If no message was set, return empty.
6018 if not len(message):
6019 return []
6020
6021 return [output_api.PresubmitPromptWarning(message)]
Mark Schillacie5a0be22022-01-19 00:38:396022
6023
Bruce Dawson33806592022-11-16 01:44:516024def CheckEsLintConfigChanges(input_api, output_api):
6025 """Suggest using "git cl presubmit --files" when .eslintrc.js files are
6026 modified. This is important because enabling an error in .eslintrc.js can
6027 trigger errors in any .js or .ts files in its directory, leading to hidden
6028 presubmit errors."""
6029 results = []
6030 eslint_filter = lambda f: input_api.FilterSourceFile(
6031 f, files_to_check=[r'.*\.eslintrc\.js$'])
6032 for f in input_api.AffectedFiles(include_deletes=False,
6033 file_filter=eslint_filter):
6034 local_dir = input_api.os_path.dirname(f.LocalPath())
6035 # Use / characters so that the commands printed work on any OS.
6036 local_dir = local_dir.replace(input_api.os_path.sep, '/')
6037 if local_dir:
6038 local_dir += '/'
6039 results.append(
6040 output_api.PresubmitNotifyResult(
6041 '%(file)s modified. Consider running \'git cl presubmit --files '
6042 '"%(dir)s*.js;%(dir)s*.ts"\' in order to check and fix the affected '
6043 'files before landing this change.' %
6044 { 'file' : f.LocalPath(), 'dir' : local_dir}))
6045 return results
6046
6047
seanmccullough4a9356252021-04-08 19:54:096048# string pattern, sequence of strings to show when pattern matches,
6049# error flag. True if match is a presubmit error, otherwise it's a warning.
6050_NON_INCLUSIVE_TERMS = (
6051 (
6052 # Note that \b pattern in python re is pretty particular. In this
6053 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
6054 # ...' will not. This may require some tweaking to catch these cases
6055 # without triggering a lot of false positives. Leaving it naive and
6056 # less matchy for now.
Josip Sokcevic9d2806a02023-12-13 03:04:026057 r'/(?i)\b((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:096058 (
6059 'Please don\'t use blacklist, whitelist, ' # nocheck
6060 'or slave in your', # nocheck
6061 'code and make every effort to use other terms. Using "// nocheck"',
6062 '"# nocheck" or "<!-- nocheck -->"',
6063 'at the end of the offending line will bypass this PRESUBMIT error',
6064 'but avoid using this whenever possible. Reach out to',
6065 '[email protected] if you have questions'),
6066 True),)
6067
Saagar Sanghavifceeaae2020-08-12 16:40:366068def ChecksCommon(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506069 """Checks common to both upload and commit."""
6070 results = []
Eric Boren6fd2b932018-01-25 15:05:086071 results.extend(
Sam Maiera6e76d72022-02-11 21:43:506072 input_api.canned_checks.PanProjectChecks(
6073 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:086074
Sam Maiera6e76d72022-02-11 21:43:506075 author = input_api.change.author_email
6076 if author and author not in _KNOWN_ROBOTS:
6077 results.extend(
6078 input_api.canned_checks.CheckAuthorizedAuthor(
6079 input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:246080
Sam Maiera6e76d72022-02-11 21:43:506081 results.extend(
6082 input_api.canned_checks.CheckChangeHasNoTabs(
6083 input_api,
6084 output_api,
6085 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
6086 results.extend(
6087 input_api.RunTests(
6088 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Edward Lesmesce51df52020-08-04 22:10:176089
Bruce Dawsonc8054482022-03-28 15:33:376090 dirmd = 'dirmd.bat' if input_api.is_windows else 'dirmd'
Sam Maiera6e76d72022-02-11 21:43:506091 dirmd_bin = input_api.os_path.join(input_api.PresubmitLocalPath(),
Bruce Dawsonc8054482022-03-28 15:33:376092 'third_party', 'depot_tools', dirmd)
Sam Maiera6e76d72022-02-11 21:43:506093 results.extend(
6094 input_api.RunTests(
6095 input_api.canned_checks.CheckDirMetadataFormat(
6096 input_api, output_api, dirmd_bin)))
6097 results.extend(
6098 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
6099 input_api, output_api))
6100 results.extend(
6101 input_api.canned_checks.CheckNoNewMetadataInOwners(
6102 input_api, output_api))
6103 results.extend(
6104 input_api.canned_checks.CheckInclusiveLanguage(
6105 input_api,
6106 output_api,
6107 excluded_directories_relative_path=[
6108 'infra', 'inclusive_language_presubmit_exempt_dirs.txt'
6109 ],
6110 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Dirk Prankee3c9c62d2021-05-18 18:35:596111
Aleksey Khoroshilov2978c942022-06-13 16:14:126112 presubmit_py_filter = lambda f: input_api.FilterSourceFile(
Bruce Dawson696963f2022-09-13 01:15:476113 f, files_to_check=[r'.*PRESUBMIT\.py$'])
Aleksey Khoroshilov2978c942022-06-13 16:14:126114 for f in input_api.AffectedFiles(include_deletes=False,
6115 file_filter=presubmit_py_filter):
6116 full_path = input_api.os_path.dirname(f.AbsoluteLocalPath())
6117 test_file = input_api.os_path.join(full_path, 'PRESUBMIT_test.py')
6118 # The PRESUBMIT.py file (and the directory containing it) might have
6119 # been affected by being moved or removed, so only try to run the tests
6120 # if they still exist.
6121 if not input_api.os_path.exists(test_file):
6122 continue
Sam Maiera6e76d72022-02-11 21:43:506123
Aleksey Khoroshilov2978c942022-06-13 16:14:126124 results.extend(
6125 input_api.canned_checks.RunUnitTestsInDirectory(
6126 input_api,
6127 output_api,
6128 full_path,
Takuto Ikuta40def482023-06-02 02:23:496129 files_to_check=[r'^PRESUBMIT_test\.py$']))
Sam Maiera6e76d72022-02-11 21:43:506130 return results
[email protected]1f7b4172010-01-28 01:17:346131
[email protected]b337cb5b2011-01-23 21:24:056132
Saagar Sanghavifceeaae2020-08-12 16:40:366133def CheckPatchFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506134 problems = [
6135 f.LocalPath() for f in input_api.AffectedFiles()
6136 if f.LocalPath().endswith(('.orig', '.rej'))
6137 ]
6138 # Cargo.toml.orig files are part of third-party crates downloaded from
6139 # crates.io and should be included.
6140 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
6141 if problems:
6142 return [
6143 output_api.PresubmitError("Don't commit .rej and .orig files.",
6144 problems)
6145 ]
6146 else:
6147 return []
[email protected]b8079ae4a2012-12-05 19:56:496148
6149
Saagar Sanghavifceeaae2020-08-12 16:40:366150def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506151 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
6152 macro_re = input_api.re.compile(
6153 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
6154 include_re = input_api.re.compile(r'^#include\s+"build/build_config.h"',
6155 input_api.re.MULTILINE)
6156 extension_re = input_api.re.compile(r'\.[a-z]+$')
6157 errors = []
Bruce Dawsonf7679202022-08-09 20:24:006158 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:506159 for f in input_api.AffectedFiles(include_deletes=False):
Bruce Dawsonf7679202022-08-09 20:24:006160 # The build-config macros are allowed to be used in build_config.h
6161 # without including itself.
6162 if f.LocalPath() == config_h_file:
6163 continue
Sam Maiera6e76d72022-02-11 21:43:506164 if not f.LocalPath().endswith(
6165 ('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
6166 continue
Arthur Sonzognia3dec412024-04-29 12:05:376167
Sam Maiera6e76d72022-02-11 21:43:506168 found_line_number = None
6169 found_macro = None
6170 all_lines = input_api.ReadFile(f, 'r').splitlines()
6171 for line_num, line in enumerate(all_lines):
6172 match = macro_re.search(line)
6173 if match:
6174 found_line_number = line_num
6175 found_macro = match.group(2)
6176 break
6177 if not found_line_number:
6178 continue
Kent Tamura5a8755d2017-06-29 23:37:076179
Sam Maiera6e76d72022-02-11 21:43:506180 found_include_line = -1
6181 for line_num, line in enumerate(all_lines):
6182 if include_re.search(line):
6183 found_include_line = line_num
6184 break
6185 if found_include_line >= 0 and found_include_line < found_line_number:
6186 continue
Kent Tamura5a8755d2017-06-29 23:37:076187
Sam Maiera6e76d72022-02-11 21:43:506188 if not f.LocalPath().endswith('.h'):
6189 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
6190 try:
6191 content = input_api.ReadFile(primary_header_path, 'r')
6192 if include_re.search(content):
6193 continue
6194 except IOError:
6195 pass
6196 errors.append('%s:%d %s macro is used without first including build/'
6197 'build_config.h.' %
6198 (f.LocalPath(), found_line_number, found_macro))
6199 if errors:
6200 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
6201 return []
Kent Tamura5a8755d2017-06-29 23:37:076202
6203
Lei Zhang1c12a22f2021-05-12 11:28:456204def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506205 stl_include_re = input_api.re.compile(r'^#include\s+<('
6206 r'algorithm|'
6207 r'array|'
6208 r'limits|'
6209 r'list|'
6210 r'map|'
6211 r'memory|'
6212 r'queue|'
6213 r'set|'
6214 r'string|'
6215 r'unordered_map|'
6216 r'unordered_set|'
6217 r'utility|'
6218 r'vector)>')
6219 std_namespace_re = input_api.re.compile(r'std::')
6220 errors = []
6221 for f in input_api.AffectedFiles():
6222 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
6223 continue
Lei Zhang1c12a22f2021-05-12 11:28:456224
Sam Maiera6e76d72022-02-11 21:43:506225 uses_std_namespace = False
6226 has_stl_include = False
6227 for line in f.NewContents():
6228 if has_stl_include and uses_std_namespace:
6229 break
Lei Zhang1c12a22f2021-05-12 11:28:456230
Sam Maiera6e76d72022-02-11 21:43:506231 if not has_stl_include and stl_include_re.search(line):
6232 has_stl_include = True
6233 continue
Lei Zhang1c12a22f2021-05-12 11:28:456234
Bruce Dawson4a5579a2022-04-08 17:11:366235 if not uses_std_namespace and (std_namespace_re.search(line)
6236 or 'no-std-usage-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:506237 uses_std_namespace = True
6238 continue
Lei Zhang1c12a22f2021-05-12 11:28:456239
Sam Maiera6e76d72022-02-11 21:43:506240 if has_stl_include and not uses_std_namespace:
6241 errors.append(
6242 '%s: Includes STL header(s) but does not reference std::' %
6243 f.LocalPath())
6244 if errors:
6245 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
6246 return []
Lei Zhang1c12a22f2021-05-12 11:28:456247
6248
Xiaohan Wang42d96c22022-01-20 17:23:116249def _CheckForDeprecatedOSMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:506250 """Check for sensible looking, totally invalid OS macros."""
6251 preprocessor_statement = input_api.re.compile(r'^\s*#')
6252 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
6253 results = []
6254 for lnum, line in f.ChangedContents():
6255 if preprocessor_statement.search(line):
6256 for match in os_macro.finditer(line):
6257 results.append(
6258 ' %s:%d: %s' %
6259 (f.LocalPath(), lnum, 'defined(OS_' + match.group(1) +
6260 ') -> BUILDFLAG(IS_' + match.group(1) + ')'))
6261 return results
[email protected]b00342e7f2013-03-26 16:21:546262
6263
Xiaohan Wang42d96c22022-01-20 17:23:116264def CheckForDeprecatedOSMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506265 """Check all affected files for invalid OS macros."""
6266 bad_macros = []
Bruce Dawsonf7679202022-08-09 20:24:006267 # The OS_ macros are allowed to be used in build/build_config.h.
6268 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:506269 for f in input_api.AffectedSourceFiles(None):
Bruce Dawsonf7679202022-08-09 20:24:006270 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')) \
6271 and f.LocalPath() != config_h_file:
Sam Maiera6e76d72022-02-11 21:43:506272 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
[email protected]b00342e7f2013-03-26 16:21:546273
Sam Maiera6e76d72022-02-11 21:43:506274 if not bad_macros:
6275 return []
[email protected]b00342e7f2013-03-26 16:21:546276
Sam Maiera6e76d72022-02-11 21:43:506277 return [
6278 output_api.PresubmitError(
6279 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
6280 'defined in build_config.h):', bad_macros)
6281 ]
[email protected]b00342e7f2013-03-26 16:21:546282
lliabraa35bab3932014-10-01 12:16:446283
6284def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:506285 """Check all affected files for invalid "if defined" macros."""
6286 ALWAYS_DEFINED_MACROS = (
6287 "TARGET_CPU_PPC",
6288 "TARGET_CPU_PPC64",
6289 "TARGET_CPU_68K",
6290 "TARGET_CPU_X86",
6291 "TARGET_CPU_ARM",
6292 "TARGET_CPU_MIPS",
6293 "TARGET_CPU_SPARC",
6294 "TARGET_CPU_ALPHA",
6295 "TARGET_IPHONE_SIMULATOR",
6296 "TARGET_OS_EMBEDDED",
6297 "TARGET_OS_IPHONE",
6298 "TARGET_OS_MAC",
6299 "TARGET_OS_UNIX",
6300 "TARGET_OS_WIN32",
6301 )
6302 ifdef_macro = input_api.re.compile(
6303 r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
6304 results = []
6305 for lnum, line in f.ChangedContents():
6306 for match in ifdef_macro.finditer(line):
6307 if match.group(1) in ALWAYS_DEFINED_MACROS:
6308 always_defined = ' %s is always defined. ' % match.group(1)
6309 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
6310 results.append(
6311 ' %s:%d %s\n\t%s' %
6312 (f.LocalPath(), lnum, always_defined, did_you_mean))
6313 return results
lliabraa35bab3932014-10-01 12:16:446314
6315
Saagar Sanghavifceeaae2020-08-12 16:40:366316def CheckForInvalidIfDefinedMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506317 """Check all affected files for invalid "if defined" macros."""
Arthur Sonzogni4fd14fd2024-06-02 18:42:526318 SKIPPED_PATHS = [
6319 'base/allocator/partition_allocator/src/partition_alloc/build_config.h',
6320 'build/build_config.h',
6321 'third_party/abseil-cpp/',
6322 'third_party/sqlite/',
6323 ]
6324 def affected_files_filter(f):
6325 # Normalize the local path to Linux-style path separators so that the
6326 # path comparisons work on Windows as well.
6327 path = f.LocalPath().replace('\\', '/')
6328
6329 for skipped_path in SKIPPED_PATHS:
6330 if path.startswith(skipped_path):
6331 return False
6332
6333 return path.endswith(('.h', '.c', '.cc', '.m', '.mm'))
6334
Sam Maiera6e76d72022-02-11 21:43:506335 bad_macros = []
Arthur Sonzogni4fd14fd2024-06-02 18:42:526336 for f in input_api.AffectedSourceFiles(affected_files_filter):
6337 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
lliabraa35bab3932014-10-01 12:16:446338
Sam Maiera6e76d72022-02-11 21:43:506339 if not bad_macros:
6340 return []
lliabraa35bab3932014-10-01 12:16:446341
Sam Maiera6e76d72022-02-11 21:43:506342 return [
6343 output_api.PresubmitError(
6344 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
6345 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
6346 bad_macros)
6347 ]
lliabraa35bab3932014-10-01 12:16:446348
Saagar Sanghavifceeaae2020-08-12 16:40:366349def CheckForIPCRules(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506350 """Check for same IPC rules described in
6351 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
6352 """
6353 base_pattern = r'IPC_ENUM_TRAITS\('
6354 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
6355 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
mlamouria82272622014-09-16 18:45:046356
Sam Maiera6e76d72022-02-11 21:43:506357 problems = []
6358 for f in input_api.AffectedSourceFiles(None):
6359 local_path = f.LocalPath()
6360 if not local_path.endswith('.h'):
6361 continue
6362 for line_number, line in f.ChangedContents():
6363 if inclusion_pattern.search(
6364 line) and not comment_pattern.search(line):
6365 problems.append('%s:%d\n %s' %
6366 (local_path, line_number, line.strip()))
mlamouria82272622014-09-16 18:45:046367
Sam Maiera6e76d72022-02-11 21:43:506368 if problems:
6369 return [
6370 output_api.PresubmitPromptWarning(_IPC_ENUM_TRAITS_DEPRECATED,
6371 problems)
6372 ]
6373 else:
6374 return []
mlamouria82272622014-09-16 18:45:046375
[email protected]b00342e7f2013-03-26 16:21:546376
Saagar Sanghavifceeaae2020-08-12 16:40:366377def CheckForLongPathnames(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506378 """Check to make sure no files being submitted have long paths.
6379 This causes issues on Windows.
6380 """
6381 problems = []
6382 for f in input_api.AffectedTestableFiles():
6383 local_path = f.LocalPath()
6384 # Windows has a path limit of 260 characters. Limit path length to 200 so
6385 # that we have some extra for the prefix on dev machines and the bots.
Weizhong Xia8b461f12024-06-21 21:46:336386 if (local_path.startswith('third_party/blink/web_tests/platform/') and
6387 not local_path.startswith('third_party/blink/web_tests/platform/win')):
6388 # Do not check length of the path for files not used by Windows
6389 continue
Sam Maiera6e76d72022-02-11 21:43:506390 if len(local_path) > 200:
6391 problems.append(local_path)
Stephen Martinis97a394142018-06-07 23:06:056392
Sam Maiera6e76d72022-02-11 21:43:506393 if problems:
6394 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
6395 else:
6396 return []
Stephen Martinis97a394142018-06-07 23:06:056397
6398
Saagar Sanghavifceeaae2020-08-12 16:40:366399def CheckForIncludeGuards(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506400 """Check that header files have proper guards against multiple inclusion.
6401 If a file should not have such guards (and it probably should) then it
Bruce Dawson4a5579a2022-04-08 17:11:366402 should include the string "no-include-guard-because-multiply-included" or
6403 "no-include-guard-because-pch-file".
Sam Maiera6e76d72022-02-11 21:43:506404 """
Daniel Bratell8ba52722018-03-02 16:06:146405
Sam Maiera6e76d72022-02-11 21:43:506406 def is_chromium_header_file(f):
6407 # We only check header files under the control of the Chromium
mikt84d6c712024-03-27 13:29:036408 # project. This excludes:
6409 # - third_party/*, except blink.
6410 # - base/allocator/partition_allocator/: PartitionAlloc is a standalone
6411 # library used outside of Chrome. Includes are referenced from its
6412 # own base directory. It has its own `CheckForIncludeGuards`
6413 # PRESUBMIT.py check.
6414 # - *_message_generator.h: They use include guards in a special,
6415 # non-typical way.
Sam Maiera6e76d72022-02-11 21:43:506416 file_with_path = input_api.os_path.normpath(f.LocalPath())
6417 return (file_with_path.endswith('.h')
6418 and not file_with_path.endswith('_message_generator.h')
Bruce Dawson4c4c2922022-05-02 18:07:336419 and not file_with_path.endswith('com_imported_mstscax.h')
mikt84d6c712024-03-27 13:29:036420 and not file_with_path.startswith('base/allocator/partition_allocator')
Sam Maiera6e76d72022-02-11 21:43:506421 and (not file_with_path.startswith('third_party')
6422 or file_with_path.startswith(
6423 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:146424
Sam Maiera6e76d72022-02-11 21:43:506425 def replace_special_with_underscore(string):
6426 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:146427
Sam Maiera6e76d72022-02-11 21:43:506428 errors = []
Daniel Bratell8ba52722018-03-02 16:06:146429
Sam Maiera6e76d72022-02-11 21:43:506430 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
6431 guard_name = None
6432 guard_line_number = None
6433 seen_guard_end = False
Lei Zhangd84f9512024-05-28 19:43:306434 bypass_checks_at_end_of_file = False
Daniel Bratell8ba52722018-03-02 16:06:146435
Sam Maiera6e76d72022-02-11 21:43:506436 file_with_path = input_api.os_path.normpath(f.LocalPath())
6437 base_file_name = input_api.os_path.splitext(
6438 input_api.os_path.basename(file_with_path))[0]
6439 upper_base_file_name = base_file_name.upper()
Daniel Bratell8ba52722018-03-02 16:06:146440
Sam Maiera6e76d72022-02-11 21:43:506441 expected_guard = replace_special_with_underscore(
6442 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:146443
Sam Maiera6e76d72022-02-11 21:43:506444 # For "path/elem/file_name.h" we should really only accept
6445 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
6446 # are too many (1000+) files with slight deviations from the
6447 # coding style. The most important part is that the include guard
6448 # is there, and that it's unique, not the name so this check is
6449 # forgiving for existing files.
6450 #
6451 # As code becomes more uniform, this could be made stricter.
Daniel Bratell8ba52722018-03-02 16:06:146452
Sam Maiera6e76d72022-02-11 21:43:506453 guard_name_pattern_list = [
6454 # Anything with the right suffix (maybe with an extra _).
6455 r'\w+_H__?',
Daniel Bratell8ba52722018-03-02 16:06:146456
Sam Maiera6e76d72022-02-11 21:43:506457 # To cover include guards with old Blink style.
6458 r'\w+_h',
Daniel Bratell8ba52722018-03-02 16:06:146459
Sam Maiera6e76d72022-02-11 21:43:506460 # Anything including the uppercase name of the file.
6461 r'\w*' + input_api.re.escape(
6462 replace_special_with_underscore(upper_base_file_name)) +
6463 r'\w*',
6464 ]
6465 guard_name_pattern = '|'.join(guard_name_pattern_list)
6466 guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
6467 guard_name_pattern + ')')
Daniel Bratell8ba52722018-03-02 16:06:146468
Sam Maiera6e76d72022-02-11 21:43:506469 for line_number, line in enumerate(f.NewContents()):
Bruce Dawson4a5579a2022-04-08 17:11:366470 if ('no-include-guard-because-multiply-included' in line
6471 or 'no-include-guard-because-pch-file' in line):
Lei Zhangd84f9512024-05-28 19:43:306472 bypass_checks_at_end_of_file = True
Sam Maiera6e76d72022-02-11 21:43:506473 break
Daniel Bratell8ba52722018-03-02 16:06:146474
Sam Maiera6e76d72022-02-11 21:43:506475 if guard_name is None:
6476 match = guard_pattern.match(line)
6477 if match:
6478 guard_name = match.group(1)
6479 guard_line_number = line_number
Daniel Bratell8ba52722018-03-02 16:06:146480
Sam Maiera6e76d72022-02-11 21:43:506481 # We allow existing files to use include guards whose names
6482 # don't match the chromium style guide, but new files should
6483 # get it right.
Bruce Dawson6cc154e2022-04-12 20:39:496484 if guard_name != expected_guard:
Bruce Dawson95eb7562022-09-14 15:27:166485 if f.Action() == 'A': # If file was just 'A'dded
Sam Maiera6e76d72022-02-11 21:43:506486 errors.append(
6487 output_api.PresubmitPromptWarning(
6488 'Header using the wrong include guard name %s'
6489 % guard_name, [
6490 '%s:%d' %
6491 (f.LocalPath(), line_number + 1)
6492 ], 'Expected: %r\nFound: %r' %
6493 (expected_guard, guard_name)))
6494 else:
6495 # The line after #ifndef should have a #define of the same name.
6496 if line_number == guard_line_number + 1:
6497 expected_line = '#define %s' % guard_name
6498 if line != expected_line:
6499 errors.append(
6500 output_api.PresubmitPromptWarning(
6501 'Missing "%s" for include guard' %
6502 expected_line,
6503 ['%s:%d' % (f.LocalPath(), line_number + 1)],
6504 'Expected: %r\nGot: %r' %
6505 (expected_line, line)))
Daniel Bratell8ba52722018-03-02 16:06:146506
Sam Maiera6e76d72022-02-11 21:43:506507 if not seen_guard_end and line == '#endif // %s' % guard_name:
6508 seen_guard_end = True
6509 elif seen_guard_end:
6510 if line.strip() != '':
6511 errors.append(
6512 output_api.PresubmitPromptWarning(
6513 'Include guard %s not covering the whole file'
6514 % (guard_name), [f.LocalPath()]))
6515 break # Nothing else to check and enough to warn once.
Daniel Bratell8ba52722018-03-02 16:06:146516
Lei Zhangd84f9512024-05-28 19:43:306517 if bypass_checks_at_end_of_file:
6518 continue
6519
Sam Maiera6e76d72022-02-11 21:43:506520 if guard_name is None:
6521 errors.append(
6522 output_api.PresubmitPromptWarning(
Bruce Dawson32114b62022-04-11 16:45:496523 'Missing include guard in %s\n'
Sam Maiera6e76d72022-02-11 21:43:506524 'Recommended name: %s\n'
6525 'This check can be disabled by having the string\n'
Bruce Dawson4a5579a2022-04-08 17:11:366526 '"no-include-guard-because-multiply-included" or\n'
6527 '"no-include-guard-because-pch-file" in the header.'
Sam Maiera6e76d72022-02-11 21:43:506528 % (f.LocalPath(), expected_guard)))
Lei Zhangd84f9512024-05-28 19:43:306529 elif not seen_guard_end:
6530 errors.append(
6531 output_api.PresubmitPromptWarning(
6532 'Incorrect or missing include guard #endif in %s\n'
6533 'Recommended #endif comment: // %s'
6534 % (f.LocalPath(), expected_guard)))
Sam Maiera6e76d72022-02-11 21:43:506535
6536 return errors
Daniel Bratell8ba52722018-03-02 16:06:146537
6538
Saagar Sanghavifceeaae2020-08-12 16:40:366539def CheckForWindowsLineEndings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506540 """Check source code and known ascii text files for Windows style line
6541 endings.
6542 """
Bruce Dawson5efbdc652022-04-11 19:29:516543 known_text_files = r'.*\.(txt|html|htm|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:236544
Sam Maiera6e76d72022-02-11 21:43:506545 file_inclusion_pattern = (known_text_files,
6546 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
6547 r'.+%s' % _HEADER_EXTENSIONS)
mostynbb639aca52015-01-07 20:31:236548
Sam Maiera6e76d72022-02-11 21:43:506549 problems = []
6550 source_file_filter = lambda f: input_api.FilterSourceFile(
6551 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
6552 for f in input_api.AffectedSourceFiles(source_file_filter):
Bruce Dawson5efbdc652022-04-11 19:29:516553 # Ignore test files that contain crlf intentionally.
6554 if f.LocalPath().endswith('crlf.txt'):
Daniel Chenga37c03db2022-05-12 17:20:346555 continue
Sam Maiera6e76d72022-02-11 21:43:506556 include_file = False
6557 for line in input_api.ReadFile(f, 'r').splitlines(True):
6558 if line.endswith('\r\n'):
6559 include_file = True
6560 if include_file:
6561 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:236562
Sam Maiera6e76d72022-02-11 21:43:506563 if problems:
6564 return [
6565 output_api.PresubmitPromptWarning(
6566 'Are you sure that you want '
6567 'these files to contain Windows style line endings?\n' +
6568 '\n'.join(problems))
6569 ]
mostynbb639aca52015-01-07 20:31:236570
Sam Maiera6e76d72022-02-11 21:43:506571 return []
6572
mostynbb639aca52015-01-07 20:31:236573
Evan Stade6cfc964c12021-05-18 20:21:166574def CheckIconFilesForLicenseHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506575 """Check that .icon files (which are fragments of C++) have license headers.
6576 """
Evan Stade6cfc964c12021-05-18 20:21:166577
Sam Maiera6e76d72022-02-11 21:43:506578 icon_files = (r'.*\.icon$', )
Evan Stade6cfc964c12021-05-18 20:21:166579
Sam Maiera6e76d72022-02-11 21:43:506580 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
6581 return input_api.canned_checks.CheckLicense(input_api,
6582 output_api,
6583 source_file_filter=icons)
6584
Evan Stade6cfc964c12021-05-18 20:21:166585
Jose Magana2b456f22021-03-09 23:26:406586def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506587 """Check source code for use of Chrome App technologies being
6588 deprecated.
6589 """
Jose Magana2b456f22021-03-09 23:26:406590
Sam Maiera6e76d72022-02-11 21:43:506591 def _CheckForDeprecatedTech(input_api,
6592 output_api,
6593 detection_list,
6594 files_to_check=None,
6595 files_to_skip=None):
Jose Magana2b456f22021-03-09 23:26:406596
Sam Maiera6e76d72022-02-11 21:43:506597 if (files_to_check or files_to_skip):
6598 source_file_filter = lambda f: input_api.FilterSourceFile(
6599 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
6600 else:
6601 source_file_filter = None
6602
6603 problems = []
6604
6605 for f in input_api.AffectedSourceFiles(source_file_filter):
6606 if f.Action() == 'D':
6607 continue
6608 for _, line in f.ChangedContents():
6609 if any(detect in line for detect in detection_list):
6610 problems.append(f.LocalPath())
6611
6612 return problems
6613
6614 # to avoid this presubmit script triggering warnings
6615 files_to_skip = ['PRESUBMIT.py', 'PRESUBMIT_test.py']
Jose Magana2b456f22021-03-09 23:26:406616
6617 problems = []
6618
Sam Maiera6e76d72022-02-11 21:43:506619 # NMF: any files with extensions .nmf or NMF
6620 _NMF_FILES = r'\.(nmf|NMF)$'
6621 problems += _CheckForDeprecatedTech(
6622 input_api,
6623 output_api,
6624 detection_list=[''], # any change to the file will trigger warning
6625 files_to_check=[r'.+%s' % _NMF_FILES])
Jose Magana2b456f22021-03-09 23:26:406626
Sam Maiera6e76d72022-02-11 21:43:506627 # MANIFEST: any manifest.json that in its diff includes "app":
6628 _MANIFEST_FILES = r'(manifest\.json)$'
6629 problems += _CheckForDeprecatedTech(
6630 input_api,
6631 output_api,
6632 detection_list=['"app":'],
6633 files_to_check=[r'.*%s' % _MANIFEST_FILES])
Jose Magana2b456f22021-03-09 23:26:406634
Sam Maiera6e76d72022-02-11 21:43:506635 # NaCl / PNaCl: any file that in its diff contains the strings in the list
6636 problems += _CheckForDeprecatedTech(
6637 input_api,
6638 output_api,
6639 detection_list=['config=nacl', 'enable-nacl', 'cpu=pnacl', 'nacl_io'],
Bruce Dawson40fece62022-09-16 19:58:316640 files_to_skip=files_to_skip + [r"^native_client_sdk/"])
Jose Magana2b456f22021-03-09 23:26:406641
Gao Shenga79ebd42022-08-08 17:25:596642 # PPAPI: any C/C++ file that in its diff includes a ppapi library
Sam Maiera6e76d72022-02-11 21:43:506643 problems += _CheckForDeprecatedTech(
6644 input_api,
6645 output_api,
6646 detection_list=['#include "ppapi', '#include <ppapi'],
6647 files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,
6648 r'.+%s' % _IMPLEMENTATION_EXTENSIONS),
Bruce Dawson40fece62022-09-16 19:58:316649 files_to_skip=[r"^ppapi/"])
Jose Magana2b456f22021-03-09 23:26:406650
Sam Maiera6e76d72022-02-11 21:43:506651 if problems:
6652 return [
6653 output_api.PresubmitPromptWarning(
6654 'You are adding/modifying code'
6655 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
6656 ' PNaCl, PPAPI). See this blog post for more details:\n'
6657 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
6658 'and this documentation for options to replace these technologies:\n'
6659 'https://developer.chrome.com/docs/apps/migration/\n' +
6660 '\n'.join(problems))
6661 ]
Jose Magana2b456f22021-03-09 23:26:406662
Sam Maiera6e76d72022-02-11 21:43:506663 return []
Jose Magana2b456f22021-03-09 23:26:406664
mostynbb639aca52015-01-07 20:31:236665
Saagar Sanghavifceeaae2020-08-12 16:40:366666def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
Sam Maiera6e76d72022-02-11 21:43:506667 """Checks that all source files use SYSLOG properly."""
6668 syslog_files = []
6669 for f in input_api.AffectedSourceFiles(src_file_filter):
6670 for line_number, line in f.ChangedContents():
6671 if 'SYSLOG' in line:
6672 syslog_files.append(f.LocalPath() + ':' + str(line_number))
pastarmovj032ba5bc2017-01-12 10:41:566673
Sam Maiera6e76d72022-02-11 21:43:506674 if syslog_files:
6675 return [
6676 output_api.PresubmitPromptWarning(
6677 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
6678 ' calls.\nFiles to check:\n',
6679 items=syslog_files)
6680 ]
6681 return []
pastarmovj89f7ee12016-09-20 14:58:136682
6683
[email protected]1f7b4172010-01-28 01:17:346684def CheckChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506685 if input_api.version < [2, 0, 0]:
6686 return [
6687 output_api.PresubmitError(
6688 "Your depot_tools is out of date. "
6689 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
6690 "but your version is %d.%d.%d" % tuple(input_api.version))
6691 ]
6692 results = []
6693 results.extend(
6694 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
6695 return results
[email protected]ca8d1982009-02-19 16:33:126696
6697
6698def CheckChangeOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506699 if input_api.version < [2, 0, 0]:
6700 return [
6701 output_api.PresubmitError(
6702 "Your depot_tools is out of date. "
6703 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
6704 "but your version is %d.%d.%d" % tuple(input_api.version))
6705 ]
Saagar Sanghavifceeaae2020-08-12 16:40:366706
Sam Maiera6e76d72022-02-11 21:43:506707 results = []
6708 # Make sure the tree is 'open'.
6709 results.extend(
6710 input_api.canned_checks.CheckTreeIsOpen(
6711 input_api,
6712 output_api,
6713 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:276714
Sam Maiera6e76d72022-02-11 21:43:506715 results.extend(
6716 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
6717 results.extend(
6718 input_api.canned_checks.CheckChangeHasBugField(input_api, output_api))
6719 results.extend(
6720 input_api.canned_checks.CheckChangeHasNoUnwantedTags(
6721 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:506722 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146723
6724
Saagar Sanghavifceeaae2020-08-12 16:40:366725def CheckStrings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506726 """Check string ICU syntax validity and if translation screenshots exist."""
6727 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
6728 # footer is set to true.
6729 git_footers = input_api.change.GitFootersFromDescription()
6730 skip_screenshot_check_footer = [
6731 footer.lower() for footer in git_footers.get(
6732 u'Skip-Translation-Screenshots-Check', [])
6733 ]
6734 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:026735
Sam Maiera6e76d72022-02-11 21:43:506736 import os
6737 import re
6738 import sys
6739 from io import StringIO
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146740
Sam Maiera6e76d72022-02-11 21:43:506741 new_or_added_paths = set(f.LocalPath() for f in input_api.AffectedFiles()
6742 if (f.Action() == 'A' or f.Action() == 'M'))
6743 removed_paths = set(f.LocalPath()
6744 for f in input_api.AffectedFiles(include_deletes=True)
6745 if f.Action() == 'D')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146746
Sam Maiera6e76d72022-02-11 21:43:506747 affected_grds = [
6748 f for f in input_api.AffectedFiles()
6749 if f.LocalPath().endswith(('.grd', '.grdp'))
6750 ]
6751 affected_grds = [
6752 f for f in affected_grds if not 'testdata' in f.LocalPath()
6753 ]
6754 if not affected_grds:
6755 return []
meacer8c0d3832019-12-26 21:46:166756
Sam Maiera6e76d72022-02-11 21:43:506757 affected_png_paths = [
6758 f.AbsoluteLocalPath() for f in input_api.AffectedFiles()
6759 if (f.LocalPath().endswith('.png'))
6760 ]
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146761
Sam Maiera6e76d72022-02-11 21:43:506762 # Check for screenshots. Developers can upload screenshots using
6763 # tools/translation/upload_screenshots.py which finds and uploads
6764 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
6765 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
6766 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
6767 #
6768 # The logic here is as follows:
6769 #
6770 # - If the CL has a .png file under the screenshots directory for a grd
6771 # file, warn the developer. Actual images should never be checked into the
6772 # Chrome repo.
6773 #
6774 # - If the CL contains modified or new messages in grd files and doesn't
6775 # contain the corresponding .sha1 files, warn the developer to add images
6776 # and upload them via tools/translation/upload_screenshots.py.
6777 #
6778 # - If the CL contains modified or new messages in grd files and the
6779 # corresponding .sha1 files, everything looks good.
6780 #
6781 # - If the CL contains removed messages in grd files but the corresponding
6782 # .sha1 files aren't removed, warn the developer to remove them.
6783 unnecessary_screenshots = []
Jens Mueller054652c2023-05-10 15:12:306784 invalid_sha1 = []
Sam Maiera6e76d72022-02-11 21:43:506785 missing_sha1 = []
Bruce Dawson55776c42022-12-09 17:23:476786 missing_sha1_modified = []
Sam Maiera6e76d72022-02-11 21:43:506787 unnecessary_sha1_files = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146788
Sam Maiera6e76d72022-02-11 21:43:506789 # This checks verifies that the ICU syntax of messages this CL touched is
6790 # valid, and reports any found syntax errors.
6791 # Without this presubmit check, ICU syntax errors in Chromium strings can land
6792 # without developers being aware of them. Later on, such ICU syntax errors
6793 # break message extraction for translation, hence would block Chromium
6794 # translations until they are fixed.
6795 icu_syntax_errors = []
Jens Mueller054652c2023-05-10 15:12:306796 sha1_pattern = input_api.re.compile(r'^[a-fA-F0-9]{40}$',
6797 input_api.re.MULTILINE)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146798
Sam Maiera6e76d72022-02-11 21:43:506799 def _CheckScreenshotAdded(screenshots_dir, message_id):
6800 sha1_path = input_api.os_path.join(screenshots_dir,
6801 message_id + '.png.sha1')
6802 if sha1_path not in new_or_added_paths:
6803 missing_sha1.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306804 elif not _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256805 invalid_sha1.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146806
Bruce Dawson55776c42022-12-09 17:23:476807 def _CheckScreenshotModified(screenshots_dir, message_id):
6808 sha1_path = input_api.os_path.join(screenshots_dir,
6809 message_id + '.png.sha1')
6810 if sha1_path not in new_or_added_paths:
6811 missing_sha1_modified.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306812 elif not _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256813 invalid_sha1.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306814
6815 def _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256816 return sha1_pattern.search(
6817 next("\n".join(f.NewContents()) for f in input_api.AffectedFiles()
6818 if f.LocalPath() == sha1_path))
Bruce Dawson55776c42022-12-09 17:23:476819
Sam Maiera6e76d72022-02-11 21:43:506820 def _CheckScreenshotRemoved(screenshots_dir, message_id):
6821 sha1_path = input_api.os_path.join(screenshots_dir,
6822 message_id + '.png.sha1')
6823 if input_api.os_path.exists(
6824 sha1_path) and sha1_path not in removed_paths:
6825 unnecessary_sha1_files.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146826
Sam Maiera6e76d72022-02-11 21:43:506827 def _ValidateIcuSyntax(text, level, signatures):
6828 """Validates ICU syntax of a text string.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146829
Sam Maiera6e76d72022-02-11 21:43:506830 Check if text looks similar to ICU and checks for ICU syntax correctness
6831 in this case. Reports various issues with ICU syntax and values of
6832 variants. Supports checking of nested messages. Accumulate information of
6833 each ICU messages found in the text for further checking.
Rainhard Findlingfc31844c52020-05-15 09:58:266834
Sam Maiera6e76d72022-02-11 21:43:506835 Args:
6836 text: a string to check.
6837 level: a number of current nesting level.
6838 signatures: an accumulator, a list of tuple of (level, variable,
6839 kind, variants).
Rainhard Findlingfc31844c52020-05-15 09:58:266840
Sam Maiera6e76d72022-02-11 21:43:506841 Returns:
6842 None if a string is not ICU or no issue detected.
6843 A tuple of (message, start index, end index) if an issue detected.
6844 """
6845 valid_types = {
6846 'plural': (frozenset(
Rainhard Findling3cde3ef02024-02-05 18:40:326847 ['=0', '=1', '=2', '=3', 'zero', 'one', 'two', 'few', 'many',
Sam Maiera6e76d72022-02-11 21:43:506848 'other']), frozenset(['=1', 'other'])),
6849 'selectordinal': (frozenset(
Rainhard Findling3cde3ef02024-02-05 18:40:326850 ['=0', '=1', '=2', '=3', 'zero', 'one', 'two', 'few', 'many',
Sam Maiera6e76d72022-02-11 21:43:506851 'other']), frozenset(['one', 'other'])),
6852 'select': (frozenset(), frozenset(['other'])),
6853 }
Rainhard Findlingfc31844c52020-05-15 09:58:266854
Sam Maiera6e76d72022-02-11 21:43:506855 # Check if the message looks like an attempt to use ICU
6856 # plural. If yes - check if its syntax strictly matches ICU format.
6857 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b',
6858 text)
6859 if not like:
6860 signatures.append((level, None, None, None))
6861 return
Rainhard Findlingfc31844c52020-05-15 09:58:266862
Sam Maiera6e76d72022-02-11 21:43:506863 # Check for valid prefix and suffix
6864 m = re.match(
6865 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
6866 r'(plural|selectordinal|select),\s*'
6867 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
6868 if not m:
6869 return (('This message looks like an ICU plural, '
6870 'but does not follow ICU syntax.'), like.start(),
6871 like.end())
6872 starting, variable, kind, variant_pairs = m.groups()
6873 variants, depth, last_pos = _ParseIcuVariants(variant_pairs,
6874 m.start(4))
6875 if depth:
6876 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
6877 len(text))
6878 first = text[0]
6879 ending = text[last_pos:]
6880 if not starting:
6881 return ('Invalid ICU format. No initial opening bracket',
6882 last_pos - 1, last_pos)
6883 if not ending or '}' not in ending:
6884 return ('Invalid ICU format. No final closing bracket',
6885 last_pos - 1, last_pos)
6886 elif first != '{':
6887 return ((
6888 'Invalid ICU format. Extra characters at the start of a complex '
6889 'message (go/icu-message-migration): "%s"') % starting, 0,
6890 len(starting))
6891 elif ending != '}':
6892 return ((
6893 'Invalid ICU format. Extra characters at the end of a complex '
6894 'message (go/icu-message-migration): "%s"') % ending,
6895 last_pos - 1, len(text) - 1)
6896 if kind not in valid_types:
6897 return (('Unknown ICU message type %s. '
6898 'Valid types are: plural, select, selectordinal') % kind,
6899 0, 0)
6900 known, required = valid_types[kind]
6901 defined_variants = set()
6902 for variant, variant_range, value, value_range in variants:
6903 start, end = variant_range
6904 if variant in defined_variants:
6905 return ('Variant "%s" is defined more than once' % variant,
6906 start, end)
6907 elif known and variant not in known:
6908 return ('Variant "%s" is not valid for %s message' %
6909 (variant, kind), start, end)
6910 defined_variants.add(variant)
6911 # Check for nested structure
6912 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
6913 if res:
6914 return (res[0], res[1] + value_range[0] + 1,
6915 res[2] + value_range[0] + 1)
6916 missing = required - defined_variants
6917 if missing:
6918 return ('Required variants missing: %s' % ', '.join(missing), 0,
6919 len(text))
6920 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:266921
Sam Maiera6e76d72022-02-11 21:43:506922 def _ParseIcuVariants(text, offset=0):
6923 """Parse variants part of ICU complex message.
Rainhard Findlingfc31844c52020-05-15 09:58:266924
Sam Maiera6e76d72022-02-11 21:43:506925 Builds a tuple of variant names and values, as well as
6926 their offsets in the input string.
Rainhard Findlingfc31844c52020-05-15 09:58:266927
Sam Maiera6e76d72022-02-11 21:43:506928 Args:
6929 text: a string to parse
6930 offset: additional offset to add to positions in the text to get correct
6931 position in the complete ICU string.
Rainhard Findlingfc31844c52020-05-15 09:58:266932
Sam Maiera6e76d72022-02-11 21:43:506933 Returns:
6934 List of tuples, each tuple consist of four fields: variant name,
6935 variant name span (tuple of two integers), variant value, value
6936 span (tuple of two integers).
6937 """
6938 depth, start, end = 0, -1, -1
6939 variants = []
6940 key = None
6941 for idx, char in enumerate(text):
6942 if char == '{':
6943 if not depth:
6944 start = idx
6945 chunk = text[end + 1:start]
6946 key = chunk.strip()
6947 pos = offset + end + 1 + chunk.find(key)
6948 span = (pos, pos + len(key))
6949 depth += 1
6950 elif char == '}':
6951 if not depth:
6952 return variants, depth, offset + idx
6953 depth -= 1
6954 if not depth:
6955 end = idx
6956 variants.append((key, span, text[start:end + 1],
6957 (offset + start, offset + end + 1)))
6958 return variants, depth, offset + end + 1
Rainhard Findlingfc31844c52020-05-15 09:58:266959
Sam Maiera6e76d72022-02-11 21:43:506960 try:
6961 old_sys_path = sys.path
6962 sys.path = sys.path + [
6963 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
6964 'translation')
6965 ]
6966 from helper import grd_helper
6967 finally:
6968 sys.path = old_sys_path
Rainhard Findlingfc31844c52020-05-15 09:58:266969
Sam Maiera6e76d72022-02-11 21:43:506970 for f in affected_grds:
6971 file_path = f.LocalPath()
6972 old_id_to_msg_map = {}
6973 new_id_to_msg_map = {}
6974 # Note that this code doesn't check if the file has been deleted. This is
6975 # OK because it only uses the old and new file contents and doesn't load
6976 # the file via its path.
6977 # It's also possible that a file's content refers to a renamed or deleted
6978 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
6979 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
6980 # .grdp files.
6981 if file_path.endswith('.grdp'):
6982 if f.OldContents():
6983 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6984 '\n'.join(f.OldContents()))
6985 if f.NewContents():
6986 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6987 '\n'.join(f.NewContents()))
6988 else:
6989 file_dir = input_api.os_path.dirname(file_path) or '.'
6990 if f.OldContents():
6991 old_id_to_msg_map = grd_helper.GetGrdMessages(
6992 StringIO('\n'.join(f.OldContents())), file_dir)
6993 if f.NewContents():
6994 new_id_to_msg_map = grd_helper.GetGrdMessages(
6995 StringIO('\n'.join(f.NewContents())), file_dir)
Rainhard Findlingfc31844c52020-05-15 09:58:266996
Sam Maiera6e76d72022-02-11 21:43:506997 grd_name, ext = input_api.os_path.splitext(
6998 input_api.os_path.basename(file_path))
6999 screenshots_dir = input_api.os_path.join(
7000 input_api.os_path.dirname(file_path),
7001 grd_name + ext.replace('.', '_'))
Rainhard Findlingfc31844c52020-05-15 09:58:267002
Sam Maiera6e76d72022-02-11 21:43:507003 # Compute added, removed and modified message IDs.
7004 old_ids = set(old_id_to_msg_map)
7005 new_ids = set(new_id_to_msg_map)
7006 added_ids = new_ids - old_ids
7007 removed_ids = old_ids - new_ids
7008 modified_ids = set([])
7009 for key in old_ids.intersection(new_ids):
7010 if (old_id_to_msg_map[key].ContentsAsXml('', True) !=
7011 new_id_to_msg_map[key].ContentsAsXml('', True)):
7012 # The message content itself changed. Require an updated screenshot.
7013 modified_ids.add(key)
7014 elif old_id_to_msg_map[key].attrs['meaning'] != \
7015 new_id_to_msg_map[key].attrs['meaning']:
Jens Mueller054652c2023-05-10 15:12:307016 # The message meaning changed. We later check for a screenshot.
7017 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147018
Sam Maiera6e76d72022-02-11 21:43:507019 if run_screenshot_check:
7020 # Check the screenshot directory for .png files. Warn if there is any.
7021 for png_path in affected_png_paths:
7022 if png_path.startswith(screenshots_dir):
7023 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147024
Sam Maiera6e76d72022-02-11 21:43:507025 for added_id in added_ids:
7026 _CheckScreenshotAdded(screenshots_dir, added_id)
Rainhard Findlingd8d04372020-08-13 13:30:097027
Sam Maiera6e76d72022-02-11 21:43:507028 for modified_id in modified_ids:
Bruce Dawson55776c42022-12-09 17:23:477029 _CheckScreenshotModified(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147030
Sam Maiera6e76d72022-02-11 21:43:507031 for removed_id in removed_ids:
7032 _CheckScreenshotRemoved(screenshots_dir, removed_id)
7033
7034 # Check new and changed strings for ICU syntax errors.
7035 for key in added_ids.union(modified_ids):
7036 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
7037 err = _ValidateIcuSyntax(msg, 0, [])
7038 if err is not None:
7039 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
7040
7041 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:267042 if run_screenshot_check:
Sam Maiera6e76d72022-02-11 21:43:507043 if unnecessary_screenshots:
7044 results.append(
7045 output_api.PresubmitError(
7046 'Do not include actual screenshots in the changelist. Run '
7047 'tools/translate/upload_screenshots.py to upload them instead:',
7048 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147049
Sam Maiera6e76d72022-02-11 21:43:507050 if missing_sha1:
7051 results.append(
7052 output_api.PresubmitError(
Bruce Dawson55776c42022-12-09 17:23:477053 'You are adding UI strings.\n'
Sam Maiera6e76d72022-02-11 21:43:507054 'To ensure the best translations, take screenshots of the relevant UI '
7055 '(https://g.co/chrome/translation) and add these files to your '
7056 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147057
Jens Mueller054652c2023-05-10 15:12:307058 if invalid_sha1:
7059 results.append(
7060 output_api.PresubmitError(
7061 'The following files do not seem to contain valid sha1 hashes. '
7062 'Make sure they contain hashes created by '
7063 'tools/translate/upload_screenshots.py:', sorted(invalid_sha1)))
7064
Bruce Dawson55776c42022-12-09 17:23:477065 if missing_sha1_modified:
7066 results.append(
7067 output_api.PresubmitError(
7068 'You are modifying UI strings or their meanings.\n'
7069 'To ensure the best translations, take screenshots of the relevant UI '
7070 '(https://g.co/chrome/translation) and add these files to your '
7071 'changelist:', sorted(missing_sha1_modified)))
7072
Sam Maiera6e76d72022-02-11 21:43:507073 if unnecessary_sha1_files:
7074 results.append(
7075 output_api.PresubmitError(
7076 'You removed strings associated with these files. Remove:',
7077 sorted(unnecessary_sha1_files)))
7078 else:
7079 results.append(
7080 output_api.PresubmitPromptOrNotify('Skipping translation '
7081 'screenshots check.'))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147082
Sam Maiera6e76d72022-02-11 21:43:507083 if icu_syntax_errors:
7084 results.append(
7085 output_api.PresubmitPromptWarning(
7086 'ICU syntax errors were found in the following strings (problems or '
7087 'feedback? Contact [email protected]):',
7088 items=icu_syntax_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:267089
Sam Maiera6e76d72022-02-11 21:43:507090 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:127091
7092
Saagar Sanghavifceeaae2020-08-12 16:40:367093def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:127094 repo_root=None,
7095 translation_expectations_path=None,
7096 grd_files=None):
Sam Maiera6e76d72022-02-11 21:43:507097 import sys
7098 affected_grds = [
7099 f for f in input_api.AffectedFiles()
7100 if (f.LocalPath().endswith('.grd') or f.LocalPath().endswith('.grdp'))
7101 ]
7102 if not affected_grds:
7103 return []
7104
7105 try:
7106 old_sys_path = sys.path
7107 sys.path = sys.path + [
7108 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
7109 'translation')
7110 ]
7111 from helper import git_helper
7112 from helper import translation_helper
7113 finally:
7114 sys.path = old_sys_path
7115
7116 # Check that translation expectations can be parsed and we can get a list of
7117 # translatable grd files. |repo_root| and |translation_expectations_path| are
7118 # only passed by tests.
7119 if not repo_root:
7120 repo_root = input_api.PresubmitLocalPath()
7121 if not translation_expectations_path:
7122 translation_expectations_path = input_api.os_path.join(
7123 repo_root, 'tools', 'gritsettings', 'translation_expectations.pyl')
7124 if not grd_files:
7125 grd_files = git_helper.list_grds_in_repository(repo_root)
7126
7127 # Ignore bogus grd files used only for testing
Gao Shenga79ebd42022-08-08 17:25:597128 # ui/webui/resources/tools/generate_grd.py.
Sam Maiera6e76d72022-02-11 21:43:507129 ignore_path = input_api.os_path.join('ui', 'webui', 'resources', 'tools',
7130 'tests')
7131 grd_files = [p for p in grd_files if ignore_path not in p]
7132
7133 try:
7134 translation_helper.get_translatable_grds(
7135 repo_root, grd_files, translation_expectations_path)
7136 except Exception as e:
7137 return [
7138 output_api.PresubmitNotifyResult(
7139 'Failed to get a list of translatable grd files. This happens when:\n'
7140 ' - One of the modified grd or grdp files cannot be parsed or\n'
7141 ' - %s is not updated.\n'
7142 'Stack:\n%s' % (translation_expectations_path, str(e)))
7143 ]
Mustafa Emre Acer51f2f742020-03-09 19:41:127144 return []
7145
Ken Rockotc31f4832020-05-29 18:58:517146
Saagar Sanghavifceeaae2020-08-12 16:40:367147def CheckStableMojomChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507148 """Changes to [Stable] mojom types must preserve backward-compatibility."""
7149 changed_mojoms = input_api.AffectedFiles(
7150 include_deletes=True,
7151 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:527152
Bruce Dawson344ab262022-06-04 11:35:107153 if not changed_mojoms or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:507154 return []
7155
7156 delta = []
7157 for mojom in changed_mojoms:
Sam Maiera6e76d72022-02-11 21:43:507158 delta.append({
7159 'filename': mojom.LocalPath(),
7160 'old': '\n'.join(mojom.OldContents()) or None,
7161 'new': '\n'.join(mojom.NewContents()) or None,
7162 })
7163
7164 process = input_api.subprocess.Popen([
Takuto Ikutadca10222022-04-13 02:51:217165 input_api.python3_executable,
Sam Maiera6e76d72022-02-11 21:43:507166 input_api.os_path.join(
7167 input_api.PresubmitLocalPath(), 'mojo', 'public', 'tools', 'mojom',
7168 'check_stable_mojom_compatibility.py'), '--src-root',
7169 input_api.PresubmitLocalPath()
7170 ],
7171 stdin=input_api.subprocess.PIPE,
7172 stdout=input_api.subprocess.PIPE,
7173 stderr=input_api.subprocess.PIPE,
7174 universal_newlines=True)
7175 (x, error) = process.communicate(input=input_api.json.dumps(delta))
7176 if process.returncode:
7177 return [
7178 output_api.PresubmitError(
7179 'One or more [Stable] mojom definitions appears to have been changed '
Alex Goughc99921652024-02-15 22:59:127180 'in a way that is not backward-compatible. See '
7181 'https://chromium.googlesource.com/chromium/src/+/HEAD/mojo/public/tools/bindings/README.md#versioning'
7182 ' for details.',
Sam Maiera6e76d72022-02-11 21:43:507183 long_text=error)
7184 ]
Erik Staabc734cd7a2021-11-23 03:11:527185 return []
7186
Dominic Battre645d42342020-12-04 16:14:107187def CheckDeprecationOfPreferences(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507188 """Removing a preference should come with a deprecation."""
Dominic Battre645d42342020-12-04 16:14:107189
Sam Maiera6e76d72022-02-11 21:43:507190 def FilterFile(affected_file):
7191 """Accept only .cc files and the like."""
7192 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
7193 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
7194 input_api.DEFAULT_FILES_TO_SKIP)
7195 return input_api.FilterSourceFile(
7196 affected_file,
7197 files_to_check=file_inclusion_pattern,
7198 files_to_skip=files_to_skip)
Dominic Battre645d42342020-12-04 16:14:107199
Sam Maiera6e76d72022-02-11 21:43:507200 def ModifiedLines(affected_file):
7201 """Returns a list of tuples (line number, line text) of added and removed
7202 lines.
Dominic Battre645d42342020-12-04 16:14:107203
Sam Maiera6e76d72022-02-11 21:43:507204 Deleted lines share the same line number as the previous line.
Dominic Battre645d42342020-12-04 16:14:107205
Sam Maiera6e76d72022-02-11 21:43:507206 This relies on the scm diff output describing each changed code section
7207 with a line of the form
Dominic Battre645d42342020-12-04 16:14:107208
Sam Maiera6e76d72022-02-11 21:43:507209 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
7210 """
7211 line_num = 0
7212 modified_lines = []
7213 for line in affected_file.GenerateScmDiff().splitlines():
7214 # Extract <new line num> of the patch fragment (see format above).
7215 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@',
7216 line)
7217 if m:
7218 line_num = int(m.groups(1)[0])
7219 continue
7220 if ((line.startswith('+') and not line.startswith('++'))
7221 or (line.startswith('-') and not line.startswith('--'))):
7222 modified_lines.append((line_num, line))
Dominic Battre645d42342020-12-04 16:14:107223
Sam Maiera6e76d72022-02-11 21:43:507224 if not line.startswith('-'):
7225 line_num += 1
7226 return modified_lines
Dominic Battre645d42342020-12-04 16:14:107227
Sam Maiera6e76d72022-02-11 21:43:507228 def FindLineWith(lines, needle):
7229 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
Dominic Battre645d42342020-12-04 16:14:107230
Sam Maiera6e76d72022-02-11 21:43:507231 If 0 or >1 lines contain `needle`, -1 is returned.
7232 """
7233 matching_line_numbers = [
7234 # + 1 for 1-based counting of line numbers.
7235 i + 1 for i, line in enumerate(lines) if needle in line
7236 ]
7237 return matching_line_numbers[0] if len(
7238 matching_line_numbers) == 1 else -1
Dominic Battre645d42342020-12-04 16:14:107239
Sam Maiera6e76d72022-02-11 21:43:507240 def ModifiedPrefMigration(affected_file):
7241 """Returns whether the MigrateObsolete.*Pref functions were modified."""
7242 # Determine first and last lines of MigrateObsolete.*Pref functions.
7243 new_contents = affected_file.NewContents()
7244 range_1 = (FindLineWith(new_contents,
7245 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
7246 FindLineWith(new_contents,
7247 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
7248 range_2 = (FindLineWith(new_contents,
7249 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
7250 FindLineWith(new_contents,
7251 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
7252 if (-1 in range_1 + range_2):
7253 raise Exception(
7254 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.'
7255 )
Dominic Battre645d42342020-12-04 16:14:107256
Sam Maiera6e76d72022-02-11 21:43:507257 # Check whether any of the modified lines are part of the
7258 # MigrateObsolete.*Pref functions.
7259 for line_nr, line in ModifiedLines(affected_file):
7260 if (range_1[0] <= line_nr <= range_1[1]
7261 or range_2[0] <= line_nr <= range_2[1]):
7262 return True
7263 return False
Dominic Battre645d42342020-12-04 16:14:107264
Sam Maiera6e76d72022-02-11 21:43:507265 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
7266 browser_prefs_file_pattern = input_api.re.compile(
7267 r'chrome/browser/prefs/browser_prefs.cc')
Dominic Battre645d42342020-12-04 16:14:107268
Sam Maiera6e76d72022-02-11 21:43:507269 changes = input_api.AffectedFiles(include_deletes=True,
7270 file_filter=FilterFile)
7271 potential_problems = []
7272 for f in changes:
7273 for line in f.GenerateScmDiff().splitlines():
7274 # Check deleted lines for pref registrations.
7275 if (line.startswith('-') and not line.startswith('--')
7276 and register_pref_pattern.search(line)):
7277 potential_problems.append('%s: %s' % (f.LocalPath(), line))
Dominic Battre645d42342020-12-04 16:14:107278
Sam Maiera6e76d72022-02-11 21:43:507279 if browser_prefs_file_pattern.search(f.LocalPath()):
7280 # If the developer modified the MigrateObsolete.*Prefs() functions, we
7281 # assume that they knew that they have to deprecate preferences and don't
7282 # warn.
7283 try:
7284 if ModifiedPrefMigration(f):
7285 return []
7286 except Exception as e:
7287 return [output_api.PresubmitError(str(e))]
Dominic Battre645d42342020-12-04 16:14:107288
Sam Maiera6e76d72022-02-11 21:43:507289 if potential_problems:
7290 return [
7291 output_api.PresubmitPromptWarning(
7292 'Discovered possible removal of preference registrations.\n\n'
7293 'Please make sure to properly deprecate preferences by clearing their\n'
7294 'value for a couple of milestones before finally removing the code.\n'
7295 'Otherwise data may stay in the preferences files forever. See\n'
7296 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
7297 'chrome/browser/prefs/README.md for examples.\n'
7298 'This may be a false positive warning (e.g. if you move preference\n'
7299 'registrations to a different place).\n', potential_problems)
7300 ]
7301 return []
7302
Matt Stark6ef08872021-07-29 01:21:467303
7304def CheckConsistentGrdChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507305 """Changes to GRD files must be consistent for tools to read them."""
7306 changed_grds = input_api.AffectedFiles(
7307 include_deletes=False,
7308 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
7309 errors = []
7310 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
7311 for matcher, msg in _INVALID_GRD_FILE_LINE]
7312 for grd in changed_grds:
7313 for i, line in enumerate(grd.NewContents()):
7314 for matcher, msg in invalid_file_regexes:
7315 if matcher.search(line):
7316 errors.append(
7317 output_api.PresubmitError(
7318 'Problem on {grd}:{i} - {msg}'.format(
7319 grd=grd.LocalPath(), i=i + 1, msg=msg)))
7320 return errors
7321
Kevin McNee967dd2d22021-11-15 16:09:297322
Henrique Ferreiro2a4b55942021-11-29 23:45:367323def CheckAssertAshOnlyCode(input_api, output_api):
7324 """Errors if a BUILD.gn file in an ash/ directory doesn't include
7325 assert(is_chromeos_ash).
7326 """
7327
7328 def FileFilter(affected_file):
7329 """Includes directories known to be Ash only."""
7330 return input_api.FilterSourceFile(
7331 affected_file,
7332 files_to_check=(
7333 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
7334 r'.*/ash/.*BUILD\.gn'), # Any path component.
7335 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
7336
7337 errors = []
7338 pattern = input_api.re.compile(r'assert\(is_chromeos_ash')
Jameson Thies0ce669f2021-12-09 15:56:567339 for f in input_api.AffectedFiles(include_deletes=False,
7340 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:367341 if (not pattern.search(input_api.ReadFile(f))):
7342 errors.append(
7343 output_api.PresubmitError(
7344 'Please add assert(is_chromeos_ash) to %s. If that\'s not '
7345 'possible, please create and issue and add a comment such '
Alison Galed6b25fe2024-04-17 13:59:047346 'as:\n # TODO(crbug.com/XXX): add '
Henrique Ferreiro2a4b55942021-11-29 23:45:367347 'assert(is_chromeos_ash) when ...' % f.LocalPath()))
7348 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:277349
7350
Kalvin Lee84ad17a2023-09-25 11:14:417351def _IsMiraclePtrDisallowed(input_api, affected_file):
Sam Maiera6e76d72022-02-11 21:43:507352 path = affected_file.LocalPath()
7353 if not _IsCPlusPlusFile(input_api, path):
7354 return False
7355
Bartek Nowierski49b1a452024-06-08 00:24:357356 # Renderer-only code is generally allowed to use MiraclePtr. These
7357 # directories, however, are specifically disallowed, for perf reasons.
Kalvin Lee84ad17a2023-09-25 11:14:417358 if ("third_party/blink/renderer/core/" in path
7359 or "third_party/blink/renderer/platform/heap/" in path
Bartek Nowierski49b1a452024-06-08 00:24:357360 or "third_party/blink/renderer/platform/wtf/" in path
7361 or "third_party/blink/renderer/platform/fonts/" in path):
7362 return True
7363
7364 # The below paths are an explicitly listed subset of Renderer-only code,
7365 # because the plan is to Oilpanize it.
7366 # TODO(crbug.com/330759291): Remove once Oilpanization is completed or
7367 # abandoned.
7368 if ("third_party/blink/renderer/core/paint/" in path
7369 or "third_party/blink/renderer/platform/graphics/compositing/" in path
7370 or "third_party/blink/renderer/platform/graphics/paint/" in path):
Sam Maiera6e76d72022-02-11 21:43:507371 return True
7372
Sam Maiera6e76d72022-02-11 21:43:507373 # We assume that everything else may be used outside of Renderer processes.
Lukasz Anforowicz7016d05e2021-11-30 03:56:277374 return False
7375
Alison Galed6b25fe2024-04-17 13:59:047376# TODO(crbug.com/40206238): Remove these checks, once they are replaced
Lukasz Anforowicz7016d05e2021-11-30 03:56:277377# by the Chromium Clang Plugin (which will be preferable because it will
7378# 1) report errors earlier - at compile-time and 2) cover more rules).
7379def CheckRawPtrUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507380 """Rough checks that raw_ptr<T> usage guidelines are followed."""
7381 errors = []
7382 # The regex below matches "raw_ptr<" following a word boundary, but not in a
7383 # C++ comment.
7384 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
Kalvin Lee84ad17a2023-09-25 11:14:417385 file_filter = lambda f: _IsMiraclePtrDisallowed(input_api, f)
Sam Maiera6e76d72022-02-11 21:43:507386 for f, line_num, line in input_api.RightHandSideLines(file_filter):
7387 if raw_ptr_matcher.search(line):
7388 errors.append(
7389 output_api.PresubmitError(
7390 'Problem on {path}:{line} - '\
Kalvin Lee84ad17a2023-09-25 11:14:417391 'raw_ptr<T> should not be used in this renderer code '\
Sam Maiera6e76d72022-02-11 21:43:507392 '(as documented in the "Pointers to unprotected memory" '\
7393 'section in //base/memory/raw_ptr.md)'.format(
7394 path=f.LocalPath(), line=line_num)))
7395 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:567396
mikt9337567c2023-09-08 18:38:177397def CheckAdvancedMemorySafetyChecksUsage(input_api, output_api):
7398 """Checks that ADVANCED_MEMORY_SAFETY_CHECKS() macro is neither added nor
7399 removed as it is managed by the memory safety team internally.
7400 Do not add / remove it manually."""
7401 paths = set([])
7402 # The regex below matches "ADVANCED_MEMORY_SAFETY_CHECKS(" following a word
7403 # boundary, but not in a C++ comment.
7404 macro_matcher = input_api.re.compile(
7405 r'^((?!//).)*\bADVANCED_MEMORY_SAFETY_CHECKS\(', input_api.re.MULTILINE)
7406 for f in input_api.AffectedFiles():
7407 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
7408 continue
7409 if macro_matcher.search(f.GenerateScmDiff()):
7410 paths.add(f.LocalPath())
7411 if not paths:
7412 return []
7413 return [output_api.PresubmitPromptWarning(
7414 'ADVANCED_MEMORY_SAFETY_CHECKS() macro is managed by ' \
7415 'the memory safety team (chrome-memory-safety@). ' \
7416 'Please contact us to add/delete the uses of the macro.',
7417 paths)]
Henrique Ferreirof9819f2e32021-11-30 13:31:567418
7419def CheckPythonShebang(input_api, output_api):
7420 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
7421 system-wide python.
7422 """
7423 errors = []
7424 sources = lambda affected_file: input_api.FilterSourceFile(
7425 affected_file,
7426 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
7427 r'third_party/blink/web_tests/external/') + input_api.
7428 DEFAULT_FILES_TO_SKIP),
7429 files_to_check=[r'.*\.py$'])
7430 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:277431 for line_num, line in f.ChangedContents():
7432 if line_num == 1 and line.startswith('#!/usr/bin/python'):
7433 errors.append(f.LocalPath())
7434 break
Henrique Ferreirof9819f2e32021-11-30 13:31:567435
7436 result = []
7437 for file in errors:
7438 result.append(
7439 output_api.PresubmitError(
7440 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
7441 file))
7442 return result
James Shen81cc0e22022-06-15 21:10:457443
7444
7445def CheckBatchAnnotation(input_api, output_api):
7446 """Checks that tests have either @Batch or @DoNotBatch annotation. If this
7447 is not an instrumentation test, disregard."""
7448
7449 batch_annotation = input_api.re.compile(r'^\s*@Batch')
7450 do_not_batch_annotation = input_api.re.compile(r'^\s*@DoNotBatch')
7451 robolectric_test = input_api.re.compile(r'[rR]obolectric')
7452 test_class_declaration = input_api.re.compile(r'^\s*public\sclass.*Test')
7453 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
Mark Schillaci8ef0d872023-07-18 22:07:597454 test_annotation_declaration = input_api.re.compile(r'^\s*public\s@interface\s.*{')
James Shen81cc0e22022-06-15 21:10:457455
ckitagawae8fd23b2022-06-17 15:29:387456 missing_annotation_errors = []
7457 extra_annotation_errors = []
James Shen81cc0e22022-06-15 21:10:457458
7459 def _FilterFile(affected_file):
7460 return input_api.FilterSourceFile(
7461 affected_file,
7462 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
7463 files_to_check=[r'.*Test\.java$'])
7464
7465 for f in input_api.AffectedSourceFiles(_FilterFile):
7466 batch_matched = None
7467 do_not_batch_matched = None
7468 is_instrumentation_test = True
Mark Schillaci8ef0d872023-07-18 22:07:597469 test_annotation_declaration_matched = None
James Shen81cc0e22022-06-15 21:10:457470 for line in f.NewContents():
7471 if robolectric_test.search(line) or uiautomator_test.search(line):
7472 # Skip Robolectric and UiAutomator tests.
7473 is_instrumentation_test = False
7474 break
7475 if not batch_matched:
7476 batch_matched = batch_annotation.search(line)
7477 if not do_not_batch_matched:
7478 do_not_batch_matched = do_not_batch_annotation.search(line)
7479 test_class_declaration_matched = test_class_declaration.search(
7480 line)
Mark Schillaci8ef0d872023-07-18 22:07:597481 test_annotation_declaration_matched = test_annotation_declaration.search(line)
7482 if test_class_declaration_matched or test_annotation_declaration_matched:
James Shen81cc0e22022-06-15 21:10:457483 break
Mark Schillaci8ef0d872023-07-18 22:07:597484 if test_annotation_declaration_matched:
7485 continue
James Shen81cc0e22022-06-15 21:10:457486 if (is_instrumentation_test and
7487 not batch_matched and
7488 not do_not_batch_matched):
Sam Maier4cef9242022-10-03 14:21:247489 missing_annotation_errors.append(str(f.LocalPath()))
ckitagawae8fd23b2022-06-17 15:29:387490 if (not is_instrumentation_test and
7491 (batch_matched or
7492 do_not_batch_matched)):
Sam Maier4cef9242022-10-03 14:21:247493 extra_annotation_errors.append(str(f.LocalPath()))
James Shen81cc0e22022-06-15 21:10:457494
7495 results = []
7496
ckitagawae8fd23b2022-06-17 15:29:387497 if missing_annotation_errors:
James Shen81cc0e22022-06-15 21:10:457498 results.append(
7499 output_api.PresubmitPromptWarning(
7500 """
Andrew Grieve43a5cf82023-09-08 15:09:467501A change was made to an on-device test that has neither been annotated with
7502@Batch nor @DoNotBatch. If this is a new test, please add the annotation. If
7503this is an existing test, please consider adding it if you are sufficiently
7504familiar with the test (but do so as a separate change).
7505
Jens Mueller2085ff82023-02-27 11:54:497506See https://source.chromium.org/chromium/chromium/src/+/main:docs/testing/batching_instrumentation_tests.md
ckitagawae8fd23b2022-06-17 15:29:387507""", missing_annotation_errors))
7508 if extra_annotation_errors:
7509 results.append(
7510 output_api.PresubmitPromptWarning(
7511 """
7512Robolectric tests do not need a @Batch or @DoNotBatch annotations.
7513""", extra_annotation_errors))
James Shen81cc0e22022-06-15 21:10:457514
7515 return results
Sam Maier4cef9242022-10-03 14:21:247516
7517
7518def CheckMockAnnotation(input_api, output_api):
7519 """Checks that we have annotated all Mockito.mock()-ed or Mockito.spy()-ed
7520 classes with @Mock or @Spy. If this is not an instrumentation test,
7521 disregard."""
7522
7523 # This is just trying to be approximately correct. We are not writing a
7524 # Java parser, so special cases like statically importing mock() then
7525 # calling an unrelated non-mockito spy() function will cause a false
7526 # positive.
7527 package_name = input_api.re.compile(r'^package\s+(\w+(?:\.\w+)+);')
7528 mock_static_import = input_api.re.compile(
7529 r'^import\s+static\s+org.mockito.Mockito.(?:mock|spy);')
7530 import_class = input_api.re.compile(r'import\s+((?:\w+\.)+)(\w+);')
7531 mock_annotation = input_api.re.compile(r'^\s*@(?:Mock|Spy)')
7532 field_type = input_api.re.compile(r'(\w+)(?:<\w+>)?\s+\w+\s*(?:;|=)')
7533 mock_or_spy_function_call = r'(?:mock|spy)\(\s*(?:new\s*)?(\w+)(?:\.class|\()'
7534 fully_qualified_mock_function = input_api.re.compile(
7535 r'Mockito\.' + mock_or_spy_function_call)
7536 statically_imported_mock_function = input_api.re.compile(
7537 r'\W' + mock_or_spy_function_call)
7538 robolectric_test = input_api.re.compile(r'[rR]obolectric')
7539 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
7540
7541 def _DoClassLookup(class_name, class_name_map, package):
7542 found = class_name_map.get(class_name)
7543 if found is not None:
7544 return found
7545 else:
7546 return package + '.' + class_name
7547
7548 def _FilterFile(affected_file):
7549 return input_api.FilterSourceFile(
7550 affected_file,
7551 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
7552 files_to_check=[r'.*Test\.java$'])
7553
7554 mocked_by_function_classes = set()
7555 mocked_by_annotation_classes = set()
7556 class_to_filename = {}
7557 for f in input_api.AffectedSourceFiles(_FilterFile):
7558 mock_function_regex = fully_qualified_mock_function
7559 next_line_is_annotated = False
7560 fully_qualified_class_map = {}
7561 package = None
7562
7563 for line in f.NewContents():
7564 if robolectric_test.search(line) or uiautomator_test.search(line):
7565 # Skip Robolectric and UiAutomator tests.
7566 break
7567
7568 m = package_name.search(line)
7569 if m:
7570 package = m.group(1)
7571 continue
7572
7573 if mock_static_import.search(line):
7574 mock_function_regex = statically_imported_mock_function
7575 continue
7576
7577 m = import_class.search(line)
7578 if m:
7579 fully_qualified_class_map[m.group(2)] = m.group(1) + m.group(2)
7580 continue
7581
7582 if next_line_is_annotated:
7583 next_line_is_annotated = False
7584 fully_qualified_class = _DoClassLookup(
7585 field_type.search(line).group(1), fully_qualified_class_map,
7586 package)
7587 mocked_by_annotation_classes.add(fully_qualified_class)
7588 continue
7589
7590 if mock_annotation.search(line):
Sam Maierb8a66a02023-10-10 13:50:557591 field_type_search = field_type.search(line)
7592 if field_type_search:
7593 fully_qualified_class = _DoClassLookup(
7594 field_type_search.group(1), fully_qualified_class_map,
7595 package)
7596 mocked_by_annotation_classes.add(fully_qualified_class)
7597 else:
7598 next_line_is_annotated = True
Sam Maier4cef9242022-10-03 14:21:247599 continue
7600
7601 m = mock_function_regex.search(line)
7602 if m:
7603 fully_qualified_class = _DoClassLookup(m.group(1),
7604 fully_qualified_class_map, package)
7605 # Skipping builtin classes, since they don't get optimized.
7606 if fully_qualified_class.startswith(
7607 'android.') or fully_qualified_class.startswith(
7608 'java.'):
7609 continue
7610 class_to_filename[fully_qualified_class] = str(f.LocalPath())
7611 mocked_by_function_classes.add(fully_qualified_class)
7612
7613 results = []
7614 missed_classes = mocked_by_function_classes - mocked_by_annotation_classes
7615 if missed_classes:
7616 error_locations = []
7617 for c in missed_classes:
7618 error_locations.append(c + ' in ' + class_to_filename[c])
7619 results.append(
7620 output_api.PresubmitPromptWarning(
7621 """
7622Mockito.mock()/spy() cause issues with our Java optimizer. You have 3 options:
76231) If the mocked variable can be a class member, annotate the member with
7624 @Mock/@Spy.
76252) If the mocked variable cannot be a class member, create a dummy member
7626 variable of that type, annotated with @Mock/@Spy. This dummy does not need
7627 to be used or initialized in any way.
76283) If the mocked type is definitely not going to be optimized, whether it's a
7629 builtin type which we don't ship, or a class you know R8 will treat
7630 specially, you can ignore this warning.
7631""", error_locations))
7632
7633 return results
Mike Dougherty1b8be712022-10-20 00:15:137634
7635def CheckNoJsInIos(input_api, output_api):
7636 """Checks to make sure that JavaScript files are not used on iOS."""
7637
7638 def _FilterFile(affected_file):
7639 return input_api.FilterSourceFile(
7640 affected_file,
7641 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP +
Daniel White44b8bd02023-08-22 16:20:367642 (r'^ios/third_party/*', r'^ios/tools/*', r'^third_party/*',
7643 r'^components/autofill/ios/form_util/resources/*'),
Mike Dougherty1b8be712022-10-20 00:15:137644 files_to_check=[r'^ios/.*\.js$', r'.*/ios/.*\.js$'])
7645
Mike Dougherty4d1050b2023-03-14 15:59:537646 deleted_files = []
7647
7648 # Collect filenames of all removed JS files.
Arthur Sonzognic66e9c82024-04-23 07:53:047649 for f in input_api.AffectedFiles(file_filter=_FilterFile):
Mike Dougherty4d1050b2023-03-14 15:59:537650 local_path = f.LocalPath()
7651
7652 if input_api.os_path.splitext(local_path)[1] == '.js' and f.Action() == 'D':
7653 deleted_files.append(input_api.os_path.basename(local_path))
7654
Mike Dougherty1b8be712022-10-20 00:15:137655 error_paths = []
Mike Dougherty4d1050b2023-03-14 15:59:537656 moved_paths = []
Mike Dougherty1b8be712022-10-20 00:15:137657 warning_paths = []
7658
7659 for f in input_api.AffectedSourceFiles(_FilterFile):
7660 local_path = f.LocalPath()
7661
7662 if input_api.os_path.splitext(local_path)[1] == '.js':
7663 if f.Action() == 'A':
Mike Dougherty4d1050b2023-03-14 15:59:537664 if input_api.os_path.basename(local_path) in deleted_files:
7665 # This script was probably moved rather than newly created.
7666 # Present a warning instead of an error for these cases.
7667 moved_paths.append(local_path)
7668 else:
7669 error_paths.append(local_path)
Mike Dougherty1b8be712022-10-20 00:15:137670 elif f.Action() != 'D':
7671 warning_paths.append(local_path)
7672
7673 results = []
7674
7675 if warning_paths:
7676 results.append(output_api.PresubmitPromptWarning(
7677 'TypeScript is now fully supported for iOS feature scripts. '
7678 'Consider converting JavaScript files to TypeScript. See '
7679 '//ios/web/public/js_messaging/README.md for more details.',
7680 warning_paths))
7681
Mike Dougherty4d1050b2023-03-14 15:59:537682 if moved_paths:
7683 results.append(output_api.PresubmitPromptWarning(
7684 'Do not use JavaScript on iOS for new files as TypeScript is '
7685 'fully supported. (If this is a moved file, you may leave the '
7686 'script unconverted.) See //ios/web/public/js_messaging/README.md '
7687 'for help using scripts on iOS.', moved_paths))
7688
Mike Dougherty1b8be712022-10-20 00:15:137689 if error_paths:
7690 results.append(output_api.PresubmitError(
7691 'Do not use JavaScript on iOS as TypeScript is fully supported. '
7692 'See //ios/web/public/js_messaging/README.md for help using '
7693 'scripts on iOS.', error_paths))
7694
7695 return results
Hans Wennborg23a81d52023-03-24 16:38:137696
7697def CheckLibcxxRevisionsMatch(input_api, output_api):
7698 """Check to make sure the libc++ version matches across deps files."""
Andrew Grieve21bb6792023-03-27 19:06:487699 # Disable check for changes to sub-repositories.
7700 if input_api.PresubmitLocalPath() != input_api.change.RepositoryRoot():
Sam Maierb926c58c2023-08-08 19:58:257701 return []
Hans Wennborg23a81d52023-03-24 16:38:137702
7703 DEPS_FILES = [ 'DEPS', 'buildtools/deps_revisions.gni' ]
7704
7705 file_filter = lambda f: f.LocalPath().replace(
7706 input_api.os_path.sep, '/') in DEPS_FILES
7707 changed_deps_files = input_api.AffectedFiles(file_filter=file_filter)
7708 if not changed_deps_files:
7709 return []
7710
7711 def LibcxxRevision(file):
7712 file = input_api.os_path.join(input_api.PresubmitLocalPath(),
7713 *file.split('/'))
7714 return input_api.re.search(
7715 r'libcxx_revision.*[:=].*[\'"](\w+)[\'"]',
7716 input_api.ReadFile(file)).group(1)
7717
7718 if len(set([LibcxxRevision(f) for f in DEPS_FILES])) == 1:
7719 return []
7720
7721 return [output_api.PresubmitError(
7722 'libcxx_revision not equal across %s' % ', '.join(DEPS_FILES),
7723 changed_deps_files)]
Arthur Sonzogni7109bd32023-10-03 10:34:427724
7725
7726def CheckDanglingUntriaged(input_api, output_api):
7727 """Warn developers adding DanglingUntriaged raw_ptr."""
7728
7729 # Ignore during git presubmit --all.
7730 #
7731 # This would be too costly, because this would check every lines of every
7732 # C++ files. Check from _BANNED_CPP_FUNCTIONS are also reading the whole
7733 # source code, but only once to apply every checks. It seems the bots like
7734 # `win-presubmit` are particularly sensitive to reading the files. Adding
7735 # this check caused the bot to run 2x longer. See https://crbug.com/1486612.
7736 if input_api.no_diffs:
Arthur Sonzogni9eafd222023-11-10 08:50:397737 return []
Arthur Sonzogni7109bd32023-10-03 10:34:427738
7739 def FilterFile(file):
7740 return input_api.FilterSourceFile(
7741 file,
7742 files_to_check=[r".*\.(h|cc|cpp|cxx|m|mm)$"],
7743 files_to_skip=[r"^base/allocator.*"],
7744 )
7745
7746 count = 0
Arthur Sonzognic66e9c82024-04-23 07:53:047747 for f in input_api.AffectedFiles(file_filter=FilterFile):
Arthur Sonzogni9eafd222023-11-10 08:50:397748 count -= sum([l.count("DanglingUntriaged") for l in f.OldContents()])
7749 count += sum([l.count("DanglingUntriaged") for l in f.NewContents()])
Arthur Sonzogni7109bd32023-10-03 10:34:427750
7751 # Most likely, nothing changed:
7752 if count == 0:
7753 return []
7754
7755 # Congrats developers for improving it:
7756 if count < 0:
Arthur Sonzogni9eafd222023-11-10 08:50:397757 message = f"DanglingUntriaged pointers removed: {-count}\nThank you!"
Arthur Sonzogni7109bd32023-10-03 10:34:427758 return [output_api.PresubmitNotifyResult(message)]
7759
7760 # Check for 'DanglingUntriaged-notes' in the description:
7761 notes_regex = input_api.re.compile("DanglingUntriaged-notes[:=]")
7762 if any(
7763 notes_regex.match(line)
7764 for line in input_api.change.DescriptionText().splitlines()):
7765 return []
7766
7767 # Check for DanglingUntriaged-notes in the git footer:
7768 if input_api.change.GitFootersFromDescription().get(
7769 "DanglingUntriaged-notes", []):
7770 return []
7771
7772 message = (
Arthur Sonzogni9eafd222023-11-10 08:50:397773 "Unexpected new occurrences of `DanglingUntriaged` detected. Please\n" +
7774 "avoid adding new ones\n" +
7775 "\n" +
7776 "See documentation:\n" +
7777 "https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr.md\n" +
7778 "\n" +
7779 "See also the guide to fix dangling pointers:\n" +
7780 "https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr_guide.md\n" +
7781 "\n" +
7782 "To disable this warning, please add in the commit description:\n" +
Alex Gough26dcd852023-12-22 16:47:197783 "DanglingUntriaged-notes: <rationale for new untriaged dangling " +
Arthur Sonzogni9eafd222023-11-10 08:50:397784 "pointers>"
Arthur Sonzogni7109bd32023-10-03 10:34:427785 )
7786 return [output_api.PresubmitPromptWarning(message)]
Jan Keitel77be7522023-10-12 20:40:497787
7788def CheckInlineConstexprDefinitionsInHeaders(input_api, output_api):
7789 """Checks that non-static constexpr definitions in headers are inline."""
7790 # In a properly formatted file, constexpr definitions inside classes or
7791 # structs will have additional whitespace at the beginning of the line.
7792 # The pattern looks for variables initialized as constexpr kVar = ...; or
7793 # constexpr kVar{...};
7794 # The pattern does not match expressions that have braces in kVar to avoid
7795 # matching constexpr functions.
7796 pattern = input_api.re.compile(r'^constexpr (?!inline )[^\(\)]*[={]')
7797 attribute_pattern = input_api.re.compile(r'(\[\[[a-zA-Z_:]+\]\]|[A-Z]+[A-Z_]+) ')
7798 problems = []
7799 for f in input_api.AffectedFiles():
7800 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
7801 continue
7802
7803 for line_number, line in f.ChangedContents():
7804 line = attribute_pattern.sub('', line)
7805 if pattern.search(line):
7806 problems.append(
7807 f"{f.LocalPath()}: {line_number}\n {line}")
7808
7809 if problems:
7810 return [
7811 output_api.PresubmitPromptWarning(
7812 'Consider inlining constexpr variable definitions in headers '
7813 'outside of classes to avoid unnecessary copies of the '
7814 'constant. See https://abseil.io/tips/168 for more details.',
7815 problems)
7816 ]
7817 else:
7818 return []
Alison Galed6b25fe2024-04-17 13:59:047819
7820def CheckTodoBugReferences(input_api, output_api):
7821 """Checks that bugs in TODOs use updated issue tracker IDs."""
7822
7823 files_to_skip = ['PRESUBMIT_test.py']
7824
7825 def _FilterFile(affected_file):
7826 return input_api.FilterSourceFile(
7827 affected_file,
7828 files_to_skip=files_to_skip)
7829
7830 # Monorail bug IDs are all less than or equal to 1524553 so check that all
7831 # bugs in TODOs are greater than that value.
7832 pattern = input_api.re.compile(r'.*TODO\([^\)0-9]*([0-9]+)\).*')
7833 problems = []
7834 for f in input_api.AffectedSourceFiles(_FilterFile):
7835 for line_number, line in f.ChangedContents():
7836 match = pattern.match(line)
7837 if match and int(match.group(1)) <= 1524553:
7838 problems.append(
7839 f"{f.LocalPath()}: {line_number}\n {line}")
7840
7841 if problems:
7842 return [
7843 output_api.PresubmitPromptWarning(
Alison Galecb598de52024-04-26 17:03:257844 'TODOs should use the new Chromium Issue Tracker IDs which can '
7845 'be found by navigating to the bug. See '
7846 'https://crbug.com/336778624 for more details.',
Alison Galed6b25fe2024-04-17 13:59:047847 problems)
7848 ]
7849 else:
7850 return []