blob: 84ef5384375787a90967e0a8f4a8be3cfccdf222 [file] [log] [blame]
Avi Drissman24976592022-09-12 15:24:311# Copyright 2012 The Chromium Authors
[email protected]ca8d19842009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
Daniel Chengd88244472022-05-16 09:08:477See https://www.chromium.org/developers/how-tos/depottools/presubmit-scripts/
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d19842009-02-19 16:33:129"""
Daniel Chenga44a1bcd2022-03-15 20:00:1510
Daniel Chenga37c03db2022-05-12 17:20:3411from typing import Callable
Daniel Chenga44a1bcd2022-03-15 20:00:1512from typing import Optional
13from typing import Sequence
mikt19226ff22024-08-27 05:28:2114from typing import Tuple
Daniel Chenga44a1bcd2022-03-15 20:00:1515from dataclasses import dataclass
16
Saagar Sanghavifceeaae2020-08-12 16:40:3617PRESUBMIT_VERSION = '2.0.0'
[email protected]eea609a2011-11-18 13:10:1218
Dirk Prankee3c9c62d2021-05-18 18:35:5919
[email protected]379e7dd2010-01-28 17:39:2120_EXCLUDED_PATHS = (
Bruce Dawson7f8566b2022-05-06 16:22:1821 # Generated file
Bruce Dawson40fece62022-09-16 19:58:3122 (r"chrome/android/webapk/shell_apk/src/org/chromium"
23 r"/webapk/lib/runtime_library/IWebApkApi.java"),
Mila Greene3aa7222021-09-07 16:34:0824 # File needs to write to stdout to emulate a tool it's replacing.
Bruce Dawson40fece62022-09-16 19:58:3125 r"chrome/updater/mac/keystone/ksadmin.mm",
Ilya Shermane8a7d2d2020-07-25 04:33:4726 # Generated file.
Bruce Dawson40fece62022-09-16 19:58:3127 (r"^components/variations/proto/devtools/"
Ilya Shermanc167a962020-08-18 18:40:2628 r"client_variations.js"),
Bruce Dawson3bd976c2022-05-06 22:47:5229 # These are video files, not typescript.
Bruce Dawson40fece62022-09-16 19:58:3130 r"^media/test/data/.*.ts",
31 r"^native_client_sdksrc/build_tools/make_rules.py",
32 r"^native_client_sdk/src/build_tools/make_simple.py",
33 r"^native_client_sdk/src/tools/.*.mk",
34 r"^net/tools/spdyshark/.*",
35 r"^skia/.*",
36 r"^third_party/blink/.*",
37 r"^third_party/breakpad/.*",
Darwin Huangd74a9d32019-07-17 17:58:4638 # sqlite is an imported third party dependency.
Bruce Dawson40fece62022-09-16 19:58:3139 r"^third_party/sqlite/.*",
40 r"^v8/.*",
[email protected]3e4eb112011-01-18 03:29:5441 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5342 r".+_autogen\.h$",
Yue Shecf1380552022-08-23 20:59:2043 r".+_pb2(_grpc)?\.py$",
Bruce Dawson40fece62022-09-16 19:58:3144 r".+/pnacl_shim\.c$",
45 r"^gpu/config/.*_list_json\.cc$",
46 r"tools/md_browser/.*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1447 # Test pages for Maps telemetry tests.
Bruce Dawson40fece62022-09-16 19:58:3148 r"tools/perf/page_sets/maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5449 # Test pages for WebRTC telemetry tests.
Bruce Dawson40fece62022-09-16 19:58:3150 r"tools/perf/page_sets/webrtc_cases.*",
dpapad2efd4452023-04-06 01:43:4551 # Test file compared with generated output.
52 r"tools/polymer/tests/html_to_wrapper/.*.html.ts$",
dpapada45be36c2024-08-07 20:19:3553 # Third-party dependency frozen at a fixed version.
54 r"chrome/test/data/webui/chromeos/chai_v4.js$",
[email protected]4306417642009-06-11 00:33:4055)
[email protected]ca8d19842009-02-19 16:33:1256
John Abd-El-Malek759fea62021-03-13 03:41:1457_EXCLUDED_SET_NO_PARENT_PATHS = (
58 # It's for historical reasons that blink isn't a top level directory, where
59 # it would be allowed to have "set noparent" to avoid top level owners
60 # accidentally +1ing changes.
61 'third_party/blink/OWNERS',
62)
63
wnwenbdc444e2016-05-25 13:44:1564
[email protected]06e6d0ff2012-12-11 01:36:4465# Fragment of a regular expression that matches C++ and Objective-C++
66# implementation files.
67_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
68
wnwenbdc444e2016-05-25 13:44:1569
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1970# Fragment of a regular expression that matches C++ and Objective-C++
71# header files.
72_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
73
74
Aleksey Khoroshilov9b28c032022-06-03 16:35:3275# Paths with sources that don't use //base.
76_NON_BASE_DEPENDENT_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:3177 r"^chrome/browser/browser_switcher/bho/",
78 r"^tools/win/",
Aleksey Khoroshilov9b28c032022-06-03 16:35:3279)
80
81
[email protected]06e6d0ff2012-12-11 01:36:4482# Regular expression that matches code only used for test binaries
83# (best effort).
84_TEST_CODE_EXCLUDED_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:3185 r'.*/(fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
Marijn Kruisselbrink2a2d5fc2024-05-15 15:23:4986 # Test support files, like:
87 # foo_test_support.cc
88 # bar_test_util_linux.cc (suffix)
89 # baz_test_base.cc
90 r'.+_test_(base|support|util)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
James Cook1b4dc132021-03-09 22:45:1391 # Test suite files, like:
92 # foo_browsertest.cc
93 # bar_unittest_mac.cc (suffix)
94 # baz_unittests.cc (plural)
95 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(s)?(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1296 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1897 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
Victor Hugo Vianna Silvac22e0202021-06-09 19:46:2198 r'.+sync_service_impl_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Bruce Dawson40fece62022-09-16 19:58:3199 r'.*/(test|tool(s)?)/.*',
danakj89f47082020-09-02 17:53:43100 # content_shell is used for running content_browsertests.
Bruce Dawson40fece62022-09-16 19:58:31101 r'content/shell/.*',
danakj89f47082020-09-02 17:53:43102 # Web test harness.
Bruce Dawson40fece62022-09-16 19:58:31103 r'content/web_test/.*',
[email protected]7b054982013-11-27 00:44:47104 # Non-production example code.
Bruce Dawson40fece62022-09-16 19:58:31105 r'mojo/examples/.*',
[email protected]8176de12014-06-20 19:07:08106 # Launcher for running iOS tests on the simulator.
Bruce Dawson40fece62022-09-16 19:58:31107 r'testing/iossim/iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:41108 # EarlGrey app side code for tests.
Bruce Dawson40fece62022-09-16 19:58:31109 r'ios/.*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:17110 # Views Examples code
Bruce Dawson40fece62022-09-16 19:58:31111 r'ui/views/examples/.*',
Austin Sullivan33da70a2020-10-07 15:39:41112 # Chromium Codelab
Bruce Dawson40fece62022-09-16 19:58:31113 r'codelabs/*'
[email protected]06e6d0ff2012-12-11 01:36:44114)
[email protected]ca8d19842009-02-19 16:33:12115
Daniel Bratell609102be2019-03-27 20:53:21116_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:15117
[email protected]eea609a2011-11-18 13:10:12118_TEST_ONLY_WARNING = (
119 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:55120 'production code. If you are doing this from inside another method\n'
121 'named as *ForTesting(), then consider exposing things to have tests\n'
122 'make that same call directly.\n'
123 'If that is not possible, you may put a comment on the same line with\n'
124 ' // IN-TEST \n'
125 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
126 'method and can be ignored. Do not do this inside production code.\n'
127 'The android-binary-size trybot will block if the method exists in the\n'
Yulun Zeng08d7d8c2024-02-01 18:46:54128 'release apk.\n'
129 'Note: this warning might be a false positive (crbug.com/1196548).')
[email protected]eea609a2011-11-18 13:10:12130
131
Daniel Chenga44a1bcd2022-03-15 20:00:15132@dataclass
133class BanRule:
Daniel Chenga37c03db2022-05-12 17:20:34134 # String pattern. If the pattern begins with a slash, the pattern will be
135 # treated as a regular expression instead.
136 pattern: str
137 # Explanation as a sequence of strings. Each string in the sequence will be
138 # printed on its own line.
mikt19226ff22024-08-27 05:28:21139 explanation: Tuple[str, ...]
Daniel Chenga37c03db2022-05-12 17:20:34140 # Whether or not to treat this ban as a fatal error. If unspecified,
141 # defaults to true.
142 treat_as_error: Optional[bool] = None
143 # Paths that should be excluded from the ban check. Each string is a regular
144 # expression that will be matched against the path of the file being checked
145 # relative to the root of the source tree.
146 excluded_paths: Optional[Sequence[str]] = None
[email protected]cf9b78f2012-11-14 11:40:28147
Daniel Chenga44a1bcd2022-03-15 20:00:15148
Daniel Cheng917ce542022-03-15 20:46:57149_BANNED_JAVA_IMPORTS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15150 BanRule(
151 'import java.net.URI;',
152 (
153 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
154 ),
155 excluded_paths=(
156 (r'net/android/javatests/src/org/chromium/net/'
157 'AndroidProxySelectorTest\.java'),
158 r'components/cronet/',
159 r'third_party/robolectric/local/',
160 ),
Michael Thiessen44457642020-02-06 00:24:15161 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15162 BanRule(
163 'import android.annotation.TargetApi;',
164 (
165 'Do not use TargetApi, use @androidx.annotation.RequiresApi instead. '
166 'RequiresApi ensures that any calls are guarded by the appropriate '
167 'SDK_INT check. See https://crbug.com/1116486.',
168 ),
169 ),
170 BanRule(
Mohamed Heikal3d7a94c2023-03-28 16:55:24171 'import androidx.test.rule.UiThreadTestRule;',
Daniel Chenga44a1bcd2022-03-15 20:00:15172 (
173 'Do not use UiThreadTestRule, just use '
174 '@org.chromium.base.test.UiThreadTest on test methods that should run '
175 'on the UI thread. See https://crbug.com/1111893.',
176 ),
177 ),
178 BanRule(
Mohamed Heikal3d7a94c2023-03-28 16:55:24179 'import androidx.test.annotation.UiThreadTest;',
180 ('Do not use androidx.test.annotation.UiThreadTest, use '
Daniel Chenga44a1bcd2022-03-15 20:00:15181 'org.chromium.base.test.UiThreadTest instead. See '
182 'https://crbug.com/1111893.',
183 ),
184 ),
185 BanRule(
Mohamed Heikal3d7a94c2023-03-28 16:55:24186 'import androidx.test.rule.ActivityTestRule;',
Daniel Chenga44a1bcd2022-03-15 20:00:15187 (
188 'Do not use ActivityTestRule, use '
189 'org.chromium.base.test.BaseActivityTestRule instead.',
190 ),
191 excluded_paths=(
192 'components/cronet/',
193 ),
194 ),
Min Qinbc44383c2023-02-22 17:25:26195 BanRule(
196 'import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;',
197 (
198 'Do not use VectorDrawableCompat, use getResources().getDrawable() to '
199 'avoid extra indirections. Please also add trace event as the call '
200 'might take more than 20 ms to complete.',
201 ),
202 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15203)
wnwenbdc444e2016-05-25 13:44:15204
Daniel Cheng917ce542022-03-15 20:46:57205_BANNED_JAVA_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15206 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41207 'StrictMode.allowThreadDiskReads()',
208 (
209 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
210 'directly.',
211 ),
212 False,
213 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15214 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41215 'StrictMode.allowThreadDiskWrites()',
216 (
217 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
218 'directly.',
219 ),
220 False,
221 ),
Daniel Cheng917ce542022-03-15 20:46:57222 BanRule(
Michael Thiessen0f2547e2020-07-27 21:55:36223 '.waitForIdleSync()',
224 (
225 'Do not use waitForIdleSync as it masks underlying issues. There is '
226 'almost always something else you should wait on instead.',
227 ),
228 False,
229 ),
Ashley Newson09cbd602022-10-26 11:40:14230 BanRule(
Ashley Newsoneb6f5ced2022-10-26 14:45:42231 r'/(?<!\bsuper\.)(?<!\bIntent )\bregisterReceiver\(',
Ashley Newson09cbd602022-10-26 11:40:14232 (
233 'Do not call android.content.Context.registerReceiver (or an override) '
234 'directly. Use one of the wrapper methods defined in '
235 'org.chromium.base.ContextUtils, such as '
236 'registerProtectedBroadcastReceiver, '
237 'registerExportedBroadcastReceiver, or '
238 'registerNonExportedBroadcastReceiver. See their documentation for '
239 'which one to use.',
240 ),
241 True,
242 excluded_paths=(
Ashley Newson22bc26d2022-11-01 20:30:57243 r'.*Test[^a-z]',
244 r'third_party/',
Ashley Newson09cbd602022-10-26 11:40:14245 'base/android/java/src/org/chromium/base/ContextUtils.java',
Brandon Mousseau7e76a9c2022-12-08 22:08:38246 'chromecast/browser/android/apk/src/org/chromium/chromecast/shell/BroadcastReceiverScope.java',
Ashley Newson09cbd602022-10-26 11:40:14247 ),
248 ),
Ted Chocd5b327b12022-11-05 02:13:22249 BanRule(
250 r'/(?:extends|new)\s*(?:android.util.)?Property<[A-Za-z.]+,\s*(?:Integer|Float)>',
251 (
252 'Do not use Property<..., Integer|Float>, but use FloatProperty or '
253 'IntProperty because it will avoid unnecessary autoboxing of '
254 'primitives.',
255 ),
256 ),
Peilin Wangbba4a8652022-11-10 16:33:57257 BanRule(
258 'requestLayout()',
259 (
260 'Layouts can be expensive. Prefer using ViewUtils.requestLayout(), '
261 'which emits a trace event with additional information to help with '
262 'scroll jank investigations. See http://crbug.com/1354176.',
263 ),
264 False,
265 excluded_paths=(
266 'ui/android/java/src/org/chromium/ui/base/ViewUtils.java',
267 ),
268 ),
Ted Chocf40ea9152023-02-14 19:02:39269 BanRule(
Ted Chocf486e3f2024-02-17 05:37:03270 'ProfileManager.getLastUsedRegularProfile()',
Ted Chocf40ea9152023-02-14 19:02:39271 (
272 'Prefer passing in the Profile reference instead of relying on the '
273 'static getLastUsedRegularProfile() call. Only top level entry points '
274 '(e.g. Activities) should call this method. Otherwise, the Profile '
275 'should either be passed in explicitly or retreived from an existing '
276 'entity with a reference to the Profile (e.g. WebContents).',
277 ),
278 False,
279 excluded_paths=(
280 r'.*Test[A-Z]?.*\.java',
281 ),
282 ),
Min Qinbc44383c2023-02-22 17:25:26283 BanRule(
284 r'/(ResourcesCompat|getResources\(\))\.getDrawable\(\)',
285 (
286 'getDrawable() can be expensive. If you have a lot of calls to '
287 'GetDrawable() or your code may introduce janks, please put your calls '
288 'inside a trace().',
289 ),
290 False,
291 excluded_paths=(
292 r'.*Test[A-Z]?.*\.java',
293 ),
294 ),
Henrique Nakashimabbf2b262023-03-10 17:21:39295 BanRule(
296 r'/RecordHistogram\.getHistogram(ValueCount|TotalCount|Samples)ForTesting\(',
297 (
298 'Raw histogram counts are easy to misuse; for example they don\'t reset '
Thiago Perrotta099034f2023-06-05 18:10:20299 'between batched tests. Use HistogramWatcher to check histogram records '
300 'instead.',
Henrique Nakashimabbf2b262023-03-10 17:21:39301 ),
302 False,
303 excluded_paths=(
304 'base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java',
305 'base/test/android/javatests/src/org/chromium/base/test/util/HistogramWatcher.java',
306 ),
307 ),
Eric Stevensona9a980972017-09-23 00:04:41308)
309
Clement Yan9b330cb2022-11-17 05:25:29310_BANNED_JAVASCRIPT_FUNCTIONS : Sequence [BanRule] = (
311 BanRule(
312 r'/\bchrome\.send\b',
313 (
314 'The use of chrome.send is disallowed in Chrome (context: https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/security/handling-messages-from-web-content.md).',
315 'Please use mojo instead for new webuis. https://docs.google.com/document/d/1RF-GSUoveYa37eoyZ9EhwMtaIwoW7Z88pIgNZ9YzQi4/edit#heading=h.gkk22wgk6wff',
316 ),
317 True,
318 (
319 r'^(?!ash\/webui).+',
320 # TODO(crbug.com/1385601): pre-existing violations still need to be
321 # cleaned up.
Rebekah Potter57aa94df2022-12-13 20:30:58322 'ash/webui/common/resources/cr.m.js',
Clement Yan9b330cb2022-11-17 05:25:29323 'ash/webui/common/resources/multidevice_setup/multidevice_setup_browser_proxy.js',
Martin Bidlingmaiera921fee72023-06-03 07:52:22324 'ash/webui/common/resources/quick_unlock/lock_screen_constants.ts',
Clement Yan9b330cb2022-11-17 05:25:29325 'ash/webui/common/resources/smb_shares/smb_browser_proxy.js',
Chad Duffin06e47de2023-12-14 18:04:13326 'ash/webui/connectivity_diagnostics/resources/connectivity_diagnostics.ts',
Clement Yan9b330cb2022-11-17 05:25:29327 'ash/webui/diagnostics_ui/resources/diagnostics_browser_proxy.ts',
328 'ash/webui/multidevice_debug/resources/logs.js',
329 'ash/webui/multidevice_debug/resources/webui.js',
330 'ash/webui/projector_app/resources/annotator/trusted/annotator_browser_proxy.js',
331 'ash/webui/projector_app/resources/app/trusted/projector_browser_proxy.js',
Ashley Prasad71f9024e2023-09-25 22:33:55332 # TODO(b/301634378): Remove violation exception once Scanning App
333 # migrated off usage of `chrome.send`.
334 'ash/webui/scanning/resources/scanning_browser_proxy.ts',
Clement Yan9b330cb2022-11-17 05:25:29335 ),
336 ),
337)
338
Daniel Cheng917ce542022-03-15 20:46:57339_BANNED_OBJC_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15340 BanRule(
[email protected]127f18ec2012-06-16 05:05:59341 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20342 (
343 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59344 'prohibited. Please use CrTrackingArea instead.',
345 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
346 ),
347 False,
348 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15349 BanRule(
[email protected]eaae1972014-04-16 04:17:26350 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20351 (
352 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59353 'instead.',
354 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
355 ),
356 False,
357 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15358 BanRule(
[email protected]127f18ec2012-06-16 05:05:59359 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20360 (
361 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59362 'Please use |convertPoint:(point) fromView:nil| instead.',
363 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
364 ),
365 True,
366 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15367 BanRule(
[email protected]127f18ec2012-06-16 05:05:59368 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20369 (
370 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59371 'Please use |convertPoint:(point) toView:nil| instead.',
372 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
373 ),
374 True,
375 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15376 BanRule(
[email protected]127f18ec2012-06-16 05:05:59377 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20378 (
379 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59380 'Please use |convertRect:(point) fromView:nil| instead.',
381 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
382 ),
383 True,
384 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15385 BanRule(
[email protected]127f18ec2012-06-16 05:05:59386 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20387 (
388 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59389 'Please use |convertRect:(point) toView:nil| instead.',
390 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
391 ),
392 True,
393 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15394 BanRule(
[email protected]127f18ec2012-06-16 05:05:59395 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20396 (
397 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59398 'Please use |convertSize:(point) fromView:nil| instead.',
399 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
400 ),
401 True,
402 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15403 BanRule(
[email protected]127f18ec2012-06-16 05:05:59404 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20405 (
406 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59407 'Please use |convertSize:(point) toView:nil| instead.',
408 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
409 ),
410 True,
411 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15412 BanRule(
jif65398702016-10-27 10:19:48413 r"/\s+UTF8String\s*]",
414 (
415 'The use of -[NSString UTF8String] is dangerous as it can return null',
416 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
417 'Please use |SysNSStringToUTF8| instead.',
418 ),
419 True,
Marijn Kruisselbrink1b7c48952023-08-31 16:58:34420 excluded_paths = (
421 '^third_party/ocmock/OCMock/',
422 ),
jif65398702016-10-27 10:19:48423 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15424 BanRule(
Sylvain Defresne4cf1d182017-09-18 14:16:34425 r'__unsafe_unretained',
426 (
427 'The use of __unsafe_unretained is almost certainly wrong, unless',
428 'when interacting with NSFastEnumeration or NSInvocation.',
429 'Please use __weak in files build with ARC, nothing otherwise.',
430 ),
431 False,
432 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15433 BanRule(
Avi Drissman7382afa02019-04-29 23:27:13434 'freeWhenDone:NO',
435 (
436 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
437 'Foundation types is prohibited.',
438 ),
439 True,
440 ),
Avi Drissman3d243a42023-08-01 16:53:59441 BanRule(
442 'This file requires ARC support.',
443 (
444 'ARC compilation is default in Chromium; do not add boilerplate to ',
445 'files that require ARC.',
446 ),
447 True,
448 ),
[email protected]127f18ec2012-06-16 05:05:59449)
450
Sylvain Defresnea8b73d252018-02-28 15:45:54451_BANNED_IOS_OBJC_FUNCTIONS = (
Daniel Chenga44a1bcd2022-03-15 20:00:15452 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54453 r'/\bTEST[(]',
454 (
455 'TEST() macro should not be used in Objective-C++ code as it does not ',
456 'drain the autorelease pool at the end of the test. Use TEST_F() ',
457 'macro instead with a fixture inheriting from PlatformTest (or a ',
458 'typedef).'
459 ),
460 True,
461 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15462 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54463 r'/\btesting::Test\b',
464 (
465 'testing::Test should not be used in Objective-C++ code as it does ',
466 'not drain the autorelease pool at the end of the test. Use ',
467 'PlatformTest instead.'
468 ),
469 True,
470 ),
Ewann2ecc8d72022-07-18 07:41:23471 BanRule(
472 ' systemImageNamed:',
473 (
474 '+[UIImage systemImageNamed:] should not be used to create symbols.',
475 'Instead use a wrapper defined in:',
Slobodan Pejic8ef56c702024-07-12 18:21:26476 'ios/chrome/browser/shared/ui/symbols/symbol_helpers.h'
Ewann2ecc8d72022-07-18 07:41:23477 ),
478 True,
Ewann450a2ef2022-07-19 14:38:23479 excluded_paths=(
Gauthier Ambard4d8756b2023-04-07 17:26:41480 'ios/chrome/browser/shared/ui/symbols/symbol_helpers.mm',
Slobodan Pejic8ef56c702024-07-12 18:21:26481 'ios/chrome/common',
Gauthier Ambardd36c10b12023-03-16 08:45:03482 'ios/chrome/search_widget_extension/',
Ewann450a2ef2022-07-19 14:38:23483 ),
Ewann2ecc8d72022-07-18 07:41:23484 ),
Sylvain Defresnea8b73d252018-02-28 15:45:54485)
486
Daniel Cheng917ce542022-03-15 20:46:57487_BANNED_IOS_EGTEST_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15488 BanRule(
Peter K. Lee6c03ccff2019-07-15 14:40:05489 r'/\bEXPECT_OCMOCK_VERIFY\b',
490 (
491 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
492 'it is meant for GTests. Use [mock verify] instead.'
493 ),
494 True,
495 ),
496)
497
Daniel Cheng566634ff2024-06-29 14:56:53498_BANNED_CPP_FUNCTIONS: Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15499 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53500 '%#0',
501 (
502 'Zero-padded values that use "#" to add prefixes don\'t exhibit ',
503 'consistent behavior, since the prefix is not prepended for zero ',
504 'values. Use "0x%0..." instead.',
505 ),
506 False,
507 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting7c0d98a2023-10-06 15:42:39508 ),
509 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53510 r'/\busing namespace ',
511 (
512 'Using directives ("using namespace x") are banned by the Google Style',
513 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
514 'Explicitly qualify symbols or use using declarations ("using x::foo").',
515 ),
516 True,
517 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting94a56c42019-10-25 21:54:04518 ),
Antonio Gomes07300d02019-03-13 20:59:57519 # Make sure that gtest's FRIEND_TEST() macro is not used; the
520 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
521 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
Daniel Chenga44a1bcd2022-03-15 20:00:15522 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53523 'FRIEND_TEST(',
524 (
525 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
526 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
527 ),
528 False,
529 excluded_paths=(
530 "base/gtest_prod_util.h",
531 "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/gtest_prod_util.h",
532 ),
[email protected]23e6cbc2012-06-16 18:51:20533 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15534 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53535 'setMatrixClip',
536 (
537 'Overriding setMatrixClip() is prohibited; ',
538 'the base function is deprecated. ',
539 ),
540 True,
541 (),
tomhudsone2c14d552016-05-26 17:07:46542 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15543 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53544 'SkRefPtr',
545 ('The use of SkRefPtr is prohibited. ', 'Please use sk_sp<> instead.'),
546 True,
547 (),
[email protected]52657f62013-05-20 05:30:31548 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15549 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53550 'SkAutoRef',
551 ('The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
552 'Please use sk_sp<> instead.'),
553 True,
554 (),
[email protected]52657f62013-05-20 05:30:31555 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15556 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53557 'SkAutoTUnref',
558 ('The use of SkAutoTUnref is dangerous because it implicitly ',
559 'converts to a raw pointer. Please use sk_sp<> instead.'),
560 True,
561 (),
[email protected]52657f62013-05-20 05:30:31562 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15563 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53564 'SkAutoUnref',
565 ('The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
566 'because it implicitly converts to a raw pointer. ',
567 'Please use sk_sp<> instead.'),
568 True,
569 (),
[email protected]52657f62013-05-20 05:30:31570 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15571 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53572 r'/HANDLE_EINTR\(.*close',
573 ('HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
574 'descriptor will be closed, and it is incorrect to retry the close.',
575 'Either call close directly and ignore its return value, or wrap close',
576 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
577 ),
578 True,
579 (),
[email protected]d89eec82013-12-03 14:10:59580 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15581 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53582 r'/IGNORE_EINTR\((?!.*close)',
583 (
584 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
585 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
586 ),
587 True,
588 (
589 # Files that #define IGNORE_EINTR.
590 r'^base/posix/eintr_wrapper\.h$',
591 r'^ppapi/tests/test_broker\.cc$',
592 ),
[email protected]d89eec82013-12-03 14:10:59593 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15594 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53595 r'/v8::Extension\(',
596 (
597 'Do not introduce new v8::Extensions into the code base, use',
598 'gin::Wrappable instead. See http://crbug.com/334679',
599 ),
600 True,
601 (r'extensions/renderer/safe_builtins\.*', ),
[email protected]ec5b3f02014-04-04 18:43:43602 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15603 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53604 '#pragma comment(lib,',
605 ('Specify libraries to link with in build files and not in the source.',
606 ),
607 True,
608 (
609 r'^base/third_party/symbolize/.*',
610 r'^third_party/abseil-cpp/.*',
611 ),
jame2d1a952016-04-02 00:27:10612 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15613 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53614 r'/base::SequenceChecker\b',
615 ('Consider using SEQUENCE_CHECKER macros instead of the class directly.',
616 ),
617 False,
618 (),
gabd52c912a2017-05-11 04:15:59619 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15620 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53621 r'/base::ThreadChecker\b',
622 ('Consider using THREAD_CHECKER macros instead of the class directly.',
623 ),
624 False,
625 (),
gabd52c912a2017-05-11 04:15:59626 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15627 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53628 r'/\b(?!(Sequenced|SingleThread))\w*TaskRunner::(GetCurrentDefault|CurrentDefaultHandle)',
629 (
630 'It is not allowed to call these methods from the subclasses ',
631 'of Sequenced or SingleThread task runners.',
632 ),
633 True,
634 (),
Sean Maher03efef12022-09-23 22:43:13635 ),
636 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53637 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
638 (
639 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
640 'deprecated (http://crbug.com/634507). Please avoid converting away',
641 'from the Time types in Chromium code, especially if any math is',
642 'being done on time values. For interfacing with platform/library',
643 'APIs, use base::Time::(From,To)DeltaSinceWindowsEpoch() or',
644 'base::{TimeDelta::In}Microseconds(), or one of the other type',
645 'converter methods instead. For faking TimeXXX values (for unit',
646 'testing only), use TimeXXX() + Microseconds(N). For',
647 'other use cases, please contact base/time/OWNERS.',
648 ),
649 False,
650 excluded_paths=(
651 "base/time/time.h",
652 "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/time/time.h",
653 ),
Yuri Wiitala2f8de5c2017-07-21 00:11:06654 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15655 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53656 'CallJavascriptFunctionUnsafe',
657 (
658 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
659 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
660 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
661 ),
662 False,
663 (
664 r'^content/browser/webui/web_ui_impl\.(cc|h)$',
665 r'^content/public/browser/web_ui\.h$',
666 r'^content/public/test/test_web_ui\.(cc|h)$',
667 ),
dbeamb6f4fde2017-06-15 04:03:06668 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15669 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53670 'leveldb::DB::Open',
671 (
672 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
673 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
674 "Chrome's tracing, making their memory usage visible.",
675 ),
676 True,
677 (r'^third_party/leveldatabase/.*\.(cc|h)$', ),
Gabriel Charette0592c3a2017-07-26 12:02:04678 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15679 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53680 'leveldb::NewMemEnv',
681 (
682 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
683 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
684 "to Chrome's tracing, making their memory usage visible.",
685 ),
686 True,
687 (r'^third_party/leveldatabase/.*\.(cc|h)$', ),
Chris Mumfordc38afb62017-10-09 17:55:08688 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15689 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53690 'RunLoop::QuitCurrent',
691 (
692 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
693 'methods of a specific RunLoop instance instead.',
694 ),
695 False,
696 (),
Gabriel Charettea44975052017-08-21 23:14:04697 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15698 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53699 'base::ScopedMockTimeMessageLoopTaskRunner',
700 (
701 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
702 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
703 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
704 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
705 'with gab@ first if you think you need it)',
706 ),
707 False,
708 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57709 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15710 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53711 'std::regex',
712 (
713 'Using std::regex adds unnecessary binary size to Chrome. Please use',
714 're2::RE2 instead (crbug.com/755321)',
715 ),
716 True,
717 [
718 # Abseil's benchmarks never linked into chrome.
719 'third_party/abseil-cpp/.*_benchmark.cc',
720 ],
Francois Doray43670e32017-09-27 12:40:38721 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15722 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53723 r'/\bstd::sto(i|l|ul|ll|ull)\b',
724 (
725 'std::sto{i,l,ul,ll,ull}() use exceptions to communicate results. ',
726 'Use base::StringTo[U]Int[64]() instead.',
727 ),
728 True,
729 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting991618a62019-06-17 22:00:09730 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15731 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53732 r'/\bstd::sto(f|d|ld)\b',
733 (
734 'std::sto{f,d,ld}() use exceptions to communicate results. ',
735 'For locale-independent values, e.g. reading numbers from disk',
736 'profiles, use base::StringToDouble().',
737 'For user-visible values, parse using ICU.',
738 ),
739 True,
740 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting991618a62019-06-17 22:00:09741 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15742 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53743 r'/\bstd::to_string\b',
744 (
745 'std::to_string() is locale dependent and slower than alternatives.',
746 'For locale-independent strings, e.g. writing numbers to disk',
747 'profiles, use base::NumberToString().',
748 'For user-visible strings, use base::FormatNumber() and',
749 'the related functions in base/i18n/number_formatting.h.',
750 ),
751 True,
752 [
753 # TODO(crbug.com/335672557): Please do not add to this list. Existing
754 # uses should removed.
Daniel Cheng566634ff2024-06-29 14:56:53755 "third_party/blink/renderer/core/css/parser/css_proto_converter.cc",
756 "third_party/blink/renderer/core/editing/ime/edit_context.cc",
757 "third_party/blink/renderer/platform/graphics/bitmap_image_test.cc",
758 "tools/binary_size/libsupersize/viewer/caspian/diff_test.cc",
759 "tools/binary_size/libsupersize/viewer/caspian/tree_builder_test.cc",
Daniel Cheng566634ff2024-06-29 14:56:53760 _THIRD_PARTY_EXCEPT_BLINK
761 ],
Daniel Bratell69334cc2019-03-26 11:07:45762 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15763 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53764 r'/#include <(cctype|ctype\.h|cwctype|wctype.h)>',
765 (
766 '<cctype>/<ctype.h>/<cwctype>/<wctype.h> are banned. Use',
767 '"third_party/abseil-cpp/absl/strings/ascii.h" instead.',
768 ),
769 True,
770 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting6f79b202023-08-09 21:25:41771 ),
772 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53773 r'/\bstd::shared_ptr\b',
774 ('std::shared_ptr is banned. Use scoped_refptr instead.', ),
775 True,
776 [
777 # Needed for interop with third-party library.
778 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
779 'array_buffer_contents\.(cc|h)',
780 '^third_party/blink/renderer/core/typed_arrays/dom_array_buffer\.cc',
781 '^third_party/blink/renderer/bindings/core/v8/' +
782 'v8_wasm_response_extensions.cc',
783 '^gin/array_buffer\.(cc|h)',
784 '^gin/per_isolate_data\.(cc|h)',
785 '^chrome/services/sharing/nearby/',
786 # Needed for interop with third-party library libunwindstack.
787 '^base/profiler/libunwindstack_unwinder_android\.(cc|h)',
788 '^base/profiler/native_unwinder_android_memory_regions_map_impl.(cc|h)',
789 # Needed for interop with third-party boringssl cert verifier
790 '^third_party/boringssl/',
791 '^net/cert/',
792 '^net/tools/cert_verify_tool/',
793 '^services/cert_verifier/',
794 '^components/certificate_transparency/',
795 '^components/media_router/common/providers/cast/certificate/',
796 # gRPC provides some C++ libraries that use std::shared_ptr<>.
797 '^chromeos/ash/services/libassistant/grpc/',
798 '^chromecast/cast_core/grpc',
799 '^chromecast/cast_core/runtime/browser',
800 '^ios/chrome/test/earl_grey/chrome_egtest_plugin_client\.(mm|h)',
801 # Fuchsia provides C++ libraries that use std::shared_ptr<>.
802 '^base/fuchsia/.*\.(cc|h)',
803 '.*fuchsia.*test\.(cc|h)',
804 # Clang plugins have different build config.
805 '^tools/clang/plugins/',
806 _THIRD_PARTY_EXCEPT_BLINK
807 ], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21808 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15809 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53810 r'/\bstd::weak_ptr\b',
811 ('std::weak_ptr is banned. Use base::WeakPtr instead.', ),
812 True,
813 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting991618a62019-06-17 22:00:09814 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15815 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53816 r'/\blong long\b',
817 ('long long is banned. Use [u]int64_t instead.', ),
818 False, # Only a warning since it is already used.
819 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21820 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15821 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53822 r'/\b(absl|std)::any\b',
823 (
824 '{absl,std}::any are banned due to incompatibility with the component ',
825 'build.',
826 ),
827 True,
828 # Not an error in third party folders, though it probably should be :)
829 [_THIRD_PARTY_EXCEPT_BLINK],
Daniel Chengc05fcc62022-01-12 16:54:29830 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15831 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53832 r'/\bstd::bind\b',
833 (
834 'std::bind() is banned because of lifetime risks. Use ',
835 'base::Bind{Once,Repeating}() instead.',
836 ),
837 True,
838 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21839 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15840 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53841 (r'/\bstd::(?:'
842 r'linear_congruential_engine|mersenne_twister_engine|'
843 r'subtract_with_carry_engine|discard_block_engine|'
844 r'independent_bits_engine|shuffle_order_engine|'
845 r'minstd_rand0?|mt19937(_64)?|ranlux(24|48)(_base)?|knuth_b|'
846 r'default_random_engine|'
847 r'random_device|'
848 r'seed_seq'
849 r')\b'),
850 (
851 'STL random number engines and generators are banned. Use the ',
852 'helpers in base/rand_util.h instead, e.g. base::RandBytes() or ',
853 'base::RandomBitGenerator.'
854 '',
855 'Please reach out to [email protected] if the base APIs are ',
856 'insufficient for your needs.',
857 ),
858 True,
859 [
860 # Not an error in third_party folders.
861 _THIRD_PARTY_EXCEPT_BLINK,
862 # Various tools which build outside of Chrome.
863 r'testing/libfuzzer',
Steinar H. Gundersone5689e42024-08-07 18:17:19864 r'testing/perf/confidence',
Daniel Cheng566634ff2024-06-29 14:56:53865 r'tools/android/io_benchmark/',
866 # Fuzzers are allowed to use standard library random number generators
867 # since fuzzing speed + reproducibility is important.
868 r'tools/ipc_fuzzer/',
869 r'.+_fuzzer\.cc$',
870 r'.+_fuzzertest\.cc$',
871 # TODO(https://crbug.com/1380528): These are all unsanctioned uses of
872 # the standard library's random number generators, and should be
873 # migrated to the //base equivalent.
874 r'ash/ambient/model/ambient_topic_queue\.cc',
875 r'base/allocator/partition_allocator/src/partition_alloc/partition_alloc_unittest\.cc',
876 r'base/ranges/algorithm_unittest\.cc',
877 r'base/test/launcher/test_launcher\.cc',
878 r'cc/metrics/video_playback_roughness_reporter_unittest\.cc',
879 r'chrome/browser/apps/app_service/metrics/website_metrics\.cc',
880 r'chrome/browser/ash/power/auto_screen_brightness/monotone_cubic_spline_unittest\.cc',
881 r'chrome/browser/ash/printing/zeroconf_printer_detector_unittest\.cc',
882 r'chrome/browser/nearby_sharing/contacts/nearby_share_contact_manager_impl_unittest\.cc',
883 r'chrome/browser/nearby_sharing/contacts/nearby_share_contacts_sorter_unittest\.cc',
884 r'chrome/browser/privacy_budget/mesa_distribution_unittest\.cc',
885 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
886 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
887 r'chrome/browser/win/conflicts/module_blocklist_cache_util_unittest\.cc',
888 r'chromeos/ash/components/memory/userspace_swap/swap_storage_unittest\.cc',
889 r'chromeos/ash/components/memory/userspace_swap/userspace_swap\.cc',
890 r'components/metrics/metrics_state_manager\.cc',
891 r'components/omnibox/browser/history_quick_provider_performance_unittest\.cc',
892 r'components/zucchini/disassembler_elf_unittest\.cc',
893 r'content/browser/webid/federated_auth_request_impl\.cc',
894 r'content/browser/webid/federated_auth_request_impl\.cc',
895 r'media/cast/test/utility/udp_proxy\.h',
896 r'sql/recover_module/module_unittest\.cc',
897 r'components/search_engines/template_url_prepopulate_data.cc',
898 # Do not add new entries to this list. If you have a use case which is
899 # not satisfied by the current APIs (i.e. you need an explicitly-seeded
900 # sequence, or stability of some sort is required), please contact
901 # [email protected].
902 ],
Daniel Cheng192683f2022-11-01 20:52:44903 ),
904 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53905 r'/\b(absl,std)::bind_front\b',
906 ('{absl,std}::bind_front() are banned. Use base::Bind{Once,Repeating}() '
907 'instead.', ),
908 True,
909 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12910 ),
911 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53912 r'/\bABSL_FLAG\b',
913 ('ABSL_FLAG is banned. Use base::CommandLine instead.', ),
914 True,
915 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12916 ),
917 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53918 r'/\babsl::c_',
919 (
920 'Abseil container utilities are banned. Use base/ranges/algorithm.h ',
921 'instead.',
922 ),
923 True,
924 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12925 ),
926 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53927 r'/\babsl::FixedArray\b',
928 ('absl::FixedArray is banned. Use base::FixedArray instead.', ),
929 True,
930 [
931 # base::FixedArray provides canonical access.
932 r'^base/types/fixed_array.h',
933 # Not an error in third_party folders.
934 _THIRD_PARTY_EXCEPT_BLINK,
935 ],
Peter Kasting431239a2023-09-29 03:11:44936 ),
937 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53938 r'/\babsl::FunctionRef\b',
939 ('absl::FunctionRef is banned. Use base::FunctionRef instead.', ),
940 True,
941 [
942 # base::Bind{Once,Repeating} references absl::FunctionRef to disallow
943 # interoperability.
944 r'^base/functional/bind_internal\.h',
945 # base::FunctionRef is implemented on top of absl::FunctionRef.
946 r'^base/functional/function_ref.*\..+',
947 # Not an error in third_party folders.
948 _THIRD_PARTY_EXCEPT_BLINK,
949 ],
Peter Kasting4f35bfc2022-10-18 18:39:12950 ),
951 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53952 r'/\babsl::(Insecure)?BitGen\b',
953 ('absl random number generators are banned. Use the helpers in '
954 'base/rand_util.h instead, e.g. base::RandBytes() or ',
955 'base::RandomBitGenerator.'),
956 True,
957 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12958 ),
959 BanRule(
Peter Kasting3b77a0c2024-08-22 00:22:26960 pattern=
961 r'/\babsl::(optional|nullopt|make_optional)\b',
962 explanation=('absl::optional is banned. Use std::optional instead.', ),
963 treat_as_error=True,
964 excluded_paths=[
965 _THIRD_PARTY_EXCEPT_BLINK,
966 ]),
967 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53968 r'/(\babsl::Span\b|#include <span>|\bstd::span\b)',
969 (
970 'absl::Span and std::span are not allowed ',
971 '(https://crbug.com/1414652). Use base::span instead.',
972 ),
973 True,
974 [
975 # Included for conversions between base and std.
976 r'base/containers/span.h',
977 # Test base::span<> compatibility against std::span<>.
978 r'base/containers/span_unittest.cc',
979 # //base/numerics can't use base or absl. So it uses std.
980 r'base/numerics/.*'
Lei Zhang1f9d9ec42024-06-20 18:42:27981
Daniel Cheng566634ff2024-06-29 14:56:53982 # Needed to use QUICHE API.
Ciara McMullinc029c8e2024-08-21 14:22:32983 r'android_webview/browser/ip_protection/.*',
Daniel Cheng566634ff2024-06-29 14:56:53984 r'chrome/browser/ip_protection/.*',
985 r'components/ip_protection/.*',
986 r'net/third_party/quiche/overrides/quiche_platform_impl/quiche_stack_trace_impl\.*',
987 r'services/network/web_transport\.cc',
Lei Zhang1f9d9ec42024-06-20 18:42:27988
Daniel Cheng566634ff2024-06-29 14:56:53989 # Not an error in third_party folders.
990 _THIRD_PARTY_EXCEPT_BLINK,
991 ],
Peter Kasting4f35bfc2022-10-18 18:39:12992 ),
993 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53994 r'/\babsl::StatusOr\b',
995 ('absl::StatusOr is banned. Use base::expected instead.', ),
996 True,
997 [
998 # Needed to use liburlpattern API.
999 r'components/url_pattern/.*',
1000 r'services/network/shared_dictionary/simple_url_pattern_matcher\.cc',
1001 r'third_party/blink/renderer/core/url_pattern/.*',
1002 r'third_party/blink/renderer/modules/manifest/manifest_parser\.cc',
Lei Zhang1f9d9ec42024-06-20 18:42:271003
Daniel Cheng566634ff2024-06-29 14:56:531004 # Needed to use QUICHE API.
Ciara McMullinc029c8e2024-08-21 14:22:321005 r'android_webview/browser/ip_protection/.*',
Daniel Cheng566634ff2024-06-29 14:56:531006 r'chrome/browser/ip_protection/.*',
1007 r'components/ip_protection/.*',
Lei Zhang1f9d9ec42024-06-20 18:42:271008
Daniel Cheng566634ff2024-06-29 14:56:531009 # Needed to use MediaPipe API.
1010 r'components/media_effects/.*\.cc',
1011 # Not an error in third_party folders.
1012 _THIRD_PARTY_EXCEPT_BLINK
1013 ],
Peter Kasting4f35bfc2022-10-18 18:39:121014 ),
1015 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531016 r'/\babsl::(StrSplit|StrJoin|StrCat|StrAppend|Substitute|StrContains)\b',
1017 ('Abseil string utilities are banned. Use base/strings instead.', ),
1018 True,
1019 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:121020 ),
1021 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531022 r'/\babsl::(Mutex|CondVar|Notification|Barrier|BlockingCounter)\b',
1023 (
1024 'Abseil synchronization primitives are banned. Use',
1025 'base/synchronization instead.',
1026 ),
1027 True,
1028 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:121029 ),
1030 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531031 r'/\babsl::(Duration|Time|TimeZone|CivilDay)\b',
1032 ('Abseil\'s time library is banned. Use base/time instead.', ),
1033 True,
1034 [
1035 # Needed to use QUICHE API.
Ciara McMullinc029c8e2024-08-21 14:22:321036 r'android_webview/browser/ip_protection/.*',
Daniel Cheng566634ff2024-06-29 14:56:531037 r'chrome/browser/ip_protection/.*',
1038 r'components/ip_protection/.*',
Lei Zhang1f9d9ec42024-06-20 18:42:271039
Daniel Cheng566634ff2024-06-29 14:56:531040 # Needed to integrate with //third_party/nearby
1041 r'components/cross_device/nearby/system_clock.cc',
1042 _THIRD_PARTY_EXCEPT_BLINK # Not an error in third_party folders.
1043 ],
1044 ),
1045 BanRule(
1046 r'/#include <chrono>',
1047 ('<chrono> is banned. Use base/time instead.', ),
1048 True,
1049 [
1050 # Not an error in third_party folders:
1051 _THIRD_PARTY_EXCEPT_BLINK,
Daniel Cheng566634ff2024-06-29 14:56:531052 # This uses openscreen API depending on std::chrono.
1053 "components/openscreen_platform/task_runner.cc",
1054 ]),
1055 BanRule(
1056 r'/#include <exception>',
1057 ('Exceptions are banned and disabled in Chromium.', ),
1058 True,
1059 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1060 ),
1061 BanRule(
1062 r'/\bstd::function\b',
1063 ('std::function is banned. Use base::{Once,Repeating}Callback instead.',
1064 ),
1065 True,
1066 [
1067 # Has tests that template trait helpers don't unintentionally match
1068 # std::function.
1069 r'base/functional/callback_helpers_unittest\.cc',
1070 # Required to implement interfaces from the third-party perfetto
1071 # library.
1072 r'base/tracing/perfetto_task_runner\.cc',
1073 r'base/tracing/perfetto_task_runner\.h',
1074 # Needed for interop with the third-party nearby library type
1075 # location::nearby::connections::ResultCallback.
1076 'chrome/services/sharing/nearby/nearby_connections_conversions\.cc'
1077 # Needed for interop with the internal libassistant library.
1078 'chromeos/ash/services/libassistant/callback_utils\.h',
1079 # Needed for interop with Fuchsia fidl APIs.
1080 'fuchsia_web/webengine/browser/context_impl_browsertest\.cc',
1081 'fuchsia_web/webengine/browser/cookie_manager_impl_unittest\.cc',
1082 'fuchsia_web/webengine/browser/media_player_impl_unittest\.cc',
1083 # Required to interop with interfaces from the third-party ChromeML
1084 # library API.
1085 'services/on_device_model/ml/chrome_ml_api\.h',
1086 'services/on_device_model/ml/on_device_model_executor\.cc',
1087 'services/on_device_model/ml/on_device_model_executor\.h',
1088 # Required to interop with interfaces from the third-party perfetto
1089 # library.
1090 'services/tracing/public/cpp/perfetto/custom_event_recorder\.cc',
1091 'services/tracing/public/cpp/perfetto/perfetto_traced_process\.cc',
1092 'services/tracing/public/cpp/perfetto/perfetto_traced_process\.h',
1093 'services/tracing/public/cpp/perfetto/perfetto_tracing_backend\.cc',
1094 'services/tracing/public/cpp/perfetto/producer_client\.cc',
1095 'services/tracing/public/cpp/perfetto/producer_client\.h',
1096 'services/tracing/public/cpp/perfetto/producer_test_utils\.cc',
1097 'services/tracing/public/cpp/perfetto/producer_test_utils\.h',
1098 # Required for interop with the third-party webrtc library.
1099 'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.cc',
1100 'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.h',
1101 # TODO(https://crbug.com/1364577): Various uses that should be
1102 # migrated to something else.
1103 # Should use base::OnceCallback or base::RepeatingCallback.
1104 'base/allocator/dispatcher/initializer_unittest\.cc',
1105 'chrome/browser/ash/accessibility/speech_monitor\.cc',
1106 'chrome/browser/ash/accessibility/speech_monitor\.h',
1107 'chrome/browser/ash/login/ash_hud_login_browsertest\.cc',
1108 'chromecast/base/observer_unittest\.cc',
1109 'chromecast/browser/cast_web_view\.h',
1110 'chromecast/public/cast_media_shlib\.h',
1111 'device/bluetooth/floss/exported_callback_manager\.h',
1112 'device/bluetooth/floss/floss_dbus_client\.h',
1113 'device/fido/cable/v2_handshake_unittest\.cc',
1114 'device/fido/pin\.cc',
1115 'services/tracing/perfetto/test_utils\.h',
1116 # Should use base::FunctionRef.
1117 'chrome/browser/media/webrtc/test_stats_dictionary\.cc',
1118 'chrome/browser/media/webrtc/test_stats_dictionary\.h',
1119 'chromeos/ash/services/libassistant/device_settings_controller\.cc',
1120 'components/browser_ui/client_certificate/android/ssl_client_certificate_request\.cc',
1121 'components/gwp_asan/client/sampling_malloc_shims_unittest\.cc',
1122 'content/browser/font_unique_name_lookup/font_unique_name_lookup_unittest\.cc',
1123 # Does not need std::function at all.
1124 'components/omnibox/browser/autocomplete_result\.cc',
1125 'device/fido/win/webauthn_api\.cc',
1126 'media/audio/alsa/alsa_util\.cc',
1127 'media/remoting/stream_provider\.h',
1128 'sql/vfs_wrapper\.cc',
1129 # TODO(https://crbug.com/1364585): Remove usage and exception list
1130 # entries.
1131 'extensions/renderer/api/automation/automation_internal_custom_bindings\.cc',
1132 'extensions/renderer/api/automation/automation_internal_custom_bindings\.h',
1133 # TODO(https://crbug.com/1364579): Remove usage and exception list
1134 # entry.
1135 'ui/views/controls/focus_ring\.h',
Lei Zhang1f9d9ec42024-06-20 18:42:271136
Daniel Cheng566634ff2024-06-29 14:56:531137 # Various pre-existing uses in //tools that is low-priority to fix.
1138 'tools/binary_size/libsupersize/viewer/caspian/diff\.cc',
1139 'tools/binary_size/libsupersize/viewer/caspian/model\.cc',
1140 'tools/binary_size/libsupersize/viewer/caspian/model\.h',
1141 'tools/binary_size/libsupersize/viewer/caspian/tree_builder\.h',
1142 'tools/clang/base_bind_rewriters/BaseBindRewriters\.cpp',
Daniel Chenge5583e3c2022-09-22 00:19:411143
Daniel Cheng566634ff2024-06-29 14:56:531144 # Not an error in third_party folders.
1145 _THIRD_PARTY_EXCEPT_BLINK
1146 ],
Daniel Bratell609102be2019-03-27 20:53:211147 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151148 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531149 r'/#include <X11/',
1150 ('Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.', ),
1151 True,
1152 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Tom Andersona95e12042020-09-09 23:08:001153 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151154 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531155 r'/\bstd::ratio\b',
1156 ('std::ratio is banned by the Google Style Guide.', ),
1157 True,
1158 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:451159 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151160 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531161 r'/\bstd::aligned_alloc\b',
1162 (
1163 'std::aligned_alloc() is not yet allowed (crbug.com/1412818). Use ',
1164 'base::AlignedAlloc() instead.',
1165 ),
1166 True,
1167 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181168 ),
1169 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531170 r'/#include <(barrier|latch|semaphore|stop_token)>',
1171 ('The thread support library is banned. Use base/synchronization '
1172 'instead.', ),
1173 True,
1174 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181175 ),
1176 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531177 r'/\bstd::execution::(par|seq)\b',
1178 ('std::execution::(par|seq) is banned; they do not fit into '
1179 ' Chrome\'s threading model, and libc++ doesn\'t have full '
mikt19226ff22024-08-27 05:28:211180 'support.', ),
Daniel Cheng566634ff2024-06-29 14:56:531181 True,
1182 [_THIRD_PARTY_EXCEPT_BLINK],
Helmut Januschka7cc8a84f2024-02-07 22:50:411183 ),
1184 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531185 r'/\bstd::bit_cast\b',
1186 ('std::bit_cast is banned; use base::bit_cast instead for values and '
1187 'standard C++ casting when pointers are involved.', ),
1188 True,
1189 [
1190 # Don't warn in third_party folders.
1191 _THIRD_PARTY_EXCEPT_BLINK,
1192 # //base/numerics can't use base or absl.
1193 r'base/numerics/.*'
1194 ],
Avi Drissman70cb7f72023-12-12 17:44:371195 ),
1196 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531197 r'/\bstd::(c8rtomb|mbrtoc8)\b',
1198 ('std::c8rtomb() and std::mbrtoc8() are banned.', ),
1199 True,
1200 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181201 ),
1202 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531203 r'/\bchar8_t|std::u8string\b',
1204 (
1205 'char8_t and std::u8string are not yet allowed. Can you use [unsigned]',
1206 ' char and std::string instead?',
1207 ),
1208 True,
1209 [
1210 # The demangler does not use this type but needs to know about it.
1211 'base/third_party/symbolize/demangle\.cc',
1212 # Don't warn in third_party folders.
1213 _THIRD_PARTY_EXCEPT_BLINK
1214 ],
Peter Kastinge2c5ee82023-02-15 17:23:081215 ),
1216 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531217 r'/(\b(co_await|co_return|co_yield)\b|#include <coroutine>)',
1218 ('Coroutines are not yet allowed (https://crbug.com/1403840).', ),
1219 True,
1220 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081221 ),
1222 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531223 r'/^\s*(export\s|import\s+["<:\w]|module(;|\s+[:\w]))',
1224 ('Modules are disallowed for now due to lack of toolchain support.', ),
1225 True,
1226 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting69357dc2023-03-14 01:34:291227 ),
1228 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531229 r'/\[\[(\w*::)?no_unique_address\]\]',
1230 (
1231 '[[no_unique_address]] does not work as expected on Windows ',
1232 '(https://crbug.com/1414621). Use NO_UNIQUE_ADDRESS instead.',
1233 ),
1234 True,
1235 [
1236 # NO_UNIQUE_ADDRESS / PA_NO_UNIQUE_ADDRESS provide canonical access.
1237 r'^base/compiler_specific\.h',
1238 r'^base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/compiler_specific\.h',
1239 # Not an error in third_party folders.
1240 _THIRD_PARTY_EXCEPT_BLINK,
1241 ],
Peter Kasting8bc046d22023-11-14 00:38:031242 ),
1243 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531244 r'/#include <format>',
1245 ('<format> is not yet allowed. Use base::StringPrintf() instead.', ),
1246 True,
1247 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081248 ),
1249 BanRule(
Daniel Cheng89719222024-07-04 04:59:291250 pattern='std::views',
1251 explanation=(
1252 'Use of std::views is banned in Chrome. If you need this '
1253 'functionality, please contact [email protected].',
1254 ),
1255 treat_as_error=True,
1256 excluded_paths=[
1257 # Don't warn in third_party folders.
1258 _THIRD_PARTY_EXCEPT_BLINK
1259 ],
1260 ),
1261 BanRule(
1262 # Ban everything except specifically allowlisted constructs.
1263 pattern=r'/std::ranges::(?!' + '|'.join((
1264 # From https://en.cppreference.com/w/cpp/ranges:
1265 # Range access
1266 'begin',
1267 'end',
1268 'cbegin',
1269 'cend',
1270 'rbegin',
1271 'rend',
1272 'crbegin',
1273 'crend',
1274 'size',
1275 'ssize',
1276 'empty',
1277 'data',
1278 'cdata',
1279 # Range primitives
1280 'iterator_t',
1281 'const_iterator_t',
1282 'sentinel_t',
1283 'const_sentinel_t',
1284 'range_difference_t',
1285 'range_size_t',
1286 'range_value_t',
1287 'range_reference_t',
1288 'range_const_reference_t',
1289 'range_rvalue_reference_t',
1290 'range_common_reference_t',
1291 # Dangling iterator handling
1292 'dangling',
1293 'borrowed_iterator_t',
1294 # Banned: borrowed_subrange_t
1295 # Range concepts
1296 'range',
1297 'borrowed_range',
1298 'sized_range',
1299 'view',
1300 'input_range',
1301 'output_range',
1302 'forward_range',
1303 'bidirectional_range',
1304 'random_access_range',
1305 'contiguous_range',
1306 'common_range',
1307 'viewable_range',
1308 'constant_range',
1309 # Banned: Views
1310 # Banned: Range factories
1311 # Banned: Range adaptors
Peter Kastinga7f93752024-10-24 22:15:401312 # Incidentally listed on
1313 # https://en.cppreference.com/w/cpp/header/ranges:
1314 'enable_borrowed_range',
1315 'enable_view',
Daniel Cheng89719222024-07-04 04:59:291316 # From https://en.cppreference.com/w/cpp/algorithm/ranges:
1317 # Constrained algorithms: non-modifying sequence operations
1318 'all_of',
1319 'any_of',
1320 'none_of',
1321 'for_each',
1322 'for_each_n',
1323 'count',
1324 'count_if',
1325 'mismatch',
1326 'equal',
1327 'lexicographical_compare',
1328 'find',
1329 'find_if',
1330 'find_if_not',
1331 'find_end',
1332 'find_first_of',
1333 'adjacent_find',
1334 'search',
1335 'search_n',
1336 # Constrained algorithms: modifying sequence operations
1337 'copy',
1338 'copy_if',
1339 'copy_n',
1340 'copy_backward',
1341 'move',
1342 'move_backward',
1343 'fill',
1344 'fill_n',
1345 'transform',
1346 'generate',
1347 'generate_n',
1348 'remove',
1349 'remove_if',
1350 'remove_copy',
1351 'remove_copy_if',
1352 'replace',
1353 'replace_if',
1354 'replace_copy',
1355 'replace_copy_if',
1356 'swap_ranges',
1357 'reverse',
1358 'reverse_copy',
1359 'rotate',
1360 'rotate_copy',
1361 'shuffle',
1362 'sample',
1363 'unique',
1364 'unique_copy',
1365 # Constrained algorithms: partitioning operations
1366 'is_partitioned',
1367 'partition',
1368 'partition_copy',
1369 'stable_partition',
1370 'partition_point',
1371 # Constrained algorithms: sorting operations
1372 'is_sorted',
1373 'is_sorted_until',
1374 'sort',
1375 'partial_sort',
1376 'partial_sort_copy',
1377 'stable_sort',
1378 'nth_element',
1379 # Constrained algorithms: binary search operations (on sorted ranges)
1380 'lower_bound',
1381 'upper_bound',
1382 'binary_search',
1383 'equal_range',
1384 # Constrained algorithms: set operations (on sorted ranges)
1385 'merge',
1386 'inplace_merge',
1387 'includes',
1388 'set_difference',
1389 'set_intersection',
1390 'set_symmetric_difference',
1391 'set_union',
1392 # Constrained algorithms: heap operations
1393 'is_heap',
1394 'is_heap_until',
1395 'make_heap',
1396 'push_heap',
1397 'pop_heap',
1398 'sort_heap',
1399 # Constrained algorithms: minimum/maximum operations
1400 'max',
1401 'max_element',
1402 'min',
1403 'min_element',
1404 'minmax',
1405 'minmax_element',
1406 'clamp',
1407 # Constrained algorithms: permutation operations
1408 'is_permutation',
1409 'next_permutation',
1410 'prev_premutation',
1411 # Constrained uninitialized memory algorithms
1412 'uninitialized_copy',
1413 'uninitialized_copy_n',
1414 'uninitialized_fill',
1415 'uninitialized_fill_n',
1416 'uninitialized_move',
1417 'uninitialized_move_n',
1418 'uninitialized_default_construct',
1419 'uninitialized_default_construct_n',
1420 'uninitialized_value_construct',
1421 'uninitialized_value_construct_n',
1422 'destroy',
1423 'destroy_n',
1424 'destroy_at',
1425 'construct_at',
1426 # Return types
1427 'in_fun_result',
1428 'in_in_result',
1429 'in_out_result',
1430 'in_in_out_result',
1431 'in_out_out_result',
1432 'min_max_result',
1433 'in_found_result',
danakj91c715b2024-07-10 13:24:261434 # From https://en.cppreference.com/w/cpp/iterator
1435 'advance',
1436 'distance',
1437 'next',
1438 'prev',
Daniel Cheng89719222024-07-04 04:59:291439 )) + r')\w+',
1440 explanation=(
1441 'Use of range views and associated helpers is banned in Chrome. '
1442 'If you need this functionality, please contact [email protected].',
1443 ),
1444 treat_as_error=True,
1445 excluded_paths=[
1446 # Don't warn in third_party folders.
1447 _THIRD_PARTY_EXCEPT_BLINK
1448 ],
Peter Kastinge2c5ee82023-02-15 17:23:081449 ),
1450 BanRule(
Peter Kasting31879d82024-10-07 20:18:391451 r'/#include <regex>',
1452 ('<regex> is not allowed. Use third_party/re2 instead.',
1453 ),
1454 True,
1455 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1456 ),
1457 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531458 r'/#include <source_location>',
1459 ('<source_location> is not yet allowed. Use base/location.h instead.',
1460 ),
1461 True,
1462 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081463 ),
1464 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531465 r'/\bstd::to_address\b',
1466 (
1467 'std::to_address is banned because it is not guaranteed to be',
1468 'SFINAE-compatible. Use base::to_address from base/types/to_address.h',
1469 'instead.',
1470 ),
1471 True,
1472 [
1473 # Needed in base::to_address implementation.
1474 r'base/types/to_address.h',
1475 _THIRD_PARTY_EXCEPT_BLINK
1476 ], # Not an error in third_party folders.
Nick Diego Yamanee522ae82024-02-27 04:23:221477 ),
1478 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531479 r'/#include <syncstream>',
1480 ('<syncstream> is banned.', ),
1481 True,
1482 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181483 ),
1484 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531485 r'/\bRunMessageLoop\b',
1486 ('RunMessageLoop is deprecated, use RunLoop instead.', ),
1487 False,
1488 (),
Gabriel Charette147335ea2018-03-22 15:59:191489 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151490 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531491 'RunAllPendingInMessageLoop()',
1492 (
1493 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
1494 "if you're convinced you need this.",
1495 ),
1496 False,
1497 (),
Gabriel Charette147335ea2018-03-22 15:59:191498 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151499 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531500 'RunAllPendingInMessageLoop(BrowserThread',
1501 (
1502 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
1503 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
1504 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
1505 'async events instead of flushing threads.',
1506 ),
1507 False,
1508 (),
Gabriel Charette147335ea2018-03-22 15:59:191509 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151510 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531511 r'MessageLoopRunner',
1512 ('MessageLoopRunner is deprecated, use RunLoop instead.', ),
1513 False,
1514 (),
Gabriel Charette147335ea2018-03-22 15:59:191515 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151516 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531517 'GetDeferredQuitTaskForRunLoop',
1518 (
1519 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
1520 "gab@ if you found a use case where this is the only solution.",
1521 ),
1522 False,
1523 (),
Gabriel Charette147335ea2018-03-22 15:59:191524 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151525 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531526 'sqlite3_initialize(',
1527 (
1528 'Instead of calling sqlite3_initialize(), depend on //sql, ',
1529 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
1530 ),
1531 True,
1532 (
1533 r'^sql/initialization\.(cc|h)$',
1534 r'^third_party/sqlite/.*\.(c|cc|h)$',
1535 ),
Victor Costan3653df62018-02-08 21:38:161536 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151537 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531538 'CREATE VIEW',
1539 (
1540 'SQL views are disabled in Chromium feature code',
1541 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-views',
1542 ),
1543 True,
1544 (
1545 _THIRD_PARTY_EXCEPT_BLINK,
1546 # sql/ itself uses views when using memory-mapped IO.
1547 r'^sql/.*',
1548 # Various performance tools that do not build as part of Chrome.
1549 r'^infra/.*',
1550 r'^tools/perf.*',
1551 r'.*perfetto.*',
1552 ),
Austin Sullivand661ab52022-11-16 08:55:151553 ),
1554 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531555 'CREATE VIRTUAL TABLE',
1556 (
1557 'SQL virtual tables are disabled in Chromium feature code',
1558 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-virtual-tables',
1559 ),
1560 True,
1561 (
1562 _THIRD_PARTY_EXCEPT_BLINK,
1563 # sql/ itself uses virtual tables in the recovery module and tests.
1564 r'^sql/.*',
1565 # TODO(https://crbug.com/695592): Remove once WebSQL is deprecated.
1566 r'third_party/blink/web_tests/storage/websql/.*'
1567 # Various performance tools that do not build as part of Chrome.
1568 r'^tools/perf.*',
1569 r'.*perfetto.*',
1570 ),
Austin Sullivand661ab52022-11-16 08:55:151571 ),
1572 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531573 'std::random_shuffle',
1574 ('std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
1575 'base::RandomShuffle instead.'),
1576 True,
1577 (),
tzik5de2157f2018-05-08 03:42:471578 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151579 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531580 'ios/web/public/test/http_server',
1581 ('web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
1582 ),
1583 False,
1584 (),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:241585 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151586 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531587 'GetAddressOf',
1588 ('Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
1589 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
1590 'operator& is generally recommended. So always use operator& instead. ',
1591 'See http://crbug.com/914910 for more conversion guidance.'),
1592 True,
1593 (),
Robert Liao764c9492019-01-24 18:46:281594 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151595 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531596 'SHFileOperation',
1597 ('SHFileOperation was deprecated in Windows Vista, and there are less ',
1598 'complex functions to achieve the same goals. Use IFileOperation for ',
1599 'any esoteric actions instead.'),
1600 True,
1601 (),
Ben Lewisa9514602019-04-29 17:53:051602 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151603 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531604 'StringFromGUID2',
1605 ('StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
1606 'Use base::win::WStringFromGUID instead.'),
1607 True,
1608 (r'/base/win/win_util_unittest.cc', ),
Cliff Smolinsky81951642019-04-30 21:39:511609 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151610 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531611 'StringFromCLSID',
1612 ('StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
1613 'Use base::win::WStringFromGUID instead.'),
1614 True,
1615 (r'/base/win/win_util_unittest.cc', ),
Cliff Smolinsky81951642019-04-30 21:39:511616 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151617 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531618 'kCFAllocatorNull',
1619 (
1620 'The use of kCFAllocatorNull with the NoCopy creation of ',
1621 'CoreFoundation types is prohibited.',
1622 ),
1623 True,
1624 (),
Avi Drissman7382afa02019-04-29 23:27:131625 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151626 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531627 'mojo::ConvertTo',
1628 ('mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1629 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1630 'StringTraits if you would like to convert between custom types and',
1631 'the wire format of mojom types.'),
1632 False,
1633 (
1634 r'^fuchsia_web/webengine/browser/url_request_rewrite_rules_manager\.cc$',
1635 r'^fuchsia_web/webengine/url_request_rewrite_type_converters\.cc$',
1636 r'^third_party/blink/.*\.(cc|h)$',
1637 r'^content/renderer/.*\.(cc|h)$',
1638 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291639 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151640 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531641 'GetInterfaceProvider',
1642 ('InterfaceProvider is deprecated.',
1643 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1644 'or Platform::GetBrowserInterfaceBroker.'),
1645 False,
1646 (),
Oksana Zhuravlovac8222d22019-12-19 19:21:161647 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151648 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531649 'CComPtr',
1650 ('New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1651 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1652 'details.'),
1653 False,
1654 (),
Robert Liao1d78df52019-11-11 20:02:011655 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151656 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531657 r'/\b(IFACE|STD)METHOD_?\(',
1658 ('IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1659 'Instead, always use IFACEMETHODIMP in the declaration.'),
1660 False,
1661 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Xiaohan Wang72bd2ba2020-02-18 21:38:201662 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151663 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531664 'set_owned_by_client',
1665 ('set_owned_by_client is deprecated.',
1666 'views::View already owns the child views by default. This introduces ',
1667 'a competing ownership model which makes the code difficult to reason ',
1668 'about. See http://crbug.com/1044687 for more details.'),
1669 False,
1670 (),
Allen Bauer53b43fb12020-03-12 17:21:471671 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151672 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531673 'RemoveAllChildViewsWithoutDeleting',
1674 ('RemoveAllChildViewsWithoutDeleting is deprecated.',
1675 'This method is deemed dangerous as, unless raw pointers are re-added,',
1676 'calls to this method introduce memory leaks.'),
1677 False,
1678 (),
Peter Boström7ff41522021-07-29 03:43:271679 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151680 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531681 r'/\bTRACE_EVENT_ASYNC_',
1682 (
1683 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1684 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1685 ),
1686 False,
1687 (
1688 r'^base/trace_event/.*',
1689 r'^base/tracing/.*',
1690 ),
Eric Secklerbe6f48d2020-05-06 18:09:121691 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151692 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531693 r'/\bbase::debug::DumpWithoutCrashingUnthrottled[(][)]',
1694 (
1695 'base::debug::DumpWithoutCrashingUnthrottled() does not throttle',
1696 'dumps and may spam crash reports. Consider if the throttled',
1697 'variants suffice instead.',
1698 ),
1699 False,
1700 (),
Aditya Kushwah5a286b72022-02-10 04:54:431701 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151702 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531703 'RoInitialize',
1704 ('Improper use of [base::win]::RoInitialize() has been implicated in a ',
1705 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
1706 'instead. See http://crbug.com/1197722 for more information.'),
1707 True,
1708 (
1709 r'^base/win/scoped_winrt_initializer\.cc$',
1710 r'^third_party/abseil-cpp/absl/.*',
1711 ),
Robert Liao22f66a52021-04-10 00:57:521712 ),
Patrick Monettec343bb982022-06-01 17:18:451713 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531714 r'base::Watchdog',
1715 (
1716 'base::Watchdog is deprecated because it creates its own thread.',
1717 'Instead, manually start a timer on a SequencedTaskRunner.',
1718 ),
1719 False,
1720 (),
Patrick Monettec343bb982022-06-01 17:18:451721 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091722 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531723 'base::Passed',
1724 ('Do not use base::Passed. It is a legacy helper for capturing ',
1725 'move-only types with base::BindRepeating, but invoking the ',
1726 'resulting RepeatingCallback moves the captured value out of ',
1727 'the callback storage, and subsequent invocations may pass the ',
1728 'value in a valid but undefined state. Prefer base::BindOnce().',
1729 'See http://crbug.com/1326449 for context.'),
1730 False,
1731 (
1732 # False positive, but it is also fine to let bind internals reference
1733 # base::Passed.
1734 r'^base[\\/]functional[\\/]bind\.h',
1735 r'^base[\\/]functional[\\/]bind_internal\.h',
1736 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091737 ),
Daniel Cheng2248b332022-07-27 06:16:591738 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531739 r'base::Feature k',
1740 ('Please use BASE_DECLARE_FEATURE() or BASE_FEATURE() instead of ',
1741 'directly declaring/defining features.'),
1742 True,
1743 [
1744 # Implements BASE_DECLARE_FEATURE().
1745 r'^base/feature_list\.h',
1746 ],
Daniel Chengba3bc2e2022-10-03 02:45:431747 ),
Robert Ogden92101dcb2022-10-19 23:49:361748 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531749 r'/\bchartorune\b',
1750 ('chartorune is not memory-safe, unless you can guarantee the input ',
1751 'string is always null-terminated. Otherwise, please use charntorune ',
1752 'from libphonenumber instead.'),
1753 True,
1754 [
1755 _THIRD_PARTY_EXCEPT_BLINK,
1756 # Exceptions to this rule should have a fuzzer.
1757 ],
Robert Ogden92101dcb2022-10-19 23:49:361758 ),
Arthur Sonzogni1da65fa2023-03-27 16:01:521759 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531760 r'/\b#include "base/atomicops\.h"\b',
1761 ('Do not use base::subtle atomics, but std::atomic, which are simpler '
1762 'to use, have better understood, clearer and richer semantics, and are '
1763 'harder to mis-use. See details in base/atomicops.h.', ),
1764 False,
1765 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Benoit Lize79cf0592023-01-27 10:01:571766 ),
Daniel Cheng566634ff2024-06-29 14:56:531767 BanRule(r'CrossThreadPersistent<', (
Arthur Sonzogni60348572e2023-04-07 10:22:521768 'Do not use blink::CrossThreadPersistent, but '
Daniel Cheng566634ff2024-06-29 14:56:531769 'blink::CrossThreadHandle. It is harder to mis-use.', 'More info: '
Arthur Sonzogni60348572e2023-04-07 10:22:521770 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1771 'Please contact platform-architecture-dev@ before adding new instances.'
Daniel Cheng566634ff2024-06-29 14:56:531772 ), False, []),
1773 BanRule(r'CrossThreadWeakPersistent<', (
Arthur Sonzogni60348572e2023-04-07 10:22:521774 'Do not use blink::CrossThreadWeakPersistent, but '
Daniel Cheng566634ff2024-06-29 14:56:531775 'blink::CrossThreadWeakHandle. It is harder to mis-use.', 'More info: '
Arthur Sonzogni60348572e2023-04-07 10:22:521776 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1777 'Please contact platform-architecture-dev@ before adding new instances.'
Daniel Cheng566634ff2024-06-29 14:56:531778 ), False, []),
1779 BanRule(r'objc/objc.h', (
Avi Drissman491617c2023-04-13 17:33:151780 'Do not include <objc/objc.h>. It defines away ARC lifetime '
1781 'annotations, and is thus dangerous.',
1782 'Please use the pimpl pattern; search for `ObjCStorage` for examples.',
1783 'For further reading on how to safely mix C++ and Obj-C, see',
1784 'https://chromium.googlesource.com/chromium/src/+/main/docs/mac/mixing_cpp_and_objc.md'
Daniel Cheng566634ff2024-06-29 14:56:531785 ), True, []),
1786 BanRule(
1787 r'/#include <filesystem>',
1788 ('libc++ <filesystem> is banned per the Google C++ styleguide.', ),
1789 True,
1790 # This fuzzing framework is a standalone open source project and
1791 # cannot rely on Chromium base.
1792 (r'third_party/centipede'),
Avi Drissman491617c2023-04-13 17:33:151793 ),
Grace Park8d59b54b2023-04-26 17:53:351794 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531795 r'TopDocument()',
1796 ('TopDocument() does not work correctly with out-of-process iframes. '
1797 'Please do not introduce new uses.', ),
1798 True,
1799 (
1800 # TODO(crbug.com/617677): Remove all remaining uses.
1801 r'^third_party/blink/renderer/core/dom/document\.cc',
1802 r'^third_party/blink/renderer/core/dom/document\.h',
1803 r'^third_party/blink/renderer/core/dom/element\.cc',
1804 r'^third_party/blink/renderer/core/exported/web_disallow_transition_scope_test\.cc',
1805 r'^third_party/blink/renderer/core/exported/web_document_test\.cc',
1806 r'^third_party/blink/renderer/core/html/html_anchor_element\.cc',
1807 r'^third_party/blink/renderer/core/html/html_dialog_element\.cc',
1808 r'^third_party/blink/renderer/core/html/html_element\.cc',
1809 r'^third_party/blink/renderer/core/html/html_frame_owner_element\.cc',
1810 r'^third_party/blink/renderer/core/html/media/video_wake_lock\.cc',
1811 r'^third_party/blink/renderer/core/loader/anchor_element_interaction_tracker\.cc',
1812 r'^third_party/blink/renderer/core/page/scrolling/root_scroller_controller\.cc',
1813 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.cc',
1814 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.h',
1815 r'^third_party/blink/renderer/core/script/classic_pending_script\.cc',
1816 r'^third_party/blink/renderer/core/script/script_loader\.cc',
1817 ),
Grace Park8d59b54b2023-04-26 17:53:351818 ),
Daniel Cheng72153e02023-05-18 21:18:141819 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531820 pattern=r'base::raw_ptr<',
1821 explanation=('Do not use base::raw_ptr, use raw_ptr.', ),
1822 treat_as_error=True,
1823 excluded_paths=(
1824 '^base/',
1825 '^tools/',
1826 ),
Daniel Cheng72153e02023-05-18 21:18:141827 ),
Arthur Sonzognif0eea302023-08-18 19:20:311828 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531829 pattern=r'base:raw_ref<',
1830 explanation=('Do not use base::raw_ref, use raw_ref.', ),
1831 treat_as_error=True,
1832 excluded_paths=(
1833 '^base/',
1834 '^tools/',
1835 ),
Arthur Sonzognif0eea302023-08-18 19:20:311836 ),
1837 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531838 pattern=r'/raw_ptr<[^;}]*\w{};',
1839 explanation=(
1840 'Do not use {} for raw_ptr initialization, use = nullptr instead.',
1841 ),
1842 treat_as_error=True,
1843 excluded_paths=(
1844 '^base/',
1845 '^tools/',
1846 ),
Arthur Sonzognif0eea302023-08-18 19:20:311847 ),
Anton Maliev66751812023-08-24 16:28:131848 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531849 pattern=r'/#include "base/allocator/.*/raw_'
1850 r'(ptr|ptr_cast|ptr_exclusion|ref).h"',
1851 explanation=(
1852 'Please include the corresponding facade headers:',
1853 '- #include "base/memory/raw_ptr.h"',
1854 '- #include "base/memory/raw_ptr_cast.h"',
1855 '- #include "base/memory/raw_ptr_exclusion.h"',
1856 '- #include "base/memory/raw_ref.h"',
1857 ),
1858 treat_as_error=True,
1859 excluded_paths=(
1860 '^base/',
1861 '^tools/',
1862 ),
Tom Sepez41eb158d2023-09-12 16:16:221863 ),
1864 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531865 pattern=r'ContentSettingsType::COOKIES',
1866 explanation=
1867 ('Do not use ContentSettingsType::COOKIES to check whether cookies are '
1868 'supported in the provided context. Instead rely on the '
1869 'content_settings::CookieSettings API. If you are using '
1870 'ContentSettingsType::COOKIES to check the user preference setting '
1871 'specifically, disregard this warning.', ),
1872 treat_as_error=False,
1873 excluded_paths=(
1874 '^chrome/browser/ui/content_settings/',
1875 '^components/content_settings/',
1876 '^services/network/cookie_settings.cc',
1877 '.*test.cc',
1878 ),
Arthur Sonzogni48c6aea22023-09-04 22:25:201879 ),
1880 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531881 pattern=r'ContentSettingsType::TRACKING_PROTECTION',
1882 explanation=
1883 ('Do not directly use ContentSettingsType::TRACKING_PROTECTION to check '
1884 'for tracking protection exceptions. Instead rely on the '
1885 'privacy_sandbox::TrackingProtectionSettings API.', ),
1886 treat_as_error=False,
1887 excluded_paths=(
1888 '^chrome/browser/ui/content_settings/',
1889 '^components/content_settings/',
1890 '^components/privacy_sandbox/tracking_protection_settings.cc',
1891 '.*test.cc',
1892 ),
Anton Maliev66751812023-08-24 16:28:131893 ),
Tom Andersoncd522072023-10-03 00:52:351894 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531895 pattern=r'/\bg_signal_connect',
1896 explanation=('Use ScopedGSignal instead of g_signal_connect*()', ),
1897 treat_as_error=True,
1898 excluded_paths=('^ui/base/glib/scoped_gsignal.h', ),
Michelle Abreo6b7437822024-04-26 17:29:041899 ),
1900 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531901 pattern=r'features::kIsolatedWebApps',
1902 explanation=(
1903 'Do not use `features::kIsolatedWebApps` directly to guard Isolated ',
1904 'Web App code. ',
1905 'Use `content::IsolatedWebAppsPolicy::AreIsolatedWebAppsEnabled()` in ',
1906 'the browser process or check the `kEnableIsolatedWebAppsInRenderer` ',
1907 'command line flag in the renderer process.',
1908 ),
1909 treat_as_error=True,
1910 excluded_paths=_TEST_CODE_EXCLUDED_PATHS +
1911 ('^chrome/browser/about_flags.cc',
1912 '^chrome/browser/web_applications/isolated_web_apps/chrome_content_browser_client_isolated_web_apps_part.cc',
1913 '^chrome/browser/ui/startup/bad_flags_prompt.cc',
1914 '^content/shell/browser/shell_content_browser_client.cc')),
1915 BanRule(
1916 pattern=r'features::kIsolatedWebAppDevMode',
1917 explanation=(
1918 'Do not use `features::kIsolatedWebAppDevMode` directly to guard code ',
1919 'related to Isolated Web App Developer Mode. ',
1920 'Use `web_app::IsIwaDevModeEnabled()` instead.',
1921 ),
1922 treat_as_error=True,
1923 excluded_paths=_TEST_CODE_EXCLUDED_PATHS + (
1924 '^chrome/browser/about_flags.cc',
1925 '^chrome/browser/web_applications/isolated_web_apps/isolated_web_app_features.cc',
1926 '^chrome/browser/ui/startup/bad_flags_prompt.cc',
1927 )),
1928 BanRule(
1929 pattern=r'features::kIsolatedWebAppUnmanagedInstall',
1930 explanation=(
1931 'Do not use `features::kIsolatedWebAppUnmanagedInstall` directly to ',
1932 'guard code related to unmanaged install flow for Isolated Web Apps. ',
1933 'Use `web_app::IsIwaUnmanagedInstallEnabled()` instead.',
1934 ),
1935 treat_as_error=True,
1936 excluded_paths=_TEST_CODE_EXCLUDED_PATHS + (
1937 '^chrome/browser/about_flags.cc',
1938 '^chrome/browser/web_applications/isolated_web_apps/isolated_web_app_features.cc',
1939 )),
1940 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531941 pattern='/(CUIAutomation|AccessibleObjectFromWindow)',
1942 explanation=
1943 ('Direct usage of UIAutomation or IAccessible2 in client code is '
1944 'discouraged in Chromium, as it is not an assistive technology and '
1945 'should not rely on accessibility APIs directly. These APIs can '
1946 'introduce significant performance overhead. However, if you believe '
1947 'your use case warrants an exception, please discuss it with an '
1948 'accessibility owner before proceeding. For more information on the '
1949 'performance implications, see https://docs.google.com/document/d/1jN4itpCe_bDXF0BhFaYwv4xVLsCWkL9eULdzjmLzkuk/edit#heading=h.pwth3nbwdub0.',
1950 ),
1951 treat_as_error=False,
Andrew Rayskiycdd45e732024-03-20 14:32:391952 ),
1953 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531954 pattern=r'/WIDGET_OWNS_NATIVE_WIDGET|'
1955 r'NATIVE_WIDGET_OWNS_WIDGET',
1956 explanation=
1957 ('WIDGET_OWNS_NATIVE_WIDGET and NATIVE_WIDGET_OWNS_WIDGET are in the '
1958 'process of being deprecated. Consider using the new '
1959 'CLIENT_OWNS_WIDGET ownership model. Eventually, this will be the only '
1960 'available ownership model available and the associated enumeration'
1961 'will be removed.', ),
1962 treat_as_error=False,
Andrew Rayskiycdd45e732024-03-20 14:32:391963 ),
1964 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531965 pattern='ProfileManager::GetLastUsedProfile',
1966 explanation=
1967 ('Most code should already be scoped to a Profile. Pass in a Profile* '
1968 'or retreive from an existing entity with a reference to the Profile '
1969 '(e.g. WebContents).', ),
1970 treat_as_error=False,
Arthur Sonzogni5cbd3e32024-02-08 17:51:321971 ),
Helmut Januschkab3f71ab52024-03-12 02:48:051972 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531973 pattern=(r'/FindBrowserWithUiElementContext|'
1974 r'FindBrowserWithTab|'
1975 r'FindBrowserWithGroup|'
1976 r'FindTabbedBrowser|'
1977 r'FindAnyBrowser|'
1978 r'FindBrowserWithProfile|'
Erik Chen5f02eb4c2024-08-23 06:30:441979 r'FindLastActive|'
Daniel Cheng566634ff2024-06-29 14:56:531980 r'FindBrowserWithActiveWindow'),
1981 explanation=
1982 ('Most code should already be scoped to a Browser. Pass in a Browser* '
1983 'or retreive from an existing entity with a reference to the Browser.',
1984 ),
1985 treat_as_error=False,
Helmut Januschkab3f71ab52024-03-12 02:48:051986 ),
1987 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531988 pattern='BrowserUserData',
1989 explanation=
1990 ('Do not use BrowserUserData to store state on a Browser instance. '
1991 'Instead use BrowserWindowFeatures. BrowserWindowFeatures is '
1992 'functionally identical but has two benefits: it does not force a '
1993 'dependency onto class Browser, and lifetime semantics are explicit '
1994 'rather than implicit. See BrowserUserData header file for more '
1995 'details.', ),
1996 treat_as_error=False,
Mike Doughertyab1bdec2024-08-06 16:39:011997 excluded_paths=(
1998 # Exclude iOS as the iOS implementation of BrowserUserData is separate
1999 # and still in use.
2000 '^ios/',
2001 ),
Erik Chen87358e82024-06-04 02:13:122002 ),
Tom Sepezea67b6e2024-08-08 18:17:272003 BanRule(
2004 pattern=r'UNSAFE_TODO(',
2005 explanation=
2006 ('Do not use UNSAFE_TODO() to write new unsafe code. Use only when '
Tom Sepeza90f92b2024-08-15 16:01:352007 'removing a pre-existing file-wide allow_unsafe_buffers pragma, or '
2008 'when incrementally converting code off of unsafe interfaces',
Tom Sepezea67b6e2024-08-08 18:17:272009 ),
2010 treat_as_error=False,
2011 ),
2012 BanRule(
2013 pattern=r'UNSAFE_BUFFERS(',
2014 explanation=
Tom Sepeza90f92b2024-08-15 16:01:352015 ('Try to avoid using UNSAFE_BUFFERS() if at all possible. Otherwise, '
2016 'be sure to justify in a // SAFETY comment why other options are not '
2017 'available, and why the code is safe.',
Tom Sepezea67b6e2024-08-08 18:17:272018 ),
2019 treat_as_error=False,
2020 ),
Erik Chend086ae02024-08-20 22:53:332021 BanRule(
2022 pattern='BrowserWithTestWindowTest',
2023 explanation=
2024 ('Do not use BrowserWithTestWindowTest. By instantiating an instance '
2025 'of class Browser, the test is no longer a unit test but is instead a '
2026 'browser test. The class BrowserWithTestWindowTest forces production '
2027 'logic to take on test-only conditionals, which is an anti-pattern. '
2028 'Features should be performing dependency injection rather than '
2029 'directly using class Browser. See '
mikt19226ff22024-08-27 05:28:212030 'docs/chrome_browser_design_principles.md for more details.',
Erik Chend086ae02024-08-20 22:53:332031 ),
2032 treat_as_error=False,
2033 ),
Erik Chen8cf3a652024-08-23 17:13:302034 BanRule(
Erik Chen959cdd72024-08-29 02:11:212035 pattern='TestWithBrowserView',
2036 explanation=
2037 ('Do not use TestWithBrowserView. See '
2038 'docs/chrome_browser_design_principles.md for details. If you want '
2039 'to write a test that has both a Browser and a BrowserView, create '
2040 'a browser_test. If you want to write a unit_test, your code must '
Erik Chendba23692024-09-26 06:43:362041 'not reference Browser*.',
Erik Chen959cdd72024-08-29 02:11:212042 ),
2043 treat_as_error=False,
2044 ),
2045 BanRule(
Erik Chen8cf3a652024-08-23 17:13:302046 pattern='RunUntilIdle',
2047 explanation=
2048 ('Do not RunUntilIdle. If possible, explicitly quit the run loop using '
2049 'run_loop.Quit() or run_loop.QuitClosure() if completion can be '
2050 'observed using a lambda or callback. Otherwise, wait for the '
mikt19226ff22024-08-27 05:28:212051 'condition to be true via base::test::RunUntil().',
Erik Chen8cf3a652024-08-23 17:13:302052 ),
2053 treat_as_error=False,
2054 ),
Daniel Chengddde13a2024-09-05 21:39:282055 BanRule(
2056 pattern=r'/\bstd::(literals|string_literals|string_view_literals)\b',
2057 explanation = (
2058 'User-defined literals are banned by the Google C++ style guide. '
2059 'Exceptions are provided in Chrome for string and string_view '
2060 'literals that embed \\0.',
2061 ),
2062 treat_as_error=True,
2063 excluded_paths=(
2064 # Various tests or test helpers that embed NUL in strings or
2065 # string_views.
2066 r'^ash/components/arc/session/serial_number_util_unittest\.cc',
2067 r'^base/strings/string_util_unittest\.cc',
2068 r'^base/strings/utf_string_conversions_unittest\.cc',
2069 r'^chrome/browser/ash/crosapi/browser_data_back_migrator_unittest\.cc',
2070 r'^chrome/browser/ash/crosapi/browser_data_migrator_util_unittest\.cc',
2071 r'^chrome/browser/ash/crosapi/move_migrator_unittest\.cc',
2072 r'^components/history/core/browser/visit_annotations_database\.cc',
2073 r'^components/history/core/browser/visit_annotations_database_unittest\.cc',
2074 r'^components/os_crypt/sync/os_crypt_unittest\.cc',
2075 r'^components/password_manager/core/browser/credentials_cleaner_unittest\.cc',
2076 r'^content/browser/file_system_access/file_system_access_file_writer_impl_unittest\.cc',
2077 r'^net/cookies/parsed_cookie_unittest\.cc',
2078 r'^third_party/blink/renderer/modules/webcodecs/test_helpers\.cc',
2079 r'^third_party/blink/renderer/modules/websockets/websocket_channel_impl_test\.cc',
2080 ),
Erik Chenba8b0cd32024-10-01 08:36:362081 ),
2082 BanRule(
2083 pattern='BUILDFLAG(GOOGLE_CHROME_BRANDING)',
2084 explanation=
2085 ('Code gated by GOOGLE_CHROME_BRANDING is effectively untested. This '
2086 'is typically wrong. Valid use cases are glue for private modules '
2087 'shipped alongside Chrome, and installation-related logic.',
2088 ),
2089 treat_as_error=False,
2090 ),
2091 BanRule(
2092 pattern='defined(OFFICIAL_BUILD)',
2093 explanation=
2094 ('Code gated by OFFICIAL_BUILD is effectively untested. This '
2095 'is typically wrong. One valid use case is low-level code that '
2096 'handles subtleties related to high-levels of optimizations that come '
2097 'with OFFICIAL_BUILD.',
2098 ),
2099 treat_as_error=False,
2100 ),
[email protected]127f18ec2012-06-16 05:05:592101)
2102
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152103_DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING = (
2104 'Used a predicate related to signin::ConsentLevel::kSync which will always '
2105 'return false in the future (crbug.com/40066949). Prefer using a predicate '
2106 'that also supports signin::ConsentLevel::kSignin when appropriate. It is '
2107 'safe to ignore this warning if you are just moving an existing call, or if '
2108 'you want special handling for users in the legacy state. In doubt, reach '
Victor Hugo Vianna Silvae2292972024-06-04 17:11:552109 'out to //components/sync/OWNERS.',
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152110)
2111
2112# C++ functions related to signin::ConsentLevel::kSync which are deprecated.
2113_DEPRECATED_SYNC_CONSENT_CPP_FUNCTIONS : Sequence[BanRule] = (
2114 BanRule(
2115 'HasSyncConsent',
2116 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2117 False,
2118 ),
2119 BanRule(
2120 'CanSyncFeatureStart',
2121 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2122 False,
2123 ),
2124 BanRule(
2125 'IsSyncFeatureEnabled',
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152126 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152127 False,
2128 ),
2129 BanRule(
2130 'IsSyncFeatureActive',
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152131 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152132 False,
2133 ),
2134)
2135
2136# Java functions related to signin::ConsentLevel::kSync which are deprecated.
2137_DEPRECATED_SYNC_CONSENT_JAVA_FUNCTIONS : Sequence[BanRule] = (
2138 BanRule(
2139 'hasSyncConsent',
2140 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2141 False,
2142 ),
2143 BanRule(
2144 'canSyncFeatureStart',
2145 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2146 False,
2147 ),
2148 BanRule(
2149 'isSyncFeatureEnabled',
2150 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2151 False,
2152 ),
2153 BanRule(
2154 'isSyncFeatureActive',
2155 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2156 False,
2157 ),
2158)
2159
Daniel Cheng92c15e32022-03-16 17:48:222160_BANNED_MOJOM_PATTERNS : Sequence[BanRule] = (
2161 BanRule(
2162 'handle<shared_buffer>',
2163 (
2164 'Please use one of the more specific shared memory types instead:',
2165 ' mojo_base.mojom.ReadOnlySharedMemoryRegion',
2166 ' mojo_base.mojom.WritableSharedMemoryRegion',
2167 ' mojo_base.mojom.UnsafeSharedMemoryRegion',
2168 ),
2169 True,
2170 ),
2171)
2172
mlamouria82272622014-09-16 18:45:042173_IPC_ENUM_TRAITS_DEPRECATED = (
2174 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:502175 'See http://www.chromium.org/Home/chromium-security/education/'
2176 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:042177
Stephen Martinis97a394142018-06-07 23:06:052178_LONG_PATH_ERROR = (
2179 'Some files included in this CL have file names that are too long (> 200'
2180 ' characters). If committed, these files will cause issues on Windows. See'
2181 ' https://crbug.com/612667 for more details.'
2182)
2183
Shenghua Zhangbfaa38b82017-11-16 21:58:022184_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Bruce Dawson40fece62022-09-16 19:58:312185 r".*/BuildHooksAndroidImpl\.java",
2186 r".*/LicenseContentProvider\.java",
2187 r".*/PlatformServiceBridgeImpl.java",
2188 r".*chrome/android/feed/dummy/.*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:022189]
[email protected]127f18ec2012-06-16 05:05:592190
Mohamed Heikald048240a2019-11-12 16:57:372191# List of image extensions that are used as resources in chromium.
2192_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
2193
Sean Kau46e29bc2017-08-28 16:31:162194# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:402195_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Bruce Dawson40fece62022-09-16 19:58:312196 r'test/data/',
2197 r'testing/buildbot/',
2198 r'^components/policy/resources/policy_templates\.json$',
2199 r'^third_party/protobuf/',
Camillo Bruni1411a352023-05-24 12:39:032200 r'^third_party/blink/perf_tests/speedometer.*/resources/todomvc/learn\.json',
Bruce Dawson40fece62022-09-16 19:58:312201 r'^third_party/blink/renderer/devtools/protocol\.json$',
2202 r'^third_party/blink/web_tests/external/wpt/',
2203 r'^tools/perf/',
2204 r'^tools/traceline/svgui/startup-release.json',
Daniel Cheng2d4c2d192022-07-01 01:38:312205 # vscode configuration files allow comments
Bruce Dawson40fece62022-09-16 19:58:312206 r'^tools/vscode/',
Sean Kau46e29bc2017-08-28 16:31:162207]
2208
Andrew Grieveb773bad2020-06-05 18:00:382209# These are not checked on the public chromium-presubmit trybot.
2210# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:042211# checkouts.
agrievef32bcc72016-04-04 14:57:402212_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:382213 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382214]
2215
2216
2217_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:042218 'android_webview/tools/run_cts.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:362219 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042220 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362221 'build/android/gyp/aar.pydeps',
2222 'build/android/gyp/aidl.pydeps',
2223 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:382224 'build/android/gyp/assert_static_initializers.pydeps',
Mohamed Heikal133e1f22023-04-18 20:04:372225 'build/android/gyp/binary_baseline_profile.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362226 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:022227 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:222228 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:112229 'build/android/gyp/compile_java.pydeps',
Peter Weneaa963f2023-01-20 19:40:302230 'build/android/gyp/compile_kt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362231 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362232 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362233 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:112234 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042235 'build/android/gyp/create_app_bundle_apks.pydeps',
2236 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362237 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:122238 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:092239 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:222240 'build/android/gyp/create_size_info_files.pydeps',
Peter Wene6e017e2022-07-27 21:40:402241 'build/android/gyp/create_test_apk_wrapper_script.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002242 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362243 'build/android/gyp/dex.pydeps',
2244 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362245 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:212246 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362247 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:362248 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362249 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:582250 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362251 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:142252 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:262253 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:472254 'build/android/gyp/java_google_api_keys.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042255 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362256 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362257 'build/android/gyp/merge_manifest.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:102258 'build/android/gyp/optimize_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362259 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:222260 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362261 'build/android/gyp/proguard.pydeps',
Mohamed Heikaldd52b452024-09-10 17:10:502262 'build/android/gyp/rename_java_classes.pydeps',
Andrew Grievee3a775ab2022-05-16 15:59:222263 'build/android/gyp/system_image_apks.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:102264 'build/android/gyp/trace_event_bytecode_rewriter.pydeps',
Peter Wen578730b2020-03-19 19:55:462265 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:302266 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:242267 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362268 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:462269 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:562270 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362271 'build/android/incremental_install/generate_android_manifest.pydeps',
2272 'build/android/incremental_install/write_installer_json.pydeps',
Stephanie Kim392913b452022-06-15 17:25:322273 'build/android/pylib/results/presentation/test_results_presentation.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042274 'build/android/resource_sizes.pydeps',
2275 'build/android/test_runner.pydeps',
2276 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:362277 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362278 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:322279 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:272280 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
2281 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:042282 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Mohannad Farrag19102742023-12-01 01:16:302283 'components/cronet/tools/check_combined_proguard_file.pydeps',
2284 'components/cronet/tools/generate_proguard_file.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002285 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382286 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002287 'content/public/android/generate_child_service.pydeps',
Hzj_jie77bdb802024-07-22 18:14:512288 'fuchsia_web/av_testing/av_sync_tests.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382289 'net/tools/testserver/testserver.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:182290 'testing/scripts/run_isolated_script_test.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:412291 'testing/merge_scripts/standard_isolated_script_merge.pydeps',
2292 'testing/merge_scripts/standard_gtest_merge.pydeps',
2293 'testing/merge_scripts/code_coverage/merge_results.pydeps',
2294 'testing/merge_scripts/code_coverage/merge_steps.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042295 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:422296 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
Yuki Shiino38eeaad12022-08-11 06:40:252297 'third_party/blink/renderer/bindings/scripts/check_generated_file_list.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:422298 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:132299 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Yuki Shiinoea477d32023-08-21 06:24:342300 'third_party/blink/renderer/bindings/scripts/generate_event_interface_names.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:502301 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:412302 'third_party/blink/tools/blinkpy/web_tests/merge_results.pydeps',
2303 'third_party/blink/tools/merge_web_test_results.pydeps',
John Budorickbc3571aa2019-04-25 02:20:062304 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:222305 'tools/binary_size/supersize.pydeps',
Ben Pastene028104a2022-08-10 19:17:452306 'tools/perf/process_perf_results.pydeps',
Peter Wence103e12024-10-09 19:23:512307 'tools/pgo/generate_profile.pydeps',
agrievef32bcc72016-04-04 14:57:402308]
2309
wnwenbdc444e2016-05-25 13:44:152310
agrievef32bcc72016-04-04 14:57:402311_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
2312
2313
Eric Boren6fd2b932018-01-25 15:05:082314# Bypass the AUTHORS check for these accounts.
2315_KNOWN_ROBOTS = set(
nqmtuan918b2232024-04-11 23:09:552316 ) | set('%[email protected]' % s for s in ('findit-for-me', 'luci-bisection')
Achuith Bhandarkar35905562018-07-25 19:28:452317 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:592318 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:522319 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:232320 'wpt-autoroller', 'chrome-weblayer-builder',
Garrett Beaty4d4fcf62021-11-24 17:57:472321 'lacros-version-skew-roller', 'skylab-test-cros-roller',
Sven Zheng722960ba2022-07-18 16:40:462322 'infra-try-recipes-tester', 'lacros-tracking-roller',
Brian Sheedy1c951e62022-10-27 01:16:182323 'lacros-sdk-version-roller', 'chrome-automated-expectation',
Stephanie Kimb49bdd242023-04-28 16:46:042324 'chromium-automated-expectation', 'chrome-branch-day',
2325 'chromium-autosharder')
Eric Boren835d71f2018-09-07 21:09:042326 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:272327 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:042328 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:162329 for s in ('chromium-internal-autoroll',)
Kyungjun Lee3b7c9352024-04-02 23:59:142330 ) | set('%[email protected]' % s
2331 for s in ('chrome-screen-ai-releaser',)
Yulan Lineb0cfba2021-04-09 18:43:162332 ) | set('%[email protected]' % s
Chong Gub277e342022-10-15 03:30:552333 for s in ('swarming-tasks',)
2334 ) | set('%[email protected]' % s
2335 for s in ('global-integration-try-builder',
Joey Scarr1103c5d2023-09-14 01:17:552336 'global-integration-ci-builder')
Suma Kasa3b9cf7a2023-09-21 22:05:542337 ) | set('%[email protected]' % s
2338 for s in ('chops-security-borg',
2339 'chops-security-cronjobs-cpesuggest'))
Eric Boren6fd2b932018-01-25 15:05:082340
Matt Stark6ef08872021-07-29 01:21:462341_INVALID_GRD_FILE_LINE = [
2342 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
2343]
Eric Boren6fd2b932018-01-25 15:05:082344
Daniel Bratell65b033262019-04-23 08:17:062345def _IsCPlusPlusFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502346 """Returns True if this file contains C++-like code (and not Python,
2347 Go, Java, MarkDown, ...)"""
Daniel Bratell65b033262019-04-23 08:17:062348
Sam Maiera6e76d72022-02-11 21:43:502349 ext = input_api.os_path.splitext(file_path)[1]
2350 # This list is compatible with CppChecker.IsCppFile but we should
2351 # consider adding ".c" to it. If we do that we can use this function
2352 # at more places in the code.
2353 return ext in (
2354 '.h',
2355 '.cc',
2356 '.cpp',
2357 '.m',
2358 '.mm',
2359 )
2360
Daniel Bratell65b033262019-04-23 08:17:062361
2362def _IsCPlusPlusHeaderFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502363 return input_api.os_path.splitext(file_path)[1] == ".h"
Daniel Bratell65b033262019-04-23 08:17:062364
2365
2366def _IsJavaFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502367 return input_api.os_path.splitext(file_path)[1] == ".java"
Daniel Bratell65b033262019-04-23 08:17:062368
2369
2370def _IsProtoFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502371 return input_api.os_path.splitext(file_path)[1] == ".proto"
Daniel Bratell65b033262019-04-23 08:17:062372
Mohamed Heikal5e5b7922020-10-29 18:57:592373
Erik Staabc734cd7a2021-11-23 03:11:522374def _IsXmlOrGrdFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502375 ext = input_api.os_path.splitext(file_path)[1]
2376 return ext in ('.grd', '.xml')
Erik Staabc734cd7a2021-11-23 03:11:522377
2378
Sven Zheng76a79ea2022-12-21 21:25:242379def _IsMojomFile(input_api, file_path):
2380 return input_api.os_path.splitext(file_path)[1] == ".mojom"
2381
2382
Mohamed Heikal5e5b7922020-10-29 18:57:592383def CheckNoUpstreamDepsOnClank(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502384 """Prevent additions of dependencies from the upstream repo on //clank."""
2385 # clank can depend on clank
2386 if input_api.change.RepositoryRoot().endswith('clank'):
2387 return []
2388 build_file_patterns = [
2389 r'(.+/)?BUILD\.gn',
2390 r'.+\.gni',
2391 ]
2392 excluded_files = [r'build[/\\]config[/\\]android[/\\]config\.gni']
2393 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
Mohamed Heikal5e5b7922020-10-29 18:57:592394
Sam Maiera6e76d72022-02-11 21:43:502395 error_message = 'Disallowed import on //clank in an upstream build file:'
Mohamed Heikal5e5b7922020-10-29 18:57:592396
Sam Maiera6e76d72022-02-11 21:43:502397 def FilterFile(affected_file):
2398 return input_api.FilterSourceFile(affected_file,
2399 files_to_check=build_file_patterns,
2400 files_to_skip=excluded_files)
Mohamed Heikal5e5b7922020-10-29 18:57:592401
Sam Maiera6e76d72022-02-11 21:43:502402 problems = []
2403 for f in input_api.AffectedSourceFiles(FilterFile):
2404 local_path = f.LocalPath()
2405 for line_number, line in f.ChangedContents():
2406 if (bad_pattern.search(line)):
2407 problems.append('%s:%d\n %s' %
2408 (local_path, line_number, line.strip()))
2409 if problems:
2410 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
2411 else:
2412 return []
Mohamed Heikal5e5b7922020-10-29 18:57:592413
2414
Saagar Sanghavifceeaae2020-08-12 16:40:362415def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502416 """Attempts to prevent use of functions intended only for testing in
2417 non-testing code. For now this is just a best-effort implementation
2418 that ignores header files and may have some false positives. A
2419 better implementation would probably need a proper C++ parser.
2420 """
2421 # We only scan .cc files and the like, as the declaration of
2422 # for-testing functions in header files are hard to distinguish from
2423 # calls to such functions without a proper C++ parser.
2424 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:192425
Sam Maiera6e76d72022-02-11 21:43:502426 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
2427 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' %
2428 base_function_pattern)
2429 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
2430 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
2431 exclusion_pattern = input_api.re.compile(
2432 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' %
2433 (base_function_pattern, base_function_pattern))
2434 # Avoid a false positive in this case, where the method name, the ::, and
2435 # the closing { are all on different lines due to line wrapping.
2436 # HelperClassForTesting::
2437 # HelperClassForTesting(
2438 # args)
2439 # : member(0) {}
2440 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:192441
Sam Maiera6e76d72022-02-11 21:43:502442 def FilterFile(affected_file):
2443 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2444 input_api.DEFAULT_FILES_TO_SKIP)
2445 return input_api.FilterSourceFile(
2446 affected_file,
2447 files_to_check=file_inclusion_pattern,
2448 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:192449
Sam Maiera6e76d72022-02-11 21:43:502450 problems = []
2451 for f in input_api.AffectedSourceFiles(FilterFile):
2452 local_path = f.LocalPath()
2453 in_method_defn = False
2454 for line_number, line in f.ChangedContents():
2455 if (inclusion_pattern.search(line)
2456 and not comment_pattern.search(line)
2457 and not exclusion_pattern.search(line)
2458 and not allowlist_pattern.search(line)
2459 and not in_method_defn):
2460 problems.append('%s:%d\n %s' %
2461 (local_path, line_number, line.strip()))
2462 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:192463
Sam Maiera6e76d72022-02-11 21:43:502464 if problems:
2465 return [
2466 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
2467 ]
2468 else:
2469 return []
[email protected]55459852011-08-10 15:17:192470
2471
Saagar Sanghavifceeaae2020-08-12 16:40:362472def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502473 """This is a simplified version of
2474 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
2475 """
2476 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
2477 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
2478 name_pattern = r'ForTest(s|ing)?'
2479 # Describes an occurrence of "ForTest*" inside a // comment.
2480 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
2481 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
2482 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
2483 # Catch calls.
2484 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
2485 # Ignore definitions. (Comments are ignored separately.)
2486 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
Andrew Grieve40f451d2023-07-06 19:46:512487 allowlist_re = input_api.re.compile(r'// IN-TEST$')
Vaclav Brozek7dbc28c2018-03-27 08:35:232488
Sam Maiera6e76d72022-02-11 21:43:502489 problems = []
2490 sources = lambda x: input_api.FilterSourceFile(
2491 x,
2492 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
2493 DEFAULT_FILES_TO_SKIP),
2494 files_to_check=[r'.*\.java$'])
2495 for f in input_api.AffectedFiles(include_deletes=False,
2496 file_filter=sources):
2497 local_path = f.LocalPath()
Vaclav Brozek7dbc28c2018-03-27 08:35:232498 is_inside_javadoc = False
Sam Maiera6e76d72022-02-11 21:43:502499 for line_number, line in f.ChangedContents():
2500 if is_inside_javadoc and javadoc_end_re.search(line):
2501 is_inside_javadoc = False
2502 if not is_inside_javadoc and javadoc_start_re.search(line):
2503 is_inside_javadoc = True
2504 if is_inside_javadoc:
2505 continue
2506 if (inclusion_re.search(line) and not comment_re.search(line)
2507 and not annotation_re.search(line)
Andrew Grieve40f451d2023-07-06 19:46:512508 and not allowlist_re.search(line)
Sam Maiera6e76d72022-02-11 21:43:502509 and not exclusion_re.search(line)):
2510 problems.append('%s:%d\n %s' %
2511 (local_path, line_number, line.strip()))
Vaclav Brozek7dbc28c2018-03-27 08:35:232512
Sam Maiera6e76d72022-02-11 21:43:502513 if problems:
2514 return [
2515 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
2516 ]
2517 else:
2518 return []
Vaclav Brozek7dbc28c2018-03-27 08:35:232519
2520
Saagar Sanghavifceeaae2020-08-12 16:40:362521def CheckNoIOStreamInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502522 """Checks to make sure no .h files include <iostream>."""
2523 files = []
2524 pattern = input_api.re.compile(r'^#include\s*<iostream>',
2525 input_api.re.MULTILINE)
2526 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2527 if not f.LocalPath().endswith('.h'):
2528 continue
2529 contents = input_api.ReadFile(f)
2530 if pattern.search(contents):
2531 files.append(f)
[email protected]10689ca2011-09-02 02:31:542532
Sam Maiera6e76d72022-02-11 21:43:502533 if len(files):
2534 return [
2535 output_api.PresubmitError(
2536 'Do not #include <iostream> in header files, since it inserts static '
2537 'initialization into every file including the header. Instead, '
2538 '#include <ostream>. See http://crbug.com/94794', files)
2539 ]
2540 return []
2541
[email protected]10689ca2011-09-02 02:31:542542
Aleksey Khoroshilov9b28c032022-06-03 16:35:322543def CheckNoStrCatRedefines(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502544 """Checks no windows headers with StrCat redefined are included directly."""
2545 files = []
Aleksey Khoroshilov9b28c032022-06-03 16:35:322546 files_to_check = (r'.+%s' % _HEADER_EXTENSIONS,
2547 r'.+%s' % _IMPLEMENTATION_EXTENSIONS)
2548 files_to_skip = (input_api.DEFAULT_FILES_TO_SKIP +
2549 _NON_BASE_DEPENDENT_PATHS)
2550 sources_filter = lambda f: input_api.FilterSourceFile(
2551 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
2552
Sam Maiera6e76d72022-02-11 21:43:502553 pattern_deny = input_api.re.compile(
2554 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
2555 input_api.re.MULTILINE)
2556 pattern_allow = input_api.re.compile(
2557 r'^#include\s"base/win/windows_defines.inc"', input_api.re.MULTILINE)
Aleksey Khoroshilov9b28c032022-06-03 16:35:322558 for f in input_api.AffectedSourceFiles(sources_filter):
Sam Maiera6e76d72022-02-11 21:43:502559 contents = input_api.ReadFile(f)
2560 if pattern_deny.search(
2561 contents) and not pattern_allow.search(contents):
2562 files.append(f.LocalPath())
Danil Chapovalov3518f362018-08-11 16:13:432563
Sam Maiera6e76d72022-02-11 21:43:502564 if len(files):
2565 return [
2566 output_api.PresubmitError(
2567 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
2568 'directly since they pollute code with StrCat macro. Instead, '
2569 'include matching header from base/win. See http://crbug.com/856536',
2570 files)
2571 ]
2572 return []
Danil Chapovalov3518f362018-08-11 16:13:432573
[email protected]10689ca2011-09-02 02:31:542574
Andrew Williamsc9f69b482023-07-10 16:07:362575def _CheckNoUNIT_TESTInSourceFiles(input_api, f):
2576 problems = []
2577
2578 unit_test_macro = input_api.re.compile(
2579 '^\s*#.*(?:ifn?def\s+UNIT_TEST|defined\s*\(?\s*UNIT_TEST\s*\)?)(?:$|\s+)')
2580 for line_num, line in f.ChangedContents():
2581 if unit_test_macro.match(line):
2582 problems.append(' %s:%d' % (f.LocalPath(), line_num))
2583
2584 return problems
2585
2586
Saagar Sanghavifceeaae2020-08-12 16:40:362587def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502588 """Checks to make sure no source files use UNIT_TEST."""
2589 problems = []
2590 for f in input_api.AffectedFiles():
2591 if (not f.LocalPath().endswith(('.cc', '.mm'))):
2592 continue
Andrew Williamsc9f69b482023-07-10 16:07:362593 problems.extend(
2594 _CheckNoUNIT_TESTInSourceFiles(input_api, f))
[email protected]72df4e782012-06-21 16:28:182595
Sam Maiera6e76d72022-02-11 21:43:502596 if not problems:
2597 return []
2598 return [
2599 output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
2600 '\n'.join(problems))
2601 ]
2602
[email protected]72df4e782012-06-21 16:28:182603
Saagar Sanghavifceeaae2020-08-12 16:40:362604def CheckNoDISABLETypoInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502605 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
Dominic Battre033531052018-09-24 15:45:342606
Sam Maiera6e76d72022-02-11 21:43:502607 This test warns if somebody tries to disable a test with the DISABLE_ prefix
2608 instead of DISABLED_. To filter false positives, reports are only generated
2609 if a corresponding MAYBE_ line exists.
2610 """
2611 problems = []
Dominic Battre033531052018-09-24 15:45:342612
Sam Maiera6e76d72022-02-11 21:43:502613 # The following two patterns are looked for in tandem - is a test labeled
2614 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
2615 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
2616 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
Dominic Battre033531052018-09-24 15:45:342617
Sam Maiera6e76d72022-02-11 21:43:502618 # This is for the case that a test is disabled on all platforms.
2619 full_disable_pattern = input_api.re.compile(
2620 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
2621 input_api.re.MULTILINE)
Dominic Battre033531052018-09-24 15:45:342622
Arthur Sonzognic66e9c82024-04-23 07:53:042623 for f in input_api.AffectedFiles(include_deletes=False):
Sam Maiera6e76d72022-02-11 21:43:502624 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2625 continue
Dominic Battre033531052018-09-24 15:45:342626
Arthur Sonzognic66e9c82024-04-23 07:53:042627 # Search for MAYBE_, DISABLE_ pairs.
Sam Maiera6e76d72022-02-11 21:43:502628 disable_lines = {} # Maps of test name to line number.
2629 maybe_lines = {}
2630 for line_num, line in f.ChangedContents():
2631 disable_match = disable_pattern.search(line)
2632 if disable_match:
2633 disable_lines[disable_match.group(1)] = line_num
2634 maybe_match = maybe_pattern.search(line)
2635 if maybe_match:
2636 maybe_lines[maybe_match.group(1)] = line_num
Dominic Battre033531052018-09-24 15:45:342637
Sam Maiera6e76d72022-02-11 21:43:502638 # Search for DISABLE_ occurrences within a TEST() macro.
2639 disable_tests = set(disable_lines.keys())
2640 maybe_tests = set(maybe_lines.keys())
2641 for test in disable_tests.intersection(maybe_tests):
2642 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
Dominic Battre033531052018-09-24 15:45:342643
Sam Maiera6e76d72022-02-11 21:43:502644 contents = input_api.ReadFile(f)
2645 full_disable_match = full_disable_pattern.search(contents)
2646 if full_disable_match:
2647 problems.append(' %s' % f.LocalPath())
Dominic Battre033531052018-09-24 15:45:342648
Sam Maiera6e76d72022-02-11 21:43:502649 if not problems:
2650 return []
2651 return [
2652 output_api.PresubmitPromptWarning(
2653 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
2654 '\n'.join(problems))
2655 ]
2656
Dominic Battre033531052018-09-24 15:45:342657
Nina Satragnof7660532021-09-20 18:03:352658def CheckForgettingMAYBEInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502659 """Checks to make sure tests disabled conditionally are not missing a
2660 corresponding MAYBE_ prefix.
2661 """
2662 # Expect at least a lowercase character in the test name. This helps rule out
2663 # false positives with macros wrapping the actual tests name.
2664 define_maybe_pattern = input_api.re.compile(
2665 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
Bruce Dawsonffc55292022-04-20 04:18:192666 # The test_maybe_pattern needs to handle all of these forms. The standard:
2667 # IN_PROC_TEST_F(SyncTest, MAYBE_Start) {
2668 # With a wrapper macro around the test name:
2669 # IN_PROC_TEST_F(SyncTest, E2E_ENABLED(MAYBE_Start)) {
2670 # And the odd-ball NACL_BROWSER_TEST_f format:
2671 # NACL_BROWSER_TEST_F(NaClBrowserTest, SimpleLoad, {
2672 # The optional E2E_ENABLED-style is handled with (\w*\()?
2673 # The NACL_BROWSER_TEST_F pattern is handled by allowing a trailing comma or
2674 # trailing ')'.
2675 test_maybe_pattern = (
2676 r'^\s*\w*TEST[^(]*\(\s*\w+,\s*(\w*\()?MAYBE_{test_name}[\),]')
Sam Maiera6e76d72022-02-11 21:43:502677 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
2678 warnings = []
Nina Satragnof7660532021-09-20 18:03:352679
Sam Maiera6e76d72022-02-11 21:43:502680 # Read the entire files. We can't just read the affected lines, forgetting to
2681 # add MAYBE_ on a change would not show up otherwise.
Arthur Sonzognic66e9c82024-04-23 07:53:042682 for f in input_api.AffectedFiles(include_deletes=False):
Sam Maiera6e76d72022-02-11 21:43:502683 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2684 continue
2685 contents = input_api.ReadFile(f)
2686 lines = contents.splitlines(True)
2687 current_position = 0
2688 warning_test_names = set()
2689 for line_num, line in enumerate(lines, start=1):
2690 current_position += len(line)
2691 maybe_match = define_maybe_pattern.search(line)
2692 if maybe_match:
2693 test_name = maybe_match.group('test_name')
2694 # Do not warn twice for the same test.
2695 if (test_name in warning_test_names):
2696 continue
2697 warning_test_names.add(test_name)
Nina Satragnof7660532021-09-20 18:03:352698
Sam Maiera6e76d72022-02-11 21:43:502699 # Attempt to find the corresponding MAYBE_ test or suite, starting from
2700 # the current position.
2701 test_match = input_api.re.compile(
2702 test_maybe_pattern.format(test_name=test_name),
2703 input_api.re.MULTILINE).search(contents, current_position)
2704 suite_match = input_api.re.compile(
2705 suite_maybe_pattern.format(test_name=test_name),
2706 input_api.re.MULTILINE).search(contents, current_position)
2707 if not test_match and not suite_match:
2708 warnings.append(
2709 output_api.PresubmitPromptWarning(
2710 '%s:%d found MAYBE_ defined without corresponding test %s'
2711 % (f.LocalPath(), line_num, test_name)))
2712 return warnings
2713
[email protected]72df4e782012-06-21 16:28:182714
Saagar Sanghavifceeaae2020-08-12 16:40:362715def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502716 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
2717 errors = []
Kalvin Lee4a3b79de2022-05-26 16:00:162718 pattern = input_api.re.compile(r'\bDCHECK_IS_ON\b(?!\(\))',
Sam Maiera6e76d72022-02-11 21:43:502719 input_api.re.MULTILINE)
2720 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2721 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
2722 continue
2723 for lnum, line in f.ChangedContents():
2724 if input_api.re.search(pattern, line):
2725 errors.append(
2726 output_api.PresubmitError((
2727 '%s:%d: Use of DCHECK_IS_ON() must be written as "#if '
2728 + 'DCHECK_IS_ON()", not forgetting the parentheses.') %
2729 (f.LocalPath(), lnum)))
2730 return errors
danakj61c1aa22015-10-26 19:55:522731
2732
Weilun Shia487fad2020-10-28 00:10:342733# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
2734# more reliable way. See
2735# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:192736
wnwenbdc444e2016-05-25 13:44:152737
Saagar Sanghavifceeaae2020-08-12 16:40:362738def CheckFlakyTestUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502739 """Check that FlakyTest annotation is our own instead of the android one"""
2740 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
2741 files = []
2742 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2743 if f.LocalPath().endswith('Test.java'):
2744 if pattern.search(input_api.ReadFile(f)):
2745 files.append(f)
2746 if len(files):
2747 return [
2748 output_api.PresubmitError(
2749 'Use org.chromium.base.test.util.FlakyTest instead of '
2750 'android.test.FlakyTest', files)
2751 ]
2752 return []
mcasasb7440c282015-02-04 14:52:192753
wnwenbdc444e2016-05-25 13:44:152754
Saagar Sanghavifceeaae2020-08-12 16:40:362755def CheckNoDEPSGIT(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502756 """Make sure .DEPS.git is never modified manually."""
2757 if any(f.LocalPath().endswith('.DEPS.git')
2758 for f in input_api.AffectedFiles()):
2759 return [
2760 output_api.PresubmitError(
2761 'Never commit changes to .DEPS.git. This file is maintained by an\n'
2762 'automated system based on what\'s in DEPS and your changes will be\n'
2763 'overwritten.\n'
2764 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
2765 'get-the-code#Rolling_DEPS\n'
2766 'for more information')
2767 ]
2768 return []
[email protected]2a8ac9c2011-10-19 17:20:442769
2770
Sven Zheng76a79ea2022-12-21 21:25:242771def CheckCrosApiNeedBrowserTest(input_api, output_api):
2772 """Check new crosapi should add browser test."""
2773 has_new_crosapi = False
2774 has_browser_test = False
2775 for f in input_api.AffectedFiles():
2776 path = f.LocalPath()
2777 if (path.startswith('chromeos/crosapi/mojom') and
2778 _IsMojomFile(input_api, path) and f.Action() == 'A'):
2779 has_new_crosapi = True
2780 if path.endswith('browsertest.cc') or path.endswith('browser_test.cc'):
2781 has_browser_test = True
2782 if has_new_crosapi and not has_browser_test:
2783 return [
2784 output_api.PresubmitPromptWarning(
2785 'You are adding a new crosapi, but there is no file ends with '
2786 'browsertest.cc file being added or modified. It is important '
2787 'to add crosapi browser test coverage to avoid version '
2788 ' skew issues.\n'
2789 'Check //docs/lacros/test_instructions.md for more information.'
2790 )
2791 ]
2792 return []
2793
2794
Saagar Sanghavifceeaae2020-08-12 16:40:362795def CheckValidHostsInDEPSOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502796 """Checks that DEPS file deps are from allowed_hosts."""
2797 # Run only if DEPS file has been modified to annoy fewer bystanders.
2798 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
2799 return []
2800 # Outsource work to gclient verify
2801 try:
2802 gclient_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
2803 'third_party', 'depot_tools',
2804 'gclient.py')
2805 input_api.subprocess.check_output(
Bruce Dawson8a43cf72022-05-13 17:10:322806 [input_api.python3_executable, gclient_path, 'verify'],
Sam Maiera6e76d72022-02-11 21:43:502807 stderr=input_api.subprocess.STDOUT)
2808 return []
2809 except input_api.subprocess.CalledProcessError as error:
2810 return [
2811 output_api.PresubmitError(
2812 'DEPS file must have only git dependencies.',
2813 long_text=error.output)
2814 ]
tandriief664692014-09-23 14:51:472815
2816
Mario Sanchez Prada2472cab2019-09-18 10:58:312817def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152818 ban_rule):
Allen Bauer84778682022-09-22 16:28:562819 """Helper method for checking for banned constructs.
Mario Sanchez Prada2472cab2019-09-18 10:58:312820
Sam Maiera6e76d72022-02-11 21:43:502821 Returns an string composed of the name of the file, the line number where the
2822 match has been found and the additional text passed as |message| in case the
2823 target type name matches the text inside the line passed as parameter.
2824 """
2825 result = []
Peng Huang9c5949a02020-06-11 19:20:542826
Daniel Chenga44a1bcd2022-03-15 20:00:152827 # Ignore comments about banned types.
2828 if input_api.re.search(r"^ *//", line):
Sam Maiera6e76d72022-02-11 21:43:502829 return result
Daniel Chenga44a1bcd2022-03-15 20:00:152830 # A // nocheck comment will bypass this error.
2831 if line.endswith(" nocheck"):
Sam Maiera6e76d72022-02-11 21:43:502832 return result
2833
2834 matched = False
Daniel Chenga44a1bcd2022-03-15 20:00:152835 if ban_rule.pattern[0:1] == '/':
2836 regex = ban_rule.pattern[1:]
Sam Maiera6e76d72022-02-11 21:43:502837 if input_api.re.search(regex, line):
2838 matched = True
Daniel Chenga44a1bcd2022-03-15 20:00:152839 elif ban_rule.pattern in line:
Sam Maiera6e76d72022-02-11 21:43:502840 matched = True
2841
2842 if matched:
2843 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
Daniel Chenga44a1bcd2022-03-15 20:00:152844 for line in ban_rule.explanation:
2845 result.append(' %s' % line)
Sam Maiera6e76d72022-02-11 21:43:502846
danakjd18e8892020-12-17 17:42:012847 return result
Mario Sanchez Prada2472cab2019-09-18 10:58:312848
2849
Saagar Sanghavifceeaae2020-08-12 16:40:362850def CheckNoBannedFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502851 """Make sure that banned functions are not used."""
2852 warnings = []
2853 errors = []
[email protected]127f18ec2012-06-16 05:05:592854
Sam Maiera6e76d72022-02-11 21:43:502855 def IsExcludedFile(affected_file, excluded_paths):
Daniel Chenga44a1bcd2022-03-15 20:00:152856 if not excluded_paths:
2857 return False
2858
Sam Maiera6e76d72022-02-11 21:43:502859 local_path = affected_file.LocalPath()
Bruce Dawson40fece62022-09-16 19:58:312860 # Consistently use / as path separator to simplify the writing of regex
2861 # expressions.
2862 local_path = local_path.replace(input_api.os_path.sep, '/')
Sam Maiera6e76d72022-02-11 21:43:502863 for item in excluded_paths:
2864 if input_api.re.match(item, local_path):
2865 return True
2866 return False
wnwenbdc444e2016-05-25 13:44:152867
Sam Maiera6e76d72022-02-11 21:43:502868 def IsIosObjcFile(affected_file):
2869 local_path = affected_file.LocalPath()
2870 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m',
2871 '.h'):
2872 return False
2873 basename = input_api.os_path.basename(local_path)
2874 if 'ios' in basename.split('_'):
2875 return True
2876 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
2877 if sep and 'ios' in local_path.split(sep):
2878 return True
2879 return False
Sylvain Defresnea8b73d252018-02-28 15:45:542880
Daniel Chenga44a1bcd2022-03-15 20:00:152881 def CheckForMatch(affected_file, line_num: int, line: str,
2882 ban_rule: BanRule):
2883 if IsExcludedFile(affected_file, ban_rule.excluded_paths):
2884 return
2885
Sam Maiera6e76d72022-02-11 21:43:502886 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152887 ban_rule)
Sam Maiera6e76d72022-02-11 21:43:502888 if problems:
Daniel Chenga44a1bcd2022-03-15 20:00:152889 if ban_rule.treat_as_error is not None and ban_rule.treat_as_error:
Sam Maiera6e76d72022-02-11 21:43:502890 errors.extend(problems)
2891 else:
2892 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:152893
Sam Maiera6e76d72022-02-11 21:43:502894 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2895 for f in input_api.AffectedFiles(file_filter=file_filter):
2896 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152897 for ban_rule in _BANNED_JAVA_FUNCTIONS:
2898 CheckForMatch(f, line_num, line, ban_rule)
Eric Stevensona9a980972017-09-23 00:04:412899
Clement Yan9b330cb2022-11-17 05:25:292900 file_filter = lambda f: f.LocalPath().endswith(('.js', '.ts'))
2901 for f in input_api.AffectedFiles(file_filter=file_filter):
2902 for line_num, line in f.ChangedContents():
2903 for ban_rule in _BANNED_JAVASCRIPT_FUNCTIONS:
2904 CheckForMatch(f, line_num, line, ban_rule)
2905
Sam Maiera6e76d72022-02-11 21:43:502906 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
2907 for f in input_api.AffectedFiles(file_filter=file_filter):
2908 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152909 for ban_rule in _BANNED_OBJC_FUNCTIONS:
2910 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:592911
Sam Maiera6e76d72022-02-11 21:43:502912 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
2913 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152914 for ban_rule in _BANNED_IOS_OBJC_FUNCTIONS:
2915 CheckForMatch(f, line_num, line, ban_rule)
Sylvain Defresnea8b73d252018-02-28 15:45:542916
Sam Maiera6e76d72022-02-11 21:43:502917 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
2918 for f in input_api.AffectedFiles(file_filter=egtest_filter):
2919 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152920 for ban_rule in _BANNED_IOS_EGTEST_FUNCTIONS:
2921 CheckForMatch(f, line_num, line, ban_rule)
Peter K. Lee6c03ccff2019-07-15 14:40:052922
Sam Maiera6e76d72022-02-11 21:43:502923 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
2924 for f in input_api.AffectedFiles(file_filter=file_filter):
2925 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152926 for ban_rule in _BANNED_CPP_FUNCTIONS:
2927 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:592928
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152929 # As of 05/2024, iOS fully migrated ConsentLevel::kSync to kSignin, and
2930 # Android is in the process of preventing new users from entering kSync.
2931 # So the warning is restricted to those platforms.
2932 ios_pattern = input_api.re.compile('(^|[\W_])ios[\W_]')
2933 file_filter = lambda f: (f.LocalPath().endswith(('.cc', '.mm', '.h')) and
2934 ('android' in f.LocalPath() or
2935 # Simply checking for an 'ios' substring would
2936 # catch unrelated cases, use a regex.
2937 ios_pattern.search(f.LocalPath())))
2938 for f in input_api.AffectedFiles(file_filter=file_filter):
2939 for line_num, line in f.ChangedContents():
2940 for ban_rule in _DEPRECATED_SYNC_CONSENT_CPP_FUNCTIONS:
2941 CheckForMatch(f, line_num, line, ban_rule)
2942
2943 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2944 for f in input_api.AffectedFiles(file_filter=file_filter):
2945 for line_num, line in f.ChangedContents():
2946 for ban_rule in _DEPRECATED_SYNC_CONSENT_JAVA_FUNCTIONS:
2947 CheckForMatch(f, line_num, line, ban_rule)
2948
Daniel Cheng92c15e32022-03-16 17:48:222949 file_filter = lambda f: f.LocalPath().endswith(('.mojom'))
2950 for f in input_api.AffectedFiles(file_filter=file_filter):
2951 for line_num, line in f.ChangedContents():
2952 for ban_rule in _BANNED_MOJOM_PATTERNS:
2953 CheckForMatch(f, line_num, line, ban_rule)
2954
2955
Sam Maiera6e76d72022-02-11 21:43:502956 result = []
2957 if (warnings):
2958 result.append(
2959 output_api.PresubmitPromptWarning('Banned functions were used.\n' +
2960 '\n'.join(warnings)))
2961 if (errors):
2962 result.append(
2963 output_api.PresubmitError('Banned functions were used.\n' +
2964 '\n'.join(errors)))
2965 return result
[email protected]127f18ec2012-06-16 05:05:592966
Michael Thiessen44457642020-02-06 00:24:152967def _CheckAndroidNoBannedImports(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502968 """Make sure that banned java imports are not used."""
2969 errors = []
Michael Thiessen44457642020-02-06 00:24:152970
Sam Maiera6e76d72022-02-11 21:43:502971 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2972 for f in input_api.AffectedFiles(file_filter=file_filter):
2973 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152974 for ban_rule in _BANNED_JAVA_IMPORTS:
2975 # Consider merging this into the above function. There is no
2976 # real difference anymore other than helping with a little
2977 # bit of boilerplate text. Doing so means things like
2978 # `treat_as_error` will also be uniformly handled.
Sam Maiera6e76d72022-02-11 21:43:502979 problems = _GetMessageForMatchingType(input_api, f, line_num,
Daniel Chenga44a1bcd2022-03-15 20:00:152980 line, ban_rule)
Sam Maiera6e76d72022-02-11 21:43:502981 if problems:
2982 errors.extend(problems)
2983 result = []
2984 if (errors):
2985 result.append(
2986 output_api.PresubmitError('Banned imports were used.\n' +
2987 '\n'.join(errors)))
2988 return result
Michael Thiessen44457642020-02-06 00:24:152989
2990
Saagar Sanghavifceeaae2020-08-12 16:40:362991def CheckNoPragmaOnce(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502992 """Make sure that banned functions are not used."""
2993 files = []
2994 pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
2995 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2996 if not f.LocalPath().endswith('.h'):
2997 continue
Bruce Dawson4c4c2922022-05-02 18:07:332998 if f.LocalPath().endswith('com_imported_mstscax.h'):
2999 continue
Sam Maiera6e76d72022-02-11 21:43:503000 contents = input_api.ReadFile(f)
3001 if pattern.search(contents):
3002 files.append(f)
[email protected]6c063c62012-07-11 19:11:063003
Sam Maiera6e76d72022-02-11 21:43:503004 if files:
3005 return [
3006 output_api.PresubmitError(
3007 'Do not use #pragma once in header files.\n'
3008 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
3009 files)
3010 ]
3011 return []
[email protected]6c063c62012-07-11 19:11:063012
[email protected]127f18ec2012-06-16 05:05:593013
Saagar Sanghavifceeaae2020-08-12 16:40:363014def CheckNoTrinaryTrueFalse(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503015 """Checks to make sure we don't introduce use of foo ? true : false."""
3016 problems = []
3017 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
3018 for f in input_api.AffectedFiles():
3019 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
3020 continue
[email protected]e7479052012-09-19 00:26:123021
Sam Maiera6e76d72022-02-11 21:43:503022 for line_num, line in f.ChangedContents():
3023 if pattern.match(line):
3024 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]e7479052012-09-19 00:26:123025
Sam Maiera6e76d72022-02-11 21:43:503026 if not problems:
3027 return []
3028 return [
3029 output_api.PresubmitPromptWarning(
3030 'Please consider avoiding the "? true : false" pattern if possible.\n'
3031 + '\n'.join(problems))
3032 ]
[email protected]e7479052012-09-19 00:26:123033
3034
Saagar Sanghavifceeaae2020-08-12 16:40:363035def CheckUnwantedDependencies(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503036 """Runs checkdeps on #include and import statements added in this
3037 change. Breaking - rules is an error, breaking ! rules is a
3038 warning.
3039 """
3040 # Return early if no relevant file types were modified.
3041 for f in input_api.AffectedFiles():
3042 path = f.LocalPath()
3043 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path)
3044 or _IsJavaFile(input_api, path)):
3045 break
[email protected]55f9f382012-07-31 11:02:183046 else:
Sam Maiera6e76d72022-02-11 21:43:503047 return []
rhalavati08acd232017-04-03 07:23:283048
Sam Maiera6e76d72022-02-11 21:43:503049 import sys
3050 # We need to wait until we have an input_api object and use this
3051 # roundabout construct to import checkdeps because this file is
3052 # eval-ed and thus doesn't have __file__.
3053 original_sys_path = sys.path
3054 try:
3055 sys.path = sys.path + [
3056 input_api.os_path.join(input_api.PresubmitLocalPath(),
3057 'buildtools', 'checkdeps')
3058 ]
3059 import checkdeps
3060 from rules import Rule
3061 finally:
3062 # Restore sys.path to what it was before.
3063 sys.path = original_sys_path
[email protected]55f9f382012-07-31 11:02:183064
Sam Maiera6e76d72022-02-11 21:43:503065 added_includes = []
3066 added_imports = []
3067 added_java_imports = []
3068 for f in input_api.AffectedFiles():
3069 if _IsCPlusPlusFile(input_api, f.LocalPath()):
3070 changed_lines = [line for _, line in f.ChangedContents()]
3071 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
3072 elif _IsProtoFile(input_api, f.LocalPath()):
3073 changed_lines = [line for _, line in f.ChangedContents()]
3074 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
3075 elif _IsJavaFile(input_api, f.LocalPath()):
3076 changed_lines = [line for _, line in f.ChangedContents()]
3077 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:243078
Sam Maiera6e76d72022-02-11 21:43:503079 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
3080
3081 error_descriptions = []
3082 warning_descriptions = []
3083 error_subjects = set()
3084 warning_subjects = set()
3085
3086 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
3087 added_includes):
3088 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3089 description_with_path = '%s\n %s' % (path, rule_description)
3090 if rule_type == Rule.DISALLOW:
3091 error_descriptions.append(description_with_path)
3092 error_subjects.add("#includes")
3093 else:
3094 warning_descriptions.append(description_with_path)
3095 warning_subjects.add("#includes")
3096
3097 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
3098 added_imports):
3099 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3100 description_with_path = '%s\n %s' % (path, rule_description)
3101 if rule_type == Rule.DISALLOW:
3102 error_descriptions.append(description_with_path)
3103 error_subjects.add("imports")
3104 else:
3105 warning_descriptions.append(description_with_path)
3106 warning_subjects.add("imports")
3107
3108 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
3109 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
3110 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3111 description_with_path = '%s\n %s' % (path, rule_description)
3112 if rule_type == Rule.DISALLOW:
3113 error_descriptions.append(description_with_path)
3114 error_subjects.add("imports")
3115 else:
3116 warning_descriptions.append(description_with_path)
3117 warning_subjects.add("imports")
3118
3119 results = []
3120 if error_descriptions:
3121 results.append(
3122 output_api.PresubmitError(
3123 'You added one or more %s that violate checkdeps rules.' %
3124 " and ".join(error_subjects), error_descriptions))
3125 if warning_descriptions:
3126 results.append(
3127 output_api.PresubmitPromptOrNotify(
3128 'You added one or more %s of files that are temporarily\n'
3129 'allowed but being removed. Can you avoid introducing the\n'
3130 '%s? See relevant DEPS file(s) for details and contacts.' %
3131 (" and ".join(warning_subjects), "/".join(warning_subjects)),
3132 warning_descriptions))
3133 return results
[email protected]55f9f382012-07-31 11:02:183134
3135
Saagar Sanghavifceeaae2020-08-12 16:40:363136def CheckFilePermissions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503137 """Check that all files have their permissions properly set."""
3138 if input_api.platform == 'win32':
3139 return []
3140 checkperms_tool = input_api.os_path.join(input_api.PresubmitLocalPath(),
3141 'tools', 'checkperms',
3142 'checkperms.py')
3143 args = [
Bruce Dawson8a43cf72022-05-13 17:10:323144 input_api.python3_executable, checkperms_tool, '--root',
Sam Maiera6e76d72022-02-11 21:43:503145 input_api.change.RepositoryRoot()
3146 ]
3147 with input_api.CreateTemporaryFile() as file_list:
3148 for f in input_api.AffectedFiles():
3149 # checkperms.py file/directory arguments must be relative to the
3150 # repository.
3151 file_list.write((f.LocalPath() + '\n').encode('utf8'))
3152 file_list.close()
3153 args += ['--file-list', file_list.name]
3154 try:
3155 input_api.subprocess.check_output(args)
3156 return []
3157 except input_api.subprocess.CalledProcessError as error:
3158 return [
3159 output_api.PresubmitError('checkperms.py failed:',
3160 long_text=error.output.decode(
3161 'utf-8', 'ignore'))
3162 ]
[email protected]fbcafe5a2012-08-08 15:31:223163
3164
Saagar Sanghavifceeaae2020-08-12 16:40:363165def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503166 """Makes sure we don't include ui/aura/window_property.h
3167 in header files.
3168 """
3169 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
3170 errors = []
3171 for f in input_api.AffectedFiles():
3172 if not f.LocalPath().endswith('.h'):
3173 continue
3174 for line_num, line in f.ChangedContents():
3175 if pattern.match(line):
3176 errors.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]c8278b32012-10-30 20:35:493177
Sam Maiera6e76d72022-02-11 21:43:503178 results = []
3179 if errors:
3180 results.append(
3181 output_api.PresubmitError(
3182 'Header files should not include ui/aura/window_property.h',
3183 errors))
3184 return results
[email protected]c8278b32012-10-30 20:35:493185
3186
Omer Katzcc77ea92021-04-26 10:23:283187def CheckNoInternalHeapIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503188 """Makes sure we don't include any headers from
3189 third_party/blink/renderer/platform/heap/impl or
3190 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
3191 third_party/blink/renderer/platform/heap
3192 """
3193 impl_pattern = input_api.re.compile(
3194 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
3195 v8_wrapper_pattern = input_api.re.compile(
3196 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"'
3197 )
Bruce Dawson40fece62022-09-16 19:58:313198 # Consistently use / as path separator to simplify the writing of regex
3199 # expressions.
Sam Maiera6e76d72022-02-11 21:43:503200 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:313201 r"^third_party/blink/renderer/platform/heap/.*",
3202 f.LocalPath().replace(input_api.os_path.sep, '/'))
Sam Maiera6e76d72022-02-11 21:43:503203 errors = []
Omer Katzcc77ea92021-04-26 10:23:283204
Sam Maiera6e76d72022-02-11 21:43:503205 for f in input_api.AffectedFiles(file_filter=file_filter):
3206 for line_num, line in f.ChangedContents():
3207 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
3208 errors.append(' %s:%d' % (f.LocalPath(), line_num))
Omer Katzcc77ea92021-04-26 10:23:283209
Sam Maiera6e76d72022-02-11 21:43:503210 results = []
3211 if errors:
3212 results.append(
3213 output_api.PresubmitError(
3214 'Do not include files from third_party/blink/renderer/platform/heap/impl'
3215 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
3216 'relevant counterparts from third_party/blink/renderer/platform/heap',
3217 errors))
3218 return results
Omer Katzcc77ea92021-04-26 10:23:283219
3220
[email protected]70ca77752012-11-20 03:45:033221def _CheckForVersionControlConflictsInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:503222 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
3223 errors = []
3224 for line_num, line in f.ChangedContents():
3225 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
3226 # First-level headers in markdown look a lot like version control
3227 # conflict markers. http://daringfireball.net/projects/markdown/basics
3228 continue
3229 if pattern.match(line):
3230 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
3231 return errors
[email protected]70ca77752012-11-20 03:45:033232
3233
Saagar Sanghavifceeaae2020-08-12 16:40:363234def CheckForVersionControlConflicts(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503235 """Usually this is not intentional and will cause a compile failure."""
3236 errors = []
3237 for f in input_api.AffectedFiles():
3238 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
[email protected]70ca77752012-11-20 03:45:033239
Sam Maiera6e76d72022-02-11 21:43:503240 results = []
3241 if errors:
3242 results.append(
3243 output_api.PresubmitError(
3244 'Version control conflict markers found, please resolve.',
3245 errors))
3246 return results
[email protected]70ca77752012-11-20 03:45:033247
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203248
Saagar Sanghavifceeaae2020-08-12 16:40:363249def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503250 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
3251 errors = []
3252 for f in input_api.AffectedFiles():
3253 for line_num, line in f.ChangedContents():
3254 if pattern.search(line):
3255 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
estadee17314a02017-01-12 16:22:163256
Sam Maiera6e76d72022-02-11 21:43:503257 results = []
3258 if errors:
3259 results.append(
3260 output_api.PresubmitPromptWarning(
3261 'Found Google support URL addressed by answer number. Please replace '
3262 'with a p= identifier instead. See crbug.com/679462\n',
3263 errors))
3264 return results
estadee17314a02017-01-12 16:22:163265
[email protected]70ca77752012-11-20 03:45:033266
Saagar Sanghavifceeaae2020-08-12 16:40:363267def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503268 def FilterFile(affected_file):
3269 """Filter function for use with input_api.AffectedSourceFiles,
3270 below. This filters out everything except non-test files from
3271 top-level directories that generally speaking should not hard-code
3272 service URLs (e.g. src/android_webview/, src/content/ and others).
3273 """
3274 return input_api.FilterSourceFile(
3275 affected_file,
Bruce Dawson40fece62022-09-16 19:58:313276 files_to_check=[r'^(android_webview|base|content|net)/.*'],
Sam Maiera6e76d72022-02-11 21:43:503277 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3278 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:443279
Sam Maiera6e76d72022-02-11 21:43:503280 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
3281 '\.(com|net)[^"]*"')
3282 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
3283 pattern = input_api.re.compile(base_pattern)
3284 problems = [] # items are (filename, line_number, line)
3285 for f in input_api.AffectedSourceFiles(FilterFile):
3286 for line_num, line in f.ChangedContents():
3287 if not comment_pattern.search(line) and pattern.search(line):
3288 problems.append((f.LocalPath(), line_num, line))
[email protected]06e6d0ff2012-12-11 01:36:443289
Sam Maiera6e76d72022-02-11 21:43:503290 if problems:
3291 return [
3292 output_api.PresubmitPromptOrNotify(
3293 'Most layers below src/chrome/ should not hardcode service URLs.\n'
3294 'Are you sure this is correct?', [
3295 ' %s:%d: %s' % (problem[0], problem[1], problem[2])
3296 for problem in problems
3297 ])
3298 ]
3299 else:
3300 return []
[email protected]06e6d0ff2012-12-11 01:36:443301
3302
Saagar Sanghavifceeaae2020-08-12 16:40:363303def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503304 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
James Cook6b6597c2019-11-06 22:05:293305
Sam Maiera6e76d72022-02-11 21:43:503306 def FileFilter(affected_file):
3307 """Includes directories known to be Chrome OS only."""
3308 return input_api.FilterSourceFile(
3309 affected_file,
3310 files_to_check=(
3311 '^ash/',
3312 '^chromeos/', # Top-level src/chromeos.
3313 '.*/chromeos/', # Any path component.
3314 '^components/arc',
3315 '^components/exo'),
3316 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:293317
Sam Maiera6e76d72022-02-11 21:43:503318 prefs = []
3319 priority_prefs = []
3320 for f in input_api.AffectedFiles(file_filter=FileFilter):
3321 for line_num, line in f.ChangedContents():
3322 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF',
3323 line):
3324 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
3325 prefs.append(' %s' % line)
3326 if input_api.re.search(
3327 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
3328 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
3329 priority_prefs.append(' %s' % line)
3330
3331 results = []
3332 if (prefs):
3333 results.append(
3334 output_api.PresubmitPromptWarning(
3335 'Preferences were registered as SYNCABLE_PREF and will be controlled '
3336 'by browser sync settings. If these prefs should be controlled by OS '
3337 'sync settings use SYNCABLE_OS_PREF instead.\n' +
3338 '\n'.join(prefs)))
3339 if (priority_prefs):
3340 results.append(
3341 output_api.PresubmitPromptWarning(
3342 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
3343 'controlled by browser sync settings. If these prefs should be '
3344 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
3345 'instead.\n' + '\n'.join(prefs)))
3346 return results
James Cook6b6597c2019-11-06 22:05:293347
3348
Saagar Sanghavifceeaae2020-08-12 16:40:363349def CheckNoAbbreviationInPngFileName(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503350 """Makes sure there are no abbreviations in the name of PNG files.
3351 The native_client_sdk directory is excluded because it has auto-generated PNG
3352 files for documentation.
3353 """
3354 errors = []
Yuanqing Zhu9eef02832022-12-04 14:42:173355 files_to_check = [r'.*\.png$']
Bruce Dawson40fece62022-09-16 19:58:313356 files_to_skip = [r'^native_client_sdk/',
3357 r'^services/test/',
3358 r'^third_party/blink/web_tests/',
Bruce Dawson3db456212022-05-02 05:34:183359 ]
Sam Maiera6e76d72022-02-11 21:43:503360 file_filter = lambda f: input_api.FilterSourceFile(
3361 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Yuanqing Zhu9eef02832022-12-04 14:42:173362 abbreviation = input_api.re.compile('.+_[a-z]\.png|.+_[a-z]_.*\.png')
Sam Maiera6e76d72022-02-11 21:43:503363 for f in input_api.AffectedFiles(include_deletes=False,
3364 file_filter=file_filter):
Yuanqing Zhu9eef02832022-12-04 14:42:173365 file_name = input_api.os_path.split(f.LocalPath())[1]
3366 if abbreviation.search(file_name):
3367 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:273368
Sam Maiera6e76d72022-02-11 21:43:503369 results = []
3370 if errors:
3371 results.append(
3372 output_api.PresubmitError(
3373 'The name of PNG files should not have abbreviations. \n'
3374 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
3375 'Contact [email protected] if you have questions.', errors))
3376 return results
[email protected]d2530012013-01-25 16:39:273377
Evan Stade7cd4a2c2022-08-04 23:37:253378def CheckNoProductIconsAddedToPublicRepo(input_api, output_api):
3379 """Heuristically identifies product icons based on their file name and reminds
3380 contributors not to add them to the Chromium repository.
3381 """
3382 errors = []
3383 files_to_check = [r'.*google.*\.png$|.*google.*\.svg$|.*google.*\.icon$']
3384 file_filter = lambda f: input_api.FilterSourceFile(
3385 f, files_to_check=files_to_check)
3386 for f in input_api.AffectedFiles(include_deletes=False,
3387 file_filter=file_filter):
3388 errors.append(' %s' % f.LocalPath())
3389
3390 results = []
3391 if errors:
Bruce Dawson3bcf0c92022-08-12 00:03:083392 # Give warnings instead of errors on presubmit --all and presubmit
3393 # --files.
3394 message_type = (output_api.PresubmitNotifyResult if input_api.no_diffs
3395 else output_api.PresubmitError)
Evan Stade7cd4a2c2022-08-04 23:37:253396 results.append(
Bruce Dawson3bcf0c92022-08-12 00:03:083397 message_type(
Evan Stade7cd4a2c2022-08-04 23:37:253398 'Trademarked images should not be added to the public repo. '
3399 'See crbug.com/944754', errors))
3400 return results
3401
[email protected]d2530012013-01-25 16:39:273402
Daniel Cheng4dcdb6b2017-04-13 08:30:173403def _ExtractAddRulesFromParsedDeps(parsed_deps):
Sam Maiera6e76d72022-02-11 21:43:503404 """Extract the rules that add dependencies from a parsed DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:173405
Sam Maiera6e76d72022-02-11 21:43:503406 Args:
3407 parsed_deps: the locals dictionary from evaluating the DEPS file."""
3408 add_rules = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:173409 add_rules.update([
Sam Maiera6e76d72022-02-11 21:43:503410 rule[1:] for rule in parsed_deps.get('include_rules', [])
Daniel Cheng4dcdb6b2017-04-13 08:30:173411 if rule.startswith('+') or rule.startswith('!')
3412 ])
Sam Maiera6e76d72022-02-11 21:43:503413 for _, rules in parsed_deps.get('specific_include_rules', {}).items():
3414 add_rules.update([
3415 rule[1:] for rule in rules
3416 if rule.startswith('+') or rule.startswith('!')
3417 ])
3418 return add_rules
Daniel Cheng4dcdb6b2017-04-13 08:30:173419
3420
3421def _ParseDeps(contents):
Sam Maiera6e76d72022-02-11 21:43:503422 """Simple helper for parsing DEPS files."""
Daniel Cheng4dcdb6b2017-04-13 08:30:173423
Sam Maiera6e76d72022-02-11 21:43:503424 # Stubs for handling special syntax in the root DEPS file.
3425 class _VarImpl:
3426 def __init__(self, local_scope):
3427 self._local_scope = local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:173428
Sam Maiera6e76d72022-02-11 21:43:503429 def Lookup(self, var_name):
3430 """Implements the Var syntax."""
3431 try:
3432 return self._local_scope['vars'][var_name]
3433 except KeyError:
3434 raise Exception('Var is not defined: %s' % var_name)
Daniel Cheng4dcdb6b2017-04-13 08:30:173435
Sam Maiera6e76d72022-02-11 21:43:503436 local_scope = {}
3437 global_scope = {
3438 'Var': _VarImpl(local_scope).Lookup,
3439 'Str': str,
3440 }
Dirk Pranke1b9e06382021-05-14 01:16:223441
Sam Maiera6e76d72022-02-11 21:43:503442 exec(contents, global_scope, local_scope)
3443 return local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:173444
3445
3446def _CalculateAddedDeps(os_path, old_contents, new_contents):
Sam Maiera6e76d72022-02-11 21:43:503447 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
3448 a set of DEPS entries that we should look up.
[email protected]14a6131c2014-01-08 01:15:413449
Sam Maiera6e76d72022-02-11 21:43:503450 For a directory (rather than a specific filename) we fake a path to
3451 a specific filename by adding /DEPS. This is chosen as a file that
3452 will seldom or never be subject to per-file include_rules.
3453 """
3454 # We ignore deps entries on auto-generated directories.
3455 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:083456
Sam Maiera6e76d72022-02-11 21:43:503457 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
3458 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
Daniel Cheng4dcdb6b2017-04-13 08:30:173459
Sam Maiera6e76d72022-02-11 21:43:503460 added_deps = new_deps.difference(old_deps)
Daniel Cheng4dcdb6b2017-04-13 08:30:173461
Sam Maiera6e76d72022-02-11 21:43:503462 results = set()
3463 for added_dep in added_deps:
3464 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
3465 continue
3466 # Assume that a rule that ends in .h is a rule for a specific file.
3467 if added_dep.endswith('.h'):
3468 results.add(added_dep)
3469 else:
3470 results.add(os_path.join(added_dep, 'DEPS'))
3471 return results
[email protected]f32e2d1e2013-07-26 21:39:083472
Stephanie Kimec4f55a2024-04-24 16:54:023473def CheckForNewDEPSDownloadFromGoogleStorageHooks(input_api, output_api):
3474 """Checks that there are no new download_from_google_storage hooks"""
3475 for f in input_api.AffectedFiles(include_deletes=False):
3476 if f.LocalPath() == 'DEPS':
3477 old_hooks = _ParseDeps('\n'.join(f.OldContents()))['hooks']
3478 new_hooks = _ParseDeps('\n'.join(f.NewContents()))['hooks']
3479 old_name_to_hook = {hook['name']: hook for hook in old_hooks}
3480 new_name_to_hook = {hook['name']: hook for hook in new_hooks}
3481 added_hook_names = set(new_name_to_hook.keys()) - set(
3482 old_name_to_hook.keys())
3483 if not added_hook_names:
3484 return []
3485 new_download_from_google_storage_hooks = []
3486 for new_hook in added_hook_names:
3487 hook = new_name_to_hook[new_hook]
3488 action_cmd = hook['action']
3489 if any('download_from_google_storage' in arg
3490 for arg in action_cmd):
3491 new_download_from_google_storage_hooks.append(new_hook)
3492 if new_download_from_google_storage_hooks:
3493 return [
3494 output_api.PresubmitError(
3495 'Please do not add new download_from_google_storage '
3496 'hooks. Instead, add a `gcs` dep_type entry to `deps`. '
3497 'See https://chromium.googlesource.com/chromium/src.git'
3498 '/+/refs/heads/main/docs/gcs_dependencies.md for more '
3499 'info. Added hooks:',
3500 items=new_download_from_google_storage_hooks)
3501 ]
3502 return []
3503
[email protected]f32e2d1e2013-07-26 21:39:083504
Rasika Navarangec2d33d22024-05-23 15:19:023505def CheckEachPerfettoTestDataFileHasDepsEntry(input_api, output_api):
3506 test_data_filter = lambda f: input_api.FilterSourceFile(
Rasika Navarange08e542162024-05-31 13:31:263507 f, files_to_check=[r'^base/tracing/test/data_sha256/.*\.sha256'])
Rasika Navarangec2d33d22024-05-23 15:19:023508 if not any(input_api.AffectedFiles(file_filter=test_data_filter)):
3509 return []
3510
3511 # Find DEPS entry
3512 deps_entry = []
Rasika Navarange277cd662024-06-04 10:14:593513 old_deps_entry = []
Rasika Navarangec2d33d22024-05-23 15:19:023514 for f in input_api.AffectedFiles(include_deletes=False):
3515 if f.LocalPath() == 'DEPS':
3516 new_deps = _ParseDeps('\n'.join(f.NewContents()))['deps']
3517 deps_entry = new_deps['src/base/tracing/test/data']
Rasika Navarange277cd662024-06-04 10:14:593518 old_deps = _ParseDeps('\n'.join(f.OldContents()))['deps']
3519 old_deps_entry = old_deps['src/base/tracing/test/data']
Rasika Navarangec2d33d22024-05-23 15:19:023520 if not deps_entry:
Rasika Navarange08e542162024-05-31 13:31:263521 # TODO(312895063):Add back error when .sha256 files have been moved.
Rasika Navaranged977df342024-06-05 10:01:273522 return [output_api.PresubmitError(
Rasika Navarangec2d33d22024-05-23 15:19:023523 'You must update the DEPS file when you update a '
Rasika Navarange08e542162024-05-31 13:31:263524 '.sha256 file in base/tracing/test/data_sha256'
Rasika Navarangec2d33d22024-05-23 15:19:023525 )]
3526
3527 output = []
3528 for f in input_api.AffectedFiles(file_filter=test_data_filter):
3529 objects = deps_entry['objects']
3530 if not f.NewContents():
3531 # Deleted file so check that DEPS entry removed
3532 sha256_from_file = f.OldContents()[0]
3533 object_entry = next(
3534 (item for item in objects if item["sha256sum"] == sha256_from_file),
3535 None)
Rasika Navarange277cd662024-06-04 10:14:593536 old_entry = next(
3537 (item for item in old_deps_entry['objects'] if item["sha256sum"] == sha256_from_file),
3538 None)
Rasika Navarangec2d33d22024-05-23 15:19:023539 if object_entry:
Rasika Navarange277cd662024-06-04 10:14:593540 # Allow renaming of objects with the same hash
3541 if object_entry['object_name'] != old_entry['object_name']:
3542 continue
Rasika Navarangec2d33d22024-05-23 15:19:023543 output.append(output_api.PresubmitError(
3544 'You deleted %s so you must also remove the corresponding DEPS entry.'
3545 % f.LocalPath()
3546 ))
3547 continue
3548
3549 sha256_from_file = f.NewContents()[0]
3550 object_entry = next(
3551 (item for item in objects if item["sha256sum"] == sha256_from_file),
3552 None)
3553 if not object_entry:
3554 output.append(output_api.PresubmitError(
3555 'No corresponding DEPS entry found for %s. '
3556 'Run `base/tracing/test/test_data.py get_deps --filepath %s` '
3557 'to generate the DEPS entry.'
3558 % (f.LocalPath(), f.LocalPath())
3559 ))
3560
3561 if output:
3562 output.append(output_api.PresubmitError(
3563 'The DEPS entry for `src/base/tracing/test/data` in the DEPS file has not been '
3564 'updated properly. Run `base/tracing/test/test_data.py get_all_deps` to see what '
3565 'the DEPS entry should look like.'
3566 ))
3567 return output
3568
3569
Saagar Sanghavifceeaae2020-08-12 16:40:363570def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503571 """When a dependency prefixed with + is added to a DEPS file, we
3572 want to make sure that the change is reviewed by an OWNER of the
3573 target file or directory, to avoid layering violations from being
3574 introduced. This check verifies that this happens.
3575 """
3576 # We rely on Gerrit's code-owners to check approvals.
3577 # input_api.gerrit is always set for Chromium, but other projects
3578 # might not use Gerrit.
Bruce Dawson344ab262022-06-04 11:35:103579 if not input_api.gerrit or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:503580 return []
Bruce Dawsonb357aeb2022-08-09 15:38:303581 if 'PRESUBMIT_SKIP_NETWORK' in input_api.environ:
Sam Maiera6e76d72022-02-11 21:43:503582 return []
Bruce Dawsonb357aeb2022-08-09 15:38:303583 try:
3584 if (input_api.change.issue and
3585 input_api.gerrit.IsOwnersOverrideApproved(
3586 input_api.change.issue)):
3587 # Skip OWNERS check when Owners-Override label is approved. This is
3588 # intended for global owners, trusted bots, and on-call sheriffs.
3589 # Review is still required for these changes.
3590 return []
3591 except Exception as e:
Sam Maier4cef9242022-10-03 14:21:243592 return [output_api.PresubmitPromptWarning(
3593 'Failed to retrieve owner override status - %s' % str(e))]
Edward Lesmes6fba51082021-01-20 04:20:233594
Sam Maiera6e76d72022-02-11 21:43:503595 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:243596
Bruce Dawson40fece62022-09-16 19:58:313597 # Consistently use / as path separator to simplify the writing of regex
3598 # expressions.
Sam Maiera6e76d72022-02-11 21:43:503599 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:313600 r"^third_party/blink/.*",
3601 f.LocalPath().replace(input_api.os_path.sep, '/'))
Sam Maiera6e76d72022-02-11 21:43:503602 for f in input_api.AffectedFiles(include_deletes=False,
3603 file_filter=file_filter):
3604 filename = input_api.os_path.basename(f.LocalPath())
3605 if filename == 'DEPS':
3606 virtual_depended_on_files.update(
3607 _CalculateAddedDeps(input_api.os_path,
3608 '\n'.join(f.OldContents()),
3609 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:553610
Sam Maiera6e76d72022-02-11 21:43:503611 if not virtual_depended_on_files:
3612 return []
[email protected]e871964c2013-05-13 14:14:553613
Sam Maiera6e76d72022-02-11 21:43:503614 if input_api.is_committing:
3615 if input_api.tbr:
3616 return [
3617 output_api.PresubmitNotifyResult(
3618 '--tbr was specified, skipping OWNERS check for DEPS additions'
3619 )
3620 ]
Daniel Cheng3008dc12022-05-13 04:02:113621 # TODO(dcheng): Make this generate an error on dry runs if the reviewer
3622 # is not added, to prevent review serialization.
Sam Maiera6e76d72022-02-11 21:43:503623 if input_api.dry_run:
3624 return [
3625 output_api.PresubmitNotifyResult(
3626 'This is a dry run, skipping OWNERS check for DEPS additions'
3627 )
3628 ]
3629 if not input_api.change.issue:
3630 return [
3631 output_api.PresubmitError(
3632 "DEPS approval by OWNERS check failed: this change has "
3633 "no change number, so we can't check it for approvals.")
3634 ]
3635 output = output_api.PresubmitError
[email protected]14a6131c2014-01-08 01:15:413636 else:
Sam Maiera6e76d72022-02-11 21:43:503637 output = output_api.PresubmitNotifyResult
[email protected]e871964c2013-05-13 14:14:553638
Sam Maiera6e76d72022-02-11 21:43:503639 owner_email, reviewers = (
3640 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3641 input_api, None, approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:553642
Sam Maiera6e76d72022-02-11 21:43:503643 owner_email = owner_email or input_api.change.author_email
3644
3645 approval_status = input_api.owners_client.GetFilesApprovalStatus(
3646 virtual_depended_on_files, reviewers.union([owner_email]), [])
3647 missing_files = [
3648 f for f in virtual_depended_on_files
3649 if approval_status[f] != input_api.owners_client.APPROVED
3650 ]
3651
3652 # We strip the /DEPS part that was added by
3653 # _FilesToCheckForIncomingDeps to fake a path to a file in a
3654 # directory.
3655 def StripDeps(path):
3656 start_deps = path.rfind('/DEPS')
3657 if start_deps != -1:
3658 return path[:start_deps]
3659 else:
3660 return path
3661
Scott Leebf6a0942024-06-26 22:59:393662 submodule_paths = set(input_api.ListSubmodules())
3663 def is_from_submodules(path, submodule_paths):
3664 path = input_api.os_path.normpath(path)
3665 while path:
3666 if path in submodule_paths:
3667 return True
3668
3669 # All deps should be a relative path from the checkout.
3670 # i.e., shouldn't start with "/" or "c:\", for example.
3671 #
3672 # That said, this is to prevent an infinite loop, just in case
3673 # an input dep path starts with "/", because
3674 # os.path.dirname("/") => "/"
3675 parent = input_api.os_path.dirname(path)
3676 if parent == path:
3677 break
3678 path = parent
3679
3680 return False
3681
Sam Maiera6e76d72022-02-11 21:43:503682 unapproved_dependencies = [
3683 "'+%s'," % StripDeps(path) for path in missing_files
Scott Leebf6a0942024-06-26 22:59:393684 # if a newly added dep is from a submodule, it becomes trickier
3685 # to get suggested owners, especially it is from a different host.
3686 #
3687 # skip the review enforcement for cross-repo deps.
3688 if not is_from_submodules(path, submodule_paths)
Sam Maiera6e76d72022-02-11 21:43:503689 ]
3690
3691 if unapproved_dependencies:
3692 output_list = [
3693 output(
3694 'You need LGTM from owners of depends-on paths in DEPS that were '
3695 'modified in this CL:\n %s' %
3696 '\n '.join(sorted(unapproved_dependencies)))
3697 ]
3698 suggested_owners = input_api.owners_client.SuggestOwners(
3699 missing_files, exclude=[owner_email])
3700 output_list.append(
3701 output('Suggested missing target path OWNERS:\n %s' %
3702 '\n '.join(suggested_owners or [])))
3703 return output_list
3704
3705 return []
[email protected]e871964c2013-05-13 14:14:553706
3707
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493708# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:363709def CheckSpamLogging(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503710 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3711 files_to_skip = (
3712 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3713 input_api.DEFAULT_FILES_TO_SKIP + (
Jaewon Jung2f323bb2022-12-07 23:55:013714 r"^base/fuchsia/scoped_fx_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313715 r"^base/logging\.h$",
3716 r"^base/logging\.cc$",
3717 r"^base/task/thread_pool/task_tracker\.cc$",
3718 r"^chrome/app/chrome_main_delegate\.cc$",
Yao Li359937b2023-02-15 23:43:033719 r"^chrome/browser/ash/arc/enterprise/cert_store/arc_cert_installer\.cc$",
3720 r"^chrome/browser/ash/policy/remote_commands/user_command_arc_job\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313721 r"^chrome/browser/chrome_browser_main\.cc$",
3722 r"^chrome/browser/ui/startup/startup_browser_creator\.cc$",
3723 r"^chrome/browser/browser_switcher/bho/.*",
3724 r"^chrome/browser/diagnostics/diagnostics_writer\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313725 r"^chrome/chrome_elf/dll_hash/dll_hash_main\.cc$",
3726 r"^chrome/installer/setup/.*",
Daniel Ruberyad36eea2024-08-01 01:38:323727 # crdmg runs as a separate binary which intentionally does
3728 # not depend on base logging.
3729 r"^chrome/utility/safe_browsing/mac/crdmg\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313730 r"^chromecast/",
Vigen Issahhanjane2d93822023-06-30 15:57:203731 r"^components/cast",
Bruce Dawson40fece62022-09-16 19:58:313732 r"^components/media_control/renderer/media_playback_options\.cc$",
Salma Elmahallawy52976452023-01-27 17:04:493733 r"^components/policy/core/common/policy_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313734 r"^components/viz/service/display/"
Sam Maiera6e76d72022-02-11 21:43:503735 r"overlay_strategy_underlay_cast\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313736 r"^components/zucchini/.*",
Sam Maiera6e76d72022-02-11 21:43:503737 # TODO(peter): Remove exception. https://crbug.com/534537
Bruce Dawson40fece62022-09-16 19:58:313738 r"^content/browser/notifications/"
Sam Maiera6e76d72022-02-11 21:43:503739 r"notification_event_dispatcher_impl\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313740 r"^content/common/gpu/client/gl_helper_benchmark\.cc$",
3741 r"^courgette/courgette_minimal_tool\.cc$",
3742 r"^courgette/courgette_tool\.cc$",
3743 r"^extensions/renderer/logging_native_handler\.cc$",
3744 r"^fuchsia_web/common/init_logging\.cc$",
3745 r"^fuchsia_web/runners/common/web_component\.cc$",
Caroline Liua7050132023-02-13 22:23:153746 r"^fuchsia_web/shell/.*\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313747 r"^headless/app/headless_shell\.cc$",
3748 r"^ipc/ipc_logging\.cc$",
3749 r"^native_client_sdk/",
3750 r"^remoting/base/logging\.h$",
3751 r"^remoting/host/.*",
3752 r"^sandbox/linux/.*",
Austin Sullivana6054e02024-05-20 16:31:293753 r"^services/webnn/tflite/graph_impl_tflite\.cc$",
3754 r"^services/webnn/coreml/graph_impl_coreml\.mm$",
Bruce Dawson40fece62022-09-16 19:58:313755 r"^storage/browser/file_system/dump_file_system\.cc$",
Steinar H. Gundersone5689e42024-08-07 18:17:193756 r"^testing/perf/",
Bruce Dawson40fece62022-09-16 19:58:313757 r"^tools/",
3758 r"^ui/base/resource/data_pack\.cc$",
3759 r"^ui/aura/bench/bench_main\.cc$",
3760 r"^ui/ozone/platform/cast/",
3761 r"^ui/base/x/xwmstartupcheck/"
Sam Maiera6e76d72022-02-11 21:43:503762 r"xwmstartupcheck\.cc$"))
3763 source_file_filter = lambda x: input_api.FilterSourceFile(
3764 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:403765
Sam Maiera6e76d72022-02-11 21:43:503766 log_info = set([])
3767 printf = set([])
[email protected]85218562013-11-22 07:41:403768
Sam Maiera6e76d72022-02-11 21:43:503769 for f in input_api.AffectedSourceFiles(source_file_filter):
3770 for _, line in f.ChangedContents():
3771 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
3772 log_info.add(f.LocalPath())
3773 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
3774 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:373775
Sam Maiera6e76d72022-02-11 21:43:503776 if input_api.re.search(r"\bprintf\(", line):
3777 printf.add(f.LocalPath())
3778 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
3779 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:403780
Sam Maiera6e76d72022-02-11 21:43:503781 if log_info:
3782 return [
3783 output_api.PresubmitError(
3784 'These files spam the console log with LOG(INFO):',
3785 items=log_info)
3786 ]
3787 if printf:
3788 return [
3789 output_api.PresubmitError(
3790 'These files spam the console log with printf/fprintf:',
3791 items=printf)
3792 ]
3793 return []
[email protected]85218562013-11-22 07:41:403794
3795
Saagar Sanghavifceeaae2020-08-12 16:40:363796def CheckForAnonymousVariables(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503797 """These types are all expected to hold locks while in scope and
3798 so should never be anonymous (which causes them to be immediately
3799 destroyed)."""
3800 they_who_must_be_named = [
3801 'base::AutoLock',
3802 'base::AutoReset',
3803 'base::AutoUnlock',
3804 'SkAutoAlphaRestore',
3805 'SkAutoBitmapShaderInstall',
3806 'SkAutoBlitterChoose',
3807 'SkAutoBounderCommit',
3808 'SkAutoCallProc',
3809 'SkAutoCanvasRestore',
3810 'SkAutoCommentBlock',
3811 'SkAutoDescriptor',
3812 'SkAutoDisableDirectionCheck',
3813 'SkAutoDisableOvalCheck',
3814 'SkAutoFree',
3815 'SkAutoGlyphCache',
3816 'SkAutoHDC',
3817 'SkAutoLockColors',
3818 'SkAutoLockPixels',
3819 'SkAutoMalloc',
3820 'SkAutoMaskFreeImage',
3821 'SkAutoMutexAcquire',
3822 'SkAutoPathBoundsUpdate',
3823 'SkAutoPDFRelease',
3824 'SkAutoRasterClipValidate',
3825 'SkAutoRef',
3826 'SkAutoTime',
3827 'SkAutoTrace',
3828 'SkAutoUnref',
3829 ]
3830 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
3831 # bad: base::AutoLock(lock.get());
3832 # not bad: base::AutoLock lock(lock.get());
3833 bad_pattern = input_api.re.compile(anonymous)
3834 # good: new base::AutoLock(lock.get())
3835 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
3836 errors = []
[email protected]49aa76a2013-12-04 06:59:163837
Sam Maiera6e76d72022-02-11 21:43:503838 for f in input_api.AffectedFiles():
3839 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
3840 continue
3841 for linenum, line in f.ChangedContents():
3842 if bad_pattern.search(line) and not good_pattern.search(line):
3843 errors.append('%s:%d' % (f.LocalPath(), linenum))
[email protected]49aa76a2013-12-04 06:59:163844
Sam Maiera6e76d72022-02-11 21:43:503845 if errors:
3846 return [
3847 output_api.PresubmitError(
3848 'These lines create anonymous variables that need to be named:',
3849 items=errors)
3850 ]
3851 return []
[email protected]49aa76a2013-12-04 06:59:163852
3853
Saagar Sanghavifceeaae2020-08-12 16:40:363854def CheckUniquePtrOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503855 # Returns whether |template_str| is of the form <T, U...> for some types T
Glen Robertson9142ffd72024-05-16 01:37:473856 # and U, or is invalid due to mismatched angle bracket pairs. Assumes that
3857 # |template_str| is already in the form <...>.
3858 def HasMoreThanOneArgOrInvalid(template_str):
Sam Maiera6e76d72022-02-11 21:43:503859 # Level of <...> nesting.
3860 nesting = 0
3861 for c in template_str:
3862 if c == '<':
3863 nesting += 1
3864 elif c == '>':
3865 nesting -= 1
3866 elif c == ',' and nesting == 1:
3867 return True
Glen Robertson9142ffd72024-05-16 01:37:473868 if nesting != 0:
Daniel Cheng566634ff2024-06-29 14:56:533869 # Invalid.
3870 return True
Sam Maiera6e76d72022-02-11 21:43:503871 return False
Vaclav Brozekb7fadb692018-08-30 06:39:533872
Sam Maiera6e76d72022-02-11 21:43:503873 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3874 sources = lambda affected_file: input_api.FilterSourceFile(
3875 affected_file,
3876 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3877 DEFAULT_FILES_TO_SKIP),
3878 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:553879
Sam Maiera6e76d72022-02-11 21:43:503880 # Pattern to capture a single "<...>" block of template arguments. It can
3881 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
3882 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
3883 # latter would likely require counting that < and > match, which is not
3884 # expressible in regular languages. Should the need arise, one can introduce
3885 # limited counting (matching up to a total number of nesting depth), which
3886 # should cover all practical cases for already a low nesting limit.
3887 template_arg_pattern = (
3888 r'<[^>]*' # Opening block of <.
3889 r'>([^<]*>)?') # Closing block of >.
3890 # Prefix expressing that whatever follows is not already inside a <...>
3891 # block.
3892 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
3893 null_construct_pattern = input_api.re.compile(
3894 not_inside_template_arg_pattern + r'\bstd::unique_ptr' +
3895 template_arg_pattern + r'\(\)')
Vaclav Brozeka54c528b2018-04-06 19:23:553896
Sam Maiera6e76d72022-02-11 21:43:503897 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
3898 template_arg_no_array_pattern = (
3899 r'<[^>]*[^]]' # Opening block of <.
3900 r'>([^(<]*[^]]>)?') # Closing block of >.
3901 # Prefix saying that what follows is the start of an expression.
3902 start_of_expr_pattern = r'(=|\breturn|^)\s*'
3903 # Suffix saying that what follows are call parentheses with a non-empty list
3904 # of arguments.
3905 nonempty_arg_list_pattern = r'\(([^)]|$)'
3906 # Put the template argument into a capture group for deeper examination later.
3907 return_construct_pattern = input_api.re.compile(
3908 start_of_expr_pattern + r'std::unique_ptr' + '(?P<template_arg>' +
3909 template_arg_no_array_pattern + ')' + nonempty_arg_list_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:553910
Sam Maiera6e76d72022-02-11 21:43:503911 problems_constructor = []
3912 problems_nullptr = []
3913 for f in input_api.AffectedSourceFiles(sources):
3914 for line_number, line in f.ChangedContents():
3915 # Disallow:
3916 # return std::unique_ptr<T>(foo);
3917 # bar = std::unique_ptr<T>(foo);
3918 # But allow:
3919 # return std::unique_ptr<T[]>(foo);
3920 # bar = std::unique_ptr<T[]>(foo);
3921 # And also allow cases when the second template argument is present. Those
3922 # cases cannot be handled by std::make_unique:
3923 # return std::unique_ptr<T, U>(foo);
3924 # bar = std::unique_ptr<T, U>(foo);
3925 local_path = f.LocalPath()
3926 return_construct_result = return_construct_pattern.search(line)
Glen Robertson9142ffd72024-05-16 01:37:473927 if return_construct_result and not HasMoreThanOneArgOrInvalid(
Sam Maiera6e76d72022-02-11 21:43:503928 return_construct_result.group('template_arg')):
3929 problems_constructor.append(
3930 '%s:%d\n %s' % (local_path, line_number, line.strip()))
3931 # Disallow:
3932 # std::unique_ptr<T>()
3933 if null_construct_pattern.search(line):
3934 problems_nullptr.append(
3935 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Vaclav Brozek851d9602018-04-04 16:13:053936
Sam Maiera6e76d72022-02-11 21:43:503937 errors = []
3938 if problems_nullptr:
3939 errors.append(
3940 output_api.PresubmitPromptWarning(
3941 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
3942 problems_nullptr))
3943 if problems_constructor:
3944 errors.append(
3945 output_api.PresubmitError(
3946 'The following files use explicit std::unique_ptr constructor. '
3947 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
3948 'std::make_unique is not an option.', problems_constructor))
3949 return errors
Peter Kasting4844e46e2018-02-23 07:27:103950
3951
Saagar Sanghavifceeaae2020-08-12 16:40:363952def CheckUserActionUpdate(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503953 """Checks if any new user action has been added."""
3954 if any('actions.xml' == input_api.os_path.basename(f)
3955 for f in input_api.LocalPaths()):
3956 # If actions.xml is already included in the changelist, the PRESUBMIT
3957 # for actions.xml will do a more complete presubmit check.
3958 return []
3959
3960 file_inclusion_pattern = [r'.*\.(cc|mm)$']
3961 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3962 input_api.DEFAULT_FILES_TO_SKIP)
3963 file_filter = lambda f: input_api.FilterSourceFile(
3964 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
3965
3966 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
3967 current_actions = None
3968 for f in input_api.AffectedFiles(file_filter=file_filter):
3969 for line_num, line in f.ChangedContents():
3970 match = input_api.re.search(action_re, line)
3971 if match:
3972 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
3973 # loaded only once.
3974 if not current_actions:
Bruce Dawson6cb2d4d2023-03-01 21:35:093975 with open('tools/metrics/actions/actions.xml',
3976 encoding='utf-8') as actions_f:
Sam Maiera6e76d72022-02-11 21:43:503977 current_actions = actions_f.read()
3978 # Search for the matched user action name in |current_actions|.
3979 for action_name in match.groups():
3980 action = 'name="{0}"'.format(action_name)
3981 if action not in current_actions:
3982 return [
3983 output_api.PresubmitPromptWarning(
3984 'File %s line %d: %s is missing in '
3985 'tools/metrics/actions/actions.xml. Please run '
3986 'tools/metrics/actions/extract_actions.py to update.'
3987 % (f.LocalPath(), line_num, action_name))
3988 ]
[email protected]999261d2014-03-03 20:08:083989 return []
3990
[email protected]999261d2014-03-03 20:08:083991
Daniel Cheng13ca61a882017-08-25 15:11:253992def _ImportJSONCommentEater(input_api):
Sam Maiera6e76d72022-02-11 21:43:503993 import sys
3994 sys.path = sys.path + [
3995 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3996 'json_comment_eater')
3997 ]
3998 import json_comment_eater
3999 return json_comment_eater
Daniel Cheng13ca61a882017-08-25 15:11:254000
4001
[email protected]99171a92014-06-03 08:44:474002def _GetJSONParseError(input_api, filename, eat_comments=True):
dchenge07de812016-06-20 19:27:174003 try:
Sam Maiera6e76d72022-02-11 21:43:504004 contents = input_api.ReadFile(filename)
4005 if eat_comments:
4006 json_comment_eater = _ImportJSONCommentEater(input_api)
4007 contents = json_comment_eater.Nom(contents)
dchenge07de812016-06-20 19:27:174008
Sam Maiera6e76d72022-02-11 21:43:504009 input_api.json.loads(contents)
4010 except ValueError as e:
4011 return e
Andrew Grieve4deedb12022-02-03 21:34:504012 return None
4013
4014
Sam Maiera6e76d72022-02-11 21:43:504015def _GetIDLParseError(input_api, filename):
4016 try:
4017 contents = input_api.ReadFile(filename)
Devlin Croninf7582a12022-04-21 21:14:284018 for i, char in enumerate(contents):
Daniel Chenga37c03db2022-05-12 17:20:344019 if not char.isascii():
4020 return (
4021 'Non-ascii character "%s" (ord %d) found at offset %d.' %
4022 (char, ord(char), i))
Sam Maiera6e76d72022-02-11 21:43:504023 idl_schema = input_api.os_path.join(input_api.PresubmitLocalPath(),
4024 'tools', 'json_schema_compiler',
4025 'idl_schema.py')
4026 process = input_api.subprocess.Popen(
Bruce Dawson679fb082022-04-14 00:47:284027 [input_api.python3_executable, idl_schema],
Sam Maiera6e76d72022-02-11 21:43:504028 stdin=input_api.subprocess.PIPE,
4029 stdout=input_api.subprocess.PIPE,
4030 stderr=input_api.subprocess.PIPE,
4031 universal_newlines=True)
4032 (_, error) = process.communicate(input=contents)
4033 return error or None
4034 except ValueError as e:
4035 return e
agrievef32bcc72016-04-04 14:57:404036
agrievef32bcc72016-04-04 14:57:404037
Sam Maiera6e76d72022-02-11 21:43:504038def CheckParseErrors(input_api, output_api):
4039 """Check that IDL and JSON files do not contain syntax errors."""
4040 actions = {
4041 '.idl': _GetIDLParseError,
4042 '.json': _GetJSONParseError,
4043 }
4044 # Most JSON files are preprocessed and support comments, but these do not.
4045 json_no_comments_patterns = [
Bruce Dawson40fece62022-09-16 19:58:314046 r'^testing/',
Sam Maiera6e76d72022-02-11 21:43:504047 ]
4048 # Only run IDL checker on files in these directories.
4049 idl_included_patterns = [
Bruce Dawson40fece62022-09-16 19:58:314050 r'^chrome/common/extensions/api/',
4051 r'^extensions/common/api/',
Sam Maiera6e76d72022-02-11 21:43:504052 ]
agrievef32bcc72016-04-04 14:57:404053
Sam Maiera6e76d72022-02-11 21:43:504054 def get_action(affected_file):
4055 filename = affected_file.LocalPath()
4056 return actions.get(input_api.os_path.splitext(filename)[1])
agrievef32bcc72016-04-04 14:57:404057
Sam Maiera6e76d72022-02-11 21:43:504058 def FilterFile(affected_file):
4059 action = get_action(affected_file)
4060 if not action:
4061 return False
4062 path = affected_file.LocalPath()
agrievef32bcc72016-04-04 14:57:404063
Sam Maiera6e76d72022-02-11 21:43:504064 if _MatchesFile(input_api,
4065 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS, path):
4066 return False
4067
4068 if (action == _GetIDLParseError
4069 and not _MatchesFile(input_api, idl_included_patterns, path)):
4070 return False
4071 return True
4072
4073 results = []
4074 for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
4075 include_deletes=False):
4076 action = get_action(affected_file)
4077 kwargs = {}
4078 if (action == _GetJSONParseError
4079 and _MatchesFile(input_api, json_no_comments_patterns,
4080 affected_file.LocalPath())):
4081 kwargs['eat_comments'] = False
4082 parse_error = action(input_api, affected_file.AbsoluteLocalPath(),
4083 **kwargs)
4084 if parse_error:
4085 results.append(
4086 output_api.PresubmitError(
4087 '%s could not be parsed: %s' %
4088 (affected_file.LocalPath(), parse_error)))
4089 return results
4090
4091
4092def CheckJavaStyle(input_api, output_api):
4093 """Runs checkstyle on changed java files and returns errors if any exist."""
4094
4095 # Return early if no java files were modified.
4096 if not any(
4097 _IsJavaFile(input_api, f.LocalPath())
4098 for f in input_api.AffectedFiles()):
4099 return []
4100
4101 import sys
4102 original_sys_path = sys.path
4103 try:
4104 sys.path = sys.path + [
4105 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4106 'android', 'checkstyle')
4107 ]
4108 import checkstyle
4109 finally:
4110 # Restore sys.path to what it was before.
4111 sys.path = original_sys_path
4112
Andrew Grieve4f88e3ca2022-11-22 19:09:204113 return checkstyle.run_presubmit(
Sam Maiera6e76d72022-02-11 21:43:504114 input_api,
4115 output_api,
Sam Maiera6e76d72022-02-11 21:43:504116 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
4117
4118
4119def CheckPythonDevilInit(input_api, output_api):
4120 """Checks to make sure devil is initialized correctly in python scripts."""
4121 script_common_initialize_pattern = input_api.re.compile(
4122 r'script_common\.InitializeEnvironment\(')
4123 devil_env_config_initialize = input_api.re.compile(
4124 r'devil_env\.config\.Initialize\(')
4125
4126 errors = []
4127
4128 sources = lambda affected_file: input_api.FilterSourceFile(
4129 affected_file,
4130 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314131 r'^build/android/devil_chromium\.py',
Sven Zheng8e079562024-05-10 20:11:064132 r'^tools/bisect-builds\.py',
Bruce Dawson40fece62022-09-16 19:58:314133 r'^third_party/.*',
Sam Maiera6e76d72022-02-11 21:43:504134 )),
4135 files_to_check=[r'.*\.py$'])
4136
4137 for f in input_api.AffectedSourceFiles(sources):
4138 for line_num, line in f.ChangedContents():
4139 if (script_common_initialize_pattern.search(line)
4140 or devil_env_config_initialize.search(line)):
4141 errors.append("%s:%d" % (f.LocalPath(), line_num))
4142
4143 results = []
4144
4145 if errors:
4146 results.append(
4147 output_api.PresubmitError(
4148 'Devil initialization should always be done using '
4149 'devil_chromium.Initialize() in the chromium project, to use better '
4150 'defaults for dependencies (ex. up-to-date version of adb).',
4151 errors))
4152
4153 return results
4154
4155
4156def _MatchesFile(input_api, patterns, path):
Bruce Dawson40fece62022-09-16 19:58:314157 # Consistently use / as path separator to simplify the writing of regex
4158 # expressions.
4159 path = path.replace(input_api.os_path.sep, '/')
Sam Maiera6e76d72022-02-11 21:43:504160 for pattern in patterns:
4161 if input_api.re.search(pattern, path):
4162 return True
4163 return False
4164
4165
Daniel Chenga37c03db2022-05-12 17:20:344166def _ChangeHasSecurityReviewer(input_api, owners_file):
4167 """Returns True iff the CL has a reviewer from SECURITY_OWNERS.
Sam Maiera6e76d72022-02-11 21:43:504168
Daniel Chenga37c03db2022-05-12 17:20:344169 Args:
4170 input_api: The presubmit input API.
4171 owners_file: OWNERS file with required reviewers. Typically, this is
4172 something like ipc/SECURITY_OWNERS.
4173
4174 Note: if the presubmit is running for commit rather than for upload, this
4175 only returns True if a security reviewer has also approved the CL.
Sam Maiera6e76d72022-02-11 21:43:504176 """
Daniel Chengd88244472022-05-16 09:08:474177 # Owners-Override should bypass all additional OWNERS enforcement checks.
4178 # A CR+1 vote will still be required to land this change.
4179 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
4180 input_api.change.issue)):
4181 return True
4182
Daniel Chenga37c03db2022-05-12 17:20:344183 owner_email, reviewers = (
4184 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
Daniel Cheng3008dc12022-05-13 04:02:114185 input_api,
4186 None,
4187 approval_needed=input_api.is_committing and not input_api.dry_run))
Sam Maiera6e76d72022-02-11 21:43:504188
Daniel Chenga37c03db2022-05-12 17:20:344189 security_owners = input_api.owners_client.ListOwners(owners_file)
4190 return any(owner in reviewers for owner in security_owners)
Sam Maiera6e76d72022-02-11 21:43:504191
Daniel Chenga37c03db2022-05-12 17:20:344192
4193@dataclass
Daniel Cheng171dad8d2022-05-21 00:40:254194class _SecurityProblemWithItems:
4195 problem: str
4196 items: Sequence[str]
4197
4198
4199@dataclass
Daniel Chenga37c03db2022-05-12 17:20:344200class _MissingSecurityOwnersResult:
Daniel Cheng171dad8d2022-05-21 00:40:254201 owners_file_problems: Sequence[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:344202 has_security_sensitive_files: bool
Daniel Cheng171dad8d2022-05-21 00:40:254203 missing_reviewer_problem: Optional[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:344204
4205
4206def _FindMissingSecurityOwners(input_api,
4207 output_api,
4208 file_patterns: Sequence[str],
4209 excluded_patterns: Sequence[str],
4210 required_owners_file: str,
4211 custom_rule_function: Optional[Callable] = None
4212 ) -> _MissingSecurityOwnersResult:
4213 """Find OWNERS files missing per-file rules for security-sensitive files.
4214
4215 Args:
4216 input_api: the PRESUBMIT input API object.
4217 output_api: the PRESUBMIT output API object.
4218 file_patterns: basename patterns that require a corresponding per-file
4219 security restriction.
4220 excluded_patterns: path patterns that should be exempted from
4221 requiring a security restriction.
4222 required_owners_file: path to the required OWNERS file, e.g.
4223 ipc/SECURITY_OWNERS
4224 cc_alias: If not None, email that will be CCed automatically if the
4225 change contains security-sensitive files, as determined by
4226 `file_patterns` and `excluded_patterns`.
4227 custom_rule_function: If not None, will be called with `input_api` and
4228 the current file under consideration. Returning True will add an
4229 exact match per-file rule check for the current file.
4230 """
4231
4232 # `to_check` is a mapping of an OWNERS file path to Patterns.
4233 #
4234 # Patterns is a dictionary mapping glob patterns (suitable for use in
4235 # per-file rules) to a PatternEntry.
4236 #
Sam Maiera6e76d72022-02-11 21:43:504237 # PatternEntry is a dictionary with two keys:
4238 # - 'files': the files that are matched by this pattern
4239 # - 'rules': the per-file rules needed for this pattern
Daniel Chenga37c03db2022-05-12 17:20:344240 #
Sam Maiera6e76d72022-02-11 21:43:504241 # For example, if we expect OWNERS file to contain rules for *.mojom and
4242 # *_struct_traits*.*, Patterns might look like this:
4243 # {
4244 # '*.mojom': {
4245 # 'files': ...,
4246 # 'rules': [
4247 # 'per-file *.mojom=set noparent',
4248 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
4249 # ],
4250 # },
4251 # '*_struct_traits*.*': {
4252 # 'files': ...,
4253 # 'rules': [
4254 # 'per-file *_struct_traits*.*=set noparent',
4255 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
4256 # ],
4257 # },
4258 # }
4259 to_check = {}
Daniel Chenga37c03db2022-05-12 17:20:344260 files_to_review = []
Sam Maiera6e76d72022-02-11 21:43:504261
Daniel Chenga37c03db2022-05-12 17:20:344262 def AddPatternToCheck(file, pattern):
Sam Maiera6e76d72022-02-11 21:43:504263 owners_file = input_api.os_path.join(
Daniel Chengd88244472022-05-16 09:08:474264 input_api.os_path.dirname(file.LocalPath()), 'OWNERS')
Sam Maiera6e76d72022-02-11 21:43:504265 if owners_file not in to_check:
4266 to_check[owners_file] = {}
4267 if pattern not in to_check[owners_file]:
4268 to_check[owners_file][pattern] = {
4269 'files': [],
4270 'rules': [
Daniel Chenga37c03db2022-05-12 17:20:344271 f'per-file {pattern}=set noparent',
4272 f'per-file {pattern}=file://{required_owners_file}',
Sam Maiera6e76d72022-02-11 21:43:504273 ]
4274 }
Daniel Chenged57a162022-05-25 02:56:344275 to_check[owners_file][pattern]['files'].append(file.LocalPath())
Daniel Chenga37c03db2022-05-12 17:20:344276 files_to_review.append(file.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:504277
Daniel Chenga37c03db2022-05-12 17:20:344278 # Only enforce security OWNERS rules for a directory if that directory has a
4279 # file that matches `file_patterns`. For example, if a directory only
4280 # contains *.mojom files and no *_messages*.h files, the check should only
4281 # ensure that rules for *.mojom files are present.
4282 for file in input_api.AffectedFiles(include_deletes=False):
4283 file_basename = input_api.os_path.basename(file.LocalPath())
4284 if custom_rule_function is not None and custom_rule_function(
4285 input_api, file):
4286 AddPatternToCheck(file, file_basename)
4287 continue
Sam Maiera6e76d72022-02-11 21:43:504288
Daniel Chenga37c03db2022-05-12 17:20:344289 if any(
4290 input_api.fnmatch.fnmatch(file.LocalPath(), pattern)
4291 for pattern in excluded_patterns):
Sam Maiera6e76d72022-02-11 21:43:504292 continue
4293
4294 for pattern in file_patterns:
Daniel Chenga37c03db2022-05-12 17:20:344295 # Unlike `excluded_patterns`, `file_patterns` is checked only against the
4296 # file's basename.
4297 if input_api.fnmatch.fnmatch(file_basename, pattern):
4298 AddPatternToCheck(file, pattern)
Sam Maiera6e76d72022-02-11 21:43:504299 break
4300
Daniel Chenga37c03db2022-05-12 17:20:344301 has_security_sensitive_files = bool(to_check)
Daniel Cheng171dad8d2022-05-21 00:40:254302
4303 # Check if any newly added lines in OWNERS files intersect with required
4304 # per-file OWNERS lines. If so, ensure that a security reviewer is included.
4305 # This is a hack, but is needed because the OWNERS check (by design) ignores
4306 # new OWNERS entries; otherwise, a non-owner could add someone as a new
4307 # OWNER and have that newly-added OWNER self-approve their own addition.
4308 newly_covered_files = []
4309 for file in input_api.AffectedFiles(include_deletes=False):
4310 if not file.LocalPath() in to_check:
4311 continue
4312 for _, line in file.ChangedContents():
4313 for _, entry in to_check[file.LocalPath()].items():
4314 if line in entry['rules']:
4315 newly_covered_files.extend(entry['files'])
4316
4317 missing_reviewer_problems = None
4318 if newly_covered_files and not _ChangeHasSecurityReviewer(
Daniel Chenga37c03db2022-05-12 17:20:344319 input_api, required_owners_file):
Daniel Cheng171dad8d2022-05-21 00:40:254320 missing_reviewer_problems = _SecurityProblemWithItems(
4321 f'Review from an owner in {required_owners_file} is required for '
4322 'the following newly-added files:',
4323 [f'{file}' for file in sorted(set(newly_covered_files))])
Sam Maiera6e76d72022-02-11 21:43:504324
4325 # Go through the OWNERS files to check, filtering out rules that are already
4326 # present in that OWNERS file.
4327 for owners_file, patterns in to_check.items():
4328 try:
Daniel Cheng171dad8d2022-05-21 00:40:254329 lines = set(
4330 input_api.ReadFile(
4331 input_api.os_path.join(input_api.change.RepositoryRoot(),
4332 owners_file)).splitlines())
4333 for entry in patterns.values():
4334 entry['rules'] = [
4335 rule for rule in entry['rules'] if rule not in lines
4336 ]
Sam Maiera6e76d72022-02-11 21:43:504337 except IOError:
4338 # No OWNERS file, so all the rules are definitely missing.
4339 continue
4340
4341 # All the remaining lines weren't found in OWNERS files, so emit an error.
Daniel Cheng171dad8d2022-05-21 00:40:254342 owners_file_problems = []
Daniel Chenga37c03db2022-05-12 17:20:344343
Sam Maiera6e76d72022-02-11 21:43:504344 for owners_file, patterns in to_check.items():
4345 missing_lines = []
4346 files = []
4347 for _, entry in patterns.items():
Daniel Chenged57a162022-05-25 02:56:344348 files.extend(entry['files'])
Sam Maiera6e76d72022-02-11 21:43:504349 missing_lines.extend(entry['rules'])
Sam Maiera6e76d72022-02-11 21:43:504350 if missing_lines:
Daniel Cheng171dad8d2022-05-21 00:40:254351 joined_missing_lines = '\n'.join(line for line in missing_lines)
4352 owners_file_problems.append(
4353 _SecurityProblemWithItems(
4354 'Found missing OWNERS lines for security-sensitive files. '
4355 f'Please add the following lines to {owners_file}:\n'
4356 f'{joined_missing_lines}\n\nTo ensure security review for:',
4357 files))
Daniel Chenga37c03db2022-05-12 17:20:344358
Daniel Cheng171dad8d2022-05-21 00:40:254359 return _MissingSecurityOwnersResult(owners_file_problems,
Daniel Chenga37c03db2022-05-12 17:20:344360 has_security_sensitive_files,
Daniel Cheng171dad8d2022-05-21 00:40:254361 missing_reviewer_problems)
Daniel Chenga37c03db2022-05-12 17:20:344362
4363
4364def _CheckChangeForIpcSecurityOwners(input_api, output_api):
4365 # Whether or not a file affects IPC is (mostly) determined by a simple list
4366 # of filename patterns.
4367 file_patterns = [
4368 # Legacy IPC:
4369 '*_messages.cc',
4370 '*_messages*.h',
4371 '*_param_traits*.*',
4372 # Mojo IPC:
4373 '*.mojom',
4374 '*_mojom_traits*.*',
4375 '*_type_converter*.*',
4376 # Android native IPC:
4377 '*.aidl',
4378 ]
4379
Daniel Chenga37c03db2022-05-12 17:20:344380 excluded_patterns = [
Daniel Cheng518943f2022-05-12 22:15:464381 # These third_party directories do not contain IPCs, but contain files
4382 # matching the above patterns, which trigger false positives.
Daniel Chenga37c03db2022-05-12 17:20:344383 'third_party/crashpad/*',
4384 'third_party/blink/renderer/platform/bindings/*',
4385 'third_party/protobuf/benchmarks/python/*',
4386 'third_party/win_build_output/*',
Daniel Chengd88244472022-05-16 09:08:474387 # Enum-only mojoms used for web metrics, so no security review needed.
4388 'third_party/blink/public/mojom/use_counter/metrics/*',
Daniel Chenga37c03db2022-05-12 17:20:344389 # These files are just used to communicate between class loaders running
4390 # in the same process.
4391 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
4392 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
4393 ]
4394
4395 def IsMojoServiceManifestFile(input_api, file):
4396 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
4397 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
4398 if not manifest_pattern.search(file.LocalPath()):
4399 return False
4400
4401 if test_manifest_pattern.search(file.LocalPath()):
4402 return False
4403
4404 # All actual service manifest files should contain at least one
4405 # qualified reference to service_manager::Manifest.
4406 return any('service_manager::Manifest' in line
4407 for line in file.NewContents())
4408
4409 return _FindMissingSecurityOwners(
4410 input_api,
4411 output_api,
4412 file_patterns,
4413 excluded_patterns,
4414 'ipc/SECURITY_OWNERS',
4415 custom_rule_function=IsMojoServiceManifestFile)
4416
4417
4418def _CheckChangeForFuchsiaSecurityOwners(input_api, output_api):
4419 file_patterns = [
4420 # Component specifications.
4421 '*.cml', # Component Framework v2.
4422 '*.cmx', # Component Framework v1.
4423
4424 # Fuchsia IDL protocol specifications.
4425 '*.fidl',
4426 ]
4427
4428 # Don't check for owners files for changes in these directories.
4429 excluded_patterns = [
4430 'third_party/crashpad/*',
4431 ]
4432
4433 return _FindMissingSecurityOwners(input_api, output_api, file_patterns,
4434 excluded_patterns,
4435 'build/fuchsia/SECURITY_OWNERS')
4436
4437
4438def CheckSecurityOwners(input_api, output_api):
4439 """Checks that various security-sensitive files have an IPC OWNERS rule."""
4440 ipc_results = _CheckChangeForIpcSecurityOwners(input_api, output_api)
4441 fuchsia_results = _CheckChangeForFuchsiaSecurityOwners(
4442 input_api, output_api)
4443
4444 if ipc_results.has_security_sensitive_files:
4445 output_api.AppendCC('[email protected]')
Sam Maiera6e76d72022-02-11 21:43:504446
4447 results = []
Daniel Chenga37c03db2022-05-12 17:20:344448
Daniel Cheng171dad8d2022-05-21 00:40:254449 missing_reviewer_problems = []
4450 if ipc_results.missing_reviewer_problem:
4451 missing_reviewer_problems.append(ipc_results.missing_reviewer_problem)
4452 if fuchsia_results.missing_reviewer_problem:
4453 missing_reviewer_problems.append(
4454 fuchsia_results.missing_reviewer_problem)
Daniel Chenga37c03db2022-05-12 17:20:344455
Daniel Cheng171dad8d2022-05-21 00:40:254456 # Missing reviewers are an error unless there's no issue number
4457 # associated with this branch; in that case, the presubmit is being run
4458 # with --all or --files.
4459 #
4460 # Note that upload should never be an error; otherwise, it would be
4461 # impossible to upload changes at all.
4462 if input_api.is_committing and input_api.change.issue:
4463 make_presubmit_message = output_api.PresubmitError
4464 else:
4465 make_presubmit_message = output_api.PresubmitNotifyResult
4466 for problem in missing_reviewer_problems:
Sam Maiera6e76d72022-02-11 21:43:504467 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:254468 make_presubmit_message(problem.problem, items=problem.items))
Daniel Chenga37c03db2022-05-12 17:20:344469
Daniel Cheng171dad8d2022-05-21 00:40:254470 owners_file_problems = []
4471 owners_file_problems.extend(ipc_results.owners_file_problems)
4472 owners_file_problems.extend(fuchsia_results.owners_file_problems)
Daniel Chenga37c03db2022-05-12 17:20:344473
Daniel Cheng171dad8d2022-05-21 00:40:254474 for problem in owners_file_problems:
Daniel Cheng3008dc12022-05-13 04:02:114475 # Missing per-file rules are always an error. While swarming and caching
4476 # means that uploading a patchset with updated OWNERS files and sending
4477 # it to the CQ again should not have a large incremental cost, it is
4478 # still frustrating to discover the error only after the change has
4479 # already been uploaded.
Daniel Chenga37c03db2022-05-12 17:20:344480 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:254481 output_api.PresubmitError(problem.problem, items=problem.items))
Sam Maiera6e76d72022-02-11 21:43:504482
4483 return results
4484
4485
4486def _GetFilesUsingSecurityCriticalFunctions(input_api):
4487 """Checks affected files for changes to security-critical calls. This
4488 function checks the full change diff, to catch both additions/changes
4489 and removals.
4490
4491 Returns a dict keyed by file name, and the value is a set of detected
4492 functions.
4493 """
4494 # Map of function pretty name (displayed in an error) to the pattern to
4495 # match it with.
4496 _PATTERNS_TO_CHECK = {
4497 'content::GetServiceSandboxType<>()': 'GetServiceSandboxType\\<'
4498 }
4499 _PATTERNS_TO_CHECK = {
4500 k: input_api.re.compile(v)
4501 for k, v in _PATTERNS_TO_CHECK.items()
4502 }
4503
Sam Maiera6e76d72022-02-11 21:43:504504 # We don't want to trigger on strings within this file.
4505 def presubmit_file_filter(f):
Daniel Chenga37c03db2022-05-12 17:20:344506 return 'PRESUBMIT.py' != input_api.os_path.split(f.LocalPath())[1]
Sam Maiera6e76d72022-02-11 21:43:504507
4508 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
4509 files_to_functions = {}
4510 for f in input_api.AffectedFiles(file_filter=presubmit_file_filter):
4511 diff = f.GenerateScmDiff()
4512 for line in diff.split('\n'):
4513 # Not using just RightHandSideLines() because removing a
4514 # call to a security-critical function can be just as important
4515 # as adding or changing the arguments.
4516 if line.startswith('-') or (line.startswith('+')
4517 and not line.startswith('++')):
4518 for name, pattern in _PATTERNS_TO_CHECK.items():
4519 if pattern.search(line):
4520 path = f.LocalPath()
4521 if not path in files_to_functions:
4522 files_to_functions[path] = set()
4523 files_to_functions[path].add(name)
4524 return files_to_functions
4525
4526
4527def CheckSecurityChanges(input_api, output_api):
4528 """Checks that changes involving security-critical functions are reviewed
4529 by the security team.
4530 """
4531 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
4532 if not len(files_to_functions):
4533 return []
4534
Sam Maiera6e76d72022-02-11 21:43:504535 owners_file = 'ipc/SECURITY_OWNERS'
Daniel Chenga37c03db2022-05-12 17:20:344536 if _ChangeHasSecurityReviewer(input_api, owners_file):
Sam Maiera6e76d72022-02-11 21:43:504537 return []
4538
Daniel Chenga37c03db2022-05-12 17:20:344539 msg = 'The following files change calls to security-sensitive functions\n' \
Sam Maiera6e76d72022-02-11 21:43:504540 'that need to be reviewed by {}.\n'.format(owners_file)
4541 for path, names in files_to_functions.items():
4542 msg += ' {}\n'.format(path)
4543 for name in names:
4544 msg += ' {}\n'.format(name)
4545 msg += '\n'
4546
4547 if input_api.is_committing:
4548 output = output_api.PresubmitError
Mohamed Heikale217fc852020-07-06 19:44:034549 else:
Sam Maiera6e76d72022-02-11 21:43:504550 output = output_api.PresubmitNotifyResult
4551 return [output(msg)]
4552
4553
4554def CheckSetNoParent(input_api, output_api):
4555 """Checks that set noparent is only used together with an OWNERS file in
4556 //build/OWNERS.setnoparent (see also
4557 //docs/code_reviews.md#owners-files-details)
4558 """
4559 # Return early if no OWNERS files were modified.
4560 if not any(f.LocalPath().endswith('OWNERS')
4561 for f in input_api.AffectedFiles(include_deletes=False)):
4562 return []
4563
4564 errors = []
4565
4566 allowed_owners_files_file = 'build/OWNERS.setnoparent'
4567 allowed_owners_files = set()
Bruce Dawson58a45d22023-02-27 11:24:164568 with open(allowed_owners_files_file, 'r', encoding='utf-8') as f:
Sam Maiera6e76d72022-02-11 21:43:504569 for line in f:
4570 line = line.strip()
4571 if not line or line.startswith('#'):
4572 continue
4573 allowed_owners_files.add(line)
4574
4575 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
4576
4577 for f in input_api.AffectedFiles(include_deletes=False):
4578 if not f.LocalPath().endswith('OWNERS'):
4579 continue
4580
4581 found_owners_files = set()
4582 found_set_noparent_lines = dict()
4583
4584 # Parse the OWNERS file.
4585 for lineno, line in enumerate(f.NewContents(), 1):
4586 line = line.strip()
4587 if line.startswith('set noparent'):
4588 found_set_noparent_lines[''] = lineno
4589 if line.startswith('file://'):
4590 if line in allowed_owners_files:
4591 found_owners_files.add('')
4592 if line.startswith('per-file'):
4593 match = per_file_pattern.match(line)
4594 if match:
4595 glob = match.group(1).strip()
4596 directive = match.group(2).strip()
4597 if directive == 'set noparent':
4598 found_set_noparent_lines[glob] = lineno
4599 if directive.startswith('file://'):
4600 if directive in allowed_owners_files:
4601 found_owners_files.add(glob)
4602
4603 # Check that every set noparent line has a corresponding file:// line
4604 # listed in build/OWNERS.setnoparent. An exception is made for top level
4605 # directories since src/OWNERS shouldn't review them.
Bruce Dawson6bb0d672022-04-06 15:13:494606 linux_path = f.LocalPath().replace(input_api.os_path.sep, '/')
4607 if (linux_path.count('/') != 1
4608 and (not linux_path in _EXCLUDED_SET_NO_PARENT_PATHS)):
Sam Maiera6e76d72022-02-11 21:43:504609 for set_noparent_line in found_set_noparent_lines:
4610 if set_noparent_line in found_owners_files:
4611 continue
4612 errors.append(' %s:%d' %
Bruce Dawson6bb0d672022-04-06 15:13:494613 (linux_path,
Sam Maiera6e76d72022-02-11 21:43:504614 found_set_noparent_lines[set_noparent_line]))
4615
4616 results = []
4617 if errors:
4618 if input_api.is_committing:
4619 output = output_api.PresubmitError
4620 else:
4621 output = output_api.PresubmitPromptWarning
4622 results.append(
4623 output(
4624 'Found the following "set noparent" restrictions in OWNERS files that '
4625 'do not include owners from build/OWNERS.setnoparent:',
4626 long_text='\n\n'.join(errors)))
4627 return results
4628
4629
4630def CheckUselessForwardDeclarations(input_api, output_api):
4631 """Checks that added or removed lines in non third party affected
4632 header files do not lead to new useless class or struct forward
4633 declaration.
4634 """
4635 results = []
4636 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
4637 input_api.re.MULTILINE)
4638 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
4639 input_api.re.MULTILINE)
4640 for f in input_api.AffectedFiles(include_deletes=False):
4641 if (f.LocalPath().startswith('third_party')
4642 and not f.LocalPath().startswith('third_party/blink')
4643 and not f.LocalPath().startswith('third_party\\blink')):
4644 continue
4645
4646 if not f.LocalPath().endswith('.h'):
4647 continue
4648
4649 contents = input_api.ReadFile(f)
4650 fwd_decls = input_api.re.findall(class_pattern, contents)
4651 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
4652
4653 useless_fwd_decls = []
4654 for decl in fwd_decls:
4655 count = sum(1 for _ in input_api.re.finditer(
4656 r'\b%s\b' % input_api.re.escape(decl), contents))
4657 if count == 1:
4658 useless_fwd_decls.append(decl)
4659
4660 if not useless_fwd_decls:
4661 continue
4662
4663 for line in f.GenerateScmDiff().splitlines():
4664 if (line.startswith('-') and not line.startswith('--')
4665 or line.startswith('+') and not line.startswith('++')):
4666 for decl in useless_fwd_decls:
4667 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
4668 results.append(
4669 output_api.PresubmitPromptWarning(
4670 '%s: %s forward declaration is no longer needed'
4671 % (f.LocalPath(), decl)))
4672 useless_fwd_decls.remove(decl)
4673
4674 return results
4675
4676
4677def _CheckAndroidDebuggableBuild(input_api, output_api):
4678 """Checks that code uses BuildInfo.isDebugAndroid() instead of
4679 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
4680 this is a debuggable build of Android.
4681 """
4682 build_type_check_pattern = input_api.re.compile(
4683 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
4684
4685 errors = []
4686
4687 sources = lambda affected_file: input_api.FilterSourceFile(
4688 affected_file,
4689 files_to_skip=(
4690 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4691 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314692 r"^android_webview/support_library/boundary_interfaces/",
4693 r"^chrome/android/webapk/.*",
4694 r'^third_party/.*',
4695 r"tools/android/customtabs_benchmark/.*",
4696 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504697 )),
4698 files_to_check=[r'.*\.java$'])
4699
4700 for f in input_api.AffectedSourceFiles(sources):
4701 for line_num, line in f.ChangedContents():
4702 if build_type_check_pattern.search(line):
4703 errors.append("%s:%d" % (f.LocalPath(), line_num))
4704
4705 results = []
4706
4707 if errors:
4708 results.append(
4709 output_api.PresubmitPromptWarning(
4710 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
4711 ' Please use BuildInfo.isDebugAndroid() instead.', errors))
4712
4713 return results
4714
4715# TODO: add unit tests
4716def _CheckAndroidToastUsage(input_api, output_api):
4717 """Checks that code uses org.chromium.ui.widget.Toast instead of
4718 android.widget.Toast (Chromium Toast doesn't force hardware
4719 acceleration on low-end devices, saving memory).
4720 """
4721 toast_import_pattern = input_api.re.compile(
4722 r'^import android\.widget\.Toast;$')
4723
4724 errors = []
4725
4726 sources = lambda affected_file: input_api.FilterSourceFile(
4727 affected_file,
4728 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
Bruce Dawson40fece62022-09-16 19:58:314729 DEFAULT_FILES_TO_SKIP + (r'^chromecast/.*',
4730 r'^remoting/.*')),
Sam Maiera6e76d72022-02-11 21:43:504731 files_to_check=[r'.*\.java$'])
4732
4733 for f in input_api.AffectedSourceFiles(sources):
4734 for line_num, line in f.ChangedContents():
4735 if toast_import_pattern.search(line):
4736 errors.append("%s:%d" % (f.LocalPath(), line_num))
4737
4738 results = []
4739
4740 if errors:
4741 results.append(
4742 output_api.PresubmitError(
4743 'android.widget.Toast usage is detected. Android toasts use hardware'
4744 ' acceleration, and can be\ncostly on low-end devices. Please use'
4745 ' org.chromium.ui.widget.Toast instead.\n'
4746 'Contact [email protected] if you have any questions.',
4747 errors))
4748
4749 return results
4750
4751
4752def _CheckAndroidCrLogUsage(input_api, output_api):
4753 """Checks that new logs using org.chromium.base.Log:
4754 - Are using 'TAG' as variable name for the tags (warn)
4755 - Are using a tag that is shorter than 20 characters (error)
4756 """
4757
4758 # Do not check format of logs in the given files
4759 cr_log_check_excluded_paths = [
4760 # //chrome/android/webapk cannot depend on //base
Bruce Dawson40fece62022-09-16 19:58:314761 r"^chrome/android/webapk/.*",
Sam Maiera6e76d72022-02-11 21:43:504762 # WebView license viewer code cannot depend on //base; used in stub APK.
Bruce Dawson40fece62022-09-16 19:58:314763 r"^android_webview/glue/java/src/com/android/"
4764 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504765 # The customtabs_benchmark is a small app that does not depend on Chromium
4766 # java pieces.
Bruce Dawson40fece62022-09-16 19:58:314767 r"tools/android/customtabs_benchmark/.*",
Sam Maiera6e76d72022-02-11 21:43:504768 ]
4769
4770 cr_log_import_pattern = input_api.re.compile(
4771 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
4772 class_in_base_pattern = input_api.re.compile(
4773 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
4774 has_some_log_import_pattern = input_api.re.compile(r'^import .*\.Log;$',
4775 input_api.re.MULTILINE)
4776 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
4777 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
4778 log_decl_pattern = input_api.re.compile(
4779 r'static final String TAG = "(?P<name>(.*))"')
4780 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
4781
4782 REF_MSG = ('See docs/android_logging.md for more info.')
4783 sources = lambda x: input_api.FilterSourceFile(
4784 x,
4785 files_to_check=[r'.*\.java$'],
4786 files_to_skip=cr_log_check_excluded_paths)
4787
4788 tag_decl_errors = []
Andrew Grieved3a35d82024-01-02 21:24:384789 tag_length_errors = []
Sam Maiera6e76d72022-02-11 21:43:504790 tag_errors = []
4791 tag_with_dot_errors = []
4792 util_log_errors = []
4793
4794 for f in input_api.AffectedSourceFiles(sources):
4795 file_content = input_api.ReadFile(f)
4796 has_modified_logs = False
4797 # Per line checks
4798 if (cr_log_import_pattern.search(file_content)
4799 or (class_in_base_pattern.search(file_content)
4800 and not has_some_log_import_pattern.search(file_content))):
4801 # Checks to run for files using cr log
4802 for line_num, line in f.ChangedContents():
4803 if rough_log_decl_pattern.search(line):
4804 has_modified_logs = True
4805
4806 # Check if the new line is doing some logging
4807 match = log_call_pattern.search(line)
4808 if match:
4809 has_modified_logs = True
4810
4811 # Make sure it uses "TAG"
4812 if not match.group('tag') == 'TAG':
4813 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
4814 else:
4815 # Report non cr Log function calls in changed lines
4816 for line_num, line in f.ChangedContents():
4817 if log_call_pattern.search(line):
4818 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
4819
4820 # Per file checks
4821 if has_modified_logs:
4822 # Make sure the tag is using the "cr" prefix and is not too long
4823 match = log_decl_pattern.search(file_content)
4824 tag_name = match.group('name') if match else None
4825 if not tag_name:
4826 tag_decl_errors.append(f.LocalPath())
Andrew Grieved3a35d82024-01-02 21:24:384827 elif len(tag_name) > 20:
4828 tag_length_errors.append(f.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:504829 elif '.' in tag_name:
4830 tag_with_dot_errors.append(f.LocalPath())
4831
4832 results = []
4833 if tag_decl_errors:
4834 results.append(
4835 output_api.PresubmitPromptWarning(
4836 'Please define your tags using the suggested format: .\n'
4837 '"private static final String TAG = "<package tag>".\n'
4838 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
4839 tag_decl_errors))
4840
Andrew Grieved3a35d82024-01-02 21:24:384841 if tag_length_errors:
4842 results.append(
4843 output_api.PresubmitError(
4844 'The tag length is restricted by the system to be at most '
4845 '20 characters.\n' + REF_MSG, tag_length_errors))
4846
Sam Maiera6e76d72022-02-11 21:43:504847 if tag_errors:
4848 results.append(
4849 output_api.PresubmitPromptWarning(
4850 'Please use a variable named "TAG" for your log tags.\n' +
4851 REF_MSG, tag_errors))
4852
4853 if util_log_errors:
4854 results.append(
4855 output_api.PresubmitPromptWarning(
4856 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
4857 util_log_errors))
4858
4859 if tag_with_dot_errors:
4860 results.append(
4861 output_api.PresubmitPromptWarning(
4862 'Dot in log tags cause them to be elided in crash reports.\n' +
4863 REF_MSG, tag_with_dot_errors))
4864
4865 return results
4866
4867
Sam Maiera6e76d72022-02-11 21:43:504868def _CheckAndroidTestAnnotationUsage(input_api, output_api):
4869 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
4870 deprecated_annotation_import_pattern = input_api.re.compile(
4871 r'^import android\.test\.suitebuilder\.annotation\..*;',
4872 input_api.re.MULTILINE)
4873 sources = lambda x: input_api.FilterSourceFile(
4874 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
4875 errors = []
4876 for f in input_api.AffectedFiles(file_filter=sources):
4877 for line_num, line in f.ChangedContents():
4878 if deprecated_annotation_import_pattern.search(line):
4879 errors.append("%s:%d" % (f.LocalPath(), line_num))
4880
4881 results = []
4882 if errors:
4883 results.append(
4884 output_api.PresubmitError(
4885 'Annotations in android.test.suitebuilder.annotation have been'
Mohamed Heikal3d7a94c2023-03-28 16:55:244886 ' deprecated since API level 24. Please use androidx.test.filters'
4887 ' from //third_party/androidx:androidx_test_runner_java instead.'
Sam Maiera6e76d72022-02-11 21:43:504888 ' Contact [email protected] if you have any questions.',
4889 errors))
4890 return results
4891
4892
4893def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
4894 """Checks if MDPI assets are placed in a correct directory."""
Bruce Dawson6c05e852022-07-21 15:48:514895 file_filter = lambda f: (f.LocalPath().endswith(
4896 '.png') and ('/res/drawable/'.replace('/', input_api.os_path.sep) in f.
4897 LocalPath() or '/res/drawable-ldrtl/'.replace(
4898 '/', input_api.os_path.sep) in f.LocalPath()))
Sam Maiera6e76d72022-02-11 21:43:504899 errors = []
4900 for f in input_api.AffectedFiles(include_deletes=False,
4901 file_filter=file_filter):
4902 errors.append(' %s' % f.LocalPath())
4903
4904 results = []
4905 if errors:
4906 results.append(
4907 output_api.PresubmitError(
4908 'MDPI assets should be placed in /res/drawable-mdpi/ or '
4909 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
4910 '/res/drawable-ldrtl/.\n'
4911 'Contact [email protected] if you have questions.', errors))
4912 return results
4913
4914
4915def _CheckAndroidWebkitImports(input_api, output_api):
4916 """Checks that code uses org.chromium.base.Callback instead of
4917 android.webview.ValueCallback except in the WebView glue layer
4918 and WebLayer.
4919 """
4920 valuecallback_import_pattern = input_api.re.compile(
4921 r'^import android\.webkit\.ValueCallback;$')
4922
4923 errors = []
4924
4925 sources = lambda affected_file: input_api.FilterSourceFile(
4926 affected_file,
4927 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4928 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314929 r'^android_webview/glue/.*',
elabadysayedcbbaea72024-08-01 16:10:424930 r'^android_webview/support_library/.*',
Bruce Dawson40fece62022-09-16 19:58:314931 r'^weblayer/.*',
Sam Maiera6e76d72022-02-11 21:43:504932 )),
4933 files_to_check=[r'.*\.java$'])
4934
4935 for f in input_api.AffectedSourceFiles(sources):
4936 for line_num, line in f.ChangedContents():
4937 if valuecallback_import_pattern.search(line):
4938 errors.append("%s:%d" % (f.LocalPath(), line_num))
4939
4940 results = []
4941
4942 if errors:
4943 results.append(
4944 output_api.PresubmitError(
4945 'android.webkit.ValueCallback usage is detected outside of the glue'
4946 ' layer. To stay compatible with the support library, android.webkit.*'
4947 ' classes should only be used inside the glue layer and'
4948 ' org.chromium.base.Callback should be used instead.', errors))
4949
4950 return results
4951
4952
4953def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
4954 """Checks Android XML styles """
4955
4956 # Return early if no relevant files were modified.
4957 if not any(
4958 _IsXmlOrGrdFile(input_api, f.LocalPath())
4959 for f in input_api.AffectedFiles(include_deletes=False)):
4960 return []
4961
4962 import sys
4963 original_sys_path = sys.path
4964 try:
4965 sys.path = sys.path + [
4966 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4967 'android', 'checkxmlstyle')
4968 ]
4969 import checkxmlstyle
4970 finally:
4971 # Restore sys.path to what it was before.
4972 sys.path = original_sys_path
4973
4974 if is_check_on_upload:
4975 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
4976 else:
4977 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
4978
4979
4980def _CheckAndroidInfoBarDeprecation(input_api, output_api):
4981 """Checks Android Infobar Deprecation """
4982
4983 import sys
4984 original_sys_path = sys.path
4985 try:
4986 sys.path = sys.path + [
4987 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4988 'android', 'infobar_deprecation')
4989 ]
4990 import infobar_deprecation
4991 finally:
4992 # Restore sys.path to what it was before.
4993 sys.path = original_sys_path
4994
4995 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
4996
4997
4998class _PydepsCheckerResult:
4999 def __init__(self, cmd, pydeps_path, process, old_contents):
5000 self._cmd = cmd
5001 self._pydeps_path = pydeps_path
5002 self._process = process
5003 self._old_contents = old_contents
5004
5005 def GetError(self):
5006 """Returns an error message, or None."""
5007 import difflib
Andrew Grieved27620b62023-07-13 16:35:075008 new_contents = self._process.stdout.read().splitlines()[2:]
Sam Maiera6e76d72022-02-11 21:43:505009 if self._process.wait() != 0:
5010 # STDERR should already be printed.
5011 return 'Command failed: ' + self._cmd
Sam Maiera6e76d72022-02-11 21:43:505012 if self._old_contents != new_contents:
5013 diff = '\n'.join(
5014 difflib.context_diff(self._old_contents, new_contents))
5015 return ('File is stale: {}\n'
5016 'Diff (apply to fix):\n'
5017 '{}\n'
5018 'To regenerate, run:\n\n'
5019 ' {}').format(self._pydeps_path, diff, self._cmd)
5020 return None
5021
5022
5023class PydepsChecker:
5024 def __init__(self, input_api, pydeps_files):
5025 self._file_cache = {}
5026 self._input_api = input_api
5027 self._pydeps_files = pydeps_files
5028
5029 def _LoadFile(self, path):
5030 """Returns the list of paths within a .pydeps file relative to //."""
5031 if path not in self._file_cache:
5032 with open(path, encoding='utf-8') as f:
5033 self._file_cache[path] = f.read()
5034 return self._file_cache[path]
5035
5036 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
Gao Shenga79ebd42022-08-08 17:25:595037 """Returns an iterable of paths within the .pydep, relativized to //."""
Sam Maiera6e76d72022-02-11 21:43:505038 pydeps_data = self._LoadFile(pydeps_path)
5039 uses_gn_paths = '--gn-paths' in pydeps_data
5040 entries = (l for l in pydeps_data.splitlines()
5041 if not l.startswith('#'))
5042 if uses_gn_paths:
5043 # Paths look like: //foo/bar/baz
5044 return (e[2:] for e in entries)
5045 else:
5046 # Paths look like: path/relative/to/file.pydeps
5047 os_path = self._input_api.os_path
5048 pydeps_dir = os_path.dirname(pydeps_path)
5049 return (os_path.normpath(os_path.join(pydeps_dir, e))
5050 for e in entries)
5051
5052 def _CreateFilesToPydepsMap(self):
5053 """Returns a map of local_path -> list_of_pydeps."""
5054 ret = {}
5055 for pydep_local_path in self._pydeps_files:
5056 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
5057 ret.setdefault(path, []).append(pydep_local_path)
5058 return ret
5059
5060 def ComputeAffectedPydeps(self):
5061 """Returns an iterable of .pydeps files that might need regenerating."""
5062 affected_pydeps = set()
5063 file_to_pydeps_map = None
5064 for f in self._input_api.AffectedFiles(include_deletes=True):
5065 local_path = f.LocalPath()
5066 # Changes to DEPS can lead to .pydeps changes if any .py files are in
5067 # subrepositories. We can't figure out which files change, so re-check
5068 # all files.
5069 # Changes to print_python_deps.py affect all .pydeps.
5070 if local_path in ('DEPS', 'PRESUBMIT.py'
5071 ) or local_path.endswith('print_python_deps.py'):
5072 return self._pydeps_files
5073 elif local_path.endswith('.pydeps'):
5074 if local_path in self._pydeps_files:
5075 affected_pydeps.add(local_path)
5076 elif local_path.endswith('.py'):
5077 if file_to_pydeps_map is None:
5078 file_to_pydeps_map = self._CreateFilesToPydepsMap()
5079 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
5080 return affected_pydeps
5081
5082 def DetermineIfStaleAsync(self, pydeps_path):
5083 """Runs print_python_deps.py to see if the files is stale."""
5084 import os
5085
5086 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
5087 if old_pydeps_data:
5088 cmd = old_pydeps_data[1][1:].strip()
5089 if '--output' not in cmd:
5090 cmd += ' --output ' + pydeps_path
5091 old_contents = old_pydeps_data[2:]
5092 else:
5093 # A default cmd that should work in most cases (as long as pydeps filename
5094 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
5095 # file is empty/new.
5096 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
5097 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
5098 old_contents = []
5099 env = dict(os.environ)
5100 env['PYTHONDONTWRITEBYTECODE'] = '1'
5101 process = self._input_api.subprocess.Popen(
5102 cmd + ' --output ""',
5103 shell=True,
5104 env=env,
5105 stdout=self._input_api.subprocess.PIPE,
5106 encoding='utf-8')
5107 return _PydepsCheckerResult(cmd, pydeps_path, process, old_contents)
agrievef32bcc72016-04-04 14:57:405108
5109
Tibor Goldschwendt360793f72019-06-25 18:23:495110def _ParseGclientArgs():
Sam Maiera6e76d72022-02-11 21:43:505111 args = {}
5112 with open('build/config/gclient_args.gni', 'r') as f:
5113 for line in f:
5114 line = line.strip()
5115 if not line or line.startswith('#'):
5116 continue
5117 attribute, value = line.split('=')
5118 args[attribute.strip()] = value.strip()
5119 return args
Tibor Goldschwendt360793f72019-06-25 18:23:495120
5121
Saagar Sanghavifceeaae2020-08-12 16:40:365122def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
Sam Maiera6e76d72022-02-11 21:43:505123 """Checks if a .pydeps file needs to be regenerated."""
5124 # This check is for Python dependency lists (.pydeps files), and involves
5125 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
5126 # doesn't work on Windows and Mac, so skip it on other platforms.
5127 if not input_api.platform.startswith('linux'):
5128 return []
Erik Staabc734cd7a2021-11-23 03:11:525129
Sam Maiera6e76d72022-02-11 21:43:505130 results = []
5131 # First, check for new / deleted .pydeps.
5132 for f in input_api.AffectedFiles(include_deletes=True):
5133 # Check whether we are running the presubmit check for a file in src.
Sam Maiera6e76d72022-02-11 21:43:505134 if f.LocalPath().endswith('.pydeps'):
Andrew Grieve713b89b2024-10-15 20:20:085135 # f.LocalPath is relative to repo (src, or internal repo).
5136 # os_path.exists is relative to src repo.
5137 # Therefore if os_path.exists is true, it means f.LocalPath is relative
5138 # to src and we can conclude that the pydeps is in src.
5139 exists = input_api.os_path.exists(f.LocalPath())
5140 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
5141 results.append(
5142 output_api.PresubmitError(
5143 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
5144 'remove %s' % f.LocalPath()))
5145 elif (f.Action() != 'D' and exists
5146 and f.LocalPath() not in _ALL_PYDEPS_FILES):
5147 results.append(
5148 output_api.PresubmitError(
5149 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
5150 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:405151
Sam Maiera6e76d72022-02-11 21:43:505152 if results:
5153 return results
5154
Gavin Mak23884402024-07-25 20:39:265155 try:
5156 parsed_args = _ParseGclientArgs()
5157 except FileNotFoundError:
5158 message = (
5159 'build/config/gclient_args.gni not found. Please make sure your '
5160 'workspace has been initialized with gclient sync.'
5161 )
5162 import sys
5163 original_sys_path = sys.path
5164 try:
5165 sys.path = sys.path + [
5166 input_api.os_path.join(input_api.PresubmitLocalPath(),
5167 'third_party', 'depot_tools')
5168 ]
5169 import gclient_utils
5170 if gclient_utils.IsEnvCog():
5171 # Users will always hit this when they run presubmits before cog
5172 # workspace initialization finishes. The check shouldn't fail in
5173 # this case. This is an unavoidable workaround that's needed for
5174 # good presubmit UX for cog.
5175 results.append(output_api.PresubmitPromptWarning(message))
5176 else:
5177 results.append(output_api.PresubmitError(message))
5178 return results
5179 finally:
5180 # Restore sys.path to what it was before.
5181 sys.path = original_sys_path
5182
5183 is_android = parsed_args.get('checkout_android', 'false') == 'true'
Sam Maiera6e76d72022-02-11 21:43:505184 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
5185 affected_pydeps = set(checker.ComputeAffectedPydeps())
5186 affected_android_pydeps = affected_pydeps.intersection(
5187 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
5188 if affected_android_pydeps and not is_android:
5189 results.append(
5190 output_api.PresubmitPromptOrNotify(
5191 'You have changed python files that may affect pydeps for android\n'
Gao Shenga79ebd42022-08-08 17:25:595192 'specific scripts. However, the relevant presubmit check cannot be\n'
Sam Maiera6e76d72022-02-11 21:43:505193 'run because you are not using an Android checkout. To validate that\n'
5194 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
5195 'use the android-internal-presubmit optional trybot.\n'
5196 'Possibly stale pydeps files:\n{}'.format(
5197 '\n'.join(affected_android_pydeps))))
5198
5199 all_pydeps = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
5200 pydeps_to_check = affected_pydeps.intersection(all_pydeps)
5201 # Process these concurrently, as each one takes 1-2 seconds.
5202 pydep_results = [checker.DetermineIfStaleAsync(p) for p in pydeps_to_check]
5203 for result in pydep_results:
5204 error_msg = result.GetError()
5205 if error_msg:
5206 results.append(output_api.PresubmitError(error_msg))
5207
agrievef32bcc72016-04-04 14:57:405208 return results
5209
agrievef32bcc72016-04-04 14:57:405210
Saagar Sanghavifceeaae2020-08-12 16:40:365211def CheckSingletonInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505212 """Checks to make sure no header files have |Singleton<|."""
5213
5214 def FileFilter(affected_file):
5215 # It's ok for base/memory/singleton.h to have |Singleton<|.
5216 files_to_skip = (_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
Bruce Dawson40fece62022-09-16 19:58:315217 (r"^base/memory/singleton\.h$",
5218 r"^net/quic/platform/impl/quic_singleton_impl\.h$"))
Sam Maiera6e76d72022-02-11 21:43:505219 return input_api.FilterSourceFile(affected_file,
5220 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:435221
Sam Maiera6e76d72022-02-11 21:43:505222 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
5223 files = []
5224 for f in input_api.AffectedSourceFiles(FileFilter):
5225 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx')
5226 or f.LocalPath().endswith('.hpp')
5227 or f.LocalPath().endswith('.inl')):
5228 contents = input_api.ReadFile(f)
5229 for line in contents.splitlines(False):
5230 if (not line.lstrip().startswith('//')
5231 and # Strip C++ comment.
5232 pattern.search(line)):
5233 files.append(f)
5234 break
glidere61efad2015-02-18 17:39:435235
Sam Maiera6e76d72022-02-11 21:43:505236 if files:
5237 return [
5238 output_api.PresubmitError(
5239 'Found base::Singleton<T> in the following header files.\n' +
5240 'Please move them to an appropriate source file so that the ' +
5241 'template gets instantiated in a single compilation unit.',
5242 files)
5243 ]
5244 return []
glidere61efad2015-02-18 17:39:435245
5246
[email protected]fd20b902014-05-09 02:14:535247_DEPRECATED_CSS = [
5248 # Values
5249 ( "-webkit-box", "flex" ),
5250 ( "-webkit-inline-box", "inline-flex" ),
5251 ( "-webkit-flex", "flex" ),
5252 ( "-webkit-inline-flex", "inline-flex" ),
5253 ( "-webkit-min-content", "min-content" ),
5254 ( "-webkit-max-content", "max-content" ),
5255
5256 # Properties
5257 ( "-webkit-background-clip", "background-clip" ),
5258 ( "-webkit-background-origin", "background-origin" ),
5259 ( "-webkit-background-size", "background-size" ),
5260 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:445261 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:535262
5263 # Functions
5264 ( "-webkit-gradient", "gradient" ),
5265 ( "-webkit-repeating-gradient", "repeating-gradient" ),
5266 ( "-webkit-linear-gradient", "linear-gradient" ),
5267 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
5268 ( "-webkit-radial-gradient", "radial-gradient" ),
5269 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
5270]
5271
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:205272
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:495273# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:365274def CheckNoDeprecatedCss(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505275 """ Make sure that we don't use deprecated CSS
5276 properties, functions or values. Our external
5277 documentation and iOS CSS for dom distiller
5278 (reader mode) are ignored by the hooks as it
5279 needs to be consumed by WebKit. """
5280 results = []
5281 file_inclusion_pattern = [r".+\.css$"]
5282 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
5283 input_api.DEFAULT_FILES_TO_SKIP +
5284 (r"^chrome/common/extensions/docs", r"^chrome/docs",
Teresa Mao1d910882024-04-26 21:06:255285 r"^native_client_sdk",
5286 # The NTP team prefers reserving -webkit-line-clamp for
5287 # ellipsis effect which can only be used with -webkit-box.
5288 r"ui/webui/resources/cr_components/most_visited/.*\.css$"))
Sam Maiera6e76d72022-02-11 21:43:505289 file_filter = lambda f: input_api.FilterSourceFile(
5290 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
5291 for fpath in input_api.AffectedFiles(file_filter=file_filter):
5292 for line_num, line in fpath.ChangedContents():
5293 for (deprecated_value, value) in _DEPRECATED_CSS:
5294 if deprecated_value in line:
5295 results.append(
5296 output_api.PresubmitError(
5297 "%s:%d: Use of deprecated CSS %s, use %s instead" %
5298 (fpath.LocalPath(), line_num, deprecated_value,
5299 value)))
5300 return results
[email protected]fd20b902014-05-09 02:14:535301
mohan.reddyf21db962014-10-16 12:26:475302
Saagar Sanghavifceeaae2020-08-12 16:40:365303def CheckForRelativeIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505304 bad_files = {}
5305 for f in input_api.AffectedFiles(include_deletes=False):
5306 if (f.LocalPath().startswith('third_party')
5307 and not f.LocalPath().startswith('third_party/blink')
5308 and not f.LocalPath().startswith('third_party\\blink')):
5309 continue
rlanday6802cf632017-05-30 17:48:365310
Sam Maiera6e76d72022-02-11 21:43:505311 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
5312 continue
rlanday6802cf632017-05-30 17:48:365313
Sam Maiera6e76d72022-02-11 21:43:505314 relative_includes = [
5315 line for _, line in f.ChangedContents()
5316 if "#include" in line and "../" in line
5317 ]
5318 if not relative_includes:
5319 continue
5320 bad_files[f.LocalPath()] = relative_includes
rlanday6802cf632017-05-30 17:48:365321
Sam Maiera6e76d72022-02-11 21:43:505322 if not bad_files:
5323 return []
rlanday6802cf632017-05-30 17:48:365324
Sam Maiera6e76d72022-02-11 21:43:505325 error_descriptions = []
5326 for file_path, bad_lines in bad_files.items():
5327 error_description = file_path
5328 for line in bad_lines:
5329 error_description += '\n ' + line
5330 error_descriptions.append(error_description)
rlanday6802cf632017-05-30 17:48:365331
Sam Maiera6e76d72022-02-11 21:43:505332 results = []
5333 results.append(
5334 output_api.PresubmitError(
5335 'You added one or more relative #include paths (including "../").\n'
5336 'These shouldn\'t be used because they can be used to include headers\n'
5337 'from code that\'s not correctly specified as a dependency in the\n'
5338 'relevant BUILD.gn file(s).', error_descriptions))
rlanday6802cf632017-05-30 17:48:365339
Sam Maiera6e76d72022-02-11 21:43:505340 return results
rlanday6802cf632017-05-30 17:48:365341
Takeshi Yoshinoe387aa32017-08-02 13:16:135342
Saagar Sanghavifceeaae2020-08-12 16:40:365343def CheckForCcIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505344 """Check that nobody tries to include a cc file. It's a relatively
5345 common error which results in duplicate symbols in object
5346 files. This may not always break the build until someone later gets
5347 very confusing linking errors."""
5348 results = []
5349 for f in input_api.AffectedFiles(include_deletes=False):
5350 # We let third_party code do whatever it wants
5351 if (f.LocalPath().startswith('third_party')
5352 and not f.LocalPath().startswith('third_party/blink')
5353 and not f.LocalPath().startswith('third_party\\blink')):
5354 continue
Daniel Bratell65b033262019-04-23 08:17:065355
Sam Maiera6e76d72022-02-11 21:43:505356 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
5357 continue
Daniel Bratell65b033262019-04-23 08:17:065358
Sam Maiera6e76d72022-02-11 21:43:505359 for _, line in f.ChangedContents():
5360 if line.startswith('#include "'):
5361 included_file = line.split('"')[1]
5362 if _IsCPlusPlusFile(input_api, included_file):
5363 # The most common naming for external files with C++ code,
5364 # apart from standard headers, is to call them foo.inc, but
5365 # Chromium sometimes uses foo-inc.cc so allow that as well.
5366 if not included_file.endswith(('.h', '-inc.cc')):
5367 results.append(
5368 output_api.PresubmitError(
5369 'Only header files or .inc files should be included in other\n'
5370 'C++ files. Compiling the contents of a cc file more than once\n'
5371 'will cause duplicate information in the build which may later\n'
5372 'result in strange link_errors.\n' +
5373 f.LocalPath() + ':\n ' + line))
Daniel Bratell65b033262019-04-23 08:17:065374
Sam Maiera6e76d72022-02-11 21:43:505375 return results
Daniel Bratell65b033262019-04-23 08:17:065376
5377
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205378def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
Sam Maiera6e76d72022-02-11 21:43:505379 if not isinstance(key, ast.Str):
5380 return 'Key at line %d must be a string literal' % key.lineno
5381 if not isinstance(value, ast.Dict):
5382 return 'Value at line %d must be a dict' % value.lineno
5383 if len(value.keys) != 1:
5384 return 'Dict at line %d must have single entry' % value.lineno
5385 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
5386 return (
5387 'Entry at line %d must have a string literal \'filepath\' as key' %
5388 value.lineno)
5389 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:135390
Takeshi Yoshinoe387aa32017-08-02 13:16:135391
Sergey Ulanov4af16052018-11-08 02:41:465392def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Sam Maiera6e76d72022-02-11 21:43:505393 if not isinstance(key, ast.Str):
5394 return 'Key at line %d must be a string literal' % key.lineno
5395 if not isinstance(value, ast.List):
5396 return 'Value at line %d must be a list' % value.lineno
5397 for element in value.elts:
5398 if not isinstance(element, ast.Str):
5399 return 'Watchlist elements on line %d is not a string' % key.lineno
5400 if not email_regex.match(element.s):
5401 return ('Watchlist element on line %d doesn\'t look like a valid '
5402 + 'email: %s') % (key.lineno, element.s)
5403 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:135404
Takeshi Yoshinoe387aa32017-08-02 13:16:135405
Sergey Ulanov4af16052018-11-08 02:41:465406def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Sam Maiera6e76d72022-02-11 21:43:505407 mismatch_template = (
5408 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
5409 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:135410
Sam Maiera6e76d72022-02-11 21:43:505411 email_regex = input_api.re.compile(
5412 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
Sergey Ulanov4af16052018-11-08 02:41:465413
Sam Maiera6e76d72022-02-11 21:43:505414 ast = input_api.ast
5415 i = 0
5416 last_key = ''
5417 while True:
5418 if i >= len(wd_dict.keys):
5419 if i >= len(w_dict.keys):
5420 return None
5421 return mismatch_template % ('missing',
5422 'line %d' % w_dict.keys[i].lineno)
5423 elif i >= len(w_dict.keys):
5424 return (mismatch_template %
5425 ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:135426
Sam Maiera6e76d72022-02-11 21:43:505427 wd_key = wd_dict.keys[i]
5428 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:135429
Sam Maiera6e76d72022-02-11 21:43:505430 result = _CheckWatchlistDefinitionsEntrySyntax(wd_key,
5431 wd_dict.values[i], ast)
5432 if result is not None:
5433 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:135434
Sam Maiera6e76d72022-02-11 21:43:505435 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast,
5436 email_regex)
5437 if result is not None:
5438 return 'Bad entry in WATCHLISTS dict: %s' % result
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205439
Sam Maiera6e76d72022-02-11 21:43:505440 if wd_key.s != w_key.s:
5441 return mismatch_template % ('%s at line %d' %
5442 (wd_key.s, wd_key.lineno),
5443 '%s at line %d' %
5444 (w_key.s, w_key.lineno))
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205445
Sam Maiera6e76d72022-02-11 21:43:505446 if wd_key.s < last_key:
5447 return (
5448 'WATCHLISTS dict is not sorted lexicographically at line %d and %d'
5449 % (wd_key.lineno, w_key.lineno))
5450 last_key = wd_key.s
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205451
Sam Maiera6e76d72022-02-11 21:43:505452 i = i + 1
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205453
5454
Sergey Ulanov4af16052018-11-08 02:41:465455def _CheckWATCHLISTSSyntax(expression, input_api):
Sam Maiera6e76d72022-02-11 21:43:505456 ast = input_api.ast
5457 if not isinstance(expression, ast.Expression):
5458 return 'WATCHLISTS file must contain a valid expression'
5459 dictionary = expression.body
5460 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
5461 return 'WATCHLISTS file must have single dict with exactly two entries'
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205462
Sam Maiera6e76d72022-02-11 21:43:505463 first_key = dictionary.keys[0]
5464 first_value = dictionary.values[0]
5465 second_key = dictionary.keys[1]
5466 second_value = dictionary.values[1]
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205467
Sam Maiera6e76d72022-02-11 21:43:505468 if (not isinstance(first_key, ast.Str)
5469 or first_key.s != 'WATCHLIST_DEFINITIONS'
5470 or not isinstance(first_value, ast.Dict)):
5471 return ('The first entry of the dict in WATCHLISTS file must be '
5472 'WATCHLIST_DEFINITIONS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205473
Sam Maiera6e76d72022-02-11 21:43:505474 if (not isinstance(second_key, ast.Str) or second_key.s != 'WATCHLISTS'
5475 or not isinstance(second_value, ast.Dict)):
5476 return ('The second entry of the dict in WATCHLISTS file must be '
5477 'WATCHLISTS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205478
Sam Maiera6e76d72022-02-11 21:43:505479 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:135480
5481
Saagar Sanghavifceeaae2020-08-12 16:40:365482def CheckWATCHLISTS(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505483 for f in input_api.AffectedFiles(include_deletes=False):
5484 if f.LocalPath() == 'WATCHLISTS':
5485 contents = input_api.ReadFile(f, 'r')
Takeshi Yoshinoe387aa32017-08-02 13:16:135486
Sam Maiera6e76d72022-02-11 21:43:505487 try:
5488 # First, make sure that it can be evaluated.
5489 input_api.ast.literal_eval(contents)
5490 # Get an AST tree for it and scan the tree for detailed style checking.
5491 expression = input_api.ast.parse(contents,
5492 filename='WATCHLISTS',
5493 mode='eval')
5494 except ValueError as e:
5495 return [
5496 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5497 long_text=repr(e))
5498 ]
5499 except SyntaxError as e:
5500 return [
5501 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5502 long_text=repr(e))
5503 ]
5504 except TypeError as e:
5505 return [
5506 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5507 long_text=repr(e))
5508 ]
Takeshi Yoshinoe387aa32017-08-02 13:16:135509
Sam Maiera6e76d72022-02-11 21:43:505510 result = _CheckWATCHLISTSSyntax(expression, input_api)
5511 if result is not None:
5512 return [output_api.PresubmitError(result)]
5513 break
Takeshi Yoshinoe387aa32017-08-02 13:16:135514
Sam Maiera6e76d72022-02-11 21:43:505515 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:135516
Sean Kaucb7c9b32022-10-25 21:25:525517def CheckGnRebasePath(input_api, output_api):
5518 """Checks that target_gen_dir is not used wtih "//" in rebase_path().
5519
5520 Developers should use root_build_dir instead of "//" when using target_gen_dir because
5521 Chromium is sometimes built outside of the source tree.
5522 """
5523
5524 def gn_files(f):
5525 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
5526
5527 rebase_path_regex = input_api.re.compile(r'rebase_path\(("\$target_gen_dir"|target_gen_dir), ("/"|"//")\)')
5528 problems = []
5529 for f in input_api.AffectedSourceFiles(gn_files):
5530 for line_num, line in f.ChangedContents():
5531 if rebase_path_regex.search(line):
5532 problems.append(
5533 'Absolute path in rebase_path() in %s:%d' %
5534 (f.LocalPath(), line_num))
5535
5536 if problems:
5537 return [
5538 output_api.PresubmitPromptWarning(
5539 'Using an absolute path in rebase_path()',
5540 items=sorted(problems),
5541 long_text=(
5542 'rebase_path() should use root_build_dir instead of "/" ',
5543 'since builds can be initiated from outside of the source ',
5544 'root.'))
5545 ]
5546 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:135547
Andrew Grieve1b290e4a22020-11-24 20:07:015548def CheckGnGlobForward(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505549 """Checks that forward_variables_from(invoker, "*") follows best practices.
Andrew Grieve1b290e4a22020-11-24 20:07:015550
Sam Maiera6e76d72022-02-11 21:43:505551 As documented at //build/docs/writing_gn_templates.md
5552 """
Andrew Grieve1b290e4a22020-11-24 20:07:015553
Sam Maiera6e76d72022-02-11 21:43:505554 def gn_files(f):
5555 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
Andrew Grieve1b290e4a22020-11-24 20:07:015556
Sam Maiera6e76d72022-02-11 21:43:505557 problems = []
5558 for f in input_api.AffectedSourceFiles(gn_files):
5559 for line_num, line in f.ChangedContents():
5560 if 'forward_variables_from(invoker, "*")' in line:
5561 problems.append(
5562 'Bare forward_variables_from(invoker, "*") in %s:%d' %
5563 (f.LocalPath(), line_num))
5564
5565 if problems:
5566 return [
5567 output_api.PresubmitPromptWarning(
5568 'forward_variables_from("*") without exclusions',
5569 items=sorted(problems),
5570 long_text=(
Gao Shenga79ebd42022-08-08 17:25:595571 'The variables "visibility" and "test_only" should be '
Sam Maiera6e76d72022-02-11 21:43:505572 'explicitly listed in forward_variables_from(). For more '
5573 'details, see:\n'
5574 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
5575 'build/docs/writing_gn_templates.md'
5576 '#Using-forward_variables_from'))
5577 ]
5578 return []
Andrew Grieve1b290e4a22020-11-24 20:07:015579
Saagar Sanghavifceeaae2020-08-12 16:40:365580def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505581 """Checks that newly added header files have corresponding GN changes.
5582 Note that this is only a heuristic. To be precise, run script:
5583 build/check_gn_headers.py.
5584 """
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195585
Sam Maiera6e76d72022-02-11 21:43:505586 def headers(f):
5587 return input_api.FilterSourceFile(
5588 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195589
Sam Maiera6e76d72022-02-11 21:43:505590 new_headers = []
5591 for f in input_api.AffectedSourceFiles(headers):
5592 if f.Action() != 'A':
5593 continue
5594 new_headers.append(f.LocalPath())
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195595
Sam Maiera6e76d72022-02-11 21:43:505596 def gn_files(f):
5597 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195598
Sam Maiera6e76d72022-02-11 21:43:505599 all_gn_changed_contents = ''
5600 for f in input_api.AffectedSourceFiles(gn_files):
5601 for _, line in f.ChangedContents():
5602 all_gn_changed_contents += line
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195603
Sam Maiera6e76d72022-02-11 21:43:505604 problems = []
5605 for header in new_headers:
5606 basename = input_api.os_path.basename(header)
5607 if basename not in all_gn_changed_contents:
5608 problems.append(header)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195609
Sam Maiera6e76d72022-02-11 21:43:505610 if problems:
5611 return [
5612 output_api.PresubmitPromptWarning(
5613 'Missing GN changes for new header files',
5614 items=sorted(problems),
5615 long_text=
5616 'Please double check whether newly added header files need '
5617 'corresponding changes in gn or gni files.\nThis checking is only a '
5618 'heuristic. Run build/check_gn_headers.py to be precise.\n'
5619 'Read https://crbug.com/661774 for more info.')
5620 ]
5621 return []
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195622
5623
Saagar Sanghavifceeaae2020-08-12 16:40:365624def CheckCorrectProductNameInMessages(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505625 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
Michael Giuffridad3bc8672018-10-25 22:48:025626
Sam Maiera6e76d72022-02-11 21:43:505627 This assumes we won't intentionally reference one product from the other
5628 product.
5629 """
5630 all_problems = []
5631 test_cases = [{
5632 "filename_postfix": "google_chrome_strings.grd",
5633 "correct_name": "Chrome",
5634 "incorrect_name": "Chromium",
5635 }, {
Thiago Perrotta099034f2023-06-05 18:10:205636 "filename_postfix": "google_chrome_strings.grd",
5637 "correct_name": "Chrome",
5638 "incorrect_name": "Chrome for Testing",
5639 }, {
Sam Maiera6e76d72022-02-11 21:43:505640 "filename_postfix": "chromium_strings.grd",
5641 "correct_name": "Chromium",
5642 "incorrect_name": "Chrome",
5643 }]
Michael Giuffridad3bc8672018-10-25 22:48:025644
Sam Maiera6e76d72022-02-11 21:43:505645 for test_case in test_cases:
5646 problems = []
5647 filename_filter = lambda x: x.LocalPath().endswith(test_case[
5648 "filename_postfix"])
Michael Giuffridad3bc8672018-10-25 22:48:025649
Sam Maiera6e76d72022-02-11 21:43:505650 # Check each new line. Can yield false positives in multiline comments, but
5651 # easier than trying to parse the XML because messages can have nested
5652 # children, and associating message elements with affected lines is hard.
5653 for f in input_api.AffectedSourceFiles(filename_filter):
5654 for line_num, line in f.ChangedContents():
5655 if "<message" in line or "<!--" in line or "-->" in line:
5656 continue
5657 if test_case["incorrect_name"] in line:
Thiago Perrotta099034f2023-06-05 18:10:205658 # Chrome for Testing is a special edge case: https://goo.gle/chrome-for-testing#bookmark=id.n1rat320av91
5659 if (test_case["correct_name"] == "Chromium" and line.count("Chrome") == line.count("Chrome for Testing")):
5660 continue
Sam Maiera6e76d72022-02-11 21:43:505661 problems.append("Incorrect product name in %s:%d" %
5662 (f.LocalPath(), line_num))
Michael Giuffridad3bc8672018-10-25 22:48:025663
Sam Maiera6e76d72022-02-11 21:43:505664 if problems:
5665 message = (
5666 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
5667 % (test_case["correct_name"], test_case["correct_name"],
5668 test_case["incorrect_name"]))
5669 all_problems.append(
5670 output_api.PresubmitPromptWarning(message, items=problems))
Michael Giuffridad3bc8672018-10-25 22:48:025671
Sam Maiera6e76d72022-02-11 21:43:505672 return all_problems
Michael Giuffridad3bc8672018-10-25 22:48:025673
5674
Saagar Sanghavifceeaae2020-08-12 16:40:365675def CheckForTooLargeFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505676 """Avoid large files, especially binary files, in the repository since
5677 git doesn't scale well for those. They will be in everyone's repo
5678 clones forever, forever making Chromium slower to clone and work
5679 with."""
Daniel Bratell93eb6c62019-04-29 20:13:365680
Sam Maiera6e76d72022-02-11 21:43:505681 # Uploading files to cloud storage is not trivial so we don't want
5682 # to set the limit too low, but the upper limit for "normal" large
5683 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
5684 # anything over 20 MB is exceptional.
Bruce Dawsonbb414db2022-12-27 20:21:255685 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024
Daniel Bratell93eb6c62019-04-29 20:13:365686
Sam Maiera6e76d72022-02-11 21:43:505687 too_large_files = []
5688 for f in input_api.AffectedFiles():
5689 # Check both added and modified files (but not deleted files).
5690 if f.Action() in ('A', 'M'):
5691 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Joe DeBlasio10a832f2023-04-21 20:20:185692 if size > TOO_LARGE_FILE_SIZE_LIMIT:
Sam Maiera6e76d72022-02-11 21:43:505693 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
Daniel Bratell93eb6c62019-04-29 20:13:365694
Sam Maiera6e76d72022-02-11 21:43:505695 if too_large_files:
5696 message = (
5697 'Do not commit large files to git since git scales badly for those.\n'
5698 +
5699 'Instead put the large files in cloud storage and use DEPS to\n' +
5700 'fetch them.\n' + '\n'.join(too_large_files))
5701 return [
5702 output_api.PresubmitError('Too large files found in commit',
5703 long_text=message + '\n')
5704 ]
5705 else:
5706 return []
Daniel Bratell93eb6c62019-04-29 20:13:365707
Max Morozb47503b2019-08-08 21:03:275708
Saagar Sanghavifceeaae2020-08-12 16:40:365709def CheckFuzzTargetsOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505710 """Checks specific for fuzz target sources."""
5711 EXPORTED_SYMBOLS = [
5712 'LLVMFuzzerInitialize',
5713 'LLVMFuzzerCustomMutator',
5714 'LLVMFuzzerCustomCrossOver',
5715 'LLVMFuzzerMutate',
5716 ]
Max Morozb47503b2019-08-08 21:03:275717
Sam Maiera6e76d72022-02-11 21:43:505718 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
Max Morozb47503b2019-08-08 21:03:275719
Sam Maiera6e76d72022-02-11 21:43:505720 def FilterFile(affected_file):
5721 """Ignore libFuzzer source code."""
5722 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
Bruce Dawson40fece62022-09-16 19:58:315723 files_to_skip = r"^third_party/libFuzzer"
Max Morozb47503b2019-08-08 21:03:275724
Sam Maiera6e76d72022-02-11 21:43:505725 return input_api.FilterSourceFile(affected_file,
5726 files_to_check=[files_to_check],
5727 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:275728
Sam Maiera6e76d72022-02-11 21:43:505729 files_with_missing_header = []
5730 for f in input_api.AffectedSourceFiles(FilterFile):
5731 contents = input_api.ReadFile(f, 'r')
5732 if REQUIRED_HEADER in contents:
5733 continue
Max Morozb47503b2019-08-08 21:03:275734
Sam Maiera6e76d72022-02-11 21:43:505735 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
5736 files_with_missing_header.append(f.LocalPath())
Max Morozb47503b2019-08-08 21:03:275737
Sam Maiera6e76d72022-02-11 21:43:505738 if not files_with_missing_header:
5739 return []
Max Morozb47503b2019-08-08 21:03:275740
Sam Maiera6e76d72022-02-11 21:43:505741 long_text = (
5742 'If you define any of the libFuzzer optional functions (%s), it is '
5743 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
5744 'work incorrectly on Mac (crbug.com/687076).\nNote that '
5745 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
5746 'to access command line arguments passed to the fuzzer. Instead, prefer '
5747 'static initialization and shared resources as documented in '
5748 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
5749 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n'
5750 % (', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER))
Max Morozb47503b2019-08-08 21:03:275751
Sam Maiera6e76d72022-02-11 21:43:505752 return [
5753 output_api.PresubmitPromptWarning(message="Missing '%s' in:" %
5754 REQUIRED_HEADER,
5755 items=files_with_missing_header,
5756 long_text=long_text)
5757 ]
Max Morozb47503b2019-08-08 21:03:275758
5759
Mohamed Heikald048240a2019-11-12 16:57:375760def _CheckNewImagesWarning(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505761 """
5762 Warns authors who add images into the repo to make sure their images are
5763 optimized before committing.
5764 """
5765 images_added = False
5766 image_paths = []
5767 errors = []
5768 filter_lambda = lambda x: input_api.FilterSourceFile(
5769 x,
5770 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
5771 DEFAULT_FILES_TO_SKIP),
5772 files_to_check=[r'.*\/(drawable|mipmap)'])
5773 for f in input_api.AffectedFiles(include_deletes=False,
5774 file_filter=filter_lambda):
5775 local_path = f.LocalPath().lower()
5776 if any(
5777 local_path.endswith(extension)
5778 for extension in _IMAGE_EXTENSIONS):
5779 images_added = True
5780 image_paths.append(f)
5781 if images_added:
5782 errors.append(
5783 output_api.PresubmitPromptWarning(
5784 'It looks like you are trying to commit some images. If these are '
5785 'non-test-only images, please make sure to read and apply the tips in '
5786 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
5787 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
5788 'FYI only and will not block your CL on the CQ.', image_paths))
5789 return errors
Mohamed Heikald048240a2019-11-12 16:57:375790
5791
Saagar Sanghavifceeaae2020-08-12 16:40:365792def ChecksAndroidSpecificOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505793 """Groups upload checks that target android code."""
5794 results = []
5795 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
5796 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
5797 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
5798 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505799 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
5800 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
5801 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
5802 results.extend(_CheckNewImagesWarning(input_api, output_api))
5803 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
5804 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
5805 return results
5806
Becky Zhou7c69b50992018-12-10 19:37:575807
Saagar Sanghavifceeaae2020-08-12 16:40:365808def ChecksAndroidSpecificOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505809 """Groups commit checks that target android code."""
5810 results = []
5811 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
5812 return results
dgnaa68d5e2015-06-10 10:08:225813
Chris Hall59f8d0c72020-05-01 07:31:195814# TODO(chrishall): could we additionally match on any path owned by
5815# ui/accessibility/OWNERS ?
5816_ACCESSIBILITY_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:315817 r"^chrome/browser.*/accessibility/",
5818 r"^chrome/browser/extensions/api/automation.*/",
5819 r"^chrome/renderer/extensions/accessibility_.*",
5820 r"^chrome/tests/data/accessibility/",
5821 r"^content/browser/accessibility/",
5822 r"^content/renderer/accessibility/",
5823 r"^content/tests/data/accessibility/",
5824 r"^extensions/renderer/api/automation/",
Katie Dektar58ef07b2022-09-27 13:19:175825 r"^services/accessibility/",
Abigail Klein7a63c572024-02-28 20:45:095826 r"^services/screen_ai/",
Bruce Dawson40fece62022-09-16 19:58:315827 r"^ui/accessibility/",
5828 r"^ui/views/accessibility/",
Chris Hall59f8d0c72020-05-01 07:31:195829)
5830
Saagar Sanghavifceeaae2020-08-12 16:40:365831def CheckAccessibilityRelnotesField(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505832 """Checks that commits to accessibility code contain an AX-Relnotes field in
5833 their commit message."""
Chris Hall59f8d0c72020-05-01 07:31:195834
Sam Maiera6e76d72022-02-11 21:43:505835 def FileFilter(affected_file):
5836 paths = _ACCESSIBILITY_PATHS
5837 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:195838
Sam Maiera6e76d72022-02-11 21:43:505839 # Only consider changes affecting accessibility paths.
5840 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
5841 return []
Akihiro Ota08108e542020-05-20 15:30:535842
Sam Maiera6e76d72022-02-11 21:43:505843 # AX-Relnotes can appear in either the description or the footer.
5844 # When searching the description, require 'AX-Relnotes:' to appear at the
5845 # beginning of a line.
5846 ax_regex = input_api.re.compile('ax-relnotes[:=]')
5847 description_has_relnotes = any(
5848 ax_regex.match(line)
5849 for line in input_api.change.DescriptionText().lower().splitlines())
Chris Hall59f8d0c72020-05-01 07:31:195850
Sam Maiera6e76d72022-02-11 21:43:505851 footer_relnotes = input_api.change.GitFootersFromDescription().get(
5852 'AX-Relnotes', [])
5853 if description_has_relnotes or footer_relnotes:
5854 return []
Chris Hall59f8d0c72020-05-01 07:31:195855
Sam Maiera6e76d72022-02-11 21:43:505856 # TODO(chrishall): link to Relnotes documentation in message.
5857 message = (
5858 "Missing 'AX-Relnotes:' field required for accessibility changes"
5859 "\n please add 'AX-Relnotes: [release notes].' to describe any "
5860 "user-facing changes"
5861 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
5862 "user-facing effects"
5863 "\n if this is confusing or annoying then please contact members "
5864 "of ui/accessibility/OWNERS.")
5865
5866 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:225867
Mark Schillacie5a0be22022-01-19 00:38:395868
5869_ACCESSIBILITY_EVENTS_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315870 r"^content/test/data/accessibility/event/.*\.html",
Mark Schillacie5a0be22022-01-19 00:38:395871)
5872
5873_ACCESSIBILITY_TREE_TEST_PATH = (
Aaron Leventhal267119f2023-08-18 22:45:345874 r"^content/test/data/accessibility/accname/"
5875 ".*-expected-(mac|win|uia-win|auralinux).txt",
5876 r"^content/test/data/accessibility/aria/"
5877 ".*-expected-(mac|win|uia-win|auralinux).txt",
5878 r"^content/test/data/accessibility/css/"
5879 ".*-expected-(mac|win|uia-win|auralinux).txt",
5880 r"^content/test/data/accessibility/event/"
5881 ".*-expected-(mac|win|uia-win|auralinux).txt",
5882 r"^content/test/data/accessibility/html/"
5883 ".*-expected-(mac|win|uia-win|auralinux).txt",
Mark Schillacie5a0be22022-01-19 00:38:395884)
5885
5886_ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315887 r"^.*/WebContentsAccessibilityEventsTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:395888)
5889
5890_ACCESSIBILITY_ANDROID_TREE_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315891 r"^.*/WebContentsAccessibilityTreeTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:395892)
5893
5894def CheckAccessibilityEventsTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505895 """Checks that commits that include a newly added, renamed/moved, or deleted
5896 test in the DumpAccessibilityEventsTest suite also includes a corresponding
5897 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:395898
Sam Maiera6e76d72022-02-11 21:43:505899 def FilePathFilter(affected_file):
5900 paths = _ACCESSIBILITY_EVENTS_TEST_PATH
5901 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395902
Sam Maiera6e76d72022-02-11 21:43:505903 def AndroidFilePathFilter(affected_file):
5904 paths = _ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH
5905 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395906
Sam Maiera6e76d72022-02-11 21:43:505907 # Only consider changes in the events test data path with html type.
5908 if not any(
5909 input_api.AffectedFiles(include_deletes=True,
5910 file_filter=FilePathFilter)):
5911 return []
Mark Schillacie5a0be22022-01-19 00:38:395912
Sam Maiera6e76d72022-02-11 21:43:505913 # If the commit contains any change to the Android test file, ignore.
5914 if any(
5915 input_api.AffectedFiles(include_deletes=True,
5916 file_filter=AndroidFilePathFilter)):
5917 return []
Mark Schillacie5a0be22022-01-19 00:38:395918
Sam Maiera6e76d72022-02-11 21:43:505919 # Only consider changes that are adding/renaming or deleting a file
5920 message = []
5921 for f in input_api.AffectedFiles(include_deletes=True,
5922 file_filter=FilePathFilter):
Aaron Leventhal267119f2023-08-18 22:45:345923 if f.Action() == 'A':
Sam Maiera6e76d72022-02-11 21:43:505924 message = (
Aaron Leventhal267119f2023-08-18 22:45:345925 "It appears that you are adding platform expectations for a"
Aaron Leventhal0de81072023-08-21 21:26:525926 "\ndump_accessibility_events* test, but have not included"
Sam Maiera6e76d72022-02-11 21:43:505927 "\na corresponding change for Android."
Aaron Leventhal267119f2023-08-18 22:45:345928 "\nPlease include the test from:"
Sam Maiera6e76d72022-02-11 21:43:505929 "\n content/public/android/javatests/src/org/chromium/"
5930 "content/browser/accessibility/"
5931 "WebContentsAccessibilityEventsTest.java"
5932 "\nIf this message is confusing or annoying, please contact"
5933 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:395934
Sam Maiera6e76d72022-02-11 21:43:505935 # If no message was set, return empty.
5936 if not len(message):
5937 return []
5938
5939 return [output_api.PresubmitPromptWarning(message)]
5940
Mark Schillacie5a0be22022-01-19 00:38:395941
5942def CheckAccessibilityTreeTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505943 """Checks that commits that include a newly added, renamed/moved, or deleted
5944 test in the DumpAccessibilityTreeTest suite also includes a corresponding
5945 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:395946
Sam Maiera6e76d72022-02-11 21:43:505947 def FilePathFilter(affected_file):
5948 paths = _ACCESSIBILITY_TREE_TEST_PATH
5949 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395950
Sam Maiera6e76d72022-02-11 21:43:505951 def AndroidFilePathFilter(affected_file):
5952 paths = _ACCESSIBILITY_ANDROID_TREE_TEST_PATH
5953 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395954
Sam Maiera6e76d72022-02-11 21:43:505955 # Only consider changes in the various tree test data paths with html type.
5956 if not any(
5957 input_api.AffectedFiles(include_deletes=True,
5958 file_filter=FilePathFilter)):
5959 return []
Mark Schillacie5a0be22022-01-19 00:38:395960
Sam Maiera6e76d72022-02-11 21:43:505961 # If the commit contains any change to the Android test file, ignore.
5962 if any(
5963 input_api.AffectedFiles(include_deletes=True,
5964 file_filter=AndroidFilePathFilter)):
5965 return []
Mark Schillacie5a0be22022-01-19 00:38:395966
Sam Maiera6e76d72022-02-11 21:43:505967 # Only consider changes that are adding/renaming or deleting a file
5968 message = []
5969 for f in input_api.AffectedFiles(include_deletes=True,
5970 file_filter=FilePathFilter):
Aaron Leventhal0de81072023-08-21 21:26:525971 if f.Action() == 'A':
Sam Maiera6e76d72022-02-11 21:43:505972 message = (
Aaron Leventhal0de81072023-08-21 21:26:525973 "It appears that you are adding platform expectations for a"
5974 "\ndump_accessibility_tree* test, but have not included"
Sam Maiera6e76d72022-02-11 21:43:505975 "\na corresponding change for Android."
5976 "\nPlease include (or remove) the test from:"
5977 "\n content/public/android/javatests/src/org/chromium/"
5978 "content/browser/accessibility/"
5979 "WebContentsAccessibilityTreeTest.java"
5980 "\nIf this message is confusing or annoying, please contact"
5981 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:395982
Sam Maiera6e76d72022-02-11 21:43:505983 # If no message was set, return empty.
5984 if not len(message):
5985 return []
5986
5987 return [output_api.PresubmitPromptWarning(message)]
Mark Schillacie5a0be22022-01-19 00:38:395988
5989
seanmccullough4a9356252021-04-08 19:54:095990# string pattern, sequence of strings to show when pattern matches,
5991# error flag. True if match is a presubmit error, otherwise it's a warning.
5992_NON_INCLUSIVE_TERMS = (
5993 (
5994 # Note that \b pattern in python re is pretty particular. In this
5995 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
5996 # ...' will not. This may require some tweaking to catch these cases
5997 # without triggering a lot of false positives. Leaving it naive and
5998 # less matchy for now.
Josip Sokcevic9d2806a02023-12-13 03:04:025999 r'/(?i)\b((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:096000 (
6001 'Please don\'t use blacklist, whitelist, ' # nocheck
6002 'or slave in your', # nocheck
6003 'code and make every effort to use other terms. Using "// nocheck"',
6004 '"# nocheck" or "<!-- nocheck -->"',
6005 'at the end of the offending line will bypass this PRESUBMIT error',
6006 'but avoid using this whenever possible. Reach out to',
6007 '[email protected] if you have questions'),
6008 True),)
6009
Saagar Sanghavifceeaae2020-08-12 16:40:366010def ChecksCommon(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506011 """Checks common to both upload and commit."""
6012 results = []
Eric Boren6fd2b932018-01-25 15:05:086013 results.extend(
Sam Maiera6e76d72022-02-11 21:43:506014 input_api.canned_checks.PanProjectChecks(
6015 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:086016
Sam Maiera6e76d72022-02-11 21:43:506017 author = input_api.change.author_email
6018 if author and author not in _KNOWN_ROBOTS:
6019 results.extend(
6020 input_api.canned_checks.CheckAuthorizedAuthor(
6021 input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:246022
Sam Maiera6e76d72022-02-11 21:43:506023 results.extend(
6024 input_api.canned_checks.CheckChangeHasNoTabs(
6025 input_api,
6026 output_api,
6027 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
6028 results.extend(
6029 input_api.RunTests(
6030 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Edward Lesmesce51df52020-08-04 22:10:176031
Bruce Dawsonc8054482022-03-28 15:33:376032 dirmd = 'dirmd.bat' if input_api.is_windows else 'dirmd'
Sam Maiera6e76d72022-02-11 21:43:506033 dirmd_bin = input_api.os_path.join(input_api.PresubmitLocalPath(),
Bruce Dawsonc8054482022-03-28 15:33:376034 'third_party', 'depot_tools', dirmd)
Sam Maiera6e76d72022-02-11 21:43:506035 results.extend(
6036 input_api.RunTests(
6037 input_api.canned_checks.CheckDirMetadataFormat(
6038 input_api, output_api, dirmd_bin)))
6039 results.extend(
6040 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
6041 input_api, output_api))
6042 results.extend(
6043 input_api.canned_checks.CheckNoNewMetadataInOwners(
6044 input_api, output_api))
6045 results.extend(
6046 input_api.canned_checks.CheckInclusiveLanguage(
6047 input_api,
6048 output_api,
6049 excluded_directories_relative_path=[
6050 'infra', 'inclusive_language_presubmit_exempt_dirs.txt'
6051 ],
6052 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Dirk Prankee3c9c62d2021-05-18 18:35:596053
Aleksey Khoroshilov2978c942022-06-13 16:14:126054 presubmit_py_filter = lambda f: input_api.FilterSourceFile(
Bruce Dawson696963f2022-09-13 01:15:476055 f, files_to_check=[r'.*PRESUBMIT\.py$'])
Aleksey Khoroshilov2978c942022-06-13 16:14:126056 for f in input_api.AffectedFiles(include_deletes=False,
6057 file_filter=presubmit_py_filter):
6058 full_path = input_api.os_path.dirname(f.AbsoluteLocalPath())
6059 test_file = input_api.os_path.join(full_path, 'PRESUBMIT_test.py')
6060 # The PRESUBMIT.py file (and the directory containing it) might have
6061 # been affected by being moved or removed, so only try to run the tests
6062 # if they still exist.
6063 if not input_api.os_path.exists(test_file):
6064 continue
Sam Maiera6e76d72022-02-11 21:43:506065
Aleksey Khoroshilov2978c942022-06-13 16:14:126066 results.extend(
6067 input_api.canned_checks.RunUnitTestsInDirectory(
6068 input_api,
6069 output_api,
6070 full_path,
Takuto Ikuta40def482023-06-02 02:23:496071 files_to_check=[r'^PRESUBMIT_test\.py$']))
Sam Maiera6e76d72022-02-11 21:43:506072 return results
[email protected]1f7b4172010-01-28 01:17:346073
[email protected]b337cb5b2011-01-23 21:24:056074
Saagar Sanghavifceeaae2020-08-12 16:40:366075def CheckPatchFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506076 problems = [
6077 f.LocalPath() for f in input_api.AffectedFiles()
6078 if f.LocalPath().endswith(('.orig', '.rej'))
6079 ]
6080 # Cargo.toml.orig files are part of third-party crates downloaded from
6081 # crates.io and should be included.
6082 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
6083 if problems:
6084 return [
6085 output_api.PresubmitError("Don't commit .rej and .orig files.",
6086 problems)
6087 ]
6088 else:
6089 return []
[email protected]b8079ae4a2012-12-05 19:56:496090
6091
Saagar Sanghavifceeaae2020-08-12 16:40:366092def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506093 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
6094 macro_re = input_api.re.compile(
6095 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
6096 include_re = input_api.re.compile(r'^#include\s+"build/build_config.h"',
6097 input_api.re.MULTILINE)
6098 extension_re = input_api.re.compile(r'\.[a-z]+$')
6099 errors = []
Bruce Dawsonf7679202022-08-09 20:24:006100 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:506101 for f in input_api.AffectedFiles(include_deletes=False):
Bruce Dawsonf7679202022-08-09 20:24:006102 # The build-config macros are allowed to be used in build_config.h
6103 # without including itself.
6104 if f.LocalPath() == config_h_file:
6105 continue
Sam Maiera6e76d72022-02-11 21:43:506106 if not f.LocalPath().endswith(
6107 ('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
6108 continue
Arthur Sonzognia3dec412024-04-29 12:05:376109
Sam Maiera6e76d72022-02-11 21:43:506110 found_line_number = None
6111 found_macro = None
6112 all_lines = input_api.ReadFile(f, 'r').splitlines()
6113 for line_num, line in enumerate(all_lines):
6114 match = macro_re.search(line)
6115 if match:
6116 found_line_number = line_num
6117 found_macro = match.group(2)
6118 break
6119 if not found_line_number:
6120 continue
Kent Tamura5a8755d2017-06-29 23:37:076121
Sam Maiera6e76d72022-02-11 21:43:506122 found_include_line = -1
6123 for line_num, line in enumerate(all_lines):
6124 if include_re.search(line):
6125 found_include_line = line_num
6126 break
6127 if found_include_line >= 0 and found_include_line < found_line_number:
6128 continue
Kent Tamura5a8755d2017-06-29 23:37:076129
Sam Maiera6e76d72022-02-11 21:43:506130 if not f.LocalPath().endswith('.h'):
6131 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
6132 try:
6133 content = input_api.ReadFile(primary_header_path, 'r')
6134 if include_re.search(content):
6135 continue
6136 except IOError:
6137 pass
6138 errors.append('%s:%d %s macro is used without first including build/'
6139 'build_config.h.' %
6140 (f.LocalPath(), found_line_number, found_macro))
6141 if errors:
6142 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
6143 return []
Kent Tamura5a8755d2017-06-29 23:37:076144
6145
Lei Zhang1c12a22f2021-05-12 11:28:456146def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506147 stl_include_re = input_api.re.compile(r'^#include\s+<('
6148 r'algorithm|'
6149 r'array|'
6150 r'limits|'
6151 r'list|'
6152 r'map|'
6153 r'memory|'
6154 r'queue|'
6155 r'set|'
6156 r'string|'
6157 r'unordered_map|'
6158 r'unordered_set|'
6159 r'utility|'
6160 r'vector)>')
6161 std_namespace_re = input_api.re.compile(r'std::')
6162 errors = []
6163 for f in input_api.AffectedFiles():
6164 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
6165 continue
Lei Zhang1c12a22f2021-05-12 11:28:456166
Sam Maiera6e76d72022-02-11 21:43:506167 uses_std_namespace = False
6168 has_stl_include = False
6169 for line in f.NewContents():
6170 if has_stl_include and uses_std_namespace:
6171 break
Lei Zhang1c12a22f2021-05-12 11:28:456172
Sam Maiera6e76d72022-02-11 21:43:506173 if not has_stl_include and stl_include_re.search(line):
6174 has_stl_include = True
6175 continue
Lei Zhang1c12a22f2021-05-12 11:28:456176
Bruce Dawson4a5579a2022-04-08 17:11:366177 if not uses_std_namespace and (std_namespace_re.search(line)
6178 or 'no-std-usage-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:506179 uses_std_namespace = True
6180 continue
Lei Zhang1c12a22f2021-05-12 11:28:456181
Sam Maiera6e76d72022-02-11 21:43:506182 if has_stl_include and not uses_std_namespace:
6183 errors.append(
6184 '%s: Includes STL header(s) but does not reference std::' %
6185 f.LocalPath())
6186 if errors:
6187 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
6188 return []
Lei Zhang1c12a22f2021-05-12 11:28:456189
6190
Xiaohan Wang42d96c22022-01-20 17:23:116191def _CheckForDeprecatedOSMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:506192 """Check for sensible looking, totally invalid OS macros."""
6193 preprocessor_statement = input_api.re.compile(r'^\s*#')
6194 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
6195 results = []
6196 for lnum, line in f.ChangedContents():
6197 if preprocessor_statement.search(line):
6198 for match in os_macro.finditer(line):
6199 results.append(
6200 ' %s:%d: %s' %
6201 (f.LocalPath(), lnum, 'defined(OS_' + match.group(1) +
6202 ') -> BUILDFLAG(IS_' + match.group(1) + ')'))
6203 return results
[email protected]b00342e7f2013-03-26 16:21:546204
6205
Xiaohan Wang42d96c22022-01-20 17:23:116206def CheckForDeprecatedOSMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506207 """Check all affected files for invalid OS macros."""
6208 bad_macros = []
Bruce Dawsonf7679202022-08-09 20:24:006209 # The OS_ macros are allowed to be used in build/build_config.h.
6210 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:506211 for f in input_api.AffectedSourceFiles(None):
Bruce Dawsonf7679202022-08-09 20:24:006212 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')) \
6213 and f.LocalPath() != config_h_file:
Sam Maiera6e76d72022-02-11 21:43:506214 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
[email protected]b00342e7f2013-03-26 16:21:546215
Sam Maiera6e76d72022-02-11 21:43:506216 if not bad_macros:
6217 return []
[email protected]b00342e7f2013-03-26 16:21:546218
Sam Maiera6e76d72022-02-11 21:43:506219 return [
6220 output_api.PresubmitError(
6221 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
6222 'defined in build_config.h):', bad_macros)
6223 ]
[email protected]b00342e7f2013-03-26 16:21:546224
lliabraa35bab3932014-10-01 12:16:446225
6226def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:506227 """Check all affected files for invalid "if defined" macros."""
6228 ALWAYS_DEFINED_MACROS = (
6229 "TARGET_CPU_PPC",
6230 "TARGET_CPU_PPC64",
6231 "TARGET_CPU_68K",
6232 "TARGET_CPU_X86",
6233 "TARGET_CPU_ARM",
6234 "TARGET_CPU_MIPS",
6235 "TARGET_CPU_SPARC",
6236 "TARGET_CPU_ALPHA",
6237 "TARGET_IPHONE_SIMULATOR",
6238 "TARGET_OS_EMBEDDED",
6239 "TARGET_OS_IPHONE",
6240 "TARGET_OS_MAC",
6241 "TARGET_OS_UNIX",
6242 "TARGET_OS_WIN32",
6243 )
6244 ifdef_macro = input_api.re.compile(
6245 r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
6246 results = []
6247 for lnum, line in f.ChangedContents():
6248 for match in ifdef_macro.finditer(line):
6249 if match.group(1) in ALWAYS_DEFINED_MACROS:
6250 always_defined = ' %s is always defined. ' % match.group(1)
6251 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
6252 results.append(
6253 ' %s:%d %s\n\t%s' %
6254 (f.LocalPath(), lnum, always_defined, did_you_mean))
6255 return results
lliabraa35bab3932014-10-01 12:16:446256
6257
Saagar Sanghavifceeaae2020-08-12 16:40:366258def CheckForInvalidIfDefinedMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506259 """Check all affected files for invalid "if defined" macros."""
Arthur Sonzogni4fd14fd2024-06-02 18:42:526260 SKIPPED_PATHS = [
6261 'base/allocator/partition_allocator/src/partition_alloc/build_config.h',
6262 'build/build_config.h',
6263 'third_party/abseil-cpp/',
6264 'third_party/sqlite/',
6265 ]
6266 def affected_files_filter(f):
6267 # Normalize the local path to Linux-style path separators so that the
6268 # path comparisons work on Windows as well.
6269 path = f.LocalPath().replace('\\', '/')
6270
6271 for skipped_path in SKIPPED_PATHS:
6272 if path.startswith(skipped_path):
6273 return False
6274
6275 return path.endswith(('.h', '.c', '.cc', '.m', '.mm'))
6276
Sam Maiera6e76d72022-02-11 21:43:506277 bad_macros = []
Arthur Sonzogni4fd14fd2024-06-02 18:42:526278 for f in input_api.AffectedSourceFiles(affected_files_filter):
6279 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
lliabraa35bab3932014-10-01 12:16:446280
Sam Maiera6e76d72022-02-11 21:43:506281 if not bad_macros:
6282 return []
lliabraa35bab3932014-10-01 12:16:446283
Sam Maiera6e76d72022-02-11 21:43:506284 return [
6285 output_api.PresubmitError(
6286 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
6287 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
6288 bad_macros)
6289 ]
lliabraa35bab3932014-10-01 12:16:446290
Saagar Sanghavifceeaae2020-08-12 16:40:366291def CheckForIPCRules(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506292 """Check for same IPC rules described in
6293 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
6294 """
6295 base_pattern = r'IPC_ENUM_TRAITS\('
6296 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
6297 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
mlamouria82272622014-09-16 18:45:046298
Sam Maiera6e76d72022-02-11 21:43:506299 problems = []
6300 for f in input_api.AffectedSourceFiles(None):
6301 local_path = f.LocalPath()
6302 if not local_path.endswith('.h'):
6303 continue
6304 for line_number, line in f.ChangedContents():
6305 if inclusion_pattern.search(
6306 line) and not comment_pattern.search(line):
6307 problems.append('%s:%d\n %s' %
6308 (local_path, line_number, line.strip()))
mlamouria82272622014-09-16 18:45:046309
Sam Maiera6e76d72022-02-11 21:43:506310 if problems:
6311 return [
6312 output_api.PresubmitPromptWarning(_IPC_ENUM_TRAITS_DEPRECATED,
6313 problems)
6314 ]
6315 else:
6316 return []
mlamouria82272622014-09-16 18:45:046317
[email protected]b00342e7f2013-03-26 16:21:546318
Saagar Sanghavifceeaae2020-08-12 16:40:366319def CheckForLongPathnames(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506320 """Check to make sure no files being submitted have long paths.
6321 This causes issues on Windows.
6322 """
6323 problems = []
6324 for f in input_api.AffectedTestableFiles():
6325 local_path = f.LocalPath()
6326 # Windows has a path limit of 260 characters. Limit path length to 200 so
6327 # that we have some extra for the prefix on dev machines and the bots.
Weizhong Xia8b461f12024-06-21 21:46:336328 if (local_path.startswith('third_party/blink/web_tests/platform/') and
6329 not local_path.startswith('third_party/blink/web_tests/platform/win')):
6330 # Do not check length of the path for files not used by Windows
6331 continue
Sam Maiera6e76d72022-02-11 21:43:506332 if len(local_path) > 200:
6333 problems.append(local_path)
Stephen Martinis97a394142018-06-07 23:06:056334
Sam Maiera6e76d72022-02-11 21:43:506335 if problems:
6336 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
6337 else:
6338 return []
Stephen Martinis97a394142018-06-07 23:06:056339
6340
Saagar Sanghavifceeaae2020-08-12 16:40:366341def CheckForIncludeGuards(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506342 """Check that header files have proper guards against multiple inclusion.
6343 If a file should not have such guards (and it probably should) then it
Bruce Dawson4a5579a2022-04-08 17:11:366344 should include the string "no-include-guard-because-multiply-included" or
6345 "no-include-guard-because-pch-file".
Sam Maiera6e76d72022-02-11 21:43:506346 """
Daniel Bratell8ba52722018-03-02 16:06:146347
Sam Maiera6e76d72022-02-11 21:43:506348 def is_chromium_header_file(f):
6349 # We only check header files under the control of the Chromium
mikt84d6c712024-03-27 13:29:036350 # project. This excludes:
6351 # - third_party/*, except blink.
6352 # - base/allocator/partition_allocator/: PartitionAlloc is a standalone
6353 # library used outside of Chrome. Includes are referenced from its
6354 # own base directory. It has its own `CheckForIncludeGuards`
6355 # PRESUBMIT.py check.
6356 # - *_message_generator.h: They use include guards in a special,
6357 # non-typical way.
Sam Maiera6e76d72022-02-11 21:43:506358 file_with_path = input_api.os_path.normpath(f.LocalPath())
6359 return (file_with_path.endswith('.h')
6360 and not file_with_path.endswith('_message_generator.h')
Bruce Dawson4c4c2922022-05-02 18:07:336361 and not file_with_path.endswith('com_imported_mstscax.h')
mikt84d6c712024-03-27 13:29:036362 and not file_with_path.startswith('base/allocator/partition_allocator')
Sam Maiera6e76d72022-02-11 21:43:506363 and (not file_with_path.startswith('third_party')
6364 or file_with_path.startswith(
6365 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:146366
Sam Maiera6e76d72022-02-11 21:43:506367 def replace_special_with_underscore(string):
6368 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:146369
Sam Maiera6e76d72022-02-11 21:43:506370 errors = []
Daniel Bratell8ba52722018-03-02 16:06:146371
Sam Maiera6e76d72022-02-11 21:43:506372 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
6373 guard_name = None
6374 guard_line_number = None
6375 seen_guard_end = False
Lei Zhangd84f9512024-05-28 19:43:306376 bypass_checks_at_end_of_file = False
Daniel Bratell8ba52722018-03-02 16:06:146377
Sam Maiera6e76d72022-02-11 21:43:506378 file_with_path = input_api.os_path.normpath(f.LocalPath())
6379 base_file_name = input_api.os_path.splitext(
6380 input_api.os_path.basename(file_with_path))[0]
6381 upper_base_file_name = base_file_name.upper()
Daniel Bratell8ba52722018-03-02 16:06:146382
Sam Maiera6e76d72022-02-11 21:43:506383 expected_guard = replace_special_with_underscore(
6384 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:146385
Sam Maiera6e76d72022-02-11 21:43:506386 # For "path/elem/file_name.h" we should really only accept
6387 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
6388 # are too many (1000+) files with slight deviations from the
6389 # coding style. The most important part is that the include guard
6390 # is there, and that it's unique, not the name so this check is
6391 # forgiving for existing files.
6392 #
6393 # As code becomes more uniform, this could be made stricter.
Daniel Bratell8ba52722018-03-02 16:06:146394
Sam Maiera6e76d72022-02-11 21:43:506395 guard_name_pattern_list = [
6396 # Anything with the right suffix (maybe with an extra _).
6397 r'\w+_H__?',
Daniel Bratell8ba52722018-03-02 16:06:146398
Sam Maiera6e76d72022-02-11 21:43:506399 # To cover include guards with old Blink style.
6400 r'\w+_h',
Daniel Bratell8ba52722018-03-02 16:06:146401
Sam Maiera6e76d72022-02-11 21:43:506402 # Anything including the uppercase name of the file.
6403 r'\w*' + input_api.re.escape(
6404 replace_special_with_underscore(upper_base_file_name)) +
6405 r'\w*',
6406 ]
6407 guard_name_pattern = '|'.join(guard_name_pattern_list)
6408 guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
6409 guard_name_pattern + ')')
Daniel Bratell8ba52722018-03-02 16:06:146410
Sam Maiera6e76d72022-02-11 21:43:506411 for line_number, line in enumerate(f.NewContents()):
Bruce Dawson4a5579a2022-04-08 17:11:366412 if ('no-include-guard-because-multiply-included' in line
6413 or 'no-include-guard-because-pch-file' in line):
Lei Zhangd84f9512024-05-28 19:43:306414 bypass_checks_at_end_of_file = True
Sam Maiera6e76d72022-02-11 21:43:506415 break
Daniel Bratell8ba52722018-03-02 16:06:146416
Sam Maiera6e76d72022-02-11 21:43:506417 if guard_name is None:
6418 match = guard_pattern.match(line)
6419 if match:
6420 guard_name = match.group(1)
6421 guard_line_number = line_number
Daniel Bratell8ba52722018-03-02 16:06:146422
Sam Maiera6e76d72022-02-11 21:43:506423 # We allow existing files to use include guards whose names
6424 # don't match the chromium style guide, but new files should
6425 # get it right.
Bruce Dawson6cc154e2022-04-12 20:39:496426 if guard_name != expected_guard:
Bruce Dawson95eb7562022-09-14 15:27:166427 if f.Action() == 'A': # If file was just 'A'dded
Sam Maiera6e76d72022-02-11 21:43:506428 errors.append(
6429 output_api.PresubmitPromptWarning(
6430 'Header using the wrong include guard name %s'
6431 % guard_name, [
6432 '%s:%d' %
6433 (f.LocalPath(), line_number + 1)
6434 ], 'Expected: %r\nFound: %r' %
6435 (expected_guard, guard_name)))
6436 else:
6437 # The line after #ifndef should have a #define of the same name.
6438 if line_number == guard_line_number + 1:
6439 expected_line = '#define %s' % guard_name
6440 if line != expected_line:
6441 errors.append(
6442 output_api.PresubmitPromptWarning(
6443 'Missing "%s" for include guard' %
6444 expected_line,
6445 ['%s:%d' % (f.LocalPath(), line_number + 1)],
6446 'Expected: %r\nGot: %r' %
6447 (expected_line, line)))
Daniel Bratell8ba52722018-03-02 16:06:146448
Sam Maiera6e76d72022-02-11 21:43:506449 if not seen_guard_end and line == '#endif // %s' % guard_name:
6450 seen_guard_end = True
6451 elif seen_guard_end:
6452 if line.strip() != '':
6453 errors.append(
6454 output_api.PresubmitPromptWarning(
6455 'Include guard %s not covering the whole file'
6456 % (guard_name), [f.LocalPath()]))
6457 break # Nothing else to check and enough to warn once.
Daniel Bratell8ba52722018-03-02 16:06:146458
Lei Zhangd84f9512024-05-28 19:43:306459 if bypass_checks_at_end_of_file:
6460 continue
6461
Sam Maiera6e76d72022-02-11 21:43:506462 if guard_name is None:
6463 errors.append(
6464 output_api.PresubmitPromptWarning(
Bruce Dawson32114b62022-04-11 16:45:496465 'Missing include guard in %s\n'
Sam Maiera6e76d72022-02-11 21:43:506466 'Recommended name: %s\n'
6467 'This check can be disabled by having the string\n'
Bruce Dawson4a5579a2022-04-08 17:11:366468 '"no-include-guard-because-multiply-included" or\n'
6469 '"no-include-guard-because-pch-file" in the header.'
Sam Maiera6e76d72022-02-11 21:43:506470 % (f.LocalPath(), expected_guard)))
Lei Zhangd84f9512024-05-28 19:43:306471 elif not seen_guard_end:
6472 errors.append(
6473 output_api.PresubmitPromptWarning(
6474 'Incorrect or missing include guard #endif in %s\n'
6475 'Recommended #endif comment: // %s'
6476 % (f.LocalPath(), expected_guard)))
Sam Maiera6e76d72022-02-11 21:43:506477
6478 return errors
Daniel Bratell8ba52722018-03-02 16:06:146479
6480
Saagar Sanghavifceeaae2020-08-12 16:40:366481def CheckForWindowsLineEndings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506482 """Check source code and known ascii text files for Windows style line
6483 endings.
6484 """
Bruce Dawson5efbdc652022-04-11 19:29:516485 known_text_files = r'.*\.(txt|html|htm|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:236486
Sam Maiera6e76d72022-02-11 21:43:506487 file_inclusion_pattern = (known_text_files,
6488 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
6489 r'.+%s' % _HEADER_EXTENSIONS)
mostynbb639aca52015-01-07 20:31:236490
Sam Maiera6e76d72022-02-11 21:43:506491 problems = []
6492 source_file_filter = lambda f: input_api.FilterSourceFile(
6493 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
6494 for f in input_api.AffectedSourceFiles(source_file_filter):
Bruce Dawson5efbdc652022-04-11 19:29:516495 # Ignore test files that contain crlf intentionally.
6496 if f.LocalPath().endswith('crlf.txt'):
Daniel Chenga37c03db2022-05-12 17:20:346497 continue
Sam Maiera6e76d72022-02-11 21:43:506498 include_file = False
6499 for line in input_api.ReadFile(f, 'r').splitlines(True):
6500 if line.endswith('\r\n'):
6501 include_file = True
6502 if include_file:
6503 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:236504
Sam Maiera6e76d72022-02-11 21:43:506505 if problems:
6506 return [
6507 output_api.PresubmitPromptWarning(
6508 'Are you sure that you want '
6509 'these files to contain Windows style line endings?\n' +
6510 '\n'.join(problems))
6511 ]
mostynbb639aca52015-01-07 20:31:236512
Sam Maiera6e76d72022-02-11 21:43:506513 return []
6514
mostynbb639aca52015-01-07 20:31:236515
Evan Stade6cfc964c12021-05-18 20:21:166516def CheckIconFilesForLicenseHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506517 """Check that .icon files (which are fragments of C++) have license headers.
6518 """
Evan Stade6cfc964c12021-05-18 20:21:166519
Sam Maiera6e76d72022-02-11 21:43:506520 icon_files = (r'.*\.icon$', )
Evan Stade6cfc964c12021-05-18 20:21:166521
Sam Maiera6e76d72022-02-11 21:43:506522 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
6523 return input_api.canned_checks.CheckLicense(input_api,
6524 output_api,
6525 source_file_filter=icons)
6526
Evan Stade6cfc964c12021-05-18 20:21:166527
Jose Magana2b456f22021-03-09 23:26:406528def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506529 """Check source code for use of Chrome App technologies being
6530 deprecated.
6531 """
Jose Magana2b456f22021-03-09 23:26:406532
Sam Maiera6e76d72022-02-11 21:43:506533 def _CheckForDeprecatedTech(input_api,
6534 output_api,
6535 detection_list,
6536 files_to_check=None,
6537 files_to_skip=None):
Jose Magana2b456f22021-03-09 23:26:406538
Sam Maiera6e76d72022-02-11 21:43:506539 if (files_to_check or files_to_skip):
6540 source_file_filter = lambda f: input_api.FilterSourceFile(
6541 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
6542 else:
6543 source_file_filter = None
6544
6545 problems = []
6546
6547 for f in input_api.AffectedSourceFiles(source_file_filter):
6548 if f.Action() == 'D':
6549 continue
6550 for _, line in f.ChangedContents():
6551 if any(detect in line for detect in detection_list):
6552 problems.append(f.LocalPath())
6553
6554 return problems
6555
6556 # to avoid this presubmit script triggering warnings
6557 files_to_skip = ['PRESUBMIT.py', 'PRESUBMIT_test.py']
Jose Magana2b456f22021-03-09 23:26:406558
6559 problems = []
6560
Sam Maiera6e76d72022-02-11 21:43:506561 # NMF: any files with extensions .nmf or NMF
6562 _NMF_FILES = r'\.(nmf|NMF)$'
6563 problems += _CheckForDeprecatedTech(
6564 input_api,
6565 output_api,
6566 detection_list=[''], # any change to the file will trigger warning
6567 files_to_check=[r'.+%s' % _NMF_FILES])
Jose Magana2b456f22021-03-09 23:26:406568
Sam Maiera6e76d72022-02-11 21:43:506569 # MANIFEST: any manifest.json that in its diff includes "app":
6570 _MANIFEST_FILES = r'(manifest\.json)$'
6571 problems += _CheckForDeprecatedTech(
6572 input_api,
6573 output_api,
6574 detection_list=['"app":'],
6575 files_to_check=[r'.*%s' % _MANIFEST_FILES])
Jose Magana2b456f22021-03-09 23:26:406576
Sam Maiera6e76d72022-02-11 21:43:506577 # NaCl / PNaCl: any file that in its diff contains the strings in the list
6578 problems += _CheckForDeprecatedTech(
6579 input_api,
6580 output_api,
6581 detection_list=['config=nacl', 'enable-nacl', 'cpu=pnacl', 'nacl_io'],
Bruce Dawson40fece62022-09-16 19:58:316582 files_to_skip=files_to_skip + [r"^native_client_sdk/"])
Jose Magana2b456f22021-03-09 23:26:406583
Gao Shenga79ebd42022-08-08 17:25:596584 # PPAPI: any C/C++ file that in its diff includes a ppapi library
Sam Maiera6e76d72022-02-11 21:43:506585 problems += _CheckForDeprecatedTech(
6586 input_api,
6587 output_api,
6588 detection_list=['#include "ppapi', '#include <ppapi'],
6589 files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,
6590 r'.+%s' % _IMPLEMENTATION_EXTENSIONS),
Bruce Dawson40fece62022-09-16 19:58:316591 files_to_skip=[r"^ppapi/"])
Jose Magana2b456f22021-03-09 23:26:406592
Sam Maiera6e76d72022-02-11 21:43:506593 if problems:
6594 return [
6595 output_api.PresubmitPromptWarning(
6596 'You are adding/modifying code'
6597 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
6598 ' PNaCl, PPAPI). See this blog post for more details:\n'
6599 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
6600 'and this documentation for options to replace these technologies:\n'
6601 'https://developer.chrome.com/docs/apps/migration/\n' +
6602 '\n'.join(problems))
6603 ]
Jose Magana2b456f22021-03-09 23:26:406604
Sam Maiera6e76d72022-02-11 21:43:506605 return []
Jose Magana2b456f22021-03-09 23:26:406606
mostynbb639aca52015-01-07 20:31:236607
Saagar Sanghavifceeaae2020-08-12 16:40:366608def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
Sam Maiera6e76d72022-02-11 21:43:506609 """Checks that all source files use SYSLOG properly."""
6610 syslog_files = []
6611 for f in input_api.AffectedSourceFiles(src_file_filter):
6612 for line_number, line in f.ChangedContents():
6613 if 'SYSLOG' in line:
6614 syslog_files.append(f.LocalPath() + ':' + str(line_number))
pastarmovj032ba5bc2017-01-12 10:41:566615
Sam Maiera6e76d72022-02-11 21:43:506616 if syslog_files:
6617 return [
6618 output_api.PresubmitPromptWarning(
6619 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
6620 ' calls.\nFiles to check:\n',
6621 items=syslog_files)
6622 ]
6623 return []
pastarmovj89f7ee12016-09-20 14:58:136624
6625
[email protected]1f7b4172010-01-28 01:17:346626def CheckChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506627 if input_api.version < [2, 0, 0]:
6628 return [
6629 output_api.PresubmitError(
6630 "Your depot_tools is out of date. "
6631 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
6632 "but your version is %d.%d.%d" % tuple(input_api.version))
6633 ]
6634 results = []
6635 results.extend(
6636 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
6637 return results
[email protected]ca8d19842009-02-19 16:33:126638
6639
6640def CheckChangeOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506641 if input_api.version < [2, 0, 0]:
6642 return [
6643 output_api.PresubmitError(
6644 "Your depot_tools is out of date. "
6645 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
6646 "but your version is %d.%d.%d" % tuple(input_api.version))
6647 ]
Saagar Sanghavifceeaae2020-08-12 16:40:366648
Sam Maiera6e76d72022-02-11 21:43:506649 results = []
6650 # Make sure the tree is 'open'.
6651 results.extend(
6652 input_api.canned_checks.CheckTreeIsOpen(
6653 input_api,
6654 output_api,
6655 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:276656
Sam Maiera6e76d72022-02-11 21:43:506657 results.extend(
6658 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
6659 results.extend(
6660 input_api.canned_checks.CheckChangeHasBugField(input_api, output_api))
6661 results.extend(
6662 input_api.canned_checks.CheckChangeHasNoUnwantedTags(
6663 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:506664 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146665
6666
Saagar Sanghavifceeaae2020-08-12 16:40:366667def CheckStrings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506668 """Check string ICU syntax validity and if translation screenshots exist."""
6669 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
6670 # footer is set to true.
6671 git_footers = input_api.change.GitFootersFromDescription()
6672 skip_screenshot_check_footer = [
6673 footer.lower() for footer in git_footers.get(
6674 u'Skip-Translation-Screenshots-Check', [])
6675 ]
6676 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:026677
Sam Maiera6e76d72022-02-11 21:43:506678 import os
6679 import re
6680 import sys
6681 from io import StringIO
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146682
Sam Maiera6e76d72022-02-11 21:43:506683 new_or_added_paths = set(f.LocalPath() for f in input_api.AffectedFiles()
6684 if (f.Action() == 'A' or f.Action() == 'M'))
6685 removed_paths = set(f.LocalPath()
6686 for f in input_api.AffectedFiles(include_deletes=True)
6687 if f.Action() == 'D')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146688
Sam Maiera6e76d72022-02-11 21:43:506689 affected_grds = [
6690 f for f in input_api.AffectedFiles()
6691 if f.LocalPath().endswith(('.grd', '.grdp'))
6692 ]
6693 affected_grds = [
6694 f for f in affected_grds if not 'testdata' in f.LocalPath()
6695 ]
6696 if not affected_grds:
6697 return []
meacer8c0d3832019-12-26 21:46:166698
Sam Maiera6e76d72022-02-11 21:43:506699 affected_png_paths = [
Andrew Grieve713b89b2024-10-15 20:20:086700 f.LocalPath() for f in input_api.AffectedFiles()
6701 if f.LocalPath().endswith('.png')
Sam Maiera6e76d72022-02-11 21:43:506702 ]
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146703
Sam Maiera6e76d72022-02-11 21:43:506704 # Check for screenshots. Developers can upload screenshots using
6705 # tools/translation/upload_screenshots.py which finds and uploads
6706 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
6707 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
6708 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
6709 #
6710 # The logic here is as follows:
6711 #
6712 # - If the CL has a .png file under the screenshots directory for a grd
6713 # file, warn the developer. Actual images should never be checked into the
6714 # Chrome repo.
6715 #
6716 # - If the CL contains modified or new messages in grd files and doesn't
6717 # contain the corresponding .sha1 files, warn the developer to add images
6718 # and upload them via tools/translation/upload_screenshots.py.
6719 #
6720 # - If the CL contains modified or new messages in grd files and the
6721 # corresponding .sha1 files, everything looks good.
6722 #
6723 # - If the CL contains removed messages in grd files but the corresponding
6724 # .sha1 files aren't removed, warn the developer to remove them.
6725 unnecessary_screenshots = []
Jens Mueller054652c2023-05-10 15:12:306726 invalid_sha1 = []
Sam Maiera6e76d72022-02-11 21:43:506727 missing_sha1 = []
Bruce Dawson55776c42022-12-09 17:23:476728 missing_sha1_modified = []
Sam Maiera6e76d72022-02-11 21:43:506729 unnecessary_sha1_files = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146730
Sam Maiera6e76d72022-02-11 21:43:506731 # This checks verifies that the ICU syntax of messages this CL touched is
6732 # valid, and reports any found syntax errors.
6733 # Without this presubmit check, ICU syntax errors in Chromium strings can land
6734 # without developers being aware of them. Later on, such ICU syntax errors
6735 # break message extraction for translation, hence would block Chromium
6736 # translations until they are fixed.
6737 icu_syntax_errors = []
Jens Mueller054652c2023-05-10 15:12:306738 sha1_pattern = input_api.re.compile(r'^[a-fA-F0-9]{40}$',
6739 input_api.re.MULTILINE)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146740
Sam Maiera6e76d72022-02-11 21:43:506741 def _CheckScreenshotAdded(screenshots_dir, message_id):
6742 sha1_path = input_api.os_path.join(screenshots_dir,
6743 message_id + '.png.sha1')
6744 if sha1_path not in new_or_added_paths:
6745 missing_sha1.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306746 elif not _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256747 invalid_sha1.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146748
Bruce Dawson55776c42022-12-09 17:23:476749 def _CheckScreenshotModified(screenshots_dir, message_id):
6750 sha1_path = input_api.os_path.join(screenshots_dir,
6751 message_id + '.png.sha1')
6752 if sha1_path not in new_or_added_paths:
6753 missing_sha1_modified.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306754 elif not _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256755 invalid_sha1.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306756
6757 def _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256758 return sha1_pattern.search(
6759 next("\n".join(f.NewContents()) for f in input_api.AffectedFiles()
6760 if f.LocalPath() == sha1_path))
Bruce Dawson55776c42022-12-09 17:23:476761
Sam Maiera6e76d72022-02-11 21:43:506762 def _CheckScreenshotRemoved(screenshots_dir, message_id):
6763 sha1_path = input_api.os_path.join(screenshots_dir,
6764 message_id + '.png.sha1')
6765 if input_api.os_path.exists(
6766 sha1_path) and sha1_path not in removed_paths:
6767 unnecessary_sha1_files.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146768
Sam Maiera6e76d72022-02-11 21:43:506769 def _ValidateIcuSyntax(text, level, signatures):
6770 """Validates ICU syntax of a text string.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146771
Sam Maiera6e76d72022-02-11 21:43:506772 Check if text looks similar to ICU and checks for ICU syntax correctness
6773 in this case. Reports various issues with ICU syntax and values of
6774 variants. Supports checking of nested messages. Accumulate information of
6775 each ICU messages found in the text for further checking.
Rainhard Findlingfc31844c52020-05-15 09:58:266776
Sam Maiera6e76d72022-02-11 21:43:506777 Args:
6778 text: a string to check.
6779 level: a number of current nesting level.
6780 signatures: an accumulator, a list of tuple of (level, variable,
6781 kind, variants).
Rainhard Findlingfc31844c52020-05-15 09:58:266782
Sam Maiera6e76d72022-02-11 21:43:506783 Returns:
6784 None if a string is not ICU or no issue detected.
6785 A tuple of (message, start index, end index) if an issue detected.
6786 """
6787 valid_types = {
6788 'plural': (frozenset(
Rainhard Findling3cde3ef02024-02-05 18:40:326789 ['=0', '=1', '=2', '=3', 'zero', 'one', 'two', 'few', 'many',
Sam Maiera6e76d72022-02-11 21:43:506790 'other']), frozenset(['=1', 'other'])),
6791 'selectordinal': (frozenset(
Rainhard Findling3cde3ef02024-02-05 18:40:326792 ['=0', '=1', '=2', '=3', 'zero', 'one', 'two', 'few', 'many',
Sam Maiera6e76d72022-02-11 21:43:506793 'other']), frozenset(['one', 'other'])),
6794 'select': (frozenset(), frozenset(['other'])),
6795 }
Rainhard Findlingfc31844c52020-05-15 09:58:266796
Sam Maiera6e76d72022-02-11 21:43:506797 # Check if the message looks like an attempt to use ICU
6798 # plural. If yes - check if its syntax strictly matches ICU format.
6799 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b',
6800 text)
6801 if not like:
6802 signatures.append((level, None, None, None))
6803 return
Rainhard Findlingfc31844c52020-05-15 09:58:266804
Sam Maiera6e76d72022-02-11 21:43:506805 # Check for valid prefix and suffix
6806 m = re.match(
6807 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
6808 r'(plural|selectordinal|select),\s*'
6809 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
6810 if not m:
6811 return (('This message looks like an ICU plural, '
6812 'but does not follow ICU syntax.'), like.start(),
6813 like.end())
6814 starting, variable, kind, variant_pairs = m.groups()
6815 variants, depth, last_pos = _ParseIcuVariants(variant_pairs,
6816 m.start(4))
6817 if depth:
6818 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
6819 len(text))
6820 first = text[0]
6821 ending = text[last_pos:]
6822 if not starting:
6823 return ('Invalid ICU format. No initial opening bracket',
6824 last_pos - 1, last_pos)
6825 if not ending or '}' not in ending:
6826 return ('Invalid ICU format. No final closing bracket',
6827 last_pos - 1, last_pos)
6828 elif first != '{':
6829 return ((
6830 'Invalid ICU format. Extra characters at the start of a complex '
6831 'message (go/icu-message-migration): "%s"') % starting, 0,
6832 len(starting))
6833 elif ending != '}':
6834 return ((
6835 'Invalid ICU format. Extra characters at the end of a complex '
6836 'message (go/icu-message-migration): "%s"') % ending,
6837 last_pos - 1, len(text) - 1)
6838 if kind not in valid_types:
6839 return (('Unknown ICU message type %s. '
6840 'Valid types are: plural, select, selectordinal') % kind,
6841 0, 0)
6842 known, required = valid_types[kind]
6843 defined_variants = set()
6844 for variant, variant_range, value, value_range in variants:
6845 start, end = variant_range
6846 if variant in defined_variants:
6847 return ('Variant "%s" is defined more than once' % variant,
6848 start, end)
6849 elif known and variant not in known:
6850 return ('Variant "%s" is not valid for %s message' %
6851 (variant, kind), start, end)
6852 defined_variants.add(variant)
6853 # Check for nested structure
6854 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
6855 if res:
6856 return (res[0], res[1] + value_range[0] + 1,
6857 res[2] + value_range[0] + 1)
6858 missing = required - defined_variants
6859 if missing:
6860 return ('Required variants missing: %s' % ', '.join(missing), 0,
6861 len(text))
6862 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:266863
Sam Maiera6e76d72022-02-11 21:43:506864 def _ParseIcuVariants(text, offset=0):
6865 """Parse variants part of ICU complex message.
Rainhard Findlingfc31844c52020-05-15 09:58:266866
Sam Maiera6e76d72022-02-11 21:43:506867 Builds a tuple of variant names and values, as well as
6868 their offsets in the input string.
Rainhard Findlingfc31844c52020-05-15 09:58:266869
Sam Maiera6e76d72022-02-11 21:43:506870 Args:
6871 text: a string to parse
6872 offset: additional offset to add to positions in the text to get correct
6873 position in the complete ICU string.
Rainhard Findlingfc31844c52020-05-15 09:58:266874
Sam Maiera6e76d72022-02-11 21:43:506875 Returns:
6876 List of tuples, each tuple consist of four fields: variant name,
6877 variant name span (tuple of two integers), variant value, value
6878 span (tuple of two integers).
6879 """
6880 depth, start, end = 0, -1, -1
6881 variants = []
6882 key = None
6883 for idx, char in enumerate(text):
6884 if char == '{':
6885 if not depth:
6886 start = idx
6887 chunk = text[end + 1:start]
6888 key = chunk.strip()
6889 pos = offset + end + 1 + chunk.find(key)
6890 span = (pos, pos + len(key))
6891 depth += 1
6892 elif char == '}':
6893 if not depth:
6894 return variants, depth, offset + idx
6895 depth -= 1
6896 if not depth:
6897 end = idx
6898 variants.append((key, span, text[start:end + 1],
6899 (offset + start, offset + end + 1)))
6900 return variants, depth, offset + end + 1
Rainhard Findlingfc31844c52020-05-15 09:58:266901
Sam Maiera6e76d72022-02-11 21:43:506902 try:
6903 old_sys_path = sys.path
6904 sys.path = sys.path + [
6905 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
6906 'translation')
6907 ]
6908 from helper import grd_helper
6909 finally:
6910 sys.path = old_sys_path
Rainhard Findlingfc31844c52020-05-15 09:58:266911
Sam Maiera6e76d72022-02-11 21:43:506912 for f in affected_grds:
6913 file_path = f.LocalPath()
6914 old_id_to_msg_map = {}
6915 new_id_to_msg_map = {}
6916 # Note that this code doesn't check if the file has been deleted. This is
6917 # OK because it only uses the old and new file contents and doesn't load
6918 # the file via its path.
6919 # It's also possible that a file's content refers to a renamed or deleted
6920 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
6921 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
6922 # .grdp files.
6923 if file_path.endswith('.grdp'):
6924 if f.OldContents():
6925 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6926 '\n'.join(f.OldContents()))
6927 if f.NewContents():
6928 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6929 '\n'.join(f.NewContents()))
6930 else:
6931 file_dir = input_api.os_path.dirname(file_path) or '.'
6932 if f.OldContents():
6933 old_id_to_msg_map = grd_helper.GetGrdMessages(
6934 StringIO('\n'.join(f.OldContents())), file_dir)
6935 if f.NewContents():
6936 new_id_to_msg_map = grd_helper.GetGrdMessages(
6937 StringIO('\n'.join(f.NewContents())), file_dir)
Rainhard Findlingfc31844c52020-05-15 09:58:266938
Sam Maiera6e76d72022-02-11 21:43:506939 grd_name, ext = input_api.os_path.splitext(
6940 input_api.os_path.basename(file_path))
6941 screenshots_dir = input_api.os_path.join(
6942 input_api.os_path.dirname(file_path),
6943 grd_name + ext.replace('.', '_'))
Rainhard Findlingfc31844c52020-05-15 09:58:266944
Sam Maiera6e76d72022-02-11 21:43:506945 # Compute added, removed and modified message IDs.
6946 old_ids = set(old_id_to_msg_map)
6947 new_ids = set(new_id_to_msg_map)
6948 added_ids = new_ids - old_ids
6949 removed_ids = old_ids - new_ids
6950 modified_ids = set([])
6951 for key in old_ids.intersection(new_ids):
6952 if (old_id_to_msg_map[key].ContentsAsXml('', True) !=
6953 new_id_to_msg_map[key].ContentsAsXml('', True)):
6954 # The message content itself changed. Require an updated screenshot.
6955 modified_ids.add(key)
6956 elif old_id_to_msg_map[key].attrs['meaning'] != \
6957 new_id_to_msg_map[key].attrs['meaning']:
Jens Mueller054652c2023-05-10 15:12:306958 # The message meaning changed. We later check for a screenshot.
6959 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146960
Sam Maiera6e76d72022-02-11 21:43:506961 if run_screenshot_check:
6962 # Check the screenshot directory for .png files. Warn if there is any.
6963 for png_path in affected_png_paths:
6964 if png_path.startswith(screenshots_dir):
6965 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146966
Sam Maiera6e76d72022-02-11 21:43:506967 for added_id in added_ids:
6968 _CheckScreenshotAdded(screenshots_dir, added_id)
Rainhard Findlingd8d04372020-08-13 13:30:096969
Sam Maiera6e76d72022-02-11 21:43:506970 for modified_id in modified_ids:
Bruce Dawson55776c42022-12-09 17:23:476971 _CheckScreenshotModified(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146972
Sam Maiera6e76d72022-02-11 21:43:506973 for removed_id in removed_ids:
6974 _CheckScreenshotRemoved(screenshots_dir, removed_id)
6975
6976 # Check new and changed strings for ICU syntax errors.
6977 for key in added_ids.union(modified_ids):
6978 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
6979 err = _ValidateIcuSyntax(msg, 0, [])
6980 if err is not None:
6981 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
6982
6983 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:266984 if run_screenshot_check:
Sam Maiera6e76d72022-02-11 21:43:506985 if unnecessary_screenshots:
6986 results.append(
6987 output_api.PresubmitError(
6988 'Do not include actual screenshots in the changelist. Run '
6989 'tools/translate/upload_screenshots.py to upload them instead:',
6990 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146991
Sam Maiera6e76d72022-02-11 21:43:506992 if missing_sha1:
6993 results.append(
6994 output_api.PresubmitError(
Bruce Dawson55776c42022-12-09 17:23:476995 'You are adding UI strings.\n'
Sam Maiera6e76d72022-02-11 21:43:506996 'To ensure the best translations, take screenshots of the relevant UI '
6997 '(https://g.co/chrome/translation) and add these files to your '
6998 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146999
Jens Mueller054652c2023-05-10 15:12:307000 if invalid_sha1:
7001 results.append(
7002 output_api.PresubmitError(
7003 'The following files do not seem to contain valid sha1 hashes. '
7004 'Make sure they contain hashes created by '
7005 'tools/translate/upload_screenshots.py:', sorted(invalid_sha1)))
7006
Bruce Dawson55776c42022-12-09 17:23:477007 if missing_sha1_modified:
7008 results.append(
7009 output_api.PresubmitError(
7010 'You are modifying UI strings or their meanings.\n'
7011 'To ensure the best translations, take screenshots of the relevant UI '
7012 '(https://g.co/chrome/translation) and add these files to your '
7013 'changelist:', sorted(missing_sha1_modified)))
7014
Sam Maiera6e76d72022-02-11 21:43:507015 if unnecessary_sha1_files:
7016 results.append(
7017 output_api.PresubmitError(
7018 'You removed strings associated with these files. Remove:',
7019 sorted(unnecessary_sha1_files)))
7020 else:
7021 results.append(
7022 output_api.PresubmitPromptOrNotify('Skipping translation '
7023 'screenshots check.'))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147024
Sam Maiera6e76d72022-02-11 21:43:507025 if icu_syntax_errors:
7026 results.append(
7027 output_api.PresubmitPromptWarning(
7028 'ICU syntax errors were found in the following strings (problems or '
7029 'feedback? Contact [email protected]):',
7030 items=icu_syntax_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:267031
Sam Maiera6e76d72022-02-11 21:43:507032 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:127033
7034
Saagar Sanghavifceeaae2020-08-12 16:40:367035def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:127036 repo_root=None,
7037 translation_expectations_path=None,
7038 grd_files=None):
Sam Maiera6e76d72022-02-11 21:43:507039 import sys
7040 affected_grds = [
7041 f for f in input_api.AffectedFiles()
7042 if (f.LocalPath().endswith('.grd') or f.LocalPath().endswith('.grdp'))
7043 ]
7044 if not affected_grds:
7045 return []
7046
7047 try:
7048 old_sys_path = sys.path
7049 sys.path = sys.path + [
7050 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
7051 'translation')
7052 ]
7053 from helper import git_helper
7054 from helper import translation_helper
7055 finally:
7056 sys.path = old_sys_path
7057
7058 # Check that translation expectations can be parsed and we can get a list of
7059 # translatable grd files. |repo_root| and |translation_expectations_path| are
7060 # only passed by tests.
7061 if not repo_root:
7062 repo_root = input_api.PresubmitLocalPath()
7063 if not translation_expectations_path:
7064 translation_expectations_path = input_api.os_path.join(
7065 repo_root, 'tools', 'gritsettings', 'translation_expectations.pyl')
7066 if not grd_files:
7067 grd_files = git_helper.list_grds_in_repository(repo_root)
7068
7069 # Ignore bogus grd files used only for testing
Gao Shenga79ebd42022-08-08 17:25:597070 # ui/webui/resources/tools/generate_grd.py.
Sam Maiera6e76d72022-02-11 21:43:507071 ignore_path = input_api.os_path.join('ui', 'webui', 'resources', 'tools',
7072 'tests')
7073 grd_files = [p for p in grd_files if ignore_path not in p]
7074
7075 try:
7076 translation_helper.get_translatable_grds(
7077 repo_root, grd_files, translation_expectations_path)
7078 except Exception as e:
7079 return [
7080 output_api.PresubmitNotifyResult(
7081 'Failed to get a list of translatable grd files. This happens when:\n'
7082 ' - One of the modified grd or grdp files cannot be parsed or\n'
7083 ' - %s is not updated.\n'
7084 'Stack:\n%s' % (translation_expectations_path, str(e)))
7085 ]
Mustafa Emre Acer51f2f742020-03-09 19:41:127086 return []
7087
Ken Rockotc31f4832020-05-29 18:58:517088
Saagar Sanghavifceeaae2020-08-12 16:40:367089def CheckStableMojomChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507090 """Changes to [Stable] mojom types must preserve backward-compatibility."""
7091 changed_mojoms = input_api.AffectedFiles(
7092 include_deletes=True,
7093 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:527094
Bruce Dawson344ab262022-06-04 11:35:107095 if not changed_mojoms or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:507096 return []
7097
7098 delta = []
7099 for mojom in changed_mojoms:
Sam Maiera6e76d72022-02-11 21:43:507100 delta.append({
7101 'filename': mojom.LocalPath(),
7102 'old': '\n'.join(mojom.OldContents()) or None,
7103 'new': '\n'.join(mojom.NewContents()) or None,
7104 })
7105
7106 process = input_api.subprocess.Popen([
Takuto Ikutadca10222022-04-13 02:51:217107 input_api.python3_executable,
Sam Maiera6e76d72022-02-11 21:43:507108 input_api.os_path.join(
7109 input_api.PresubmitLocalPath(), 'mojo', 'public', 'tools', 'mojom',
7110 'check_stable_mojom_compatibility.py'), '--src-root',
7111 input_api.PresubmitLocalPath()
7112 ],
7113 stdin=input_api.subprocess.PIPE,
7114 stdout=input_api.subprocess.PIPE,
7115 stderr=input_api.subprocess.PIPE,
7116 universal_newlines=True)
7117 (x, error) = process.communicate(input=input_api.json.dumps(delta))
7118 if process.returncode:
7119 return [
7120 output_api.PresubmitError(
7121 'One or more [Stable] mojom definitions appears to have been changed '
Alex Goughc99921652024-02-15 22:59:127122 'in a way that is not backward-compatible. See '
7123 'https://chromium.googlesource.com/chromium/src/+/HEAD/mojo/public/tools/bindings/README.md#versioning'
7124 ' for details.',
Sam Maiera6e76d72022-02-11 21:43:507125 long_text=error)
7126 ]
Erik Staabc734cd7a2021-11-23 03:11:527127 return []
7128
Dominic Battre645d42342020-12-04 16:14:107129def CheckDeprecationOfPreferences(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507130 """Removing a preference should come with a deprecation."""
Dominic Battre645d42342020-12-04 16:14:107131
Sam Maiera6e76d72022-02-11 21:43:507132 def FilterFile(affected_file):
7133 """Accept only .cc files and the like."""
7134 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
7135 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
7136 input_api.DEFAULT_FILES_TO_SKIP)
7137 return input_api.FilterSourceFile(
7138 affected_file,
7139 files_to_check=file_inclusion_pattern,
7140 files_to_skip=files_to_skip)
Dominic Battre645d42342020-12-04 16:14:107141
Sam Maiera6e76d72022-02-11 21:43:507142 def ModifiedLines(affected_file):
7143 """Returns a list of tuples (line number, line text) of added and removed
7144 lines.
Dominic Battre645d42342020-12-04 16:14:107145
Sam Maiera6e76d72022-02-11 21:43:507146 Deleted lines share the same line number as the previous line.
Dominic Battre645d42342020-12-04 16:14:107147
Sam Maiera6e76d72022-02-11 21:43:507148 This relies on the scm diff output describing each changed code section
7149 with a line of the form
Dominic Battre645d42342020-12-04 16:14:107150
Sam Maiera6e76d72022-02-11 21:43:507151 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
7152 """
7153 line_num = 0
7154 modified_lines = []
7155 for line in affected_file.GenerateScmDiff().splitlines():
7156 # Extract <new line num> of the patch fragment (see format above).
7157 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@',
7158 line)
7159 if m:
7160 line_num = int(m.groups(1)[0])
7161 continue
7162 if ((line.startswith('+') and not line.startswith('++'))
7163 or (line.startswith('-') and not line.startswith('--'))):
7164 modified_lines.append((line_num, line))
Dominic Battre645d42342020-12-04 16:14:107165
Sam Maiera6e76d72022-02-11 21:43:507166 if not line.startswith('-'):
7167 line_num += 1
7168 return modified_lines
Dominic Battre645d42342020-12-04 16:14:107169
Sam Maiera6e76d72022-02-11 21:43:507170 def FindLineWith(lines, needle):
7171 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
Dominic Battre645d42342020-12-04 16:14:107172
Sam Maiera6e76d72022-02-11 21:43:507173 If 0 or >1 lines contain `needle`, -1 is returned.
7174 """
7175 matching_line_numbers = [
7176 # + 1 for 1-based counting of line numbers.
7177 i + 1 for i, line in enumerate(lines) if needle in line
7178 ]
7179 return matching_line_numbers[0] if len(
7180 matching_line_numbers) == 1 else -1
Dominic Battre645d42342020-12-04 16:14:107181
Sam Maiera6e76d72022-02-11 21:43:507182 def ModifiedPrefMigration(affected_file):
7183 """Returns whether the MigrateObsolete.*Pref functions were modified."""
7184 # Determine first and last lines of MigrateObsolete.*Pref functions.
7185 new_contents = affected_file.NewContents()
7186 range_1 = (FindLineWith(new_contents,
7187 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
7188 FindLineWith(new_contents,
7189 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
7190 range_2 = (FindLineWith(new_contents,
7191 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
7192 FindLineWith(new_contents,
7193 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
7194 if (-1 in range_1 + range_2):
7195 raise Exception(
7196 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.'
7197 )
Dominic Battre645d42342020-12-04 16:14:107198
Sam Maiera6e76d72022-02-11 21:43:507199 # Check whether any of the modified lines are part of the
7200 # MigrateObsolete.*Pref functions.
7201 for line_nr, line in ModifiedLines(affected_file):
7202 if (range_1[0] <= line_nr <= range_1[1]
7203 or range_2[0] <= line_nr <= range_2[1]):
7204 return True
7205 return False
Dominic Battre645d42342020-12-04 16:14:107206
Sam Maiera6e76d72022-02-11 21:43:507207 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
7208 browser_prefs_file_pattern = input_api.re.compile(
7209 r'chrome/browser/prefs/browser_prefs.cc')
Dominic Battre645d42342020-12-04 16:14:107210
Sam Maiera6e76d72022-02-11 21:43:507211 changes = input_api.AffectedFiles(include_deletes=True,
7212 file_filter=FilterFile)
7213 potential_problems = []
7214 for f in changes:
7215 for line in f.GenerateScmDiff().splitlines():
7216 # Check deleted lines for pref registrations.
7217 if (line.startswith('-') and not line.startswith('--')
7218 and register_pref_pattern.search(line)):
7219 potential_problems.append('%s: %s' % (f.LocalPath(), line))
Dominic Battre645d42342020-12-04 16:14:107220
Sam Maiera6e76d72022-02-11 21:43:507221 if browser_prefs_file_pattern.search(f.LocalPath()):
7222 # If the developer modified the MigrateObsolete.*Prefs() functions, we
7223 # assume that they knew that they have to deprecate preferences and don't
7224 # warn.
7225 try:
7226 if ModifiedPrefMigration(f):
7227 return []
7228 except Exception as e:
7229 return [output_api.PresubmitError(str(e))]
Dominic Battre645d42342020-12-04 16:14:107230
Sam Maiera6e76d72022-02-11 21:43:507231 if potential_problems:
7232 return [
7233 output_api.PresubmitPromptWarning(
7234 'Discovered possible removal of preference registrations.\n\n'
7235 'Please make sure to properly deprecate preferences by clearing their\n'
7236 'value for a couple of milestones before finally removing the code.\n'
7237 'Otherwise data may stay in the preferences files forever. See\n'
7238 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
7239 'chrome/browser/prefs/README.md for examples.\n'
7240 'This may be a false positive warning (e.g. if you move preference\n'
7241 'registrations to a different place).\n', potential_problems)
7242 ]
7243 return []
7244
Matt Stark6ef08872021-07-29 01:21:467245
7246def CheckConsistentGrdChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507247 """Changes to GRD files must be consistent for tools to read them."""
7248 changed_grds = input_api.AffectedFiles(
7249 include_deletes=False,
7250 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
7251 errors = []
7252 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
7253 for matcher, msg in _INVALID_GRD_FILE_LINE]
7254 for grd in changed_grds:
7255 for i, line in enumerate(grd.NewContents()):
7256 for matcher, msg in invalid_file_regexes:
7257 if matcher.search(line):
7258 errors.append(
7259 output_api.PresubmitError(
7260 'Problem on {grd}:{i} - {msg}'.format(
7261 grd=grd.LocalPath(), i=i + 1, msg=msg)))
7262 return errors
7263
Kevin McNee967dd2d22021-11-15 16:09:297264
Henrique Ferreiro2a4b55942021-11-29 23:45:367265def CheckAssertAshOnlyCode(input_api, output_api):
7266 """Errors if a BUILD.gn file in an ash/ directory doesn't include
Georg Neis94f87f02024-10-22 08:20:137267 assert(is_chromeos).
7268 For a transition period, assert(is_chromeos_ash) is also accepted.
Henrique Ferreiro2a4b55942021-11-29 23:45:367269 """
7270
7271 def FileFilter(affected_file):
7272 """Includes directories known to be Ash only."""
7273 return input_api.FilterSourceFile(
7274 affected_file,
7275 files_to_check=(
7276 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
7277 r'.*/ash/.*BUILD\.gn'), # Any path component.
7278 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
7279
7280 errors = []
Georg Neis94f87f02024-10-22 08:20:137281 pattern = input_api.re.compile(r'assert\(is_chromeos(_ash)?\b')
Jameson Thies0ce669f2021-12-09 15:56:567282 for f in input_api.AffectedFiles(include_deletes=False,
7283 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:367284 if (not pattern.search(input_api.ReadFile(f))):
7285 errors.append(
7286 output_api.PresubmitError(
Georg Neis94f87f02024-10-22 08:20:137287 'Please add assert(is_chromeos) to %s. If that\'s not '
7288 'possible, please create an issue and add a comment such '
Alison Galed6b25fe2024-04-17 13:59:047289 'as:\n # TODO(crbug.com/XXX): add '
Georg Neis94f87f02024-10-22 08:20:137290 'assert(is_chromeos) when ...' % f.LocalPath()))
Henrique Ferreiro2a4b55942021-11-29 23:45:367291 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:277292
7293
Kalvin Lee84ad17a2023-09-25 11:14:417294def _IsMiraclePtrDisallowed(input_api, affected_file):
Sam Maiera6e76d72022-02-11 21:43:507295 path = affected_file.LocalPath()
7296 if not _IsCPlusPlusFile(input_api, path):
7297 return False
7298
Bartek Nowierski49b1a452024-06-08 00:24:357299 # Renderer-only code is generally allowed to use MiraclePtr. These
7300 # directories, however, are specifically disallowed, for perf reasons.
Kalvin Lee84ad17a2023-09-25 11:14:417301 if ("third_party/blink/renderer/core/" in path
7302 or "third_party/blink/renderer/platform/heap/" in path
Bartek Nowierski49b1a452024-06-08 00:24:357303 or "third_party/blink/renderer/platform/wtf/" in path
7304 or "third_party/blink/renderer/platform/fonts/" in path):
7305 return True
7306
7307 # The below paths are an explicitly listed subset of Renderer-only code,
7308 # because the plan is to Oilpanize it.
7309 # TODO(crbug.com/330759291): Remove once Oilpanization is completed or
7310 # abandoned.
7311 if ("third_party/blink/renderer/core/paint/" in path
7312 or "third_party/blink/renderer/platform/graphics/compositing/" in path
7313 or "third_party/blink/renderer/platform/graphics/paint/" in path):
Sam Maiera6e76d72022-02-11 21:43:507314 return True
7315
Sam Maiera6e76d72022-02-11 21:43:507316 # We assume that everything else may be used outside of Renderer processes.
Lukasz Anforowicz7016d05e2021-11-30 03:56:277317 return False
7318
Alison Galed6b25fe2024-04-17 13:59:047319# TODO(crbug.com/40206238): Remove these checks, once they are replaced
Lukasz Anforowicz7016d05e2021-11-30 03:56:277320# by the Chromium Clang Plugin (which will be preferable because it will
7321# 1) report errors earlier - at compile-time and 2) cover more rules).
7322def CheckRawPtrUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507323 """Rough checks that raw_ptr<T> usage guidelines are followed."""
7324 errors = []
7325 # The regex below matches "raw_ptr<" following a word boundary, but not in a
7326 # C++ comment.
7327 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
Kalvin Lee84ad17a2023-09-25 11:14:417328 file_filter = lambda f: _IsMiraclePtrDisallowed(input_api, f)
Sam Maiera6e76d72022-02-11 21:43:507329 for f, line_num, line in input_api.RightHandSideLines(file_filter):
7330 if raw_ptr_matcher.search(line):
7331 errors.append(
7332 output_api.PresubmitError(
7333 'Problem on {path}:{line} - '\
Kalvin Lee84ad17a2023-09-25 11:14:417334 'raw_ptr<T> should not be used in this renderer code '\
Sam Maiera6e76d72022-02-11 21:43:507335 '(as documented in the "Pointers to unprotected memory" '\
7336 'section in //base/memory/raw_ptr.md)'.format(
7337 path=f.LocalPath(), line=line_num)))
7338 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:567339
mikt9337567c2023-09-08 18:38:177340def CheckAdvancedMemorySafetyChecksUsage(input_api, output_api):
7341 """Checks that ADVANCED_MEMORY_SAFETY_CHECKS() macro is neither added nor
7342 removed as it is managed by the memory safety team internally.
7343 Do not add / remove it manually."""
7344 paths = set([])
7345 # The regex below matches "ADVANCED_MEMORY_SAFETY_CHECKS(" following a word
7346 # boundary, but not in a C++ comment.
7347 macro_matcher = input_api.re.compile(
7348 r'^((?!//).)*\bADVANCED_MEMORY_SAFETY_CHECKS\(', input_api.re.MULTILINE)
7349 for f in input_api.AffectedFiles():
7350 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
7351 continue
7352 if macro_matcher.search(f.GenerateScmDiff()):
7353 paths.add(f.LocalPath())
7354 if not paths:
7355 return []
7356 return [output_api.PresubmitPromptWarning(
7357 'ADVANCED_MEMORY_SAFETY_CHECKS() macro is managed by ' \
7358 'the memory safety team (chrome-memory-safety@). ' \
7359 'Please contact us to add/delete the uses of the macro.',
7360 paths)]
Henrique Ferreirof9819f2e32021-11-30 13:31:567361
7362def CheckPythonShebang(input_api, output_api):
7363 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
7364 system-wide python.
7365 """
7366 errors = []
7367 sources = lambda affected_file: input_api.FilterSourceFile(
7368 affected_file,
7369 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
7370 r'third_party/blink/web_tests/external/') + input_api.
7371 DEFAULT_FILES_TO_SKIP),
7372 files_to_check=[r'.*\.py$'])
7373 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:277374 for line_num, line in f.ChangedContents():
7375 if line_num == 1 and line.startswith('#!/usr/bin/python'):
7376 errors.append(f.LocalPath())
7377 break
Henrique Ferreirof9819f2e32021-11-30 13:31:567378
7379 result = []
7380 for file in errors:
7381 result.append(
7382 output_api.PresubmitError(
7383 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
7384 file))
7385 return result
James Shen81cc0e22022-06-15 21:10:457386
7387
7388def CheckBatchAnnotation(input_api, output_api):
7389 """Checks that tests have either @Batch or @DoNotBatch annotation. If this
7390 is not an instrumentation test, disregard."""
7391
7392 batch_annotation = input_api.re.compile(r'^\s*@Batch')
7393 do_not_batch_annotation = input_api.re.compile(r'^\s*@DoNotBatch')
7394 robolectric_test = input_api.re.compile(r'[rR]obolectric')
7395 test_class_declaration = input_api.re.compile(r'^\s*public\sclass.*Test')
7396 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
Mark Schillaci8ef0d872023-07-18 22:07:597397 test_annotation_declaration = input_api.re.compile(r'^\s*public\s@interface\s.*{')
James Shen81cc0e22022-06-15 21:10:457398
ckitagawae8fd23b2022-06-17 15:29:387399 missing_annotation_errors = []
7400 extra_annotation_errors = []
James Shen81cc0e22022-06-15 21:10:457401
7402 def _FilterFile(affected_file):
7403 return input_api.FilterSourceFile(
7404 affected_file,
7405 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
7406 files_to_check=[r'.*Test\.java$'])
7407
7408 for f in input_api.AffectedSourceFiles(_FilterFile):
7409 batch_matched = None
7410 do_not_batch_matched = None
7411 is_instrumentation_test = True
Mark Schillaci8ef0d872023-07-18 22:07:597412 test_annotation_declaration_matched = None
James Shen81cc0e22022-06-15 21:10:457413 for line in f.NewContents():
7414 if robolectric_test.search(line) or uiautomator_test.search(line):
7415 # Skip Robolectric and UiAutomator tests.
7416 is_instrumentation_test = False
7417 break
7418 if not batch_matched:
7419 batch_matched = batch_annotation.search(line)
7420 if not do_not_batch_matched:
7421 do_not_batch_matched = do_not_batch_annotation.search(line)
7422 test_class_declaration_matched = test_class_declaration.search(
7423 line)
Mark Schillaci8ef0d872023-07-18 22:07:597424 test_annotation_declaration_matched = test_annotation_declaration.search(line)
7425 if test_class_declaration_matched or test_annotation_declaration_matched:
James Shen81cc0e22022-06-15 21:10:457426 break
Mark Schillaci8ef0d872023-07-18 22:07:597427 if test_annotation_declaration_matched:
7428 continue
James Shen81cc0e22022-06-15 21:10:457429 if (is_instrumentation_test and
7430 not batch_matched and
7431 not do_not_batch_matched):
Sam Maier4cef9242022-10-03 14:21:247432 missing_annotation_errors.append(str(f.LocalPath()))
ckitagawae8fd23b2022-06-17 15:29:387433 if (not is_instrumentation_test and
7434 (batch_matched or
7435 do_not_batch_matched)):
Sam Maier4cef9242022-10-03 14:21:247436 extra_annotation_errors.append(str(f.LocalPath()))
James Shen81cc0e22022-06-15 21:10:457437
7438 results = []
7439
ckitagawae8fd23b2022-06-17 15:29:387440 if missing_annotation_errors:
James Shen81cc0e22022-06-15 21:10:457441 results.append(
7442 output_api.PresubmitPromptWarning(
7443 """
Andrew Grieve43a5cf82023-09-08 15:09:467444A change was made to an on-device test that has neither been annotated with
7445@Batch nor @DoNotBatch. If this is a new test, please add the annotation. If
7446this is an existing test, please consider adding it if you are sufficiently
7447familiar with the test (but do so as a separate change).
7448
Jens Mueller2085ff82023-02-27 11:54:497449See https://source.chromium.org/chromium/chromium/src/+/main:docs/testing/batching_instrumentation_tests.md
ckitagawae8fd23b2022-06-17 15:29:387450""", missing_annotation_errors))
7451 if extra_annotation_errors:
7452 results.append(
7453 output_api.PresubmitPromptWarning(
7454 """
7455Robolectric tests do not need a @Batch or @DoNotBatch annotations.
7456""", extra_annotation_errors))
James Shen81cc0e22022-06-15 21:10:457457
7458 return results
Sam Maier4cef9242022-10-03 14:21:247459
7460
7461def CheckMockAnnotation(input_api, output_api):
7462 """Checks that we have annotated all Mockito.mock()-ed or Mockito.spy()-ed
7463 classes with @Mock or @Spy. If this is not an instrumentation test,
7464 disregard."""
7465
7466 # This is just trying to be approximately correct. We are not writing a
7467 # Java parser, so special cases like statically importing mock() then
7468 # calling an unrelated non-mockito spy() function will cause a false
7469 # positive.
7470 package_name = input_api.re.compile(r'^package\s+(\w+(?:\.\w+)+);')
7471 mock_static_import = input_api.re.compile(
7472 r'^import\s+static\s+org.mockito.Mockito.(?:mock|spy);')
7473 import_class = input_api.re.compile(r'import\s+((?:\w+\.)+)(\w+);')
7474 mock_annotation = input_api.re.compile(r'^\s*@(?:Mock|Spy)')
7475 field_type = input_api.re.compile(r'(\w+)(?:<\w+>)?\s+\w+\s*(?:;|=)')
7476 mock_or_spy_function_call = r'(?:mock|spy)\(\s*(?:new\s*)?(\w+)(?:\.class|\()'
7477 fully_qualified_mock_function = input_api.re.compile(
7478 r'Mockito\.' + mock_or_spy_function_call)
7479 statically_imported_mock_function = input_api.re.compile(
7480 r'\W' + mock_or_spy_function_call)
7481 robolectric_test = input_api.re.compile(r'[rR]obolectric')
7482 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
7483
7484 def _DoClassLookup(class_name, class_name_map, package):
7485 found = class_name_map.get(class_name)
7486 if found is not None:
7487 return found
7488 else:
7489 return package + '.' + class_name
7490
7491 def _FilterFile(affected_file):
7492 return input_api.FilterSourceFile(
7493 affected_file,
7494 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
7495 files_to_check=[r'.*Test\.java$'])
7496
7497 mocked_by_function_classes = set()
7498 mocked_by_annotation_classes = set()
7499 class_to_filename = {}
7500 for f in input_api.AffectedSourceFiles(_FilterFile):
7501 mock_function_regex = fully_qualified_mock_function
7502 next_line_is_annotated = False
7503 fully_qualified_class_map = {}
7504 package = None
7505
7506 for line in f.NewContents():
7507 if robolectric_test.search(line) or uiautomator_test.search(line):
7508 # Skip Robolectric and UiAutomator tests.
7509 break
7510
7511 m = package_name.search(line)
7512 if m:
7513 package = m.group(1)
7514 continue
7515
7516 if mock_static_import.search(line):
7517 mock_function_regex = statically_imported_mock_function
7518 continue
7519
7520 m = import_class.search(line)
7521 if m:
7522 fully_qualified_class_map[m.group(2)] = m.group(1) + m.group(2)
7523 continue
7524
7525 if next_line_is_annotated:
7526 next_line_is_annotated = False
7527 fully_qualified_class = _DoClassLookup(
7528 field_type.search(line).group(1), fully_qualified_class_map,
7529 package)
7530 mocked_by_annotation_classes.add(fully_qualified_class)
7531 continue
7532
7533 if mock_annotation.search(line):
Sam Maierb8a66a02023-10-10 13:50:557534 field_type_search = field_type.search(line)
7535 if field_type_search:
7536 fully_qualified_class = _DoClassLookup(
7537 field_type_search.group(1), fully_qualified_class_map,
7538 package)
7539 mocked_by_annotation_classes.add(fully_qualified_class)
7540 else:
7541 next_line_is_annotated = True
Sam Maier4cef9242022-10-03 14:21:247542 continue
7543
7544 m = mock_function_regex.search(line)
7545 if m:
7546 fully_qualified_class = _DoClassLookup(m.group(1),
7547 fully_qualified_class_map, package)
7548 # Skipping builtin classes, since they don't get optimized.
7549 if fully_qualified_class.startswith(
7550 'android.') or fully_qualified_class.startswith(
7551 'java.'):
7552 continue
7553 class_to_filename[fully_qualified_class] = str(f.LocalPath())
7554 mocked_by_function_classes.add(fully_qualified_class)
7555
7556 results = []
7557 missed_classes = mocked_by_function_classes - mocked_by_annotation_classes
7558 if missed_classes:
7559 error_locations = []
7560 for c in missed_classes:
7561 error_locations.append(c + ' in ' + class_to_filename[c])
7562 results.append(
7563 output_api.PresubmitPromptWarning(
7564 """
7565Mockito.mock()/spy() cause issues with our Java optimizer. You have 3 options:
75661) If the mocked variable can be a class member, annotate the member with
7567 @Mock/@Spy.
75682) If the mocked variable cannot be a class member, create a dummy member
7569 variable of that type, annotated with @Mock/@Spy. This dummy does not need
7570 to be used or initialized in any way.
75713) If the mocked type is definitely not going to be optimized, whether it's a
7572 builtin type which we don't ship, or a class you know R8 will treat
7573 specially, you can ignore this warning.
7574""", error_locations))
7575
7576 return results
Mike Dougherty1b8be712022-10-20 00:15:137577
7578def CheckNoJsInIos(input_api, output_api):
7579 """Checks to make sure that JavaScript files are not used on iOS."""
7580
7581 def _FilterFile(affected_file):
7582 return input_api.FilterSourceFile(
7583 affected_file,
7584 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP +
Daniel White44b8bd02023-08-22 16:20:367585 (r'^ios/third_party/*', r'^ios/tools/*', r'^third_party/*',
7586 r'^components/autofill/ios/form_util/resources/*'),
Mike Dougherty1b8be712022-10-20 00:15:137587 files_to_check=[r'^ios/.*\.js$', r'.*/ios/.*\.js$'])
7588
Mike Dougherty4d1050b2023-03-14 15:59:537589 deleted_files = []
7590
7591 # Collect filenames of all removed JS files.
Arthur Sonzognic66e9c82024-04-23 07:53:047592 for f in input_api.AffectedFiles(file_filter=_FilterFile):
Mike Dougherty4d1050b2023-03-14 15:59:537593 local_path = f.LocalPath()
7594
7595 if input_api.os_path.splitext(local_path)[1] == '.js' and f.Action() == 'D':
7596 deleted_files.append(input_api.os_path.basename(local_path))
7597
Mike Dougherty1b8be712022-10-20 00:15:137598 error_paths = []
Mike Dougherty4d1050b2023-03-14 15:59:537599 moved_paths = []
Mike Dougherty1b8be712022-10-20 00:15:137600 warning_paths = []
7601
7602 for f in input_api.AffectedSourceFiles(_FilterFile):
7603 local_path = f.LocalPath()
7604
7605 if input_api.os_path.splitext(local_path)[1] == '.js':
7606 if f.Action() == 'A':
Mike Dougherty4d1050b2023-03-14 15:59:537607 if input_api.os_path.basename(local_path) in deleted_files:
7608 # This script was probably moved rather than newly created.
7609 # Present a warning instead of an error for these cases.
7610 moved_paths.append(local_path)
7611 else:
7612 error_paths.append(local_path)
Mike Dougherty1b8be712022-10-20 00:15:137613 elif f.Action() != 'D':
7614 warning_paths.append(local_path)
7615
7616 results = []
7617
7618 if warning_paths:
7619 results.append(output_api.PresubmitPromptWarning(
7620 'TypeScript is now fully supported for iOS feature scripts. '
7621 'Consider converting JavaScript files to TypeScript. See '
7622 '//ios/web/public/js_messaging/README.md for more details.',
7623 warning_paths))
7624
Mike Dougherty4d1050b2023-03-14 15:59:537625 if moved_paths:
7626 results.append(output_api.PresubmitPromptWarning(
7627 'Do not use JavaScript on iOS for new files as TypeScript is '
7628 'fully supported. (If this is a moved file, you may leave the '
7629 'script unconverted.) See //ios/web/public/js_messaging/README.md '
7630 'for help using scripts on iOS.', moved_paths))
7631
Mike Dougherty1b8be712022-10-20 00:15:137632 if error_paths:
7633 results.append(output_api.PresubmitError(
7634 'Do not use JavaScript on iOS as TypeScript is fully supported. '
7635 'See //ios/web/public/js_messaging/README.md for help using '
7636 'scripts on iOS.', error_paths))
7637
7638 return results
Hans Wennborg23a81d52023-03-24 16:38:137639
7640def CheckLibcxxRevisionsMatch(input_api, output_api):
7641 """Check to make sure the libc++ version matches across deps files."""
Andrew Grieve21bb6792023-03-27 19:06:487642 # Disable check for changes to sub-repositories.
7643 if input_api.PresubmitLocalPath() != input_api.change.RepositoryRoot():
Sam Maierb926c58c2023-08-08 19:58:257644 return []
Hans Wennborg23a81d52023-03-24 16:38:137645
7646 DEPS_FILES = [ 'DEPS', 'buildtools/deps_revisions.gni' ]
7647
7648 file_filter = lambda f: f.LocalPath().replace(
7649 input_api.os_path.sep, '/') in DEPS_FILES
7650 changed_deps_files = input_api.AffectedFiles(file_filter=file_filter)
7651 if not changed_deps_files:
7652 return []
7653
7654 def LibcxxRevision(file):
7655 file = input_api.os_path.join(input_api.PresubmitLocalPath(),
7656 *file.split('/'))
7657 return input_api.re.search(
7658 r'libcxx_revision.*[:=].*[\'"](\w+)[\'"]',
7659 input_api.ReadFile(file)).group(1)
7660
7661 if len(set([LibcxxRevision(f) for f in DEPS_FILES])) == 1:
7662 return []
7663
7664 return [output_api.PresubmitError(
7665 'libcxx_revision not equal across %s' % ', '.join(DEPS_FILES),
7666 changed_deps_files)]
Arthur Sonzogni7109bd32023-10-03 10:34:427667
7668
7669def CheckDanglingUntriaged(input_api, output_api):
7670 """Warn developers adding DanglingUntriaged raw_ptr."""
7671
7672 # Ignore during git presubmit --all.
7673 #
7674 # This would be too costly, because this would check every lines of every
7675 # C++ files. Check from _BANNED_CPP_FUNCTIONS are also reading the whole
7676 # source code, but only once to apply every checks. It seems the bots like
7677 # `win-presubmit` are particularly sensitive to reading the files. Adding
7678 # this check caused the bot to run 2x longer. See https://crbug.com/1486612.
7679 if input_api.no_diffs:
Arthur Sonzogni9eafd222023-11-10 08:50:397680 return []
Arthur Sonzogni7109bd32023-10-03 10:34:427681
7682 def FilterFile(file):
7683 return input_api.FilterSourceFile(
7684 file,
7685 files_to_check=[r".*\.(h|cc|cpp|cxx|m|mm)$"],
7686 files_to_skip=[r"^base/allocator.*"],
7687 )
7688
7689 count = 0
Arthur Sonzognic66e9c82024-04-23 07:53:047690 for f in input_api.AffectedFiles(file_filter=FilterFile):
Arthur Sonzogni9eafd222023-11-10 08:50:397691 count -= sum([l.count("DanglingUntriaged") for l in f.OldContents()])
7692 count += sum([l.count("DanglingUntriaged") for l in f.NewContents()])
Arthur Sonzogni7109bd32023-10-03 10:34:427693
7694 # Most likely, nothing changed:
7695 if count == 0:
7696 return []
7697
7698 # Congrats developers for improving it:
7699 if count < 0:
Arthur Sonzogni9eafd222023-11-10 08:50:397700 message = f"DanglingUntriaged pointers removed: {-count}\nThank you!"
Arthur Sonzogni7109bd32023-10-03 10:34:427701 return [output_api.PresubmitNotifyResult(message)]
7702
7703 # Check for 'DanglingUntriaged-notes' in the description:
7704 notes_regex = input_api.re.compile("DanglingUntriaged-notes[:=]")
7705 if any(
7706 notes_regex.match(line)
7707 for line in input_api.change.DescriptionText().splitlines()):
7708 return []
7709
7710 # Check for DanglingUntriaged-notes in the git footer:
7711 if input_api.change.GitFootersFromDescription().get(
7712 "DanglingUntriaged-notes", []):
7713 return []
7714
7715 message = (
Arthur Sonzogni9eafd222023-11-10 08:50:397716 "Unexpected new occurrences of `DanglingUntriaged` detected. Please\n" +
7717 "avoid adding new ones\n" +
7718 "\n" +
7719 "See documentation:\n" +
7720 "https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr.md\n" +
7721 "\n" +
7722 "See also the guide to fix dangling pointers:\n" +
7723 "https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr_guide.md\n" +
7724 "\n" +
7725 "To disable this warning, please add in the commit description:\n" +
Alex Gough26dcd852023-12-22 16:47:197726 "DanglingUntriaged-notes: <rationale for new untriaged dangling " +
Arthur Sonzogni9eafd222023-11-10 08:50:397727 "pointers>"
Arthur Sonzogni7109bd32023-10-03 10:34:427728 )
7729 return [output_api.PresubmitPromptWarning(message)]
Jan Keitel77be7522023-10-12 20:40:497730
7731def CheckInlineConstexprDefinitionsInHeaders(input_api, output_api):
7732 """Checks that non-static constexpr definitions in headers are inline."""
7733 # In a properly formatted file, constexpr definitions inside classes or
7734 # structs will have additional whitespace at the beginning of the line.
7735 # The pattern looks for variables initialized as constexpr kVar = ...; or
7736 # constexpr kVar{...};
7737 # The pattern does not match expressions that have braces in kVar to avoid
7738 # matching constexpr functions.
7739 pattern = input_api.re.compile(r'^constexpr (?!inline )[^\(\)]*[={]')
7740 attribute_pattern = input_api.re.compile(r'(\[\[[a-zA-Z_:]+\]\]|[A-Z]+[A-Z_]+) ')
7741 problems = []
7742 for f in input_api.AffectedFiles():
7743 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
7744 continue
7745
7746 for line_number, line in f.ChangedContents():
7747 line = attribute_pattern.sub('', line)
7748 if pattern.search(line):
7749 problems.append(
7750 f"{f.LocalPath()}: {line_number}\n {line}")
7751
7752 if problems:
7753 return [
7754 output_api.PresubmitPromptWarning(
7755 'Consider inlining constexpr variable definitions in headers '
7756 'outside of classes to avoid unnecessary copies of the '
7757 'constant. See https://abseil.io/tips/168 for more details.',
7758 problems)
7759 ]
7760 else:
7761 return []
Alison Galed6b25fe2024-04-17 13:59:047762
7763def CheckTodoBugReferences(input_api, output_api):
7764 """Checks that bugs in TODOs use updated issue tracker IDs."""
7765
7766 files_to_skip = ['PRESUBMIT_test.py']
7767
7768 def _FilterFile(affected_file):
7769 return input_api.FilterSourceFile(
7770 affected_file,
7771 files_to_skip=files_to_skip)
7772
7773 # Monorail bug IDs are all less than or equal to 1524553 so check that all
7774 # bugs in TODOs are greater than that value.
7775 pattern = input_api.re.compile(r'.*TODO\([^\)0-9]*([0-9]+)\).*')
7776 problems = []
7777 for f in input_api.AffectedSourceFiles(_FilterFile):
7778 for line_number, line in f.ChangedContents():
7779 match = pattern.match(line)
7780 if match and int(match.group(1)) <= 1524553:
7781 problems.append(
7782 f"{f.LocalPath()}: {line_number}\n {line}")
7783
7784 if problems:
7785 return [
7786 output_api.PresubmitPromptWarning(
Alison Galecb598de52024-04-26 17:03:257787 'TODOs should use the new Chromium Issue Tracker IDs which can '
7788 'be found by navigating to the bug. See '
7789 'https://crbug.com/336778624 for more details.',
Alison Galed6b25fe2024-04-17 13:59:047790 problems)
7791 ]
7792 else:
7793 return []