blob: c46c216d76f698166b52fd57aefa78075ad32d4d [file] [log] [blame]
Avi Drissman24976592022-09-12 15:24:311# Copyright 2012 The Chromium Authors
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
Daniel Chengd88244472022-05-16 09:08:477See https://www.chromium.org/developers/how-tos/depottools/presubmit-scripts/
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d1982009-02-19 16:33:129"""
Daniel Chenga44a1bcd2022-03-15 20:00:1510
Daniel Chenga37c03db2022-05-12 17:20:3411from typing import Callable
Daniel Chenga44a1bcd2022-03-15 20:00:1512from typing import Optional
13from typing import Sequence
14from dataclasses import dataclass
15
Saagar Sanghavifceeaae2020-08-12 16:40:3616PRESUBMIT_VERSION = '2.0.0'
[email protected]eea609a2011-11-18 13:10:1217
Dirk Prankee3c9c62d2021-05-18 18:35:5918
[email protected]379e7dd2010-01-28 17:39:2119_EXCLUDED_PATHS = (
Bruce Dawson7f8566b2022-05-06 16:22:1820 # Generated file
Bruce Dawson40fece62022-09-16 19:58:3121 (r"chrome/android/webapk/shell_apk/src/org/chromium"
22 r"/webapk/lib/runtime_library/IWebApkApi.java"),
Mila Greene3aa7222021-09-07 16:34:0823 # File needs to write to stdout to emulate a tool it's replacing.
Bruce Dawson40fece62022-09-16 19:58:3124 r"chrome/updater/mac/keystone/ksadmin.mm",
Ilya Shermane8a7d2d2020-07-25 04:33:4725 # Generated file.
Bruce Dawson40fece62022-09-16 19:58:3126 (r"^components/variations/proto/devtools/"
Ilya Shermanc167a962020-08-18 18:40:2627 r"client_variations.js"),
Bruce Dawson3bd976c2022-05-06 22:47:5228 # These are video files, not typescript.
Bruce Dawson40fece62022-09-16 19:58:3129 r"^media/test/data/.*.ts",
30 r"^native_client_sdksrc/build_tools/make_rules.py",
31 r"^native_client_sdk/src/build_tools/make_simple.py",
32 r"^native_client_sdk/src/tools/.*.mk",
33 r"^net/tools/spdyshark/.*",
34 r"^skia/.*",
35 r"^third_party/blink/.*",
36 r"^third_party/breakpad/.*",
Darwin Huangd74a9d32019-07-17 17:58:4637 # sqlite is an imported third party dependency.
Bruce Dawson40fece62022-09-16 19:58:3138 r"^third_party/sqlite/.*",
39 r"^v8/.*",
[email protected]3e4eb112011-01-18 03:29:5440 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5341 r".+_autogen\.h$",
Yue Shecf1380552022-08-23 20:59:2042 r".+_pb2(_grpc)?\.py$",
Bruce Dawson40fece62022-09-16 19:58:3143 r".+/pnacl_shim\.c$",
44 r"^gpu/config/.*_list_json\.cc$",
45 r"tools/md_browser/.*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1446 # Test pages for Maps telemetry tests.
Bruce Dawson40fece62022-09-16 19:58:3147 r"tools/perf/page_sets/maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5448 # Test pages for WebRTC telemetry tests.
Bruce Dawson40fece62022-09-16 19:58:3149 r"tools/perf/page_sets/webrtc_cases.*",
dpapad2efd4452023-04-06 01:43:4550 # Test file compared with generated output.
51 r"tools/polymer/tests/html_to_wrapper/.*.html.ts$",
dpapada45be36c2024-08-07 20:19:3552 # Third-party dependency frozen at a fixed version.
53 r"chrome/test/data/webui/chromeos/chai_v4.js$",
[email protected]4306417642009-06-11 00:33:4054)
[email protected]ca8d1982009-02-19 16:33:1255
John Abd-El-Malek759fea62021-03-13 03:41:1456_EXCLUDED_SET_NO_PARENT_PATHS = (
57 # It's for historical reasons that blink isn't a top level directory, where
58 # it would be allowed to have "set noparent" to avoid top level owners
59 # accidentally +1ing changes.
60 'third_party/blink/OWNERS',
61)
62
wnwenbdc444e2016-05-25 13:44:1563
[email protected]06e6d0ff2012-12-11 01:36:4464# Fragment of a regular expression that matches C++ and Objective-C++
65# implementation files.
66_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
67
wnwenbdc444e2016-05-25 13:44:1568
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1969# Fragment of a regular expression that matches C++ and Objective-C++
70# header files.
71_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
72
73
Aleksey Khoroshilov9b28c032022-06-03 16:35:3274# Paths with sources that don't use //base.
75_NON_BASE_DEPENDENT_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:3176 r"^chrome/browser/browser_switcher/bho/",
77 r"^tools/win/",
Aleksey Khoroshilov9b28c032022-06-03 16:35:3278)
79
80
[email protected]06e6d0ff2012-12-11 01:36:4481# Regular expression that matches code only used for test binaries
82# (best effort).
83_TEST_CODE_EXCLUDED_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:3184 r'.*/(fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
Marijn Kruisselbrink2a2d5fc2024-05-15 15:23:4985 # Test support files, like:
86 # foo_test_support.cc
87 # bar_test_util_linux.cc (suffix)
88 # baz_test_base.cc
89 r'.+_test_(base|support|util)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
James Cook1b4dc132021-03-09 22:45:1390 # Test suite files, like:
91 # foo_browsertest.cc
92 # bar_unittest_mac.cc (suffix)
93 # baz_unittests.cc (plural)
94 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(s)?(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1295 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1896 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
Victor Hugo Vianna Silvac22e0202021-06-09 19:46:2197 r'.+sync_service_impl_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Bruce Dawson40fece62022-09-16 19:58:3198 r'.*/(test|tool(s)?)/.*',
danakj89f47082020-09-02 17:53:4399 # content_shell is used for running content_browsertests.
Bruce Dawson40fece62022-09-16 19:58:31100 r'content/shell/.*',
danakj89f47082020-09-02 17:53:43101 # Web test harness.
Bruce Dawson40fece62022-09-16 19:58:31102 r'content/web_test/.*',
[email protected]7b054982013-11-27 00:44:47103 # Non-production example code.
Bruce Dawson40fece62022-09-16 19:58:31104 r'mojo/examples/.*',
[email protected]8176de12014-06-20 19:07:08105 # Launcher for running iOS tests on the simulator.
Bruce Dawson40fece62022-09-16 19:58:31106 r'testing/iossim/iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:41107 # EarlGrey app side code for tests.
Bruce Dawson40fece62022-09-16 19:58:31108 r'ios/.*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:17109 # Views Examples code
Bruce Dawson40fece62022-09-16 19:58:31110 r'ui/views/examples/.*',
Austin Sullivan33da70a2020-10-07 15:39:41111 # Chromium Codelab
Bruce Dawson40fece62022-09-16 19:58:31112 r'codelabs/*'
[email protected]06e6d0ff2012-12-11 01:36:44113)
[email protected]ca8d1982009-02-19 16:33:12114
Daniel Bratell609102be2019-03-27 20:53:21115_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:15116
[email protected]eea609a2011-11-18 13:10:12117_TEST_ONLY_WARNING = (
118 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:55119 'production code. If you are doing this from inside another method\n'
120 'named as *ForTesting(), then consider exposing things to have tests\n'
121 'make that same call directly.\n'
122 'If that is not possible, you may put a comment on the same line with\n'
123 ' // IN-TEST \n'
124 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
125 'method and can be ignored. Do not do this inside production code.\n'
126 'The android-binary-size trybot will block if the method exists in the\n'
Yulun Zeng08d7d8c2024-02-01 18:46:54127 'release apk.\n'
128 'Note: this warning might be a false positive (crbug.com/1196548).')
[email protected]eea609a2011-11-18 13:10:12129
130
Daniel Chenga44a1bcd2022-03-15 20:00:15131@dataclass
132class BanRule:
Daniel Chenga37c03db2022-05-12 17:20:34133 # String pattern. If the pattern begins with a slash, the pattern will be
134 # treated as a regular expression instead.
135 pattern: str
136 # Explanation as a sequence of strings. Each string in the sequence will be
137 # printed on its own line.
138 explanation: Sequence[str]
139 # Whether or not to treat this ban as a fatal error. If unspecified,
140 # defaults to true.
141 treat_as_error: Optional[bool] = None
142 # Paths that should be excluded from the ban check. Each string is a regular
143 # expression that will be matched against the path of the file being checked
144 # relative to the root of the source tree.
145 excluded_paths: Optional[Sequence[str]] = None
[email protected]cf9b78f2012-11-14 11:40:28146
Daniel Chenga44a1bcd2022-03-15 20:00:15147
Daniel Cheng917ce542022-03-15 20:46:57148_BANNED_JAVA_IMPORTS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15149 BanRule(
150 'import java.net.URI;',
151 (
152 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
153 ),
154 excluded_paths=(
155 (r'net/android/javatests/src/org/chromium/net/'
156 'AndroidProxySelectorTest\.java'),
157 r'components/cronet/',
158 r'third_party/robolectric/local/',
159 ),
Michael Thiessen44457642020-02-06 00:24:15160 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15161 BanRule(
162 'import android.annotation.TargetApi;',
163 (
164 'Do not use TargetApi, use @androidx.annotation.RequiresApi instead. '
165 'RequiresApi ensures that any calls are guarded by the appropriate '
166 'SDK_INT check. See https://crbug.com/1116486.',
167 ),
168 ),
169 BanRule(
Mohamed Heikal3d7a94c2023-03-28 16:55:24170 'import androidx.test.rule.UiThreadTestRule;',
Daniel Chenga44a1bcd2022-03-15 20:00:15171 (
172 'Do not use UiThreadTestRule, just use '
173 '@org.chromium.base.test.UiThreadTest on test methods that should run '
174 'on the UI thread. See https://crbug.com/1111893.',
175 ),
176 ),
177 BanRule(
Mohamed Heikal3d7a94c2023-03-28 16:55:24178 'import androidx.test.annotation.UiThreadTest;',
179 ('Do not use androidx.test.annotation.UiThreadTest, use '
Daniel Chenga44a1bcd2022-03-15 20:00:15180 'org.chromium.base.test.UiThreadTest instead. See '
181 'https://crbug.com/1111893.',
182 ),
183 ),
184 BanRule(
Mohamed Heikal3d7a94c2023-03-28 16:55:24185 'import androidx.test.rule.ActivityTestRule;',
Daniel Chenga44a1bcd2022-03-15 20:00:15186 (
187 'Do not use ActivityTestRule, use '
188 'org.chromium.base.test.BaseActivityTestRule instead.',
189 ),
190 excluded_paths=(
191 'components/cronet/',
192 ),
193 ),
Min Qinbc44383c2023-02-22 17:25:26194 BanRule(
195 'import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;',
196 (
197 'Do not use VectorDrawableCompat, use getResources().getDrawable() to '
198 'avoid extra indirections. Please also add trace event as the call '
199 'might take more than 20 ms to complete.',
200 ),
201 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15202)
wnwenbdc444e2016-05-25 13:44:15203
Daniel Cheng917ce542022-03-15 20:46:57204_BANNED_JAVA_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15205 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41206 'StrictMode.allowThreadDiskReads()',
207 (
208 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
209 'directly.',
210 ),
211 False,
212 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15213 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41214 'StrictMode.allowThreadDiskWrites()',
215 (
216 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
217 'directly.',
218 ),
219 False,
220 ),
Daniel Cheng917ce542022-03-15 20:46:57221 BanRule(
Michael Thiessen0f2547e2020-07-27 21:55:36222 '.waitForIdleSync()',
223 (
224 'Do not use waitForIdleSync as it masks underlying issues. There is '
225 'almost always something else you should wait on instead.',
226 ),
227 False,
228 ),
Ashley Newson09cbd602022-10-26 11:40:14229 BanRule(
Ashley Newsoneb6f5ce2022-10-26 14:45:42230 r'/(?<!\bsuper\.)(?<!\bIntent )\bregisterReceiver\(',
Ashley Newson09cbd602022-10-26 11:40:14231 (
232 'Do not call android.content.Context.registerReceiver (or an override) '
233 'directly. Use one of the wrapper methods defined in '
234 'org.chromium.base.ContextUtils, such as '
235 'registerProtectedBroadcastReceiver, '
236 'registerExportedBroadcastReceiver, or '
237 'registerNonExportedBroadcastReceiver. See their documentation for '
238 'which one to use.',
239 ),
240 True,
241 excluded_paths=(
Ashley Newson22bc26d2022-11-01 20:30:57242 r'.*Test[^a-z]',
243 r'third_party/',
Ashley Newson09cbd602022-10-26 11:40:14244 'base/android/java/src/org/chromium/base/ContextUtils.java',
Brandon Mousseau7e76a9c2022-12-08 22:08:38245 'chromecast/browser/android/apk/src/org/chromium/chromecast/shell/BroadcastReceiverScope.java',
Ashley Newson09cbd602022-10-26 11:40:14246 ),
247 ),
Ted Chocd5b327b12022-11-05 02:13:22248 BanRule(
249 r'/(?:extends|new)\s*(?:android.util.)?Property<[A-Za-z.]+,\s*(?:Integer|Float)>',
250 (
251 'Do not use Property<..., Integer|Float>, but use FloatProperty or '
252 'IntProperty because it will avoid unnecessary autoboxing of '
253 'primitives.',
254 ),
255 ),
Peilin Wangbba4a8652022-11-10 16:33:57256 BanRule(
257 'requestLayout()',
258 (
259 'Layouts can be expensive. Prefer using ViewUtils.requestLayout(), '
260 'which emits a trace event with additional information to help with '
261 'scroll jank investigations. See http://crbug.com/1354176.',
262 ),
263 False,
264 excluded_paths=(
265 'ui/android/java/src/org/chromium/ui/base/ViewUtils.java',
266 ),
267 ),
Ted Chocf40ea9152023-02-14 19:02:39268 BanRule(
Ted Chocf486e3f2024-02-17 05:37:03269 'ProfileManager.getLastUsedRegularProfile()',
Ted Chocf40ea9152023-02-14 19:02:39270 (
271 'Prefer passing in the Profile reference instead of relying on the '
272 'static getLastUsedRegularProfile() call. Only top level entry points '
273 '(e.g. Activities) should call this method. Otherwise, the Profile '
274 'should either be passed in explicitly or retreived from an existing '
275 'entity with a reference to the Profile (e.g. WebContents).',
276 ),
277 False,
278 excluded_paths=(
279 r'.*Test[A-Z]?.*\.java',
280 ),
281 ),
Min Qinbc44383c2023-02-22 17:25:26282 BanRule(
283 r'/(ResourcesCompat|getResources\(\))\.getDrawable\(\)',
284 (
285 'getDrawable() can be expensive. If you have a lot of calls to '
286 'GetDrawable() or your code may introduce janks, please put your calls '
287 'inside a trace().',
288 ),
289 False,
290 excluded_paths=(
291 r'.*Test[A-Z]?.*\.java',
292 ),
293 ),
Henrique Nakashimabbf2b262023-03-10 17:21:39294 BanRule(
295 r'/RecordHistogram\.getHistogram(ValueCount|TotalCount|Samples)ForTesting\(',
296 (
297 'Raw histogram counts are easy to misuse; for example they don\'t reset '
Thiago Perrotta099034f2023-06-05 18:10:20298 'between batched tests. Use HistogramWatcher to check histogram records '
299 'instead.',
Henrique Nakashimabbf2b262023-03-10 17:21:39300 ),
301 False,
302 excluded_paths=(
303 'base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java',
304 'base/test/android/javatests/src/org/chromium/base/test/util/HistogramWatcher.java',
305 ),
306 ),
Eric Stevensona9a980972017-09-23 00:04:41307)
308
Clement Yan9b330cb2022-11-17 05:25:29309_BANNED_JAVASCRIPT_FUNCTIONS : Sequence [BanRule] = (
310 BanRule(
311 r'/\bchrome\.send\b',
312 (
313 '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).',
314 'Please use mojo instead for new webuis. https://docs.google.com/document/d/1RF-GSUoveYa37eoyZ9EhwMtaIwoW7Z88pIgNZ9YzQi4/edit#heading=h.gkk22wgk6wff',
315 ),
316 True,
317 (
318 r'^(?!ash\/webui).+',
319 # TODO(crbug.com/1385601): pre-existing violations still need to be
320 # cleaned up.
Rebekah Potter57aa94df2022-12-13 20:30:58321 'ash/webui/common/resources/cr.m.js',
Clement Yan9b330cb2022-11-17 05:25:29322 'ash/webui/common/resources/multidevice_setup/multidevice_setup_browser_proxy.js',
Martin Bidlingmaiera921fee72023-06-03 07:52:22323 'ash/webui/common/resources/quick_unlock/lock_screen_constants.ts',
Clement Yan9b330cb2022-11-17 05:25:29324 'ash/webui/common/resources/smb_shares/smb_browser_proxy.js',
Chad Duffin06e47de2023-12-14 18:04:13325 'ash/webui/connectivity_diagnostics/resources/connectivity_diagnostics.ts',
Clement Yan9b330cb2022-11-17 05:25:29326 'ash/webui/diagnostics_ui/resources/diagnostics_browser_proxy.ts',
327 'ash/webui/multidevice_debug/resources/logs.js',
328 'ash/webui/multidevice_debug/resources/webui.js',
329 'ash/webui/projector_app/resources/annotator/trusted/annotator_browser_proxy.js',
330 'ash/webui/projector_app/resources/app/trusted/projector_browser_proxy.js',
Ashley Prasad71f9024e2023-09-25 22:33:55331 # TODO(b/301634378): Remove violation exception once Scanning App
332 # migrated off usage of `chrome.send`.
333 'ash/webui/scanning/resources/scanning_browser_proxy.ts',
Clement Yan9b330cb2022-11-17 05:25:29334 ),
335 ),
336)
337
Daniel Cheng917ce542022-03-15 20:46:57338_BANNED_OBJC_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15339 BanRule(
[email protected]127f18ec2012-06-16 05:05:59340 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20341 (
342 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59343 'prohibited. Please use CrTrackingArea instead.',
344 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
345 ),
346 False,
347 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15348 BanRule(
[email protected]eaae1972014-04-16 04:17:26349 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20350 (
351 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59352 'instead.',
353 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
354 ),
355 False,
356 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15357 BanRule(
[email protected]127f18ec2012-06-16 05:05:59358 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20359 (
360 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59361 'Please use |convertPoint:(point) fromView:nil| instead.',
362 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
363 ),
364 True,
365 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15366 BanRule(
[email protected]127f18ec2012-06-16 05:05:59367 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20368 (
369 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59370 'Please use |convertPoint:(point) toView:nil| instead.',
371 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
372 ),
373 True,
374 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15375 BanRule(
[email protected]127f18ec2012-06-16 05:05:59376 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20377 (
378 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59379 'Please use |convertRect:(point) fromView:nil| instead.',
380 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
381 ),
382 True,
383 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15384 BanRule(
[email protected]127f18ec2012-06-16 05:05:59385 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20386 (
387 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59388 'Please use |convertRect:(point) toView:nil| instead.',
389 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
390 ),
391 True,
392 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15393 BanRule(
[email protected]127f18ec2012-06-16 05:05:59394 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20395 (
396 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59397 'Please use |convertSize:(point) fromView:nil| instead.',
398 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
399 ),
400 True,
401 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15402 BanRule(
[email protected]127f18ec2012-06-16 05:05:59403 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20404 (
405 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59406 'Please use |convertSize:(point) toView:nil| instead.',
407 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
408 ),
409 True,
410 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15411 BanRule(
jif65398702016-10-27 10:19:48412 r"/\s+UTF8String\s*]",
413 (
414 'The use of -[NSString UTF8String] is dangerous as it can return null',
415 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
416 'Please use |SysNSStringToUTF8| instead.',
417 ),
418 True,
Marijn Kruisselbrink1b7c48952023-08-31 16:58:34419 excluded_paths = (
420 '^third_party/ocmock/OCMock/',
421 ),
jif65398702016-10-27 10:19:48422 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15423 BanRule(
Sylvain Defresne4cf1d182017-09-18 14:16:34424 r'__unsafe_unretained',
425 (
426 'The use of __unsafe_unretained is almost certainly wrong, unless',
427 'when interacting with NSFastEnumeration or NSInvocation.',
428 'Please use __weak in files build with ARC, nothing otherwise.',
429 ),
430 False,
431 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15432 BanRule(
Avi Drissman7382afa02019-04-29 23:27:13433 'freeWhenDone:NO',
434 (
435 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
436 'Foundation types is prohibited.',
437 ),
438 True,
439 ),
Avi Drissman3d243a42023-08-01 16:53:59440 BanRule(
441 'This file requires ARC support.',
442 (
443 'ARC compilation is default in Chromium; do not add boilerplate to ',
444 'files that require ARC.',
445 ),
446 True,
447 ),
[email protected]127f18ec2012-06-16 05:05:59448)
449
Sylvain Defresnea8b73d252018-02-28 15:45:54450_BANNED_IOS_OBJC_FUNCTIONS = (
Daniel Chenga44a1bcd2022-03-15 20:00:15451 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54452 r'/\bTEST[(]',
453 (
454 'TEST() macro should not be used in Objective-C++ code as it does not ',
455 'drain the autorelease pool at the end of the test. Use TEST_F() ',
456 'macro instead with a fixture inheriting from PlatformTest (or a ',
457 'typedef).'
458 ),
459 True,
460 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15461 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54462 r'/\btesting::Test\b',
463 (
464 'testing::Test should not be used in Objective-C++ code as it does ',
465 'not drain the autorelease pool at the end of the test. Use ',
466 'PlatformTest instead.'
467 ),
468 True,
469 ),
Ewann2ecc8d72022-07-18 07:41:23470 BanRule(
471 ' systemImageNamed:',
472 (
473 '+[UIImage systemImageNamed:] should not be used to create symbols.',
474 'Instead use a wrapper defined in:',
Slobodan Pejic8ef56c702024-07-12 18:21:26475 'ios/chrome/browser/shared/ui/symbols/symbol_helpers.h'
Ewann2ecc8d72022-07-18 07:41:23476 ),
477 True,
Ewann450a2ef2022-07-19 14:38:23478 excluded_paths=(
Gauthier Ambard4d8756b2023-04-07 17:26:41479 'ios/chrome/browser/shared/ui/symbols/symbol_helpers.mm',
Slobodan Pejic8ef56c702024-07-12 18:21:26480 'ios/chrome/common',
Gauthier Ambardd36c10b12023-03-16 08:45:03481 'ios/chrome/search_widget_extension/',
Ewann450a2ef2022-07-19 14:38:23482 ),
Ewann2ecc8d72022-07-18 07:41:23483 ),
Sylvain Defresnea8b73d252018-02-28 15:45:54484)
485
Daniel Cheng917ce542022-03-15 20:46:57486_BANNED_IOS_EGTEST_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15487 BanRule(
Peter K. Lee6c03ccff2019-07-15 14:40:05488 r'/\bEXPECT_OCMOCK_VERIFY\b',
489 (
490 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
491 'it is meant for GTests. Use [mock verify] instead.'
492 ),
493 True,
494 ),
495)
496
Daniel Cheng566634ff2024-06-29 14:56:53497_BANNED_CPP_FUNCTIONS: Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15498 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53499 '%#0',
500 (
501 'Zero-padded values that use "#" to add prefixes don\'t exhibit ',
502 'consistent behavior, since the prefix is not prepended for zero ',
503 'values. Use "0x%0..." instead.',
504 ),
505 False,
506 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting7c0d98a2023-10-06 15:42:39507 ),
508 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53509 r'/\busing namespace ',
510 (
511 'Using directives ("using namespace x") are banned by the Google Style',
512 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
513 'Explicitly qualify symbols or use using declarations ("using x::foo").',
514 ),
515 True,
516 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting94a56c42019-10-25 21:54:04517 ),
Antonio Gomes07300d02019-03-13 20:59:57518 # Make sure that gtest's FRIEND_TEST() macro is not used; the
519 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
520 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
Daniel Chenga44a1bcd2022-03-15 20:00:15521 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53522 'FRIEND_TEST(',
523 (
524 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
525 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
526 ),
527 False,
528 excluded_paths=(
529 "base/gtest_prod_util.h",
530 "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/gtest_prod_util.h",
531 ),
[email protected]23e6cbc2012-06-16 18:51:20532 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15533 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53534 'setMatrixClip',
535 (
536 'Overriding setMatrixClip() is prohibited; ',
537 'the base function is deprecated. ',
538 ),
539 True,
540 (),
tomhudsone2c14d552016-05-26 17:07:46541 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15542 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53543 'SkRefPtr',
544 ('The use of SkRefPtr is prohibited. ', 'Please use sk_sp<> instead.'),
545 True,
546 (),
[email protected]52657f62013-05-20 05:30:31547 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15548 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53549 'SkAutoRef',
550 ('The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
551 'Please use sk_sp<> instead.'),
552 True,
553 (),
[email protected]52657f62013-05-20 05:30:31554 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15555 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53556 'SkAutoTUnref',
557 ('The use of SkAutoTUnref is dangerous because it implicitly ',
558 'converts to a raw pointer. Please use sk_sp<> instead.'),
559 True,
560 (),
[email protected]52657f62013-05-20 05:30:31561 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15562 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53563 'SkAutoUnref',
564 ('The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
565 'because it implicitly converts to a raw pointer. ',
566 'Please use sk_sp<> instead.'),
567 True,
568 (),
[email protected]52657f62013-05-20 05:30:31569 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15570 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53571 r'/HANDLE_EINTR\(.*close',
572 ('HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
573 'descriptor will be closed, and it is incorrect to retry the close.',
574 'Either call close directly and ignore its return value, or wrap close',
575 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
576 ),
577 True,
578 (),
[email protected]d89eec82013-12-03 14:10:59579 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15580 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53581 r'/IGNORE_EINTR\((?!.*close)',
582 (
583 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
584 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
585 ),
586 True,
587 (
588 # Files that #define IGNORE_EINTR.
589 r'^base/posix/eintr_wrapper\.h$',
590 r'^ppapi/tests/test_broker\.cc$',
591 ),
[email protected]d89eec82013-12-03 14:10:59592 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15593 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53594 r'/v8::Extension\(',
595 (
596 'Do not introduce new v8::Extensions into the code base, use',
597 'gin::Wrappable instead. See http://crbug.com/334679',
598 ),
599 True,
600 (r'extensions/renderer/safe_builtins\.*', ),
[email protected]ec5b3f02014-04-04 18:43:43601 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15602 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53603 '#pragma comment(lib,',
604 ('Specify libraries to link with in build files and not in the source.',
605 ),
606 True,
607 (
608 r'^base/third_party/symbolize/.*',
609 r'^third_party/abseil-cpp/.*',
610 ),
jame2d1a952016-04-02 00:27:10611 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15612 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53613 r'/base::SequenceChecker\b',
614 ('Consider using SEQUENCE_CHECKER macros instead of the class directly.',
615 ),
616 False,
617 (),
gabd52c912a2017-05-11 04:15:59618 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15619 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53620 r'/base::ThreadChecker\b',
621 ('Consider using THREAD_CHECKER macros instead of the class directly.',
622 ),
623 False,
624 (),
gabd52c912a2017-05-11 04:15:59625 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15626 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53627 r'/\b(?!(Sequenced|SingleThread))\w*TaskRunner::(GetCurrentDefault|CurrentDefaultHandle)',
628 (
629 'It is not allowed to call these methods from the subclasses ',
630 'of Sequenced or SingleThread task runners.',
631 ),
632 True,
633 (),
Sean Maher03efef12022-09-23 22:43:13634 ),
635 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53636 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
637 (
638 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
639 'deprecated (http://crbug.com/634507). Please avoid converting away',
640 'from the Time types in Chromium code, especially if any math is',
641 'being done on time values. For interfacing with platform/library',
642 'APIs, use base::Time::(From,To)DeltaSinceWindowsEpoch() or',
643 'base::{TimeDelta::In}Microseconds(), or one of the other type',
644 'converter methods instead. For faking TimeXXX values (for unit',
645 'testing only), use TimeXXX() + Microseconds(N). For',
646 'other use cases, please contact base/time/OWNERS.',
647 ),
648 False,
649 excluded_paths=(
650 "base/time/time.h",
651 "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/time/time.h",
652 ),
Yuri Wiitala2f8de5c2017-07-21 00:11:06653 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15654 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53655 'CallJavascriptFunctionUnsafe',
656 (
657 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
658 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
659 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
660 ),
661 False,
662 (
663 r'^content/browser/webui/web_ui_impl\.(cc|h)$',
664 r'^content/public/browser/web_ui\.h$',
665 r'^content/public/test/test_web_ui\.(cc|h)$',
666 ),
dbeamb6f4fde2017-06-15 04:03:06667 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15668 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53669 'leveldb::DB::Open',
670 (
671 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
672 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
673 "Chrome's tracing, making their memory usage visible.",
674 ),
675 True,
676 (r'^third_party/leveldatabase/.*\.(cc|h)$', ),
Gabriel Charette0592c3a2017-07-26 12:02:04677 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15678 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53679 'leveldb::NewMemEnv',
680 (
681 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
682 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
683 "to Chrome's tracing, making their memory usage visible.",
684 ),
685 True,
686 (r'^third_party/leveldatabase/.*\.(cc|h)$', ),
Chris Mumfordc38afb62017-10-09 17:55:08687 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15688 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53689 'RunLoop::QuitCurrent',
690 (
691 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
692 'methods of a specific RunLoop instance instead.',
693 ),
694 False,
695 (),
Gabriel Charettea44975052017-08-21 23:14:04696 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15697 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53698 'base::ScopedMockTimeMessageLoopTaskRunner',
699 (
700 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
701 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
702 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
703 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
704 'with gab@ first if you think you need it)',
705 ),
706 False,
707 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57708 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15709 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53710 'std::regex',
711 (
712 'Using std::regex adds unnecessary binary size to Chrome. Please use',
713 're2::RE2 instead (crbug.com/755321)',
714 ),
715 True,
716 [
717 # Abseil's benchmarks never linked into chrome.
718 'third_party/abseil-cpp/.*_benchmark.cc',
719 ],
Francois Doray43670e32017-09-27 12:40:38720 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15721 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53722 r'/\bstd::sto(i|l|ul|ll|ull)\b',
723 (
724 'std::sto{i,l,ul,ll,ull}() use exceptions to communicate results. ',
725 'Use base::StringTo[U]Int[64]() instead.',
726 ),
727 True,
728 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting991618a62019-06-17 22:00:09729 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15730 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53731 r'/\bstd::sto(f|d|ld)\b',
732 (
733 'std::sto{f,d,ld}() use exceptions to communicate results. ',
734 'For locale-independent values, e.g. reading numbers from disk',
735 'profiles, use base::StringToDouble().',
736 'For user-visible values, parse using ICU.',
737 ),
738 True,
739 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting991618a62019-06-17 22:00:09740 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15741 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53742 r'/\bstd::to_string\b',
743 (
744 'std::to_string() is locale dependent and slower than alternatives.',
745 'For locale-independent strings, e.g. writing numbers to disk',
746 'profiles, use base::NumberToString().',
747 'For user-visible strings, use base::FormatNumber() and',
748 'the related functions in base/i18n/number_formatting.h.',
749 ),
750 True,
751 [
752 # TODO(crbug.com/335672557): Please do not add to this list. Existing
753 # uses should removed.
754 "base/linux_util.cc",
755 "chrome/services/file_util/public/cpp/zip_file_creator_browsertest.cc",
756 "chrome/test/chromedriver/chrome/web_view_impl.cc",
757 "chrome/test/chromedriver/log_replay/log_replay_socket.cc",
758 "chromecast/crash/linux/dump_info.cc",
759 "chromeos/ash/components/dbus/biod/fake_biod_client.cc",
760 "chromeos/ash/components/dbus/biod/fake_biod_client_unittest.cc",
761 "chromeos/ash/components/report/utils/time_utils.cc",
762 "chromeos/ash/services/device_sync/cryptauth_device_manager_impl.cc",
763 "chromeos/ash/services/device_sync/cryptauth_device_manager_impl_unittest.cc",
764 "chromeos/ash/services/secure_channel/ble_weave_packet_receiver.cc",
765 "chromeos/ash/services/secure_channel/bluetooth_helper_impl_unittest.cc",
766 "chromeos/process_proxy/process_proxy.cc",
767 "components/chromeos_camera/jpeg_encode_accelerator_unittest.cc",
768 "components/cronet/native/perftest/perf_test.cc",
769 "components/download/internal/common/download_item_impl_unittest.cc",
770 "components/gcm_driver/gcm_client_impl_unittest.cc",
771 "components/history/core/test/fake_web_history_service.cc",
772 "components/history_clusters/core/clustering_test_utils.cc",
773 "components/language/content/browser/ulp_language_code_locator/s2langquadtree_datatest.cc",
774 "components/live_caption/views/caption_bubble_controller_views.cc",
775 "components/offline_pages/core/offline_event_logger_unittest.cc",
776 "components/offline_pages/core/offline_page_model_event_logger.cc",
777 "components/omnibox/browser/history_quick_provider_performance_unittest.cc",
778 "components/omnibox/browser/in_memory_url_index_unittest.cc",
779 "components/payments/content/payment_method_manifest_table_unittest.cc",
780 "components/policy/core/common/cloud/device_management_service_unittest.cc",
781 "components/policy/core/common/schema.cc",
782 "components/sync_bookmarks/bookmark_model_observer_impl_unittest.cc",
783 "components/tracing/test/trace_event_perftest.cc",
784 "components/ui_devtools/views/overlay_agent_views.cc",
785 "components/url_pattern_index/closed_hash_map_unittest.cc",
786 "components/url_pattern_index/url_pattern_index_unittest.cc",
787 "content/browser/accessibility/accessibility_tree_formatter_blink.cc",
788 "content/browser/background_fetch/mock_background_fetch_delegate.cc",
789 "content/browser/background_fetch/storage/database_helpers.cc",
790 "content/browser/background_sync/background_sync_launcher_unittest.cc",
791 "content/browser/browser_child_process_host_impl.cc",
792 "content/browser/devtools/protocol/security_handler.cc",
793 "content/browser/notifications/platform_notification_context_trigger_unittest.cc",
794 "content/browser/renderer_host/input/touch_action_browsertest.cc",
795 "content/browser/renderer_host/render_process_host_impl.cc",
796 "content/browser/renderer_host/text_input_manager.cc",
797 "content/browser/sandbox_parameters_mac.mm",
798 "device/fido/mock_fido_device.cc",
799 "gpu/command_buffer/tests/gl_webgl_multi_draw_test.cc",
800 "gpu/config/gpu_control_list.cc",
801 "media/audio/win/core_audio_util_win.cc",
802 "media/gpu/android/media_codec_video_decoder.cc",
803 "media/gpu/vaapi/vaapi_wrapper.cc",
804 "remoting/host/linux/certificate_watcher_unittest.cc",
805 "testing/libfuzzer/fuzzers/url_parse_proto_fuzzer.cc",
806 "testing/libfuzzer/proto/url_proto_converter.cc",
807 "third_party/blink/renderer/core/css/parser/css_proto_converter.cc",
808 "third_party/blink/renderer/core/editing/ime/edit_context.cc",
809 "third_party/blink/renderer/platform/graphics/bitmap_image_test.cc",
810 "tools/binary_size/libsupersize/viewer/caspian/diff_test.cc",
811 "tools/binary_size/libsupersize/viewer/caspian/tree_builder_test.cc",
812 "ui/base/ime/win/tsf_text_store.cc",
813 "ui/ozone/platform/drm/gpu/hardware_display_plane.cc",
814 _THIRD_PARTY_EXCEPT_BLINK
815 ],
Daniel Bratell69334cc2019-03-26 11:07:45816 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15817 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53818 r'/#include <(cctype|ctype\.h|cwctype|wctype.h)>',
819 (
820 '<cctype>/<ctype.h>/<cwctype>/<wctype.h> are banned. Use',
821 '"third_party/abseil-cpp/absl/strings/ascii.h" instead.',
822 ),
823 True,
824 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting6f79b202023-08-09 21:25:41825 ),
826 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53827 r'/\bstd::shared_ptr\b',
828 ('std::shared_ptr is banned. Use scoped_refptr instead.', ),
829 True,
830 [
831 # Needed for interop with third-party library.
832 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
833 'array_buffer_contents\.(cc|h)',
834 '^third_party/blink/renderer/core/typed_arrays/dom_array_buffer\.cc',
835 '^third_party/blink/renderer/bindings/core/v8/' +
836 'v8_wasm_response_extensions.cc',
837 '^gin/array_buffer\.(cc|h)',
838 '^gin/per_isolate_data\.(cc|h)',
839 '^chrome/services/sharing/nearby/',
840 # Needed for interop with third-party library libunwindstack.
841 '^base/profiler/libunwindstack_unwinder_android\.(cc|h)',
842 '^base/profiler/native_unwinder_android_memory_regions_map_impl.(cc|h)',
843 # Needed for interop with third-party boringssl cert verifier
844 '^third_party/boringssl/',
845 '^net/cert/',
846 '^net/tools/cert_verify_tool/',
847 '^services/cert_verifier/',
848 '^components/certificate_transparency/',
849 '^components/media_router/common/providers/cast/certificate/',
850 # gRPC provides some C++ libraries that use std::shared_ptr<>.
851 '^chromeos/ash/services/libassistant/grpc/',
852 '^chromecast/cast_core/grpc',
853 '^chromecast/cast_core/runtime/browser',
854 '^ios/chrome/test/earl_grey/chrome_egtest_plugin_client\.(mm|h)',
855 # Fuchsia provides C++ libraries that use std::shared_ptr<>.
856 '^base/fuchsia/.*\.(cc|h)',
857 '.*fuchsia.*test\.(cc|h)',
858 # Clang plugins have different build config.
859 '^tools/clang/plugins/',
860 _THIRD_PARTY_EXCEPT_BLINK
861 ], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21862 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15863 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53864 r'/\bstd::weak_ptr\b',
865 ('std::weak_ptr is banned. Use base::WeakPtr instead.', ),
866 True,
867 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting991618a62019-06-17 22:00:09868 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15869 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53870 r'/\blong long\b',
871 ('long long is banned. Use [u]int64_t instead.', ),
872 False, # Only a warning since it is already used.
873 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21874 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15875 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53876 r'/\b(absl|std)::any\b',
877 (
878 '{absl,std}::any are banned due to incompatibility with the component ',
879 'build.',
880 ),
881 True,
882 # Not an error in third party folders, though it probably should be :)
883 [_THIRD_PARTY_EXCEPT_BLINK],
Daniel Chengc05fcc62022-01-12 16:54:29884 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15885 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53886 r'/\bstd::bind\b',
887 (
888 'std::bind() is banned because of lifetime risks. Use ',
889 'base::Bind{Once,Repeating}() instead.',
890 ),
891 True,
892 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21893 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15894 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53895 (r'/\bstd::(?:'
896 r'linear_congruential_engine|mersenne_twister_engine|'
897 r'subtract_with_carry_engine|discard_block_engine|'
898 r'independent_bits_engine|shuffle_order_engine|'
899 r'minstd_rand0?|mt19937(_64)?|ranlux(24|48)(_base)?|knuth_b|'
900 r'default_random_engine|'
901 r'random_device|'
902 r'seed_seq'
903 r')\b'),
904 (
905 'STL random number engines and generators are banned. Use the ',
906 'helpers in base/rand_util.h instead, e.g. base::RandBytes() or ',
907 'base::RandomBitGenerator.'
908 '',
909 'Please reach out to [email protected] if the base APIs are ',
910 'insufficient for your needs.',
911 ),
912 True,
913 [
914 # Not an error in third_party folders.
915 _THIRD_PARTY_EXCEPT_BLINK,
916 # Various tools which build outside of Chrome.
917 r'testing/libfuzzer',
Steinar H. Gundersone5689e42024-08-07 18:17:19918 r'testing/perf/confidence',
Daniel Cheng566634ff2024-06-29 14:56:53919 r'tools/android/io_benchmark/',
920 # Fuzzers are allowed to use standard library random number generators
921 # since fuzzing speed + reproducibility is important.
922 r'tools/ipc_fuzzer/',
923 r'.+_fuzzer\.cc$',
924 r'.+_fuzzertest\.cc$',
925 # TODO(https://crbug.com/1380528): These are all unsanctioned uses of
926 # the standard library's random number generators, and should be
927 # migrated to the //base equivalent.
928 r'ash/ambient/model/ambient_topic_queue\.cc',
929 r'base/allocator/partition_allocator/src/partition_alloc/partition_alloc_unittest\.cc',
930 r'base/ranges/algorithm_unittest\.cc',
931 r'base/test/launcher/test_launcher\.cc',
932 r'cc/metrics/video_playback_roughness_reporter_unittest\.cc',
933 r'chrome/browser/apps/app_service/metrics/website_metrics\.cc',
934 r'chrome/browser/ash/power/auto_screen_brightness/monotone_cubic_spline_unittest\.cc',
935 r'chrome/browser/ash/printing/zeroconf_printer_detector_unittest\.cc',
936 r'chrome/browser/nearby_sharing/contacts/nearby_share_contact_manager_impl_unittest\.cc',
937 r'chrome/browser/nearby_sharing/contacts/nearby_share_contacts_sorter_unittest\.cc',
938 r'chrome/browser/privacy_budget/mesa_distribution_unittest\.cc',
939 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
940 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
941 r'chrome/browser/win/conflicts/module_blocklist_cache_util_unittest\.cc',
942 r'chromeos/ash/components/memory/userspace_swap/swap_storage_unittest\.cc',
943 r'chromeos/ash/components/memory/userspace_swap/userspace_swap\.cc',
944 r'components/metrics/metrics_state_manager\.cc',
945 r'components/omnibox/browser/history_quick_provider_performance_unittest\.cc',
946 r'components/zucchini/disassembler_elf_unittest\.cc',
947 r'content/browser/webid/federated_auth_request_impl\.cc',
948 r'content/browser/webid/federated_auth_request_impl\.cc',
949 r'media/cast/test/utility/udp_proxy\.h',
950 r'sql/recover_module/module_unittest\.cc',
951 r'components/search_engines/template_url_prepopulate_data.cc',
952 # Do not add new entries to this list. If you have a use case which is
953 # not satisfied by the current APIs (i.e. you need an explicitly-seeded
954 # sequence, or stability of some sort is required), please contact
955 # [email protected].
956 ],
Daniel Cheng192683f2022-11-01 20:52:44957 ),
958 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53959 r'/\b(absl,std)::bind_front\b',
960 ('{absl,std}::bind_front() are banned. Use base::Bind{Once,Repeating}() '
961 'instead.', ),
962 True,
963 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12964 ),
965 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53966 r'/\bABSL_FLAG\b',
967 ('ABSL_FLAG is banned. Use base::CommandLine instead.', ),
968 True,
969 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12970 ),
971 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53972 r'/\babsl::c_',
973 (
974 'Abseil container utilities are banned. Use base/ranges/algorithm.h ',
975 'instead.',
976 ),
977 True,
978 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:12979 ),
980 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53981 r'/\babsl::FixedArray\b',
982 ('absl::FixedArray is banned. Use base::FixedArray instead.', ),
983 True,
984 [
985 # base::FixedArray provides canonical access.
986 r'^base/types/fixed_array.h',
987 # Not an error in third_party folders.
988 _THIRD_PARTY_EXCEPT_BLINK,
989 ],
Peter Kasting431239a2023-09-29 03:11:44990 ),
991 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:53992 r'/\babsl::FunctionRef\b',
993 ('absl::FunctionRef is banned. Use base::FunctionRef instead.', ),
994 True,
995 [
996 # base::Bind{Once,Repeating} references absl::FunctionRef to disallow
997 # interoperability.
998 r'^base/functional/bind_internal\.h',
999 # base::FunctionRef is implemented on top of absl::FunctionRef.
1000 r'^base/functional/function_ref.*\..+',
1001 # Not an error in third_party folders.
1002 _THIRD_PARTY_EXCEPT_BLINK,
1003 ],
Peter Kasting4f35bfc2022-10-18 18:39:121004 ),
1005 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531006 r'/\babsl::(Insecure)?BitGen\b',
1007 ('absl random number generators are banned. Use the helpers in '
1008 'base/rand_util.h instead, e.g. base::RandBytes() or ',
1009 'base::RandomBitGenerator.'),
1010 True,
1011 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:121012 ),
1013 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531014 r'/(\babsl::Span\b|#include <span>|\bstd::span\b)',
1015 (
1016 'absl::Span and std::span are not allowed ',
1017 '(https://crbug.com/1414652). Use base::span instead.',
1018 ),
1019 True,
1020 [
1021 # Included for conversions between base and std.
1022 r'base/containers/span.h',
1023 # Test base::span<> compatibility against std::span<>.
1024 r'base/containers/span_unittest.cc',
1025 # //base/numerics can't use base or absl. So it uses std.
1026 r'base/numerics/.*'
Lei Zhang1f9d9ec42024-06-20 18:42:271027
Daniel Cheng566634ff2024-06-29 14:56:531028 # Needed to use QUICHE API.
Ciara McMullinc029c8e2024-08-21 14:22:321029 r'android_webview/browser/ip_protection/.*',
Daniel Cheng566634ff2024-06-29 14:56:531030 r'chrome/browser/ip_protection/.*',
1031 r'components/ip_protection/.*',
1032 r'net/third_party/quiche/overrides/quiche_platform_impl/quiche_stack_trace_impl\.*',
1033 r'services/network/web_transport\.cc',
Lei Zhang1f9d9ec42024-06-20 18:42:271034
Daniel Cheng566634ff2024-06-29 14:56:531035 # Not an error in third_party folders.
1036 _THIRD_PARTY_EXCEPT_BLINK,
1037 ],
Peter Kasting4f35bfc2022-10-18 18:39:121038 ),
1039 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531040 r'/\babsl::StatusOr\b',
1041 ('absl::StatusOr is banned. Use base::expected instead.', ),
1042 True,
1043 [
1044 # Needed to use liburlpattern API.
1045 r'components/url_pattern/.*',
1046 r'services/network/shared_dictionary/simple_url_pattern_matcher\.cc',
1047 r'third_party/blink/renderer/core/url_pattern/.*',
1048 r'third_party/blink/renderer/modules/manifest/manifest_parser\.cc',
Lei Zhang1f9d9ec42024-06-20 18:42:271049
Daniel Cheng566634ff2024-06-29 14:56:531050 # Needed to use QUICHE API.
Ciara McMullinc029c8e2024-08-21 14:22:321051 r'android_webview/browser/ip_protection/.*',
Daniel Cheng566634ff2024-06-29 14:56:531052 r'chrome/browser/ip_protection/.*',
1053 r'components/ip_protection/.*',
Lei Zhang1f9d9ec42024-06-20 18:42:271054
Daniel Cheng566634ff2024-06-29 14:56:531055 # Needed to use MediaPipe API.
1056 r'components/media_effects/.*\.cc',
1057 # Not an error in third_party folders.
1058 _THIRD_PARTY_EXCEPT_BLINK
1059 ],
Peter Kasting4f35bfc2022-10-18 18:39:121060 ),
1061 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531062 r'/\babsl::StrFormat\b',
1063 (
1064 'absl::StrFormat() is not allowed yet (https://crbug.com/1371963). ',
1065 'Use base::StringPrintf() instead.',
1066 ),
1067 True,
1068 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:121069 ),
1070 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531071 r'/\babsl::(StrSplit|StrJoin|StrCat|StrAppend|Substitute|StrContains)\b',
1072 ('Abseil string utilities are banned. Use base/strings instead.', ),
1073 True,
1074 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:121075 ),
1076 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531077 r'/\babsl::(Mutex|CondVar|Notification|Barrier|BlockingCounter)\b',
1078 (
1079 'Abseil synchronization primitives are banned. Use',
1080 'base/synchronization instead.',
1081 ),
1082 True,
1083 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Peter Kasting4f35bfc2022-10-18 18:39:121084 ),
1085 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531086 r'/\babsl::(Duration|Time|TimeZone|CivilDay)\b',
1087 ('Abseil\'s time library is banned. Use base/time instead.', ),
1088 True,
1089 [
1090 # Needed to use QUICHE API.
Ciara McMullinc029c8e2024-08-21 14:22:321091 r'android_webview/browser/ip_protection/.*',
Daniel Cheng566634ff2024-06-29 14:56:531092 r'chrome/browser/ip_protection/.*',
1093 r'components/ip_protection/.*',
Lei Zhang1f9d9ec42024-06-20 18:42:271094
Daniel Cheng566634ff2024-06-29 14:56:531095 # Needed to integrate with //third_party/nearby
1096 r'components/cross_device/nearby/system_clock.cc',
1097 _THIRD_PARTY_EXCEPT_BLINK # Not an error in third_party folders.
1098 ],
1099 ),
1100 BanRule(
1101 r'/#include <chrono>',
1102 ('<chrono> is banned. Use base/time instead.', ),
1103 True,
1104 [
1105 # Not an error in third_party folders:
1106 _THIRD_PARTY_EXCEPT_BLINK,
Daniel Cheng566634ff2024-06-29 14:56:531107 # This uses openscreen API depending on std::chrono.
1108 "components/openscreen_platform/task_runner.cc",
1109 ]),
1110 BanRule(
1111 r'/#include <exception>',
1112 ('Exceptions are banned and disabled in Chromium.', ),
1113 True,
1114 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1115 ),
1116 BanRule(
1117 r'/\bstd::function\b',
1118 ('std::function is banned. Use base::{Once,Repeating}Callback instead.',
1119 ),
1120 True,
1121 [
1122 # Has tests that template trait helpers don't unintentionally match
1123 # std::function.
1124 r'base/functional/callback_helpers_unittest\.cc',
1125 # Required to implement interfaces from the third-party perfetto
1126 # library.
1127 r'base/tracing/perfetto_task_runner\.cc',
1128 r'base/tracing/perfetto_task_runner\.h',
1129 # Needed for interop with the third-party nearby library type
1130 # location::nearby::connections::ResultCallback.
1131 'chrome/services/sharing/nearby/nearby_connections_conversions\.cc'
1132 # Needed for interop with the internal libassistant library.
1133 'chromeos/ash/services/libassistant/callback_utils\.h',
1134 # Needed for interop with Fuchsia fidl APIs.
1135 'fuchsia_web/webengine/browser/context_impl_browsertest\.cc',
1136 'fuchsia_web/webengine/browser/cookie_manager_impl_unittest\.cc',
1137 'fuchsia_web/webengine/browser/media_player_impl_unittest\.cc',
1138 # Required to interop with interfaces from the third-party ChromeML
1139 # library API.
1140 'services/on_device_model/ml/chrome_ml_api\.h',
1141 'services/on_device_model/ml/on_device_model_executor\.cc',
1142 'services/on_device_model/ml/on_device_model_executor\.h',
1143 # Required to interop with interfaces from the third-party perfetto
1144 # library.
1145 'services/tracing/public/cpp/perfetto/custom_event_recorder\.cc',
1146 'services/tracing/public/cpp/perfetto/perfetto_traced_process\.cc',
1147 'services/tracing/public/cpp/perfetto/perfetto_traced_process\.h',
1148 'services/tracing/public/cpp/perfetto/perfetto_tracing_backend\.cc',
1149 'services/tracing/public/cpp/perfetto/producer_client\.cc',
1150 'services/tracing/public/cpp/perfetto/producer_client\.h',
1151 'services/tracing/public/cpp/perfetto/producer_test_utils\.cc',
1152 'services/tracing/public/cpp/perfetto/producer_test_utils\.h',
1153 # Required for interop with the third-party webrtc library.
1154 'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.cc',
1155 'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.h',
1156 # TODO(https://crbug.com/1364577): Various uses that should be
1157 # migrated to something else.
1158 # Should use base::OnceCallback or base::RepeatingCallback.
1159 'base/allocator/dispatcher/initializer_unittest\.cc',
1160 'chrome/browser/ash/accessibility/speech_monitor\.cc',
1161 'chrome/browser/ash/accessibility/speech_monitor\.h',
1162 'chrome/browser/ash/login/ash_hud_login_browsertest\.cc',
1163 'chromecast/base/observer_unittest\.cc',
1164 'chromecast/browser/cast_web_view\.h',
1165 'chromecast/public/cast_media_shlib\.h',
1166 'device/bluetooth/floss/exported_callback_manager\.h',
1167 'device/bluetooth/floss/floss_dbus_client\.h',
1168 'device/fido/cable/v2_handshake_unittest\.cc',
1169 'device/fido/pin\.cc',
1170 'services/tracing/perfetto/test_utils\.h',
1171 # Should use base::FunctionRef.
1172 'chrome/browser/media/webrtc/test_stats_dictionary\.cc',
1173 'chrome/browser/media/webrtc/test_stats_dictionary\.h',
1174 'chromeos/ash/services/libassistant/device_settings_controller\.cc',
1175 'components/browser_ui/client_certificate/android/ssl_client_certificate_request\.cc',
1176 'components/gwp_asan/client/sampling_malloc_shims_unittest\.cc',
1177 'content/browser/font_unique_name_lookup/font_unique_name_lookup_unittest\.cc',
1178 # Does not need std::function at all.
1179 'components/omnibox/browser/autocomplete_result\.cc',
1180 'device/fido/win/webauthn_api\.cc',
1181 'media/audio/alsa/alsa_util\.cc',
1182 'media/remoting/stream_provider\.h',
1183 'sql/vfs_wrapper\.cc',
1184 # TODO(https://crbug.com/1364585): Remove usage and exception list
1185 # entries.
1186 'extensions/renderer/api/automation/automation_internal_custom_bindings\.cc',
1187 'extensions/renderer/api/automation/automation_internal_custom_bindings\.h',
1188 # TODO(https://crbug.com/1364579): Remove usage and exception list
1189 # entry.
1190 'ui/views/controls/focus_ring\.h',
Lei Zhang1f9d9ec42024-06-20 18:42:271191
Daniel Cheng566634ff2024-06-29 14:56:531192 # Various pre-existing uses in //tools that is low-priority to fix.
1193 'tools/binary_size/libsupersize/viewer/caspian/diff\.cc',
1194 'tools/binary_size/libsupersize/viewer/caspian/model\.cc',
1195 'tools/binary_size/libsupersize/viewer/caspian/model\.h',
1196 'tools/binary_size/libsupersize/viewer/caspian/tree_builder\.h',
1197 'tools/clang/base_bind_rewriters/BaseBindRewriters\.cpp',
Daniel Chenge5583e3c2022-09-22 00:19:411198
Daniel Cheng566634ff2024-06-29 14:56:531199 # Not an error in third_party folders.
1200 _THIRD_PARTY_EXCEPT_BLINK
1201 ],
Daniel Bratell609102be2019-03-27 20:53:211202 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151203 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531204 r'/#include <X11/',
1205 ('Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.', ),
1206 True,
1207 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Tom Andersona95e12042020-09-09 23:08:001208 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151209 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531210 r'/\bstd::ratio\b',
1211 ('std::ratio is banned by the Google Style Guide.', ),
1212 True,
1213 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:451214 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151215 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531216 r'/\bstd::aligned_alloc\b',
1217 (
1218 'std::aligned_alloc() is not yet allowed (crbug.com/1412818). Use ',
1219 'base::AlignedAlloc() instead.',
1220 ),
1221 True,
1222 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181223 ),
1224 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531225 r'/#include <(barrier|latch|semaphore|stop_token)>',
1226 ('The thread support library is banned. Use base/synchronization '
1227 'instead.', ),
1228 True,
1229 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181230 ),
1231 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531232 r'/\bstd::execution::(par|seq)\b',
1233 ('std::execution::(par|seq) is banned; they do not fit into '
1234 ' Chrome\'s threading model, and libc++ doesn\'t have full '
1235 'support.'),
1236 True,
1237 [_THIRD_PARTY_EXCEPT_BLINK],
Helmut Januschka7cc8a84f2024-02-07 22:50:411238 ),
1239 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531240 r'/\bstd::bit_cast\b',
1241 ('std::bit_cast is banned; use base::bit_cast instead for values and '
1242 'standard C++ casting when pointers are involved.', ),
1243 True,
1244 [
1245 # Don't warn in third_party folders.
1246 _THIRD_PARTY_EXCEPT_BLINK,
1247 # //base/numerics can't use base or absl.
1248 r'base/numerics/.*'
1249 ],
Avi Drissman70cb7f72023-12-12 17:44:371250 ),
1251 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531252 r'/\bstd::(c8rtomb|mbrtoc8)\b',
1253 ('std::c8rtomb() and std::mbrtoc8() are banned.', ),
1254 True,
1255 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181256 ),
1257 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531258 r'/\bchar8_t|std::u8string\b',
1259 (
1260 'char8_t and std::u8string are not yet allowed. Can you use [unsigned]',
1261 ' char and std::string instead?',
1262 ),
1263 True,
1264 [
1265 # The demangler does not use this type but needs to know about it.
1266 'base/third_party/symbolize/demangle\.cc',
1267 # Don't warn in third_party folders.
1268 _THIRD_PARTY_EXCEPT_BLINK
1269 ],
Peter Kastinge2c5ee82023-02-15 17:23:081270 ),
1271 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531272 r'/(\b(co_await|co_return|co_yield)\b|#include <coroutine>)',
1273 ('Coroutines are not yet allowed (https://crbug.com/1403840).', ),
1274 True,
1275 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081276 ),
1277 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531278 r'/^\s*(export\s|import\s+["<:\w]|module(;|\s+[:\w]))',
1279 ('Modules are disallowed for now due to lack of toolchain support.', ),
1280 True,
1281 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting69357dc2023-03-14 01:34:291282 ),
1283 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531284 r'/\[\[(\w*::)?no_unique_address\]\]',
1285 (
1286 '[[no_unique_address]] does not work as expected on Windows ',
1287 '(https://crbug.com/1414621). Use NO_UNIQUE_ADDRESS instead.',
1288 ),
1289 True,
1290 [
1291 # NO_UNIQUE_ADDRESS / PA_NO_UNIQUE_ADDRESS provide canonical access.
1292 r'^base/compiler_specific\.h',
1293 r'^base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/compiler_specific\.h',
1294 # Not an error in third_party folders.
1295 _THIRD_PARTY_EXCEPT_BLINK,
1296 ],
Peter Kasting8bc046d22023-11-14 00:38:031297 ),
1298 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531299 r'/#include <format>',
1300 ('<format> is not yet allowed. Use base::StringPrintf() instead.', ),
1301 True,
1302 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081303 ),
1304 BanRule(
Daniel Cheng89719222024-07-04 04:59:291305 pattern='std::views',
1306 explanation=(
1307 'Use of std::views is banned in Chrome. If you need this '
1308 'functionality, please contact [email protected].',
1309 ),
1310 treat_as_error=True,
1311 excluded_paths=[
1312 # Don't warn in third_party folders.
1313 _THIRD_PARTY_EXCEPT_BLINK
1314 ],
1315 ),
1316 BanRule(
1317 # Ban everything except specifically allowlisted constructs.
1318 pattern=r'/std::ranges::(?!' + '|'.join((
1319 # From https://en.cppreference.com/w/cpp/ranges:
1320 # Range access
1321 'begin',
1322 'end',
1323 'cbegin',
1324 'cend',
1325 'rbegin',
1326 'rend',
1327 'crbegin',
1328 'crend',
1329 'size',
1330 'ssize',
1331 'empty',
1332 'data',
1333 'cdata',
1334 # Range primitives
1335 'iterator_t',
1336 'const_iterator_t',
1337 'sentinel_t',
1338 'const_sentinel_t',
1339 'range_difference_t',
1340 'range_size_t',
1341 'range_value_t',
1342 'range_reference_t',
1343 'range_const_reference_t',
1344 'range_rvalue_reference_t',
1345 'range_common_reference_t',
1346 # Dangling iterator handling
1347 'dangling',
1348 'borrowed_iterator_t',
1349 # Banned: borrowed_subrange_t
1350 # Range concepts
1351 'range',
1352 'borrowed_range',
1353 'sized_range',
1354 'view',
1355 'input_range',
1356 'output_range',
1357 'forward_range',
1358 'bidirectional_range',
1359 'random_access_range',
1360 'contiguous_range',
1361 'common_range',
1362 'viewable_range',
1363 'constant_range',
1364 # Banned: Views
1365 # Banned: Range factories
1366 # Banned: Range adaptors
1367 # From https://en.cppreference.com/w/cpp/algorithm/ranges:
1368 # Constrained algorithms: non-modifying sequence operations
1369 'all_of',
1370 'any_of',
1371 'none_of',
1372 'for_each',
1373 'for_each_n',
1374 'count',
1375 'count_if',
1376 'mismatch',
1377 'equal',
1378 'lexicographical_compare',
1379 'find',
1380 'find_if',
1381 'find_if_not',
1382 'find_end',
1383 'find_first_of',
1384 'adjacent_find',
1385 'search',
1386 'search_n',
1387 # Constrained algorithms: modifying sequence operations
1388 'copy',
1389 'copy_if',
1390 'copy_n',
1391 'copy_backward',
1392 'move',
1393 'move_backward',
1394 'fill',
1395 'fill_n',
1396 'transform',
1397 'generate',
1398 'generate_n',
1399 'remove',
1400 'remove_if',
1401 'remove_copy',
1402 'remove_copy_if',
1403 'replace',
1404 'replace_if',
1405 'replace_copy',
1406 'replace_copy_if',
1407 'swap_ranges',
1408 'reverse',
1409 'reverse_copy',
1410 'rotate',
1411 'rotate_copy',
1412 'shuffle',
1413 'sample',
1414 'unique',
1415 'unique_copy',
1416 # Constrained algorithms: partitioning operations
1417 'is_partitioned',
1418 'partition',
1419 'partition_copy',
1420 'stable_partition',
1421 'partition_point',
1422 # Constrained algorithms: sorting operations
1423 'is_sorted',
1424 'is_sorted_until',
1425 'sort',
1426 'partial_sort',
1427 'partial_sort_copy',
1428 'stable_sort',
1429 'nth_element',
1430 # Constrained algorithms: binary search operations (on sorted ranges)
1431 'lower_bound',
1432 'upper_bound',
1433 'binary_search',
1434 'equal_range',
1435 # Constrained algorithms: set operations (on sorted ranges)
1436 'merge',
1437 'inplace_merge',
1438 'includes',
1439 'set_difference',
1440 'set_intersection',
1441 'set_symmetric_difference',
1442 'set_union',
1443 # Constrained algorithms: heap operations
1444 'is_heap',
1445 'is_heap_until',
1446 'make_heap',
1447 'push_heap',
1448 'pop_heap',
1449 'sort_heap',
1450 # Constrained algorithms: minimum/maximum operations
1451 'max',
1452 'max_element',
1453 'min',
1454 'min_element',
1455 'minmax',
1456 'minmax_element',
1457 'clamp',
1458 # Constrained algorithms: permutation operations
1459 'is_permutation',
1460 'next_permutation',
1461 'prev_premutation',
1462 # Constrained uninitialized memory algorithms
1463 'uninitialized_copy',
1464 'uninitialized_copy_n',
1465 'uninitialized_fill',
1466 'uninitialized_fill_n',
1467 'uninitialized_move',
1468 'uninitialized_move_n',
1469 'uninitialized_default_construct',
1470 'uninitialized_default_construct_n',
1471 'uninitialized_value_construct',
1472 'uninitialized_value_construct_n',
1473 'destroy',
1474 'destroy_n',
1475 'destroy_at',
1476 'construct_at',
1477 # Return types
1478 'in_fun_result',
1479 'in_in_result',
1480 'in_out_result',
1481 'in_in_out_result',
1482 'in_out_out_result',
1483 'min_max_result',
1484 'in_found_result',
danakj91c715b2024-07-10 13:24:261485 # From https://en.cppreference.com/w/cpp/iterator
1486 'advance',
1487 'distance',
1488 'next',
1489 'prev',
Daniel Cheng89719222024-07-04 04:59:291490 )) + r')\w+',
1491 explanation=(
1492 'Use of range views and associated helpers is banned in Chrome. '
1493 'If you need this functionality, please contact [email protected].',
1494 ),
1495 treat_as_error=True,
1496 excluded_paths=[
1497 # Don't warn in third_party folders.
1498 _THIRD_PARTY_EXCEPT_BLINK
1499 ],
Peter Kastinge2c5ee82023-02-15 17:23:081500 ),
1501 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531502 r'/#include <source_location>',
1503 ('<source_location> is not yet allowed. Use base/location.h instead.',
1504 ),
1505 True,
1506 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kastinge2c5ee82023-02-15 17:23:081507 ),
1508 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531509 r'/\bstd::to_address\b',
1510 (
1511 'std::to_address is banned because it is not guaranteed to be',
1512 'SFINAE-compatible. Use base::to_address from base/types/to_address.h',
1513 'instead.',
1514 ),
1515 True,
1516 [
1517 # Needed in base::to_address implementation.
1518 r'base/types/to_address.h',
1519 _THIRD_PARTY_EXCEPT_BLINK
1520 ], # Not an error in third_party folders.
Nick Diego Yamanee522ae82024-02-27 04:23:221521 ),
1522 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531523 r'/#include <syncstream>',
1524 ('<syncstream> is banned.', ),
1525 True,
1526 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Peter Kasting6d77e9d2023-02-09 21:58:181527 ),
1528 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531529 r'/\bRunMessageLoop\b',
1530 ('RunMessageLoop is deprecated, use RunLoop instead.', ),
1531 False,
1532 (),
Gabriel Charette147335ea2018-03-22 15:59:191533 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151534 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531535 'RunAllPendingInMessageLoop()',
1536 (
1537 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
1538 "if you're convinced you need this.",
1539 ),
1540 False,
1541 (),
Gabriel Charette147335ea2018-03-22 15:59:191542 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151543 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531544 'RunAllPendingInMessageLoop(BrowserThread',
1545 (
1546 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
1547 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
1548 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
1549 'async events instead of flushing threads.',
1550 ),
1551 False,
1552 (),
Gabriel Charette147335ea2018-03-22 15:59:191553 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151554 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531555 r'MessageLoopRunner',
1556 ('MessageLoopRunner is deprecated, use RunLoop instead.', ),
1557 False,
1558 (),
Gabriel Charette147335ea2018-03-22 15:59:191559 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151560 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531561 'GetDeferredQuitTaskForRunLoop',
1562 (
1563 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
1564 "gab@ if you found a use case where this is the only solution.",
1565 ),
1566 False,
1567 (),
Gabriel Charette147335ea2018-03-22 15:59:191568 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151569 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531570 'sqlite3_initialize(',
1571 (
1572 'Instead of calling sqlite3_initialize(), depend on //sql, ',
1573 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
1574 ),
1575 True,
1576 (
1577 r'^sql/initialization\.(cc|h)$',
1578 r'^third_party/sqlite/.*\.(c|cc|h)$',
1579 ),
Victor Costan3653df62018-02-08 21:38:161580 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151581 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531582 'CREATE VIEW',
1583 (
1584 'SQL views are disabled in Chromium feature code',
1585 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-views',
1586 ),
1587 True,
1588 (
1589 _THIRD_PARTY_EXCEPT_BLINK,
1590 # sql/ itself uses views when using memory-mapped IO.
1591 r'^sql/.*',
1592 # Various performance tools that do not build as part of Chrome.
1593 r'^infra/.*',
1594 r'^tools/perf.*',
1595 r'.*perfetto.*',
1596 ),
Austin Sullivand661ab52022-11-16 08:55:151597 ),
1598 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531599 'CREATE VIRTUAL TABLE',
1600 (
1601 'SQL virtual tables are disabled in Chromium feature code',
1602 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-virtual-tables',
1603 ),
1604 True,
1605 (
1606 _THIRD_PARTY_EXCEPT_BLINK,
1607 # sql/ itself uses virtual tables in the recovery module and tests.
1608 r'^sql/.*',
1609 # TODO(https://crbug.com/695592): Remove once WebSQL is deprecated.
1610 r'third_party/blink/web_tests/storage/websql/.*'
1611 # Various performance tools that do not build as part of Chrome.
1612 r'^tools/perf.*',
1613 r'.*perfetto.*',
1614 ),
Austin Sullivand661ab52022-11-16 08:55:151615 ),
1616 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531617 'std::random_shuffle',
1618 ('std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
1619 'base::RandomShuffle instead.'),
1620 True,
1621 (),
tzik5de2157f2018-05-08 03:42:471622 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151623 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531624 'ios/web/public/test/http_server',
1625 ('web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
1626 ),
1627 False,
1628 (),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:241629 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151630 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531631 'GetAddressOf',
1632 ('Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
1633 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
1634 'operator& is generally recommended. So always use operator& instead. ',
1635 'See http://crbug.com/914910 for more conversion guidance.'),
1636 True,
1637 (),
Robert Liao764c9492019-01-24 18:46:281638 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151639 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531640 'SHFileOperation',
1641 ('SHFileOperation was deprecated in Windows Vista, and there are less ',
1642 'complex functions to achieve the same goals. Use IFileOperation for ',
1643 'any esoteric actions instead.'),
1644 True,
1645 (),
Ben Lewisa9514602019-04-29 17:53:051646 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151647 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531648 'StringFromGUID2',
1649 ('StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
1650 'Use base::win::WStringFromGUID instead.'),
1651 True,
1652 (r'/base/win/win_util_unittest.cc', ),
Cliff Smolinsky81951642019-04-30 21:39:511653 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151654 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531655 'StringFromCLSID',
1656 ('StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
1657 'Use base::win::WStringFromGUID instead.'),
1658 True,
1659 (r'/base/win/win_util_unittest.cc', ),
Cliff Smolinsky81951642019-04-30 21:39:511660 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151661 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531662 'kCFAllocatorNull',
1663 (
1664 'The use of kCFAllocatorNull with the NoCopy creation of ',
1665 'CoreFoundation types is prohibited.',
1666 ),
1667 True,
1668 (),
Avi Drissman7382afa02019-04-29 23:27:131669 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151670 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531671 'mojo::ConvertTo',
1672 ('mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1673 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1674 'StringTraits if you would like to convert between custom types and',
1675 'the wire format of mojom types.'),
1676 False,
1677 (
1678 r'^fuchsia_web/webengine/browser/url_request_rewrite_rules_manager\.cc$',
1679 r'^fuchsia_web/webengine/url_request_rewrite_type_converters\.cc$',
1680 r'^third_party/blink/.*\.(cc|h)$',
1681 r'^content/renderer/.*\.(cc|h)$',
1682 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291683 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151684 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531685 'GetInterfaceProvider',
1686 ('InterfaceProvider is deprecated.',
1687 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1688 'or Platform::GetBrowserInterfaceBroker.'),
1689 False,
1690 (),
Oksana Zhuravlovac8222d22019-12-19 19:21:161691 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151692 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531693 'CComPtr',
1694 ('New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1695 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1696 'details.'),
1697 False,
1698 (),
Robert Liao1d78df52019-11-11 20:02:011699 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151700 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531701 r'/\b(IFACE|STD)METHOD_?\(',
1702 ('IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1703 'Instead, always use IFACEMETHODIMP in the declaration.'),
1704 False,
1705 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Xiaohan Wang72bd2ba2020-02-18 21:38:201706 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151707 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531708 'set_owned_by_client',
1709 ('set_owned_by_client is deprecated.',
1710 'views::View already owns the child views by default. This introduces ',
1711 'a competing ownership model which makes the code difficult to reason ',
1712 'about. See http://crbug.com/1044687 for more details.'),
1713 False,
1714 (),
Allen Bauer53b43fb12020-03-12 17:21:471715 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151716 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531717 'RemoveAllChildViewsWithoutDeleting',
1718 ('RemoveAllChildViewsWithoutDeleting is deprecated.',
1719 'This method is deemed dangerous as, unless raw pointers are re-added,',
1720 'calls to this method introduce memory leaks.'),
1721 False,
1722 (),
Peter Boström7ff41522021-07-29 03:43:271723 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151724 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531725 r'/\bTRACE_EVENT_ASYNC_',
1726 (
1727 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1728 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1729 ),
1730 False,
1731 (
1732 r'^base/trace_event/.*',
1733 r'^base/tracing/.*',
1734 ),
Eric Secklerbe6f48d2020-05-06 18:09:121735 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151736 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531737 r'/\bbase::debug::DumpWithoutCrashingUnthrottled[(][)]',
1738 (
1739 'base::debug::DumpWithoutCrashingUnthrottled() does not throttle',
1740 'dumps and may spam crash reports. Consider if the throttled',
1741 'variants suffice instead.',
1742 ),
1743 False,
1744 (),
Aditya Kushwah5a286b72022-02-10 04:54:431745 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151746 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531747 'RoInitialize',
1748 ('Improper use of [base::win]::RoInitialize() has been implicated in a ',
1749 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
1750 'instead. See http://crbug.com/1197722 for more information.'),
1751 True,
1752 (
1753 r'^base/win/scoped_winrt_initializer\.cc$',
1754 r'^third_party/abseil-cpp/absl/.*',
1755 ),
Robert Liao22f66a52021-04-10 00:57:521756 ),
Patrick Monettec343bb982022-06-01 17:18:451757 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531758 r'base::Watchdog',
1759 (
1760 'base::Watchdog is deprecated because it creates its own thread.',
1761 'Instead, manually start a timer on a SequencedTaskRunner.',
1762 ),
1763 False,
1764 (),
Patrick Monettec343bb982022-06-01 17:18:451765 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091766 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531767 'base::Passed',
1768 ('Do not use base::Passed. It is a legacy helper for capturing ',
1769 'move-only types with base::BindRepeating, but invoking the ',
1770 'resulting RepeatingCallback moves the captured value out of ',
1771 'the callback storage, and subsequent invocations may pass the ',
1772 'value in a valid but undefined state. Prefer base::BindOnce().',
1773 'See http://crbug.com/1326449 for context.'),
1774 False,
1775 (
1776 # False positive, but it is also fine to let bind internals reference
1777 # base::Passed.
1778 r'^base[\\/]functional[\\/]bind\.h',
1779 r'^base[\\/]functional[\\/]bind_internal\.h',
1780 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091781 ),
Daniel Cheng2248b332022-07-27 06:16:591782 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531783 r'base::Feature k',
1784 ('Please use BASE_DECLARE_FEATURE() or BASE_FEATURE() instead of ',
1785 'directly declaring/defining features.'),
1786 True,
1787 [
1788 # Implements BASE_DECLARE_FEATURE().
1789 r'^base/feature_list\.h',
1790 ],
Daniel Chengba3bc2e2022-10-03 02:45:431791 ),
Robert Ogden92101dcb2022-10-19 23:49:361792 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531793 r'/\bchartorune\b',
1794 ('chartorune is not memory-safe, unless you can guarantee the input ',
1795 'string is always null-terminated. Otherwise, please use charntorune ',
1796 'from libphonenumber instead.'),
1797 True,
1798 [
1799 _THIRD_PARTY_EXCEPT_BLINK,
1800 # Exceptions to this rule should have a fuzzer.
1801 ],
Robert Ogden92101dcb2022-10-19 23:49:361802 ),
Arthur Sonzogni1da65fa2023-03-27 16:01:521803 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531804 r'/\b#include "base/atomicops\.h"\b',
1805 ('Do not use base::subtle atomics, but std::atomic, which are simpler '
1806 'to use, have better understood, clearer and richer semantics, and are '
1807 'harder to mis-use. See details in base/atomicops.h.', ),
1808 False,
1809 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Benoit Lize79cf0592023-01-27 10:01:571810 ),
Daniel Cheng566634ff2024-06-29 14:56:531811 BanRule(r'CrossThreadPersistent<', (
Arthur Sonzogni60348572e2023-04-07 10:22:521812 'Do not use blink::CrossThreadPersistent, but '
Daniel Cheng566634ff2024-06-29 14:56:531813 'blink::CrossThreadHandle. It is harder to mis-use.', 'More info: '
Arthur Sonzogni60348572e2023-04-07 10:22:521814 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1815 'Please contact platform-architecture-dev@ before adding new instances.'
Daniel Cheng566634ff2024-06-29 14:56:531816 ), False, []),
1817 BanRule(r'CrossThreadWeakPersistent<', (
Arthur Sonzogni60348572e2023-04-07 10:22:521818 'Do not use blink::CrossThreadWeakPersistent, but '
Daniel Cheng566634ff2024-06-29 14:56:531819 'blink::CrossThreadWeakHandle. It is harder to mis-use.', 'More info: '
Arthur Sonzogni60348572e2023-04-07 10:22:521820 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1821 'Please contact platform-architecture-dev@ before adding new instances.'
Daniel Cheng566634ff2024-06-29 14:56:531822 ), False, []),
1823 BanRule(r'objc/objc.h', (
Avi Drissman491617c2023-04-13 17:33:151824 'Do not include <objc/objc.h>. It defines away ARC lifetime '
1825 'annotations, and is thus dangerous.',
1826 'Please use the pimpl pattern; search for `ObjCStorage` for examples.',
1827 'For further reading on how to safely mix C++ and Obj-C, see',
1828 'https://chromium.googlesource.com/chromium/src/+/main/docs/mac/mixing_cpp_and_objc.md'
Daniel Cheng566634ff2024-06-29 14:56:531829 ), True, []),
1830 BanRule(
1831 r'/#include <filesystem>',
1832 ('libc++ <filesystem> is banned per the Google C++ styleguide.', ),
1833 True,
1834 # This fuzzing framework is a standalone open source project and
1835 # cannot rely on Chromium base.
1836 (r'third_party/centipede'),
Avi Drissman491617c2023-04-13 17:33:151837 ),
Grace Park8d59b54b2023-04-26 17:53:351838 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531839 r'TopDocument()',
1840 ('TopDocument() does not work correctly with out-of-process iframes. '
1841 'Please do not introduce new uses.', ),
1842 True,
1843 (
1844 # TODO(crbug.com/617677): Remove all remaining uses.
1845 r'^third_party/blink/renderer/core/dom/document\.cc',
1846 r'^third_party/blink/renderer/core/dom/document\.h',
1847 r'^third_party/blink/renderer/core/dom/element\.cc',
1848 r'^third_party/blink/renderer/core/exported/web_disallow_transition_scope_test\.cc',
1849 r'^third_party/blink/renderer/core/exported/web_document_test\.cc',
1850 r'^third_party/blink/renderer/core/html/html_anchor_element\.cc',
1851 r'^third_party/blink/renderer/core/html/html_dialog_element\.cc',
1852 r'^third_party/blink/renderer/core/html/html_element\.cc',
1853 r'^third_party/blink/renderer/core/html/html_frame_owner_element\.cc',
1854 r'^third_party/blink/renderer/core/html/media/video_wake_lock\.cc',
1855 r'^third_party/blink/renderer/core/loader/anchor_element_interaction_tracker\.cc',
1856 r'^third_party/blink/renderer/core/page/scrolling/root_scroller_controller\.cc',
1857 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.cc',
1858 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.h',
1859 r'^third_party/blink/renderer/core/script/classic_pending_script\.cc',
1860 r'^third_party/blink/renderer/core/script/script_loader\.cc',
1861 ),
Grace Park8d59b54b2023-04-26 17:53:351862 ),
Daniel Cheng72153e02023-05-18 21:18:141863 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531864 pattern=r'base::raw_ptr<',
1865 explanation=('Do not use base::raw_ptr, use raw_ptr.', ),
1866 treat_as_error=True,
1867 excluded_paths=(
1868 '^base/',
1869 '^tools/',
1870 ),
Daniel Cheng72153e02023-05-18 21:18:141871 ),
Arthur Sonzognif0eea302023-08-18 19:20:311872 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531873 pattern=r'base:raw_ref<',
1874 explanation=('Do not use base::raw_ref, use raw_ref.', ),
1875 treat_as_error=True,
1876 excluded_paths=(
1877 '^base/',
1878 '^tools/',
1879 ),
Arthur Sonzognif0eea302023-08-18 19:20:311880 ),
1881 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531882 pattern=r'/raw_ptr<[^;}]*\w{};',
1883 explanation=(
1884 'Do not use {} for raw_ptr initialization, use = nullptr instead.',
1885 ),
1886 treat_as_error=True,
1887 excluded_paths=(
1888 '^base/',
1889 '^tools/',
1890 ),
Arthur Sonzognif0eea302023-08-18 19:20:311891 ),
Anton Maliev66751812023-08-24 16:28:131892 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531893 pattern=r'/#include "base/allocator/.*/raw_'
1894 r'(ptr|ptr_cast|ptr_exclusion|ref).h"',
1895 explanation=(
1896 'Please include the corresponding facade headers:',
1897 '- #include "base/memory/raw_ptr.h"',
1898 '- #include "base/memory/raw_ptr_cast.h"',
1899 '- #include "base/memory/raw_ptr_exclusion.h"',
1900 '- #include "base/memory/raw_ref.h"',
1901 ),
1902 treat_as_error=True,
1903 excluded_paths=(
1904 '^base/',
1905 '^tools/',
1906 ),
Tom Sepez41eb158d2023-09-12 16:16:221907 ),
1908 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531909 pattern=r'ContentSettingsType::COOKIES',
1910 explanation=
1911 ('Do not use ContentSettingsType::COOKIES to check whether cookies are '
1912 'supported in the provided context. Instead rely on the '
1913 'content_settings::CookieSettings API. If you are using '
1914 'ContentSettingsType::COOKIES to check the user preference setting '
1915 'specifically, disregard this warning.', ),
1916 treat_as_error=False,
1917 excluded_paths=(
1918 '^chrome/browser/ui/content_settings/',
1919 '^components/content_settings/',
1920 '^services/network/cookie_settings.cc',
1921 '.*test.cc',
1922 ),
Arthur Sonzogni48c6aea22023-09-04 22:25:201923 ),
1924 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531925 pattern=r'ContentSettingsType::TRACKING_PROTECTION',
1926 explanation=
1927 ('Do not directly use ContentSettingsType::TRACKING_PROTECTION to check '
1928 'for tracking protection exceptions. Instead rely on the '
1929 'privacy_sandbox::TrackingProtectionSettings API.', ),
1930 treat_as_error=False,
1931 excluded_paths=(
1932 '^chrome/browser/ui/content_settings/',
1933 '^components/content_settings/',
1934 '^components/privacy_sandbox/tracking_protection_settings.cc',
1935 '.*test.cc',
1936 ),
Anton Maliev66751812023-08-24 16:28:131937 ),
Tom Andersoncd522072023-10-03 00:52:351938 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531939 pattern=r'/\bg_signal_connect',
1940 explanation=('Use ScopedGSignal instead of g_signal_connect*()', ),
1941 treat_as_error=True,
1942 excluded_paths=('^ui/base/glib/scoped_gsignal.h', ),
Michelle Abreo6b7437822024-04-26 17:29:041943 ),
1944 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:531945 pattern=r'features::kIsolatedWebApps',
1946 explanation=(
1947 'Do not use `features::kIsolatedWebApps` directly to guard Isolated ',
1948 'Web App code. ',
1949 'Use `content::IsolatedWebAppsPolicy::AreIsolatedWebAppsEnabled()` in ',
1950 'the browser process or check the `kEnableIsolatedWebAppsInRenderer` ',
1951 'command line flag in the renderer process.',
1952 ),
1953 treat_as_error=True,
1954 excluded_paths=_TEST_CODE_EXCLUDED_PATHS +
1955 ('^chrome/browser/about_flags.cc',
1956 '^chrome/browser/web_applications/isolated_web_apps/chrome_content_browser_client_isolated_web_apps_part.cc',
1957 '^chrome/browser/ui/startup/bad_flags_prompt.cc',
1958 '^content/shell/browser/shell_content_browser_client.cc')),
1959 BanRule(
1960 pattern=r'features::kIsolatedWebAppDevMode',
1961 explanation=(
1962 'Do not use `features::kIsolatedWebAppDevMode` directly to guard code ',
1963 'related to Isolated Web App Developer Mode. ',
1964 'Use `web_app::IsIwaDevModeEnabled()` instead.',
1965 ),
1966 treat_as_error=True,
1967 excluded_paths=_TEST_CODE_EXCLUDED_PATHS + (
1968 '^chrome/browser/about_flags.cc',
1969 '^chrome/browser/web_applications/isolated_web_apps/isolated_web_app_features.cc',
1970 '^chrome/browser/ui/startup/bad_flags_prompt.cc',
1971 )),
1972 BanRule(
1973 pattern=r'features::kIsolatedWebAppUnmanagedInstall',
1974 explanation=(
1975 'Do not use `features::kIsolatedWebAppUnmanagedInstall` directly to ',
1976 'guard code related to unmanaged install flow for Isolated Web Apps. ',
1977 'Use `web_app::IsIwaUnmanagedInstallEnabled()` instead.',
1978 ),
1979 treat_as_error=True,
1980 excluded_paths=_TEST_CODE_EXCLUDED_PATHS + (
1981 '^chrome/browser/about_flags.cc',
1982 '^chrome/browser/web_applications/isolated_web_apps/isolated_web_app_features.cc',
1983 )),
1984 BanRule(
1985 pattern=
1986 r'/\babsl::(optional|nullopt|make_optional|in_place|in_place_t)\b',
1987 explanation=('Don\'t use `absl::optional`. Use `std::optional`.', ),
1988 # TODO(b/40288126): Enforce after completing the rewrite.
1989 treat_as_error=False,
1990 excluded_paths=[
1991 _THIRD_PARTY_EXCEPT_BLINK,
1992 ]),
1993 BanRule(
1994 pattern=r'(base::)?\bStringPiece\b',
1995 explanation=(
1996 'Don\'t use `base::StringPiece`. Use `std::string_view`.', ),
1997 treat_as_error=False,
Tom Andersoncd522072023-10-03 00:52:351998 ),
Christian Flach8da3bf82023-10-12 09:42:531999 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:532000 pattern=r'(base::)?\bStringPiece16\b',
2001 explanation=(
2002 'Don\'t use `base::StringPiece16`. Use `std::u16string_view`.', ),
2003 treat_as_error=False,
Christian Flach8da3bf82023-10-12 09:42:532004 ),
Arthur Sonzogni5cbd3e32024-02-08 17:51:322005 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:532006 pattern='/(CUIAutomation|AccessibleObjectFromWindow)',
2007 explanation=
2008 ('Direct usage of UIAutomation or IAccessible2 in client code is '
2009 'discouraged in Chromium, as it is not an assistive technology and '
2010 'should not rely on accessibility APIs directly. These APIs can '
2011 'introduce significant performance overhead. However, if you believe '
2012 'your use case warrants an exception, please discuss it with an '
2013 'accessibility owner before proceeding. For more information on the '
2014 'performance implications, see https://docs.google.com/document/d/1jN4itpCe_bDXF0BhFaYwv4xVLsCWkL9eULdzjmLzkuk/edit#heading=h.pwth3nbwdub0.',
2015 ),
2016 treat_as_error=False,
Andrew Rayskiycdd45e732024-03-20 14:32:392017 ),
2018 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:532019 pattern=r'/WIDGET_OWNS_NATIVE_WIDGET|'
2020 r'NATIVE_WIDGET_OWNS_WIDGET',
2021 explanation=
2022 ('WIDGET_OWNS_NATIVE_WIDGET and NATIVE_WIDGET_OWNS_WIDGET are in the '
2023 'process of being deprecated. Consider using the new '
2024 'CLIENT_OWNS_WIDGET ownership model. Eventually, this will be the only '
2025 'available ownership model available and the associated enumeration'
2026 'will be removed.', ),
2027 treat_as_error=False,
Andrew Rayskiycdd45e732024-03-20 14:32:392028 ),
2029 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:532030 pattern='ProfileManager::GetLastUsedProfile',
2031 explanation=
2032 ('Most code should already be scoped to a Profile. Pass in a Profile* '
2033 'or retreive from an existing entity with a reference to the Profile '
2034 '(e.g. WebContents).', ),
2035 treat_as_error=False,
Arthur Sonzogni5cbd3e32024-02-08 17:51:322036 ),
Helmut Januschkab3f71ab52024-03-12 02:48:052037 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:532038 pattern=(r'/FindBrowserWithUiElementContext|'
2039 r'FindBrowserWithTab|'
2040 r'FindBrowserWithGroup|'
2041 r'FindTabbedBrowser|'
2042 r'FindAnyBrowser|'
2043 r'FindBrowserWithProfile|'
2044 r'FindBrowserWithActiveWindow'),
2045 explanation=
2046 ('Most code should already be scoped to a Browser. Pass in a Browser* '
2047 'or retreive from an existing entity with a reference to the Browser.',
2048 ),
2049 treat_as_error=False,
Helmut Januschkab3f71ab52024-03-12 02:48:052050 ),
2051 BanRule(
Daniel Cheng566634ff2024-06-29 14:56:532052 pattern='BrowserUserData',
2053 explanation=
2054 ('Do not use BrowserUserData to store state on a Browser instance. '
2055 'Instead use BrowserWindowFeatures. BrowserWindowFeatures is '
2056 'functionally identical but has two benefits: it does not force a '
2057 'dependency onto class Browser, and lifetime semantics are explicit '
2058 'rather than implicit. See BrowserUserData header file for more '
2059 'details.', ),
2060 treat_as_error=False,
Mike Doughertyab1bdec2024-08-06 16:39:012061 excluded_paths=(
2062 # Exclude iOS as the iOS implementation of BrowserUserData is separate
2063 # and still in use.
2064 '^ios/',
2065 ),
Erik Chen87358e82024-06-04 02:13:122066 ),
Tom Sepezea67b6e2024-08-08 18:17:272067 BanRule(
2068 pattern=r'UNSAFE_TODO(',
2069 explanation=
2070 ('Do not use UNSAFE_TODO() to write new unsafe code. Use only when '
Tom Sepeza90f92b2024-08-15 16:01:352071 'removing a pre-existing file-wide allow_unsafe_buffers pragma, or '
2072 'when incrementally converting code off of unsafe interfaces',
Tom Sepezea67b6e2024-08-08 18:17:272073 ),
2074 treat_as_error=False,
2075 ),
2076 BanRule(
2077 pattern=r'UNSAFE_BUFFERS(',
2078 explanation=
Tom Sepeza90f92b2024-08-15 16:01:352079 ('Try to avoid using UNSAFE_BUFFERS() if at all possible. Otherwise, '
2080 'be sure to justify in a // SAFETY comment why other options are not '
2081 'available, and why the code is safe.',
Tom Sepezea67b6e2024-08-08 18:17:272082 ),
2083 treat_as_error=False,
2084 ),
Erik Chend086ae02024-08-20 22:53:332085 BanRule(
2086 pattern='BrowserWithTestWindowTest',
2087 explanation=
2088 ('Do not use BrowserWithTestWindowTest. By instantiating an instance '
2089 'of class Browser, the test is no longer a unit test but is instead a '
2090 'browser test. The class BrowserWithTestWindowTest forces production '
2091 'logic to take on test-only conditionals, which is an anti-pattern. '
2092 'Features should be performing dependency injection rather than '
2093 'directly using class Browser. See '
2094 'docs/chrome_browser_design_principles.md for more details.'
2095 ),
2096 treat_as_error=False,
2097 ),
[email protected]127f18ec2012-06-16 05:05:592098)
2099
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152100_DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING = (
2101 'Used a predicate related to signin::ConsentLevel::kSync which will always '
2102 'return false in the future (crbug.com/40066949). Prefer using a predicate '
2103 'that also supports signin::ConsentLevel::kSignin when appropriate. It is '
2104 'safe to ignore this warning if you are just moving an existing call, or if '
2105 'you want special handling for users in the legacy state. In doubt, reach '
Victor Hugo Vianna Silvae2292972024-06-04 17:11:552106 'out to //components/sync/OWNERS.',
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152107)
2108
2109# C++ functions related to signin::ConsentLevel::kSync which are deprecated.
2110_DEPRECATED_SYNC_CONSENT_CPP_FUNCTIONS : Sequence[BanRule] = (
2111 BanRule(
2112 'HasSyncConsent',
2113 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2114 False,
2115 ),
2116 BanRule(
2117 'CanSyncFeatureStart',
2118 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2119 False,
2120 ),
2121 BanRule(
2122 'IsSyncFeatureEnabled',
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152123 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152124 False,
2125 ),
2126 BanRule(
2127 'IsSyncFeatureActive',
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152128 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152129 False,
2130 ),
2131)
2132
2133# Java functions related to signin::ConsentLevel::kSync which are deprecated.
2134_DEPRECATED_SYNC_CONSENT_JAVA_FUNCTIONS : Sequence[BanRule] = (
2135 BanRule(
2136 'hasSyncConsent',
2137 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2138 False,
2139 ),
2140 BanRule(
2141 'canSyncFeatureStart',
2142 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2143 False,
2144 ),
2145 BanRule(
2146 'isSyncFeatureEnabled',
2147 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2148 False,
2149 ),
2150 BanRule(
2151 'isSyncFeatureActive',
2152 _DEPRECATED_SYNC_CONSENT_FUNCTION_WARNING,
2153 False,
2154 ),
2155)
2156
Daniel Cheng92c15e32022-03-16 17:48:222157_BANNED_MOJOM_PATTERNS : Sequence[BanRule] = (
2158 BanRule(
2159 'handle<shared_buffer>',
2160 (
2161 'Please use one of the more specific shared memory types instead:',
2162 ' mojo_base.mojom.ReadOnlySharedMemoryRegion',
2163 ' mojo_base.mojom.WritableSharedMemoryRegion',
2164 ' mojo_base.mojom.UnsafeSharedMemoryRegion',
2165 ),
2166 True,
2167 ),
2168)
2169
mlamouria82272622014-09-16 18:45:042170_IPC_ENUM_TRAITS_DEPRECATED = (
2171 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:502172 'See http://www.chromium.org/Home/chromium-security/education/'
2173 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:042174
Stephen Martinis97a394142018-06-07 23:06:052175_LONG_PATH_ERROR = (
2176 'Some files included in this CL have file names that are too long (> 200'
2177 ' characters). If committed, these files will cause issues on Windows. See'
2178 ' https://crbug.com/612667 for more details.'
2179)
2180
Shenghua Zhangbfaa38b82017-11-16 21:58:022181_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Bruce Dawson40fece62022-09-16 19:58:312182 r".*/AppHooksImpl\.java",
2183 r".*/BuildHooksAndroidImpl\.java",
2184 r".*/LicenseContentProvider\.java",
2185 r".*/PlatformServiceBridgeImpl.java",
2186 r".*chrome/android/feed/dummy/.*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:022187]
[email protected]127f18ec2012-06-16 05:05:592188
Mohamed Heikald048240a2019-11-12 16:57:372189# List of image extensions that are used as resources in chromium.
2190_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
2191
Sean Kau46e29bc2017-08-28 16:31:162192# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:402193_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Bruce Dawson40fece62022-09-16 19:58:312194 r'test/data/',
2195 r'testing/buildbot/',
2196 r'^components/policy/resources/policy_templates\.json$',
2197 r'^third_party/protobuf/',
Camillo Bruni1411a352023-05-24 12:39:032198 r'^third_party/blink/perf_tests/speedometer.*/resources/todomvc/learn\.json',
Bruce Dawson40fece62022-09-16 19:58:312199 r'^third_party/blink/renderer/devtools/protocol\.json$',
2200 r'^third_party/blink/web_tests/external/wpt/',
2201 r'^tools/perf/',
2202 r'^tools/traceline/svgui/startup-release.json',
Daniel Cheng2d4c2d192022-07-01 01:38:312203 # vscode configuration files allow comments
Bruce Dawson40fece62022-09-16 19:58:312204 r'^tools/vscode/',
Sean Kau46e29bc2017-08-28 16:31:162205]
2206
Andrew Grieveb773bad2020-06-05 18:00:382207# These are not checked on the public chromium-presubmit trybot.
2208# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:042209# checkouts.
agrievef32bcc72016-04-04 14:57:402210_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:382211 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382212]
2213
2214
2215_GENERIC_PYDEPS_FILES = [
Bruce Dawson853b739e62022-05-03 23:03:102216 'android_webview/test/components/run_webview_component_smoketest.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042217 'android_webview/tools/run_cts.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:362218 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042219 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362220 'build/android/gyp/aar.pydeps',
2221 'build/android/gyp/aidl.pydeps',
2222 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:382223 'build/android/gyp/assert_static_initializers.pydeps',
Mohamed Heikal133e1f22023-04-18 20:04:372224 'build/android/gyp/binary_baseline_profile.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362225 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:022226 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:222227 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:112228 'build/android/gyp/compile_java.pydeps',
Peter Weneaa963f2023-01-20 19:40:302229 'build/android/gyp/compile_kt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362230 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362231 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362232 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:112233 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042234 'build/android/gyp/create_app_bundle_apks.pydeps',
2235 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362236 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:122237 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:092238 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:222239 'build/android/gyp/create_size_info_files.pydeps',
Peter Wene6e017e2022-07-27 21:40:402240 'build/android/gyp/create_test_apk_wrapper_script.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002241 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362242 'build/android/gyp/dex.pydeps',
2243 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362244 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:212245 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362246 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:362247 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362248 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:582249 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362250 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:142251 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:262252 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:472253 'build/android/gyp/java_google_api_keys.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042254 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362255 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362256 'build/android/gyp/merge_manifest.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:102257 'build/android/gyp/optimize_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362258 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:222259 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362260 'build/android/gyp/proguard.pydeps',
Andrew Grievee3a775ab2022-05-16 15:59:222261 'build/android/gyp/system_image_apks.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:102262 'build/android/gyp/trace_event_bytecode_rewriter.pydeps',
Peter Wen578730b2020-03-19 19:55:462263 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:302264 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:242265 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362266 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:462267 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:562268 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362269 'build/android/incremental_install/generate_android_manifest.pydeps',
2270 'build/android/incremental_install/write_installer_json.pydeps',
Stephanie Kim392913b452022-06-15 17:25:322271 'build/android/pylib/results/presentation/test_results_presentation.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042272 'build/android/resource_sizes.pydeps',
2273 'build/android/test_runner.pydeps',
2274 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:362275 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:362276 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:322277 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:272278 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
2279 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:042280 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Mohannad Farrag19102742023-12-01 01:16:302281 'components/cronet/tools/check_combined_proguard_file.pydeps',
2282 'components/cronet/tools/generate_proguard_file.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002283 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382284 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:002285 'content/public/android/generate_child_service.pydeps',
Hzj_jie77bdb802024-07-22 18:14:512286 'fuchsia_web/av_testing/av_sync_tests.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:382287 'net/tools/testserver/testserver.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:182288 'testing/scripts/run_isolated_script_test.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:412289 'testing/merge_scripts/standard_isolated_script_merge.pydeps',
2290 'testing/merge_scripts/standard_gtest_merge.pydeps',
2291 'testing/merge_scripts/code_coverage/merge_results.pydeps',
2292 'testing/merge_scripts/code_coverage/merge_steps.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:042293 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:422294 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
Yuki Shiino38eeaad12022-08-11 06:40:252295 'third_party/blink/renderer/bindings/scripts/check_generated_file_list.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:422296 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:132297 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Yuki Shiinoea477d32023-08-21 06:24:342298 'third_party/blink/renderer/bindings/scripts/generate_event_interface_names.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:502299 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:412300 'third_party/blink/tools/blinkpy/web_tests/merge_results.pydeps',
2301 'third_party/blink/tools/merge_web_test_results.pydeps',
John Budorickbc3571aa2019-04-25 02:20:062302 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:222303 'tools/binary_size/supersize.pydeps',
Ben Pastene028104a2022-08-10 19:17:452304 'tools/perf/process_perf_results.pydeps',
agrievef32bcc72016-04-04 14:57:402305]
2306
wnwenbdc444e2016-05-25 13:44:152307
agrievef32bcc72016-04-04 14:57:402308_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
2309
2310
Eric Boren6fd2b932018-01-25 15:05:082311# Bypass the AUTHORS check for these accounts.
2312_KNOWN_ROBOTS = set(
nqmtuan918b2232024-04-11 23:09:552313 ) | set('%[email protected]' % s for s in ('findit-for-me', 'luci-bisection')
Achuith Bhandarkar35905562018-07-25 19:28:452314 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:592315 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:522316 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:232317 'wpt-autoroller', 'chrome-weblayer-builder',
Garrett Beaty4d4fcf62021-11-24 17:57:472318 'lacros-version-skew-roller', 'skylab-test-cros-roller',
Sven Zheng722960ba2022-07-18 16:40:462319 'infra-try-recipes-tester', 'lacros-tracking-roller',
Brian Sheedy1c951e62022-10-27 01:16:182320 'lacros-sdk-version-roller', 'chrome-automated-expectation',
Stephanie Kimb49bdd242023-04-28 16:46:042321 'chromium-automated-expectation', 'chrome-branch-day',
2322 'chromium-autosharder')
Eric Boren835d71f2018-09-07 21:09:042323 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:272324 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:042325 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:162326 for s in ('chromium-internal-autoroll',)
Kyungjun Lee3b7c9352024-04-02 23:59:142327 ) | set('%[email protected]' % s
2328 for s in ('chrome-screen-ai-releaser',)
Yulan Lineb0cfba2021-04-09 18:43:162329 ) | set('%[email protected]' % s
Chong Gub277e342022-10-15 03:30:552330 for s in ('swarming-tasks',)
2331 ) | set('%[email protected]' % s
2332 for s in ('global-integration-try-builder',
Joey Scarr1103c5d2023-09-14 01:17:552333 'global-integration-ci-builder')
Suma Kasa3b9cf7a2023-09-21 22:05:542334 ) | set('%[email protected]' % s
2335 for s in ('chops-security-borg',
2336 'chops-security-cronjobs-cpesuggest'))
Eric Boren6fd2b932018-01-25 15:05:082337
Matt Stark6ef08872021-07-29 01:21:462338_INVALID_GRD_FILE_LINE = [
2339 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
2340]
Eric Boren6fd2b932018-01-25 15:05:082341
Daniel Bratell65b033262019-04-23 08:17:062342def _IsCPlusPlusFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502343 """Returns True if this file contains C++-like code (and not Python,
2344 Go, Java, MarkDown, ...)"""
Daniel Bratell65b033262019-04-23 08:17:062345
Sam Maiera6e76d72022-02-11 21:43:502346 ext = input_api.os_path.splitext(file_path)[1]
2347 # This list is compatible with CppChecker.IsCppFile but we should
2348 # consider adding ".c" to it. If we do that we can use this function
2349 # at more places in the code.
2350 return ext in (
2351 '.h',
2352 '.cc',
2353 '.cpp',
2354 '.m',
2355 '.mm',
2356 )
2357
Daniel Bratell65b033262019-04-23 08:17:062358
2359def _IsCPlusPlusHeaderFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502360 return input_api.os_path.splitext(file_path)[1] == ".h"
Daniel Bratell65b033262019-04-23 08:17:062361
2362
2363def _IsJavaFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502364 return input_api.os_path.splitext(file_path)[1] == ".java"
Daniel Bratell65b033262019-04-23 08:17:062365
2366
2367def _IsProtoFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502368 return input_api.os_path.splitext(file_path)[1] == ".proto"
Daniel Bratell65b033262019-04-23 08:17:062369
Mohamed Heikal5e5b7922020-10-29 18:57:592370
Erik Staabc734cd7a2021-11-23 03:11:522371def _IsXmlOrGrdFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:502372 ext = input_api.os_path.splitext(file_path)[1]
2373 return ext in ('.grd', '.xml')
Erik Staabc734cd7a2021-11-23 03:11:522374
2375
Sven Zheng76a79ea2022-12-21 21:25:242376def _IsMojomFile(input_api, file_path):
2377 return input_api.os_path.splitext(file_path)[1] == ".mojom"
2378
2379
Mohamed Heikal5e5b7922020-10-29 18:57:592380def CheckNoUpstreamDepsOnClank(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502381 """Prevent additions of dependencies from the upstream repo on //clank."""
2382 # clank can depend on clank
2383 if input_api.change.RepositoryRoot().endswith('clank'):
2384 return []
2385 build_file_patterns = [
2386 r'(.+/)?BUILD\.gn',
2387 r'.+\.gni',
2388 ]
2389 excluded_files = [r'build[/\\]config[/\\]android[/\\]config\.gni']
2390 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
Mohamed Heikal5e5b7922020-10-29 18:57:592391
Sam Maiera6e76d72022-02-11 21:43:502392 error_message = 'Disallowed import on //clank in an upstream build file:'
Mohamed Heikal5e5b7922020-10-29 18:57:592393
Sam Maiera6e76d72022-02-11 21:43:502394 def FilterFile(affected_file):
2395 return input_api.FilterSourceFile(affected_file,
2396 files_to_check=build_file_patterns,
2397 files_to_skip=excluded_files)
Mohamed Heikal5e5b7922020-10-29 18:57:592398
Sam Maiera6e76d72022-02-11 21:43:502399 problems = []
2400 for f in input_api.AffectedSourceFiles(FilterFile):
2401 local_path = f.LocalPath()
2402 for line_number, line in f.ChangedContents():
2403 if (bad_pattern.search(line)):
2404 problems.append('%s:%d\n %s' %
2405 (local_path, line_number, line.strip()))
2406 if problems:
2407 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
2408 else:
2409 return []
Mohamed Heikal5e5b7922020-10-29 18:57:592410
2411
Saagar Sanghavifceeaae2020-08-12 16:40:362412def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502413 """Attempts to prevent use of functions intended only for testing in
2414 non-testing code. For now this is just a best-effort implementation
2415 that ignores header files and may have some false positives. A
2416 better implementation would probably need a proper C++ parser.
2417 """
2418 # We only scan .cc files and the like, as the declaration of
2419 # for-testing functions in header files are hard to distinguish from
2420 # calls to such functions without a proper C++ parser.
2421 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:192422
Sam Maiera6e76d72022-02-11 21:43:502423 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
2424 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' %
2425 base_function_pattern)
2426 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
2427 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
2428 exclusion_pattern = input_api.re.compile(
2429 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' %
2430 (base_function_pattern, base_function_pattern))
2431 # Avoid a false positive in this case, where the method name, the ::, and
2432 # the closing { are all on different lines due to line wrapping.
2433 # HelperClassForTesting::
2434 # HelperClassForTesting(
2435 # args)
2436 # : member(0) {}
2437 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:192438
Sam Maiera6e76d72022-02-11 21:43:502439 def FilterFile(affected_file):
2440 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2441 input_api.DEFAULT_FILES_TO_SKIP)
2442 return input_api.FilterSourceFile(
2443 affected_file,
2444 files_to_check=file_inclusion_pattern,
2445 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:192446
Sam Maiera6e76d72022-02-11 21:43:502447 problems = []
2448 for f in input_api.AffectedSourceFiles(FilterFile):
2449 local_path = f.LocalPath()
2450 in_method_defn = False
2451 for line_number, line in f.ChangedContents():
2452 if (inclusion_pattern.search(line)
2453 and not comment_pattern.search(line)
2454 and not exclusion_pattern.search(line)
2455 and not allowlist_pattern.search(line)
2456 and not in_method_defn):
2457 problems.append('%s:%d\n %s' %
2458 (local_path, line_number, line.strip()))
2459 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:192460
Sam Maiera6e76d72022-02-11 21:43:502461 if problems:
2462 return [
2463 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
2464 ]
2465 else:
2466 return []
[email protected]55459852011-08-10 15:17:192467
2468
Saagar Sanghavifceeaae2020-08-12 16:40:362469def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502470 """This is a simplified version of
2471 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
2472 """
2473 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
2474 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
2475 name_pattern = r'ForTest(s|ing)?'
2476 # Describes an occurrence of "ForTest*" inside a // comment.
2477 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
2478 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
2479 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
2480 # Catch calls.
2481 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
2482 # Ignore definitions. (Comments are ignored separately.)
2483 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
Andrew Grieve40f451d2023-07-06 19:46:512484 allowlist_re = input_api.re.compile(r'// IN-TEST$')
Vaclav Brozek7dbc28c2018-03-27 08:35:232485
Sam Maiera6e76d72022-02-11 21:43:502486 problems = []
2487 sources = lambda x: input_api.FilterSourceFile(
2488 x,
2489 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
2490 DEFAULT_FILES_TO_SKIP),
2491 files_to_check=[r'.*\.java$'])
2492 for f in input_api.AffectedFiles(include_deletes=False,
2493 file_filter=sources):
2494 local_path = f.LocalPath()
Vaclav Brozek7dbc28c2018-03-27 08:35:232495 is_inside_javadoc = False
Sam Maiera6e76d72022-02-11 21:43:502496 for line_number, line in f.ChangedContents():
2497 if is_inside_javadoc and javadoc_end_re.search(line):
2498 is_inside_javadoc = False
2499 if not is_inside_javadoc and javadoc_start_re.search(line):
2500 is_inside_javadoc = True
2501 if is_inside_javadoc:
2502 continue
2503 if (inclusion_re.search(line) and not comment_re.search(line)
2504 and not annotation_re.search(line)
Andrew Grieve40f451d2023-07-06 19:46:512505 and not allowlist_re.search(line)
Sam Maiera6e76d72022-02-11 21:43:502506 and not exclusion_re.search(line)):
2507 problems.append('%s:%d\n %s' %
2508 (local_path, line_number, line.strip()))
Vaclav Brozek7dbc28c2018-03-27 08:35:232509
Sam Maiera6e76d72022-02-11 21:43:502510 if problems:
2511 return [
2512 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
2513 ]
2514 else:
2515 return []
Vaclav Brozek7dbc28c2018-03-27 08:35:232516
2517
Saagar Sanghavifceeaae2020-08-12 16:40:362518def CheckNoIOStreamInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502519 """Checks to make sure no .h files include <iostream>."""
2520 files = []
2521 pattern = input_api.re.compile(r'^#include\s*<iostream>',
2522 input_api.re.MULTILINE)
2523 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2524 if not f.LocalPath().endswith('.h'):
2525 continue
2526 contents = input_api.ReadFile(f)
2527 if pattern.search(contents):
2528 files.append(f)
[email protected]10689ca2011-09-02 02:31:542529
Sam Maiera6e76d72022-02-11 21:43:502530 if len(files):
2531 return [
2532 output_api.PresubmitError(
2533 'Do not #include <iostream> in header files, since it inserts static '
2534 'initialization into every file including the header. Instead, '
2535 '#include <ostream>. See http://crbug.com/94794', files)
2536 ]
2537 return []
2538
[email protected]10689ca2011-09-02 02:31:542539
Aleksey Khoroshilov9b28c032022-06-03 16:35:322540def CheckNoStrCatRedefines(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502541 """Checks no windows headers with StrCat redefined are included directly."""
2542 files = []
Aleksey Khoroshilov9b28c032022-06-03 16:35:322543 files_to_check = (r'.+%s' % _HEADER_EXTENSIONS,
2544 r'.+%s' % _IMPLEMENTATION_EXTENSIONS)
2545 files_to_skip = (input_api.DEFAULT_FILES_TO_SKIP +
2546 _NON_BASE_DEPENDENT_PATHS)
2547 sources_filter = lambda f: input_api.FilterSourceFile(
2548 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
2549
Sam Maiera6e76d72022-02-11 21:43:502550 pattern_deny = input_api.re.compile(
2551 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
2552 input_api.re.MULTILINE)
2553 pattern_allow = input_api.re.compile(
2554 r'^#include\s"base/win/windows_defines.inc"', input_api.re.MULTILINE)
Aleksey Khoroshilov9b28c032022-06-03 16:35:322555 for f in input_api.AffectedSourceFiles(sources_filter):
Sam Maiera6e76d72022-02-11 21:43:502556 contents = input_api.ReadFile(f)
2557 if pattern_deny.search(
2558 contents) and not pattern_allow.search(contents):
2559 files.append(f.LocalPath())
Danil Chapovalov3518f362018-08-11 16:13:432560
Sam Maiera6e76d72022-02-11 21:43:502561 if len(files):
2562 return [
2563 output_api.PresubmitError(
2564 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
2565 'directly since they pollute code with StrCat macro. Instead, '
2566 'include matching header from base/win. See http://crbug.com/856536',
2567 files)
2568 ]
2569 return []
Danil Chapovalov3518f362018-08-11 16:13:432570
[email protected]10689ca2011-09-02 02:31:542571
Andrew Williamsc9f69b482023-07-10 16:07:362572def _CheckNoUNIT_TESTInSourceFiles(input_api, f):
2573 problems = []
2574
2575 unit_test_macro = input_api.re.compile(
2576 '^\s*#.*(?:ifn?def\s+UNIT_TEST|defined\s*\(?\s*UNIT_TEST\s*\)?)(?:$|\s+)')
2577 for line_num, line in f.ChangedContents():
2578 if unit_test_macro.match(line):
2579 problems.append(' %s:%d' % (f.LocalPath(), line_num))
2580
2581 return problems
2582
2583
Saagar Sanghavifceeaae2020-08-12 16:40:362584def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502585 """Checks to make sure no source files use UNIT_TEST."""
2586 problems = []
2587 for f in input_api.AffectedFiles():
2588 if (not f.LocalPath().endswith(('.cc', '.mm'))):
2589 continue
Andrew Williamsc9f69b482023-07-10 16:07:362590 problems.extend(
2591 _CheckNoUNIT_TESTInSourceFiles(input_api, f))
[email protected]72df4e782012-06-21 16:28:182592
Sam Maiera6e76d72022-02-11 21:43:502593 if not problems:
2594 return []
2595 return [
2596 output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
2597 '\n'.join(problems))
2598 ]
2599
[email protected]72df4e782012-06-21 16:28:182600
Saagar Sanghavifceeaae2020-08-12 16:40:362601def CheckNoDISABLETypoInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502602 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
Dominic Battre033531052018-09-24 15:45:342603
Sam Maiera6e76d72022-02-11 21:43:502604 This test warns if somebody tries to disable a test with the DISABLE_ prefix
2605 instead of DISABLED_. To filter false positives, reports are only generated
2606 if a corresponding MAYBE_ line exists.
2607 """
2608 problems = []
Dominic Battre033531052018-09-24 15:45:342609
Sam Maiera6e76d72022-02-11 21:43:502610 # The following two patterns are looked for in tandem - is a test labeled
2611 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
2612 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
2613 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
Dominic Battre033531052018-09-24 15:45:342614
Sam Maiera6e76d72022-02-11 21:43:502615 # This is for the case that a test is disabled on all platforms.
2616 full_disable_pattern = input_api.re.compile(
2617 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
2618 input_api.re.MULTILINE)
Dominic Battre033531052018-09-24 15:45:342619
Arthur Sonzognic66e9c82024-04-23 07:53:042620 for f in input_api.AffectedFiles(include_deletes=False):
Sam Maiera6e76d72022-02-11 21:43:502621 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2622 continue
Dominic Battre033531052018-09-24 15:45:342623
Arthur Sonzognic66e9c82024-04-23 07:53:042624 # Search for MAYBE_, DISABLE_ pairs.
Sam Maiera6e76d72022-02-11 21:43:502625 disable_lines = {} # Maps of test name to line number.
2626 maybe_lines = {}
2627 for line_num, line in f.ChangedContents():
2628 disable_match = disable_pattern.search(line)
2629 if disable_match:
2630 disable_lines[disable_match.group(1)] = line_num
2631 maybe_match = maybe_pattern.search(line)
2632 if maybe_match:
2633 maybe_lines[maybe_match.group(1)] = line_num
Dominic Battre033531052018-09-24 15:45:342634
Sam Maiera6e76d72022-02-11 21:43:502635 # Search for DISABLE_ occurrences within a TEST() macro.
2636 disable_tests = set(disable_lines.keys())
2637 maybe_tests = set(maybe_lines.keys())
2638 for test in disable_tests.intersection(maybe_tests):
2639 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
Dominic Battre033531052018-09-24 15:45:342640
Sam Maiera6e76d72022-02-11 21:43:502641 contents = input_api.ReadFile(f)
2642 full_disable_match = full_disable_pattern.search(contents)
2643 if full_disable_match:
2644 problems.append(' %s' % f.LocalPath())
Dominic Battre033531052018-09-24 15:45:342645
Sam Maiera6e76d72022-02-11 21:43:502646 if not problems:
2647 return []
2648 return [
2649 output_api.PresubmitPromptWarning(
2650 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
2651 '\n'.join(problems))
2652 ]
2653
Dominic Battre033531052018-09-24 15:45:342654
Nina Satragnof7660532021-09-20 18:03:352655def CheckForgettingMAYBEInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502656 """Checks to make sure tests disabled conditionally are not missing a
2657 corresponding MAYBE_ prefix.
2658 """
2659 # Expect at least a lowercase character in the test name. This helps rule out
2660 # false positives with macros wrapping the actual tests name.
2661 define_maybe_pattern = input_api.re.compile(
2662 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
Bruce Dawsonffc55292022-04-20 04:18:192663 # The test_maybe_pattern needs to handle all of these forms. The standard:
2664 # IN_PROC_TEST_F(SyncTest, MAYBE_Start) {
2665 # With a wrapper macro around the test name:
2666 # IN_PROC_TEST_F(SyncTest, E2E_ENABLED(MAYBE_Start)) {
2667 # And the odd-ball NACL_BROWSER_TEST_f format:
2668 # NACL_BROWSER_TEST_F(NaClBrowserTest, SimpleLoad, {
2669 # The optional E2E_ENABLED-style is handled with (\w*\()?
2670 # The NACL_BROWSER_TEST_F pattern is handled by allowing a trailing comma or
2671 # trailing ')'.
2672 test_maybe_pattern = (
2673 r'^\s*\w*TEST[^(]*\(\s*\w+,\s*(\w*\()?MAYBE_{test_name}[\),]')
Sam Maiera6e76d72022-02-11 21:43:502674 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
2675 warnings = []
Nina Satragnof7660532021-09-20 18:03:352676
Sam Maiera6e76d72022-02-11 21:43:502677 # Read the entire files. We can't just read the affected lines, forgetting to
2678 # add MAYBE_ on a change would not show up otherwise.
Arthur Sonzognic66e9c82024-04-23 07:53:042679 for f in input_api.AffectedFiles(include_deletes=False):
Sam Maiera6e76d72022-02-11 21:43:502680 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2681 continue
2682 contents = input_api.ReadFile(f)
2683 lines = contents.splitlines(True)
2684 current_position = 0
2685 warning_test_names = set()
2686 for line_num, line in enumerate(lines, start=1):
2687 current_position += len(line)
2688 maybe_match = define_maybe_pattern.search(line)
2689 if maybe_match:
2690 test_name = maybe_match.group('test_name')
2691 # Do not warn twice for the same test.
2692 if (test_name in warning_test_names):
2693 continue
2694 warning_test_names.add(test_name)
Nina Satragnof7660532021-09-20 18:03:352695
Sam Maiera6e76d72022-02-11 21:43:502696 # Attempt to find the corresponding MAYBE_ test or suite, starting from
2697 # the current position.
2698 test_match = input_api.re.compile(
2699 test_maybe_pattern.format(test_name=test_name),
2700 input_api.re.MULTILINE).search(contents, current_position)
2701 suite_match = input_api.re.compile(
2702 suite_maybe_pattern.format(test_name=test_name),
2703 input_api.re.MULTILINE).search(contents, current_position)
2704 if not test_match and not suite_match:
2705 warnings.append(
2706 output_api.PresubmitPromptWarning(
2707 '%s:%d found MAYBE_ defined without corresponding test %s'
2708 % (f.LocalPath(), line_num, test_name)))
2709 return warnings
2710
[email protected]72df4e782012-06-21 16:28:182711
Saagar Sanghavifceeaae2020-08-12 16:40:362712def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502713 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
2714 errors = []
Kalvin Lee4a3b79de2022-05-26 16:00:162715 pattern = input_api.re.compile(r'\bDCHECK_IS_ON\b(?!\(\))',
Sam Maiera6e76d72022-02-11 21:43:502716 input_api.re.MULTILINE)
2717 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2718 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
2719 continue
2720 for lnum, line in f.ChangedContents():
2721 if input_api.re.search(pattern, line):
2722 errors.append(
2723 output_api.PresubmitError((
2724 '%s:%d: Use of DCHECK_IS_ON() must be written as "#if '
2725 + 'DCHECK_IS_ON()", not forgetting the parentheses.') %
2726 (f.LocalPath(), lnum)))
2727 return errors
danakj61c1aa22015-10-26 19:55:522728
2729
Weilun Shia487fad2020-10-28 00:10:342730# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
2731# more reliable way. See
2732# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:192733
wnwenbdc444e2016-05-25 13:44:152734
Saagar Sanghavifceeaae2020-08-12 16:40:362735def CheckFlakyTestUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502736 """Check that FlakyTest annotation is our own instead of the android one"""
2737 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
2738 files = []
2739 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2740 if f.LocalPath().endswith('Test.java'):
2741 if pattern.search(input_api.ReadFile(f)):
2742 files.append(f)
2743 if len(files):
2744 return [
2745 output_api.PresubmitError(
2746 'Use org.chromium.base.test.util.FlakyTest instead of '
2747 'android.test.FlakyTest', files)
2748 ]
2749 return []
mcasasb7440c282015-02-04 14:52:192750
wnwenbdc444e2016-05-25 13:44:152751
Saagar Sanghavifceeaae2020-08-12 16:40:362752def CheckNoDEPSGIT(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502753 """Make sure .DEPS.git is never modified manually."""
2754 if any(f.LocalPath().endswith('.DEPS.git')
2755 for f in input_api.AffectedFiles()):
2756 return [
2757 output_api.PresubmitError(
2758 'Never commit changes to .DEPS.git. This file is maintained by an\n'
2759 'automated system based on what\'s in DEPS and your changes will be\n'
2760 'overwritten.\n'
2761 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
2762 'get-the-code#Rolling_DEPS\n'
2763 'for more information')
2764 ]
2765 return []
[email protected]2a8ac9c2011-10-19 17:20:442766
2767
Sven Zheng76a79ea2022-12-21 21:25:242768def CheckCrosApiNeedBrowserTest(input_api, output_api):
2769 """Check new crosapi should add browser test."""
2770 has_new_crosapi = False
2771 has_browser_test = False
2772 for f in input_api.AffectedFiles():
2773 path = f.LocalPath()
2774 if (path.startswith('chromeos/crosapi/mojom') and
2775 _IsMojomFile(input_api, path) and f.Action() == 'A'):
2776 has_new_crosapi = True
2777 if path.endswith('browsertest.cc') or path.endswith('browser_test.cc'):
2778 has_browser_test = True
2779 if has_new_crosapi and not has_browser_test:
2780 return [
2781 output_api.PresubmitPromptWarning(
2782 'You are adding a new crosapi, but there is no file ends with '
2783 'browsertest.cc file being added or modified. It is important '
2784 'to add crosapi browser test coverage to avoid version '
2785 ' skew issues.\n'
2786 'Check //docs/lacros/test_instructions.md for more information.'
2787 )
2788 ]
2789 return []
2790
2791
Saagar Sanghavifceeaae2020-08-12 16:40:362792def CheckValidHostsInDEPSOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502793 """Checks that DEPS file deps are from allowed_hosts."""
2794 # Run only if DEPS file has been modified to annoy fewer bystanders.
2795 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
2796 return []
2797 # Outsource work to gclient verify
2798 try:
2799 gclient_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
2800 'third_party', 'depot_tools',
2801 'gclient.py')
2802 input_api.subprocess.check_output(
Bruce Dawson8a43cf72022-05-13 17:10:322803 [input_api.python3_executable, gclient_path, 'verify'],
Sam Maiera6e76d72022-02-11 21:43:502804 stderr=input_api.subprocess.STDOUT)
2805 return []
2806 except input_api.subprocess.CalledProcessError as error:
2807 return [
2808 output_api.PresubmitError(
2809 'DEPS file must have only git dependencies.',
2810 long_text=error.output)
2811 ]
tandriief664692014-09-23 14:51:472812
2813
Mario Sanchez Prada2472cab2019-09-18 10:58:312814def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152815 ban_rule):
Allen Bauer84778682022-09-22 16:28:562816 """Helper method for checking for banned constructs.
Mario Sanchez Prada2472cab2019-09-18 10:58:312817
Sam Maiera6e76d72022-02-11 21:43:502818 Returns an string composed of the name of the file, the line number where the
2819 match has been found and the additional text passed as |message| in case the
2820 target type name matches the text inside the line passed as parameter.
2821 """
2822 result = []
Peng Huang9c5949a02020-06-11 19:20:542823
Daniel Chenga44a1bcd2022-03-15 20:00:152824 # Ignore comments about banned types.
2825 if input_api.re.search(r"^ *//", line):
Sam Maiera6e76d72022-02-11 21:43:502826 return result
Daniel Chenga44a1bcd2022-03-15 20:00:152827 # A // nocheck comment will bypass this error.
2828 if line.endswith(" nocheck"):
Sam Maiera6e76d72022-02-11 21:43:502829 return result
2830
2831 matched = False
Daniel Chenga44a1bcd2022-03-15 20:00:152832 if ban_rule.pattern[0:1] == '/':
2833 regex = ban_rule.pattern[1:]
Sam Maiera6e76d72022-02-11 21:43:502834 if input_api.re.search(regex, line):
2835 matched = True
Daniel Chenga44a1bcd2022-03-15 20:00:152836 elif ban_rule.pattern in line:
Sam Maiera6e76d72022-02-11 21:43:502837 matched = True
2838
2839 if matched:
2840 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
Daniel Chenga44a1bcd2022-03-15 20:00:152841 for line in ban_rule.explanation:
2842 result.append(' %s' % line)
Sam Maiera6e76d72022-02-11 21:43:502843
danakjd18e8892020-12-17 17:42:012844 return result
Mario Sanchez Prada2472cab2019-09-18 10:58:312845
2846
Saagar Sanghavifceeaae2020-08-12 16:40:362847def CheckNoBannedFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502848 """Make sure that banned functions are not used."""
2849 warnings = []
2850 errors = []
[email protected]127f18ec2012-06-16 05:05:592851
Sam Maiera6e76d72022-02-11 21:43:502852 def IsExcludedFile(affected_file, excluded_paths):
Daniel Chenga44a1bcd2022-03-15 20:00:152853 if not excluded_paths:
2854 return False
2855
Sam Maiera6e76d72022-02-11 21:43:502856 local_path = affected_file.LocalPath()
Bruce Dawson40fece62022-09-16 19:58:312857 # Consistently use / as path separator to simplify the writing of regex
2858 # expressions.
2859 local_path = local_path.replace(input_api.os_path.sep, '/')
Sam Maiera6e76d72022-02-11 21:43:502860 for item in excluded_paths:
2861 if input_api.re.match(item, local_path):
2862 return True
2863 return False
wnwenbdc444e2016-05-25 13:44:152864
Sam Maiera6e76d72022-02-11 21:43:502865 def IsIosObjcFile(affected_file):
2866 local_path = affected_file.LocalPath()
2867 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m',
2868 '.h'):
2869 return False
2870 basename = input_api.os_path.basename(local_path)
2871 if 'ios' in basename.split('_'):
2872 return True
2873 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
2874 if sep and 'ios' in local_path.split(sep):
2875 return True
2876 return False
Sylvain Defresnea8b73d252018-02-28 15:45:542877
Daniel Chenga44a1bcd2022-03-15 20:00:152878 def CheckForMatch(affected_file, line_num: int, line: str,
2879 ban_rule: BanRule):
2880 if IsExcludedFile(affected_file, ban_rule.excluded_paths):
2881 return
2882
Sam Maiera6e76d72022-02-11 21:43:502883 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152884 ban_rule)
Sam Maiera6e76d72022-02-11 21:43:502885 if problems:
Daniel Chenga44a1bcd2022-03-15 20:00:152886 if ban_rule.treat_as_error is not None and ban_rule.treat_as_error:
Sam Maiera6e76d72022-02-11 21:43:502887 errors.extend(problems)
2888 else:
2889 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:152890
Sam Maiera6e76d72022-02-11 21:43:502891 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2892 for f in input_api.AffectedFiles(file_filter=file_filter):
2893 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152894 for ban_rule in _BANNED_JAVA_FUNCTIONS:
2895 CheckForMatch(f, line_num, line, ban_rule)
Eric Stevensona9a980972017-09-23 00:04:412896
Clement Yan9b330cb2022-11-17 05:25:292897 file_filter = lambda f: f.LocalPath().endswith(('.js', '.ts'))
2898 for f in input_api.AffectedFiles(file_filter=file_filter):
2899 for line_num, line in f.ChangedContents():
2900 for ban_rule in _BANNED_JAVASCRIPT_FUNCTIONS:
2901 CheckForMatch(f, line_num, line, ban_rule)
2902
Sam Maiera6e76d72022-02-11 21:43:502903 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
2904 for f in input_api.AffectedFiles(file_filter=file_filter):
2905 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152906 for ban_rule in _BANNED_OBJC_FUNCTIONS:
2907 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:592908
Sam Maiera6e76d72022-02-11 21:43:502909 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
2910 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152911 for ban_rule in _BANNED_IOS_OBJC_FUNCTIONS:
2912 CheckForMatch(f, line_num, line, ban_rule)
Sylvain Defresnea8b73d252018-02-28 15:45:542913
Sam Maiera6e76d72022-02-11 21:43:502914 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
2915 for f in input_api.AffectedFiles(file_filter=egtest_filter):
2916 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152917 for ban_rule in _BANNED_IOS_EGTEST_FUNCTIONS:
2918 CheckForMatch(f, line_num, line, ban_rule)
Peter K. Lee6c03ccff2019-07-15 14:40:052919
Sam Maiera6e76d72022-02-11 21:43:502920 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
2921 for f in input_api.AffectedFiles(file_filter=file_filter):
2922 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152923 for ban_rule in _BANNED_CPP_FUNCTIONS:
2924 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:592925
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:152926 # As of 05/2024, iOS fully migrated ConsentLevel::kSync to kSignin, and
2927 # Android is in the process of preventing new users from entering kSync.
2928 # So the warning is restricted to those platforms.
2929 ios_pattern = input_api.re.compile('(^|[\W_])ios[\W_]')
2930 file_filter = lambda f: (f.LocalPath().endswith(('.cc', '.mm', '.h')) and
2931 ('android' in f.LocalPath() or
2932 # Simply checking for an 'ios' substring would
2933 # catch unrelated cases, use a regex.
2934 ios_pattern.search(f.LocalPath())))
2935 for f in input_api.AffectedFiles(file_filter=file_filter):
2936 for line_num, line in f.ChangedContents():
2937 for ban_rule in _DEPRECATED_SYNC_CONSENT_CPP_FUNCTIONS:
2938 CheckForMatch(f, line_num, line, ban_rule)
2939
2940 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2941 for f in input_api.AffectedFiles(file_filter=file_filter):
2942 for line_num, line in f.ChangedContents():
2943 for ban_rule in _DEPRECATED_SYNC_CONSENT_JAVA_FUNCTIONS:
2944 CheckForMatch(f, line_num, line, ban_rule)
2945
Daniel Cheng92c15e32022-03-16 17:48:222946 file_filter = lambda f: f.LocalPath().endswith(('.mojom'))
2947 for f in input_api.AffectedFiles(file_filter=file_filter):
2948 for line_num, line in f.ChangedContents():
2949 for ban_rule in _BANNED_MOJOM_PATTERNS:
2950 CheckForMatch(f, line_num, line, ban_rule)
2951
2952
Sam Maiera6e76d72022-02-11 21:43:502953 result = []
2954 if (warnings):
2955 result.append(
2956 output_api.PresubmitPromptWarning('Banned functions were used.\n' +
2957 '\n'.join(warnings)))
2958 if (errors):
2959 result.append(
2960 output_api.PresubmitError('Banned functions were used.\n' +
2961 '\n'.join(errors)))
2962 return result
[email protected]127f18ec2012-06-16 05:05:592963
Michael Thiessen44457642020-02-06 00:24:152964def _CheckAndroidNoBannedImports(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502965 """Make sure that banned java imports are not used."""
2966 errors = []
Michael Thiessen44457642020-02-06 00:24:152967
Sam Maiera6e76d72022-02-11 21:43:502968 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2969 for f in input_api.AffectedFiles(file_filter=file_filter):
2970 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152971 for ban_rule in _BANNED_JAVA_IMPORTS:
2972 # Consider merging this into the above function. There is no
2973 # real difference anymore other than helping with a little
2974 # bit of boilerplate text. Doing so means things like
2975 # `treat_as_error` will also be uniformly handled.
Sam Maiera6e76d72022-02-11 21:43:502976 problems = _GetMessageForMatchingType(input_api, f, line_num,
Daniel Chenga44a1bcd2022-03-15 20:00:152977 line, ban_rule)
Sam Maiera6e76d72022-02-11 21:43:502978 if problems:
2979 errors.extend(problems)
2980 result = []
2981 if (errors):
2982 result.append(
2983 output_api.PresubmitError('Banned imports were used.\n' +
2984 '\n'.join(errors)))
2985 return result
Michael Thiessen44457642020-02-06 00:24:152986
2987
Saagar Sanghavifceeaae2020-08-12 16:40:362988def CheckNoPragmaOnce(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502989 """Make sure that banned functions are not used."""
2990 files = []
2991 pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
2992 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2993 if not f.LocalPath().endswith('.h'):
2994 continue
Bruce Dawson4c4c2922022-05-02 18:07:332995 if f.LocalPath().endswith('com_imported_mstscax.h'):
2996 continue
Sam Maiera6e76d72022-02-11 21:43:502997 contents = input_api.ReadFile(f)
2998 if pattern.search(contents):
2999 files.append(f)
[email protected]6c063c62012-07-11 19:11:063000
Sam Maiera6e76d72022-02-11 21:43:503001 if files:
3002 return [
3003 output_api.PresubmitError(
3004 'Do not use #pragma once in header files.\n'
3005 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
3006 files)
3007 ]
3008 return []
[email protected]6c063c62012-07-11 19:11:063009
[email protected]127f18ec2012-06-16 05:05:593010
Saagar Sanghavifceeaae2020-08-12 16:40:363011def CheckNoTrinaryTrueFalse(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503012 """Checks to make sure we don't introduce use of foo ? true : false."""
3013 problems = []
3014 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
3015 for f in input_api.AffectedFiles():
3016 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
3017 continue
[email protected]e7479052012-09-19 00:26:123018
Sam Maiera6e76d72022-02-11 21:43:503019 for line_num, line in f.ChangedContents():
3020 if pattern.match(line):
3021 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]e7479052012-09-19 00:26:123022
Sam Maiera6e76d72022-02-11 21:43:503023 if not problems:
3024 return []
3025 return [
3026 output_api.PresubmitPromptWarning(
3027 'Please consider avoiding the "? true : false" pattern if possible.\n'
3028 + '\n'.join(problems))
3029 ]
[email protected]e7479052012-09-19 00:26:123030
3031
Saagar Sanghavifceeaae2020-08-12 16:40:363032def CheckUnwantedDependencies(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503033 """Runs checkdeps on #include and import statements added in this
3034 change. Breaking - rules is an error, breaking ! rules is a
3035 warning.
3036 """
3037 # Return early if no relevant file types were modified.
3038 for f in input_api.AffectedFiles():
3039 path = f.LocalPath()
3040 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path)
3041 or _IsJavaFile(input_api, path)):
3042 break
[email protected]55f9f382012-07-31 11:02:183043 else:
Sam Maiera6e76d72022-02-11 21:43:503044 return []
rhalavati08acd232017-04-03 07:23:283045
Sam Maiera6e76d72022-02-11 21:43:503046 import sys
3047 # We need to wait until we have an input_api object and use this
3048 # roundabout construct to import checkdeps because this file is
3049 # eval-ed and thus doesn't have __file__.
3050 original_sys_path = sys.path
3051 try:
3052 sys.path = sys.path + [
3053 input_api.os_path.join(input_api.PresubmitLocalPath(),
3054 'buildtools', 'checkdeps')
3055 ]
3056 import checkdeps
3057 from rules import Rule
3058 finally:
3059 # Restore sys.path to what it was before.
3060 sys.path = original_sys_path
[email protected]55f9f382012-07-31 11:02:183061
Sam Maiera6e76d72022-02-11 21:43:503062 added_includes = []
3063 added_imports = []
3064 added_java_imports = []
3065 for f in input_api.AffectedFiles():
3066 if _IsCPlusPlusFile(input_api, f.LocalPath()):
3067 changed_lines = [line for _, line in f.ChangedContents()]
3068 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
3069 elif _IsProtoFile(input_api, f.LocalPath()):
3070 changed_lines = [line for _, line in f.ChangedContents()]
3071 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
3072 elif _IsJavaFile(input_api, f.LocalPath()):
3073 changed_lines = [line for _, line in f.ChangedContents()]
3074 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:243075
Sam Maiera6e76d72022-02-11 21:43:503076 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
3077
3078 error_descriptions = []
3079 warning_descriptions = []
3080 error_subjects = set()
3081 warning_subjects = set()
3082
3083 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
3084 added_includes):
3085 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3086 description_with_path = '%s\n %s' % (path, rule_description)
3087 if rule_type == Rule.DISALLOW:
3088 error_descriptions.append(description_with_path)
3089 error_subjects.add("#includes")
3090 else:
3091 warning_descriptions.append(description_with_path)
3092 warning_subjects.add("#includes")
3093
3094 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
3095 added_imports):
3096 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3097 description_with_path = '%s\n %s' % (path, rule_description)
3098 if rule_type == Rule.DISALLOW:
3099 error_descriptions.append(description_with_path)
3100 error_subjects.add("imports")
3101 else:
3102 warning_descriptions.append(description_with_path)
3103 warning_subjects.add("imports")
3104
3105 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
3106 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
3107 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
3108 description_with_path = '%s\n %s' % (path, rule_description)
3109 if rule_type == Rule.DISALLOW:
3110 error_descriptions.append(description_with_path)
3111 error_subjects.add("imports")
3112 else:
3113 warning_descriptions.append(description_with_path)
3114 warning_subjects.add("imports")
3115
3116 results = []
3117 if error_descriptions:
3118 results.append(
3119 output_api.PresubmitError(
3120 'You added one or more %s that violate checkdeps rules.' %
3121 " and ".join(error_subjects), error_descriptions))
3122 if warning_descriptions:
3123 results.append(
3124 output_api.PresubmitPromptOrNotify(
3125 'You added one or more %s of files that are temporarily\n'
3126 'allowed but being removed. Can you avoid introducing the\n'
3127 '%s? See relevant DEPS file(s) for details and contacts.' %
3128 (" and ".join(warning_subjects), "/".join(warning_subjects)),
3129 warning_descriptions))
3130 return results
[email protected]55f9f382012-07-31 11:02:183131
3132
Saagar Sanghavifceeaae2020-08-12 16:40:363133def CheckFilePermissions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503134 """Check that all files have their permissions properly set."""
3135 if input_api.platform == 'win32':
3136 return []
3137 checkperms_tool = input_api.os_path.join(input_api.PresubmitLocalPath(),
3138 'tools', 'checkperms',
3139 'checkperms.py')
3140 args = [
Bruce Dawson8a43cf72022-05-13 17:10:323141 input_api.python3_executable, checkperms_tool, '--root',
Sam Maiera6e76d72022-02-11 21:43:503142 input_api.change.RepositoryRoot()
3143 ]
3144 with input_api.CreateTemporaryFile() as file_list:
3145 for f in input_api.AffectedFiles():
3146 # checkperms.py file/directory arguments must be relative to the
3147 # repository.
3148 file_list.write((f.LocalPath() + '\n').encode('utf8'))
3149 file_list.close()
3150 args += ['--file-list', file_list.name]
3151 try:
3152 input_api.subprocess.check_output(args)
3153 return []
3154 except input_api.subprocess.CalledProcessError as error:
3155 return [
3156 output_api.PresubmitError('checkperms.py failed:',
3157 long_text=error.output.decode(
3158 'utf-8', 'ignore'))
3159 ]
[email protected]fbcafe5a2012-08-08 15:31:223160
3161
Saagar Sanghavifceeaae2020-08-12 16:40:363162def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503163 """Makes sure we don't include ui/aura/window_property.h
3164 in header files.
3165 """
3166 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
3167 errors = []
3168 for f in input_api.AffectedFiles():
3169 if not f.LocalPath().endswith('.h'):
3170 continue
3171 for line_num, line in f.ChangedContents():
3172 if pattern.match(line):
3173 errors.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]c8278b32012-10-30 20:35:493174
Sam Maiera6e76d72022-02-11 21:43:503175 results = []
3176 if errors:
3177 results.append(
3178 output_api.PresubmitError(
3179 'Header files should not include ui/aura/window_property.h',
3180 errors))
3181 return results
[email protected]c8278b32012-10-30 20:35:493182
3183
Omer Katzcc77ea92021-04-26 10:23:283184def CheckNoInternalHeapIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503185 """Makes sure we don't include any headers from
3186 third_party/blink/renderer/platform/heap/impl or
3187 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
3188 third_party/blink/renderer/platform/heap
3189 """
3190 impl_pattern = input_api.re.compile(
3191 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
3192 v8_wrapper_pattern = input_api.re.compile(
3193 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"'
3194 )
Bruce Dawson40fece62022-09-16 19:58:313195 # Consistently use / as path separator to simplify the writing of regex
3196 # expressions.
Sam Maiera6e76d72022-02-11 21:43:503197 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:313198 r"^third_party/blink/renderer/platform/heap/.*",
3199 f.LocalPath().replace(input_api.os_path.sep, '/'))
Sam Maiera6e76d72022-02-11 21:43:503200 errors = []
Omer Katzcc77ea92021-04-26 10:23:283201
Sam Maiera6e76d72022-02-11 21:43:503202 for f in input_api.AffectedFiles(file_filter=file_filter):
3203 for line_num, line in f.ChangedContents():
3204 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
3205 errors.append(' %s:%d' % (f.LocalPath(), line_num))
Omer Katzcc77ea92021-04-26 10:23:283206
Sam Maiera6e76d72022-02-11 21:43:503207 results = []
3208 if errors:
3209 results.append(
3210 output_api.PresubmitError(
3211 'Do not include files from third_party/blink/renderer/platform/heap/impl'
3212 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
3213 'relevant counterparts from third_party/blink/renderer/platform/heap',
3214 errors))
3215 return results
Omer Katzcc77ea92021-04-26 10:23:283216
3217
[email protected]70ca77752012-11-20 03:45:033218def _CheckForVersionControlConflictsInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:503219 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
3220 errors = []
3221 for line_num, line in f.ChangedContents():
3222 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
3223 # First-level headers in markdown look a lot like version control
3224 # conflict markers. http://daringfireball.net/projects/markdown/basics
3225 continue
3226 if pattern.match(line):
3227 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
3228 return errors
[email protected]70ca77752012-11-20 03:45:033229
3230
Saagar Sanghavifceeaae2020-08-12 16:40:363231def CheckForVersionControlConflicts(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503232 """Usually this is not intentional and will cause a compile failure."""
3233 errors = []
3234 for f in input_api.AffectedFiles():
3235 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
[email protected]70ca77752012-11-20 03:45:033236
Sam Maiera6e76d72022-02-11 21:43:503237 results = []
3238 if errors:
3239 results.append(
3240 output_api.PresubmitError(
3241 'Version control conflict markers found, please resolve.',
3242 errors))
3243 return results
[email protected]70ca77752012-11-20 03:45:033244
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203245
Saagar Sanghavifceeaae2020-08-12 16:40:363246def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503247 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
3248 errors = []
3249 for f in input_api.AffectedFiles():
3250 for line_num, line in f.ChangedContents():
3251 if pattern.search(line):
3252 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
estadee17314a02017-01-12 16:22:163253
Sam Maiera6e76d72022-02-11 21:43:503254 results = []
3255 if errors:
3256 results.append(
3257 output_api.PresubmitPromptWarning(
3258 'Found Google support URL addressed by answer number. Please replace '
3259 'with a p= identifier instead. See crbug.com/679462\n',
3260 errors))
3261 return results
estadee17314a02017-01-12 16:22:163262
[email protected]70ca77752012-11-20 03:45:033263
Saagar Sanghavifceeaae2020-08-12 16:40:363264def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503265 def FilterFile(affected_file):
3266 """Filter function for use with input_api.AffectedSourceFiles,
3267 below. This filters out everything except non-test files from
3268 top-level directories that generally speaking should not hard-code
3269 service URLs (e.g. src/android_webview/, src/content/ and others).
3270 """
3271 return input_api.FilterSourceFile(
3272 affected_file,
Bruce Dawson40fece62022-09-16 19:58:313273 files_to_check=[r'^(android_webview|base|content|net)/.*'],
Sam Maiera6e76d72022-02-11 21:43:503274 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3275 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:443276
Sam Maiera6e76d72022-02-11 21:43:503277 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
3278 '\.(com|net)[^"]*"')
3279 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
3280 pattern = input_api.re.compile(base_pattern)
3281 problems = [] # items are (filename, line_number, line)
3282 for f in input_api.AffectedSourceFiles(FilterFile):
3283 for line_num, line in f.ChangedContents():
3284 if not comment_pattern.search(line) and pattern.search(line):
3285 problems.append((f.LocalPath(), line_num, line))
[email protected]06e6d0ff2012-12-11 01:36:443286
Sam Maiera6e76d72022-02-11 21:43:503287 if problems:
3288 return [
3289 output_api.PresubmitPromptOrNotify(
3290 'Most layers below src/chrome/ should not hardcode service URLs.\n'
3291 'Are you sure this is correct?', [
3292 ' %s:%d: %s' % (problem[0], problem[1], problem[2])
3293 for problem in problems
3294 ])
3295 ]
3296 else:
3297 return []
[email protected]06e6d0ff2012-12-11 01:36:443298
3299
Saagar Sanghavifceeaae2020-08-12 16:40:363300def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503301 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
James Cook6b6597c2019-11-06 22:05:293302
Sam Maiera6e76d72022-02-11 21:43:503303 def FileFilter(affected_file):
3304 """Includes directories known to be Chrome OS only."""
3305 return input_api.FilterSourceFile(
3306 affected_file,
3307 files_to_check=(
3308 '^ash/',
3309 '^chromeos/', # Top-level src/chromeos.
3310 '.*/chromeos/', # Any path component.
3311 '^components/arc',
3312 '^components/exo'),
3313 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:293314
Sam Maiera6e76d72022-02-11 21:43:503315 prefs = []
3316 priority_prefs = []
3317 for f in input_api.AffectedFiles(file_filter=FileFilter):
3318 for line_num, line in f.ChangedContents():
3319 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF',
3320 line):
3321 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
3322 prefs.append(' %s' % line)
3323 if input_api.re.search(
3324 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
3325 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
3326 priority_prefs.append(' %s' % line)
3327
3328 results = []
3329 if (prefs):
3330 results.append(
3331 output_api.PresubmitPromptWarning(
3332 'Preferences were registered as SYNCABLE_PREF and will be controlled '
3333 'by browser sync settings. If these prefs should be controlled by OS '
3334 'sync settings use SYNCABLE_OS_PREF instead.\n' +
3335 '\n'.join(prefs)))
3336 if (priority_prefs):
3337 results.append(
3338 output_api.PresubmitPromptWarning(
3339 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
3340 'controlled by browser sync settings. If these prefs should be '
3341 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
3342 'instead.\n' + '\n'.join(prefs)))
3343 return results
James Cook6b6597c2019-11-06 22:05:293344
3345
Saagar Sanghavifceeaae2020-08-12 16:40:363346def CheckNoAbbreviationInPngFileName(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503347 """Makes sure there are no abbreviations in the name of PNG files.
3348 The native_client_sdk directory is excluded because it has auto-generated PNG
3349 files for documentation.
3350 """
3351 errors = []
Yuanqing Zhu9eef02832022-12-04 14:42:173352 files_to_check = [r'.*\.png$']
Bruce Dawson40fece62022-09-16 19:58:313353 files_to_skip = [r'^native_client_sdk/',
3354 r'^services/test/',
3355 r'^third_party/blink/web_tests/',
Bruce Dawson3db456212022-05-02 05:34:183356 ]
Sam Maiera6e76d72022-02-11 21:43:503357 file_filter = lambda f: input_api.FilterSourceFile(
3358 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Yuanqing Zhu9eef02832022-12-04 14:42:173359 abbreviation = input_api.re.compile('.+_[a-z]\.png|.+_[a-z]_.*\.png')
Sam Maiera6e76d72022-02-11 21:43:503360 for f in input_api.AffectedFiles(include_deletes=False,
3361 file_filter=file_filter):
Yuanqing Zhu9eef02832022-12-04 14:42:173362 file_name = input_api.os_path.split(f.LocalPath())[1]
3363 if abbreviation.search(file_name):
3364 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:273365
Sam Maiera6e76d72022-02-11 21:43:503366 results = []
3367 if errors:
3368 results.append(
3369 output_api.PresubmitError(
3370 'The name of PNG files should not have abbreviations. \n'
3371 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
3372 'Contact [email protected] if you have questions.', errors))
3373 return results
[email protected]d2530012013-01-25 16:39:273374
Evan Stade7cd4a2c2022-08-04 23:37:253375def CheckNoProductIconsAddedToPublicRepo(input_api, output_api):
3376 """Heuristically identifies product icons based on their file name and reminds
3377 contributors not to add them to the Chromium repository.
3378 """
3379 errors = []
3380 files_to_check = [r'.*google.*\.png$|.*google.*\.svg$|.*google.*\.icon$']
3381 file_filter = lambda f: input_api.FilterSourceFile(
3382 f, files_to_check=files_to_check)
3383 for f in input_api.AffectedFiles(include_deletes=False,
3384 file_filter=file_filter):
3385 errors.append(' %s' % f.LocalPath())
3386
3387 results = []
3388 if errors:
Bruce Dawson3bcf0c92022-08-12 00:03:083389 # Give warnings instead of errors on presubmit --all and presubmit
3390 # --files.
3391 message_type = (output_api.PresubmitNotifyResult if input_api.no_diffs
3392 else output_api.PresubmitError)
Evan Stade7cd4a2c2022-08-04 23:37:253393 results.append(
Bruce Dawson3bcf0c92022-08-12 00:03:083394 message_type(
Evan Stade7cd4a2c2022-08-04 23:37:253395 'Trademarked images should not be added to the public repo. '
3396 'See crbug.com/944754', errors))
3397 return results
3398
[email protected]d2530012013-01-25 16:39:273399
Daniel Cheng4dcdb6b2017-04-13 08:30:173400def _ExtractAddRulesFromParsedDeps(parsed_deps):
Sam Maiera6e76d72022-02-11 21:43:503401 """Extract the rules that add dependencies from a parsed DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:173402
Sam Maiera6e76d72022-02-11 21:43:503403 Args:
3404 parsed_deps: the locals dictionary from evaluating the DEPS file."""
3405 add_rules = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:173406 add_rules.update([
Sam Maiera6e76d72022-02-11 21:43:503407 rule[1:] for rule in parsed_deps.get('include_rules', [])
Daniel Cheng4dcdb6b2017-04-13 08:30:173408 if rule.startswith('+') or rule.startswith('!')
3409 ])
Sam Maiera6e76d72022-02-11 21:43:503410 for _, rules in parsed_deps.get('specific_include_rules', {}).items():
3411 add_rules.update([
3412 rule[1:] for rule in rules
3413 if rule.startswith('+') or rule.startswith('!')
3414 ])
3415 return add_rules
Daniel Cheng4dcdb6b2017-04-13 08:30:173416
3417
3418def _ParseDeps(contents):
Sam Maiera6e76d72022-02-11 21:43:503419 """Simple helper for parsing DEPS files."""
Daniel Cheng4dcdb6b2017-04-13 08:30:173420
Sam Maiera6e76d72022-02-11 21:43:503421 # Stubs for handling special syntax in the root DEPS file.
3422 class _VarImpl:
3423 def __init__(self, local_scope):
3424 self._local_scope = local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:173425
Sam Maiera6e76d72022-02-11 21:43:503426 def Lookup(self, var_name):
3427 """Implements the Var syntax."""
3428 try:
3429 return self._local_scope['vars'][var_name]
3430 except KeyError:
3431 raise Exception('Var is not defined: %s' % var_name)
Daniel Cheng4dcdb6b2017-04-13 08:30:173432
Sam Maiera6e76d72022-02-11 21:43:503433 local_scope = {}
3434 global_scope = {
3435 'Var': _VarImpl(local_scope).Lookup,
3436 'Str': str,
3437 }
Dirk Pranke1b9e06382021-05-14 01:16:223438
Sam Maiera6e76d72022-02-11 21:43:503439 exec(contents, global_scope, local_scope)
3440 return local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:173441
3442
3443def _CalculateAddedDeps(os_path, old_contents, new_contents):
Sam Maiera6e76d72022-02-11 21:43:503444 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
3445 a set of DEPS entries that we should look up.
[email protected]14a6131c2014-01-08 01:15:413446
Sam Maiera6e76d72022-02-11 21:43:503447 For a directory (rather than a specific filename) we fake a path to
3448 a specific filename by adding /DEPS. This is chosen as a file that
3449 will seldom or never be subject to per-file include_rules.
3450 """
3451 # We ignore deps entries on auto-generated directories.
3452 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:083453
Sam Maiera6e76d72022-02-11 21:43:503454 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
3455 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
Daniel Cheng4dcdb6b2017-04-13 08:30:173456
Sam Maiera6e76d72022-02-11 21:43:503457 added_deps = new_deps.difference(old_deps)
Daniel Cheng4dcdb6b2017-04-13 08:30:173458
Sam Maiera6e76d72022-02-11 21:43:503459 results = set()
3460 for added_dep in added_deps:
3461 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
3462 continue
3463 # Assume that a rule that ends in .h is a rule for a specific file.
3464 if added_dep.endswith('.h'):
3465 results.add(added_dep)
3466 else:
3467 results.add(os_path.join(added_dep, 'DEPS'))
3468 return results
[email protected]f32e2d1e2013-07-26 21:39:083469
Stephanie Kimec4f55a2024-04-24 16:54:023470def CheckForNewDEPSDownloadFromGoogleStorageHooks(input_api, output_api):
3471 """Checks that there are no new download_from_google_storage hooks"""
3472 for f in input_api.AffectedFiles(include_deletes=False):
3473 if f.LocalPath() == 'DEPS':
3474 old_hooks = _ParseDeps('\n'.join(f.OldContents()))['hooks']
3475 new_hooks = _ParseDeps('\n'.join(f.NewContents()))['hooks']
3476 old_name_to_hook = {hook['name']: hook for hook in old_hooks}
3477 new_name_to_hook = {hook['name']: hook for hook in new_hooks}
3478 added_hook_names = set(new_name_to_hook.keys()) - set(
3479 old_name_to_hook.keys())
3480 if not added_hook_names:
3481 return []
3482 new_download_from_google_storage_hooks = []
3483 for new_hook in added_hook_names:
3484 hook = new_name_to_hook[new_hook]
3485 action_cmd = hook['action']
3486 if any('download_from_google_storage' in arg
3487 for arg in action_cmd):
3488 new_download_from_google_storage_hooks.append(new_hook)
3489 if new_download_from_google_storage_hooks:
3490 return [
3491 output_api.PresubmitError(
3492 'Please do not add new download_from_google_storage '
3493 'hooks. Instead, add a `gcs` dep_type entry to `deps`. '
3494 'See https://chromium.googlesource.com/chromium/src.git'
3495 '/+/refs/heads/main/docs/gcs_dependencies.md for more '
3496 'info. Added hooks:',
3497 items=new_download_from_google_storage_hooks)
3498 ]
3499 return []
3500
[email protected]f32e2d1e2013-07-26 21:39:083501
Rasika Navarangec2d33d22024-05-23 15:19:023502def CheckEachPerfettoTestDataFileHasDepsEntry(input_api, output_api):
3503 test_data_filter = lambda f: input_api.FilterSourceFile(
Rasika Navarange08e542162024-05-31 13:31:263504 f, files_to_check=[r'^base/tracing/test/data_sha256/.*\.sha256'])
Rasika Navarangec2d33d22024-05-23 15:19:023505 if not any(input_api.AffectedFiles(file_filter=test_data_filter)):
3506 return []
3507
3508 # Find DEPS entry
3509 deps_entry = []
Rasika Navarange277cd662024-06-04 10:14:593510 old_deps_entry = []
Rasika Navarangec2d33d22024-05-23 15:19:023511 for f in input_api.AffectedFiles(include_deletes=False):
3512 if f.LocalPath() == 'DEPS':
3513 new_deps = _ParseDeps('\n'.join(f.NewContents()))['deps']
3514 deps_entry = new_deps['src/base/tracing/test/data']
Rasika Navarange277cd662024-06-04 10:14:593515 old_deps = _ParseDeps('\n'.join(f.OldContents()))['deps']
3516 old_deps_entry = old_deps['src/base/tracing/test/data']
Rasika Navarangec2d33d22024-05-23 15:19:023517 if not deps_entry:
Rasika Navarange08e542162024-05-31 13:31:263518 # TODO(312895063):Add back error when .sha256 files have been moved.
Rasika Navaranged977df342024-06-05 10:01:273519 return [output_api.PresubmitError(
Rasika Navarangec2d33d22024-05-23 15:19:023520 'You must update the DEPS file when you update a '
Rasika Navarange08e542162024-05-31 13:31:263521 '.sha256 file in base/tracing/test/data_sha256'
Rasika Navarangec2d33d22024-05-23 15:19:023522 )]
3523
3524 output = []
3525 for f in input_api.AffectedFiles(file_filter=test_data_filter):
3526 objects = deps_entry['objects']
3527 if not f.NewContents():
3528 # Deleted file so check that DEPS entry removed
3529 sha256_from_file = f.OldContents()[0]
3530 object_entry = next(
3531 (item for item in objects if item["sha256sum"] == sha256_from_file),
3532 None)
Rasika Navarange277cd662024-06-04 10:14:593533 old_entry = next(
3534 (item for item in old_deps_entry['objects'] if item["sha256sum"] == sha256_from_file),
3535 None)
Rasika Navarangec2d33d22024-05-23 15:19:023536 if object_entry:
Rasika Navarange277cd662024-06-04 10:14:593537 # Allow renaming of objects with the same hash
3538 if object_entry['object_name'] != old_entry['object_name']:
3539 continue
Rasika Navarangec2d33d22024-05-23 15:19:023540 output.append(output_api.PresubmitError(
3541 'You deleted %s so you must also remove the corresponding DEPS entry.'
3542 % f.LocalPath()
3543 ))
3544 continue
3545
3546 sha256_from_file = f.NewContents()[0]
3547 object_entry = next(
3548 (item for item in objects if item["sha256sum"] == sha256_from_file),
3549 None)
3550 if not object_entry:
3551 output.append(output_api.PresubmitError(
3552 'No corresponding DEPS entry found for %s. '
3553 'Run `base/tracing/test/test_data.py get_deps --filepath %s` '
3554 'to generate the DEPS entry.'
3555 % (f.LocalPath(), f.LocalPath())
3556 ))
3557
3558 if output:
3559 output.append(output_api.PresubmitError(
3560 'The DEPS entry for `src/base/tracing/test/data` in the DEPS file has not been '
3561 'updated properly. Run `base/tracing/test/test_data.py get_all_deps` to see what '
3562 'the DEPS entry should look like.'
3563 ))
3564 return output
3565
3566
Saagar Sanghavifceeaae2020-08-12 16:40:363567def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503568 """When a dependency prefixed with + is added to a DEPS file, we
3569 want to make sure that the change is reviewed by an OWNER of the
3570 target file or directory, to avoid layering violations from being
3571 introduced. This check verifies that this happens.
3572 """
3573 # We rely on Gerrit's code-owners to check approvals.
3574 # input_api.gerrit is always set for Chromium, but other projects
3575 # might not use Gerrit.
Bruce Dawson344ab262022-06-04 11:35:103576 if not input_api.gerrit or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:503577 return []
Bruce Dawsonb357aeb2022-08-09 15:38:303578 if 'PRESUBMIT_SKIP_NETWORK' in input_api.environ:
Sam Maiera6e76d72022-02-11 21:43:503579 return []
Bruce Dawsonb357aeb2022-08-09 15:38:303580 try:
3581 if (input_api.change.issue and
3582 input_api.gerrit.IsOwnersOverrideApproved(
3583 input_api.change.issue)):
3584 # Skip OWNERS check when Owners-Override label is approved. This is
3585 # intended for global owners, trusted bots, and on-call sheriffs.
3586 # Review is still required for these changes.
3587 return []
3588 except Exception as e:
Sam Maier4cef9242022-10-03 14:21:243589 return [output_api.PresubmitPromptWarning(
3590 'Failed to retrieve owner override status - %s' % str(e))]
Edward Lesmes6fba51082021-01-20 04:20:233591
Sam Maiera6e76d72022-02-11 21:43:503592 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:243593
Bruce Dawson40fece62022-09-16 19:58:313594 # Consistently use / as path separator to simplify the writing of regex
3595 # expressions.
Sam Maiera6e76d72022-02-11 21:43:503596 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:313597 r"^third_party/blink/.*",
3598 f.LocalPath().replace(input_api.os_path.sep, '/'))
Sam Maiera6e76d72022-02-11 21:43:503599 for f in input_api.AffectedFiles(include_deletes=False,
3600 file_filter=file_filter):
3601 filename = input_api.os_path.basename(f.LocalPath())
3602 if filename == 'DEPS':
3603 virtual_depended_on_files.update(
3604 _CalculateAddedDeps(input_api.os_path,
3605 '\n'.join(f.OldContents()),
3606 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:553607
Sam Maiera6e76d72022-02-11 21:43:503608 if not virtual_depended_on_files:
3609 return []
[email protected]e871964c2013-05-13 14:14:553610
Sam Maiera6e76d72022-02-11 21:43:503611 if input_api.is_committing:
3612 if input_api.tbr:
3613 return [
3614 output_api.PresubmitNotifyResult(
3615 '--tbr was specified, skipping OWNERS check for DEPS additions'
3616 )
3617 ]
Daniel Cheng3008dc12022-05-13 04:02:113618 # TODO(dcheng): Make this generate an error on dry runs if the reviewer
3619 # is not added, to prevent review serialization.
Sam Maiera6e76d72022-02-11 21:43:503620 if input_api.dry_run:
3621 return [
3622 output_api.PresubmitNotifyResult(
3623 'This is a dry run, skipping OWNERS check for DEPS additions'
3624 )
3625 ]
3626 if not input_api.change.issue:
3627 return [
3628 output_api.PresubmitError(
3629 "DEPS approval by OWNERS check failed: this change has "
3630 "no change number, so we can't check it for approvals.")
3631 ]
3632 output = output_api.PresubmitError
[email protected]14a6131c2014-01-08 01:15:413633 else:
Sam Maiera6e76d72022-02-11 21:43:503634 output = output_api.PresubmitNotifyResult
[email protected]e871964c2013-05-13 14:14:553635
Sam Maiera6e76d72022-02-11 21:43:503636 owner_email, reviewers = (
3637 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3638 input_api, None, approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:553639
Sam Maiera6e76d72022-02-11 21:43:503640 owner_email = owner_email or input_api.change.author_email
3641
3642 approval_status = input_api.owners_client.GetFilesApprovalStatus(
3643 virtual_depended_on_files, reviewers.union([owner_email]), [])
3644 missing_files = [
3645 f for f in virtual_depended_on_files
3646 if approval_status[f] != input_api.owners_client.APPROVED
3647 ]
3648
3649 # We strip the /DEPS part that was added by
3650 # _FilesToCheckForIncomingDeps to fake a path to a file in a
3651 # directory.
3652 def StripDeps(path):
3653 start_deps = path.rfind('/DEPS')
3654 if start_deps != -1:
3655 return path[:start_deps]
3656 else:
3657 return path
3658
Scott Leebf6a0942024-06-26 22:59:393659 submodule_paths = set(input_api.ListSubmodules())
3660 def is_from_submodules(path, submodule_paths):
3661 path = input_api.os_path.normpath(path)
3662 while path:
3663 if path in submodule_paths:
3664 return True
3665
3666 # All deps should be a relative path from the checkout.
3667 # i.e., shouldn't start with "/" or "c:\", for example.
3668 #
3669 # That said, this is to prevent an infinite loop, just in case
3670 # an input dep path starts with "/", because
3671 # os.path.dirname("/") => "/"
3672 parent = input_api.os_path.dirname(path)
3673 if parent == path:
3674 break
3675 path = parent
3676
3677 return False
3678
Sam Maiera6e76d72022-02-11 21:43:503679 unapproved_dependencies = [
3680 "'+%s'," % StripDeps(path) for path in missing_files
Scott Leebf6a0942024-06-26 22:59:393681 # if a newly added dep is from a submodule, it becomes trickier
3682 # to get suggested owners, especially it is from a different host.
3683 #
3684 # skip the review enforcement for cross-repo deps.
3685 if not is_from_submodules(path, submodule_paths)
Sam Maiera6e76d72022-02-11 21:43:503686 ]
3687
3688 if unapproved_dependencies:
3689 output_list = [
3690 output(
3691 'You need LGTM from owners of depends-on paths in DEPS that were '
3692 'modified in this CL:\n %s' %
3693 '\n '.join(sorted(unapproved_dependencies)))
3694 ]
3695 suggested_owners = input_api.owners_client.SuggestOwners(
3696 missing_files, exclude=[owner_email])
3697 output_list.append(
3698 output('Suggested missing target path OWNERS:\n %s' %
3699 '\n '.join(suggested_owners or [])))
3700 return output_list
3701
3702 return []
[email protected]e871964c2013-05-13 14:14:553703
3704
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493705# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:363706def CheckSpamLogging(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503707 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3708 files_to_skip = (
3709 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3710 input_api.DEFAULT_FILES_TO_SKIP + (
Jaewon Jung2f323bb2022-12-07 23:55:013711 r"^base/fuchsia/scoped_fx_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313712 r"^base/logging\.h$",
3713 r"^base/logging\.cc$",
3714 r"^base/task/thread_pool/task_tracker\.cc$",
3715 r"^chrome/app/chrome_main_delegate\.cc$",
Yao Li359937b2023-02-15 23:43:033716 r"^chrome/browser/ash/arc/enterprise/cert_store/arc_cert_installer\.cc$",
3717 r"^chrome/browser/ash/policy/remote_commands/user_command_arc_job\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313718 r"^chrome/browser/chrome_browser_main\.cc$",
3719 r"^chrome/browser/ui/startup/startup_browser_creator\.cc$",
3720 r"^chrome/browser/browser_switcher/bho/.*",
3721 r"^chrome/browser/diagnostics/diagnostics_writer\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313722 r"^chrome/chrome_elf/dll_hash/dll_hash_main\.cc$",
3723 r"^chrome/installer/setup/.*",
Daniel Ruberyad36eea2024-08-01 01:38:323724 # crdmg runs as a separate binary which intentionally does
3725 # not depend on base logging.
3726 r"^chrome/utility/safe_browsing/mac/crdmg\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313727 r"^chromecast/",
Vigen Issahhanjane2d93822023-06-30 15:57:203728 r"^components/cast",
Bruce Dawson40fece62022-09-16 19:58:313729 r"^components/media_control/renderer/media_playback_options\.cc$",
Salma Elmahallawy52976452023-01-27 17:04:493730 r"^components/policy/core/common/policy_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313731 r"^components/viz/service/display/"
Sam Maiera6e76d72022-02-11 21:43:503732 r"overlay_strategy_underlay_cast\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313733 r"^components/zucchini/.*",
Sam Maiera6e76d72022-02-11 21:43:503734 # TODO(peter): Remove exception. https://crbug.com/534537
Bruce Dawson40fece62022-09-16 19:58:313735 r"^content/browser/notifications/"
Sam Maiera6e76d72022-02-11 21:43:503736 r"notification_event_dispatcher_impl\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313737 r"^content/common/gpu/client/gl_helper_benchmark\.cc$",
3738 r"^courgette/courgette_minimal_tool\.cc$",
3739 r"^courgette/courgette_tool\.cc$",
3740 r"^extensions/renderer/logging_native_handler\.cc$",
3741 r"^fuchsia_web/common/init_logging\.cc$",
3742 r"^fuchsia_web/runners/common/web_component\.cc$",
Caroline Liua7050132023-02-13 22:23:153743 r"^fuchsia_web/shell/.*\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313744 r"^headless/app/headless_shell\.cc$",
3745 r"^ipc/ipc_logging\.cc$",
3746 r"^native_client_sdk/",
3747 r"^remoting/base/logging\.h$",
3748 r"^remoting/host/.*",
3749 r"^sandbox/linux/.*",
Austin Sullivana6054e02024-05-20 16:31:293750 r"^services/webnn/tflite/graph_impl_tflite\.cc$",
3751 r"^services/webnn/coreml/graph_impl_coreml\.mm$",
Bruce Dawson40fece62022-09-16 19:58:313752 r"^storage/browser/file_system/dump_file_system\.cc$",
Steinar H. Gundersone5689e42024-08-07 18:17:193753 r"^testing/perf/",
Bruce Dawson40fece62022-09-16 19:58:313754 r"^tools/",
3755 r"^ui/base/resource/data_pack\.cc$",
3756 r"^ui/aura/bench/bench_main\.cc$",
3757 r"^ui/ozone/platform/cast/",
3758 r"^ui/base/x/xwmstartupcheck/"
Sam Maiera6e76d72022-02-11 21:43:503759 r"xwmstartupcheck\.cc$"))
3760 source_file_filter = lambda x: input_api.FilterSourceFile(
3761 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:403762
Sam Maiera6e76d72022-02-11 21:43:503763 log_info = set([])
3764 printf = set([])
[email protected]85218562013-11-22 07:41:403765
Sam Maiera6e76d72022-02-11 21:43:503766 for f in input_api.AffectedSourceFiles(source_file_filter):
3767 for _, line in f.ChangedContents():
3768 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
3769 log_info.add(f.LocalPath())
3770 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
3771 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:373772
Sam Maiera6e76d72022-02-11 21:43:503773 if input_api.re.search(r"\bprintf\(", line):
3774 printf.add(f.LocalPath())
3775 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
3776 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:403777
Sam Maiera6e76d72022-02-11 21:43:503778 if log_info:
3779 return [
3780 output_api.PresubmitError(
3781 'These files spam the console log with LOG(INFO):',
3782 items=log_info)
3783 ]
3784 if printf:
3785 return [
3786 output_api.PresubmitError(
3787 'These files spam the console log with printf/fprintf:',
3788 items=printf)
3789 ]
3790 return []
[email protected]85218562013-11-22 07:41:403791
3792
Saagar Sanghavifceeaae2020-08-12 16:40:363793def CheckForAnonymousVariables(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503794 """These types are all expected to hold locks while in scope and
3795 so should never be anonymous (which causes them to be immediately
3796 destroyed)."""
3797 they_who_must_be_named = [
3798 'base::AutoLock',
3799 'base::AutoReset',
3800 'base::AutoUnlock',
3801 'SkAutoAlphaRestore',
3802 'SkAutoBitmapShaderInstall',
3803 'SkAutoBlitterChoose',
3804 'SkAutoBounderCommit',
3805 'SkAutoCallProc',
3806 'SkAutoCanvasRestore',
3807 'SkAutoCommentBlock',
3808 'SkAutoDescriptor',
3809 'SkAutoDisableDirectionCheck',
3810 'SkAutoDisableOvalCheck',
3811 'SkAutoFree',
3812 'SkAutoGlyphCache',
3813 'SkAutoHDC',
3814 'SkAutoLockColors',
3815 'SkAutoLockPixels',
3816 'SkAutoMalloc',
3817 'SkAutoMaskFreeImage',
3818 'SkAutoMutexAcquire',
3819 'SkAutoPathBoundsUpdate',
3820 'SkAutoPDFRelease',
3821 'SkAutoRasterClipValidate',
3822 'SkAutoRef',
3823 'SkAutoTime',
3824 'SkAutoTrace',
3825 'SkAutoUnref',
3826 ]
3827 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
3828 # bad: base::AutoLock(lock.get());
3829 # not bad: base::AutoLock lock(lock.get());
3830 bad_pattern = input_api.re.compile(anonymous)
3831 # good: new base::AutoLock(lock.get())
3832 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
3833 errors = []
[email protected]49aa76a2013-12-04 06:59:163834
Sam Maiera6e76d72022-02-11 21:43:503835 for f in input_api.AffectedFiles():
3836 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
3837 continue
3838 for linenum, line in f.ChangedContents():
3839 if bad_pattern.search(line) and not good_pattern.search(line):
3840 errors.append('%s:%d' % (f.LocalPath(), linenum))
[email protected]49aa76a2013-12-04 06:59:163841
Sam Maiera6e76d72022-02-11 21:43:503842 if errors:
3843 return [
3844 output_api.PresubmitError(
3845 'These lines create anonymous variables that need to be named:',
3846 items=errors)
3847 ]
3848 return []
[email protected]49aa76a2013-12-04 06:59:163849
3850
Saagar Sanghavifceeaae2020-08-12 16:40:363851def CheckUniquePtrOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503852 # Returns whether |template_str| is of the form <T, U...> for some types T
Glen Robertson9142ffd72024-05-16 01:37:473853 # and U, or is invalid due to mismatched angle bracket pairs. Assumes that
3854 # |template_str| is already in the form <...>.
3855 def HasMoreThanOneArgOrInvalid(template_str):
Sam Maiera6e76d72022-02-11 21:43:503856 # Level of <...> nesting.
3857 nesting = 0
3858 for c in template_str:
3859 if c == '<':
3860 nesting += 1
3861 elif c == '>':
3862 nesting -= 1
3863 elif c == ',' and nesting == 1:
3864 return True
Glen Robertson9142ffd72024-05-16 01:37:473865 if nesting != 0:
Daniel Cheng566634ff2024-06-29 14:56:533866 # Invalid.
3867 return True
Sam Maiera6e76d72022-02-11 21:43:503868 return False
Vaclav Brozekb7fadb692018-08-30 06:39:533869
Sam Maiera6e76d72022-02-11 21:43:503870 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3871 sources = lambda affected_file: input_api.FilterSourceFile(
3872 affected_file,
3873 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3874 DEFAULT_FILES_TO_SKIP),
3875 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:553876
Sam Maiera6e76d72022-02-11 21:43:503877 # Pattern to capture a single "<...>" block of template arguments. It can
3878 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
3879 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
3880 # latter would likely require counting that < and > match, which is not
3881 # expressible in regular languages. Should the need arise, one can introduce
3882 # limited counting (matching up to a total number of nesting depth), which
3883 # should cover all practical cases for already a low nesting limit.
3884 template_arg_pattern = (
3885 r'<[^>]*' # Opening block of <.
3886 r'>([^<]*>)?') # Closing block of >.
3887 # Prefix expressing that whatever follows is not already inside a <...>
3888 # block.
3889 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
3890 null_construct_pattern = input_api.re.compile(
3891 not_inside_template_arg_pattern + r'\bstd::unique_ptr' +
3892 template_arg_pattern + r'\(\)')
Vaclav Brozeka54c528b2018-04-06 19:23:553893
Sam Maiera6e76d72022-02-11 21:43:503894 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
3895 template_arg_no_array_pattern = (
3896 r'<[^>]*[^]]' # Opening block of <.
3897 r'>([^(<]*[^]]>)?') # Closing block of >.
3898 # Prefix saying that what follows is the start of an expression.
3899 start_of_expr_pattern = r'(=|\breturn|^)\s*'
3900 # Suffix saying that what follows are call parentheses with a non-empty list
3901 # of arguments.
3902 nonempty_arg_list_pattern = r'\(([^)]|$)'
3903 # Put the template argument into a capture group for deeper examination later.
3904 return_construct_pattern = input_api.re.compile(
3905 start_of_expr_pattern + r'std::unique_ptr' + '(?P<template_arg>' +
3906 template_arg_no_array_pattern + ')' + nonempty_arg_list_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:553907
Sam Maiera6e76d72022-02-11 21:43:503908 problems_constructor = []
3909 problems_nullptr = []
3910 for f in input_api.AffectedSourceFiles(sources):
3911 for line_number, line in f.ChangedContents():
3912 # Disallow:
3913 # return std::unique_ptr<T>(foo);
3914 # bar = std::unique_ptr<T>(foo);
3915 # But allow:
3916 # return std::unique_ptr<T[]>(foo);
3917 # bar = std::unique_ptr<T[]>(foo);
3918 # And also allow cases when the second template argument is present. Those
3919 # cases cannot be handled by std::make_unique:
3920 # return std::unique_ptr<T, U>(foo);
3921 # bar = std::unique_ptr<T, U>(foo);
3922 local_path = f.LocalPath()
3923 return_construct_result = return_construct_pattern.search(line)
Glen Robertson9142ffd72024-05-16 01:37:473924 if return_construct_result and not HasMoreThanOneArgOrInvalid(
Sam Maiera6e76d72022-02-11 21:43:503925 return_construct_result.group('template_arg')):
3926 problems_constructor.append(
3927 '%s:%d\n %s' % (local_path, line_number, line.strip()))
3928 # Disallow:
3929 # std::unique_ptr<T>()
3930 if null_construct_pattern.search(line):
3931 problems_nullptr.append(
3932 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Vaclav Brozek851d9602018-04-04 16:13:053933
Sam Maiera6e76d72022-02-11 21:43:503934 errors = []
3935 if problems_nullptr:
3936 errors.append(
3937 output_api.PresubmitPromptWarning(
3938 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
3939 problems_nullptr))
3940 if problems_constructor:
3941 errors.append(
3942 output_api.PresubmitError(
3943 'The following files use explicit std::unique_ptr constructor. '
3944 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
3945 'std::make_unique is not an option.', problems_constructor))
3946 return errors
Peter Kasting4844e46e2018-02-23 07:27:103947
3948
Saagar Sanghavifceeaae2020-08-12 16:40:363949def CheckUserActionUpdate(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503950 """Checks if any new user action has been added."""
3951 if any('actions.xml' == input_api.os_path.basename(f)
3952 for f in input_api.LocalPaths()):
3953 # If actions.xml is already included in the changelist, the PRESUBMIT
3954 # for actions.xml will do a more complete presubmit check.
3955 return []
3956
3957 file_inclusion_pattern = [r'.*\.(cc|mm)$']
3958 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3959 input_api.DEFAULT_FILES_TO_SKIP)
3960 file_filter = lambda f: input_api.FilterSourceFile(
3961 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
3962
3963 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
3964 current_actions = None
3965 for f in input_api.AffectedFiles(file_filter=file_filter):
3966 for line_num, line in f.ChangedContents():
3967 match = input_api.re.search(action_re, line)
3968 if match:
3969 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
3970 # loaded only once.
3971 if not current_actions:
Bruce Dawson6cb2d4d2023-03-01 21:35:093972 with open('tools/metrics/actions/actions.xml',
3973 encoding='utf-8') as actions_f:
Sam Maiera6e76d72022-02-11 21:43:503974 current_actions = actions_f.read()
3975 # Search for the matched user action name in |current_actions|.
3976 for action_name in match.groups():
3977 action = 'name="{0}"'.format(action_name)
3978 if action not in current_actions:
3979 return [
3980 output_api.PresubmitPromptWarning(
3981 'File %s line %d: %s is missing in '
3982 'tools/metrics/actions/actions.xml. Please run '
3983 'tools/metrics/actions/extract_actions.py to update.'
3984 % (f.LocalPath(), line_num, action_name))
3985 ]
[email protected]999261d2014-03-03 20:08:083986 return []
3987
[email protected]999261d2014-03-03 20:08:083988
Daniel Cheng13ca61a882017-08-25 15:11:253989def _ImportJSONCommentEater(input_api):
Sam Maiera6e76d72022-02-11 21:43:503990 import sys
3991 sys.path = sys.path + [
3992 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3993 'json_comment_eater')
3994 ]
3995 import json_comment_eater
3996 return json_comment_eater
Daniel Cheng13ca61a882017-08-25 15:11:253997
3998
[email protected]99171a92014-06-03 08:44:473999def _GetJSONParseError(input_api, filename, eat_comments=True):
dchenge07de812016-06-20 19:27:174000 try:
Sam Maiera6e76d72022-02-11 21:43:504001 contents = input_api.ReadFile(filename)
4002 if eat_comments:
4003 json_comment_eater = _ImportJSONCommentEater(input_api)
4004 contents = json_comment_eater.Nom(contents)
dchenge07de812016-06-20 19:27:174005
Sam Maiera6e76d72022-02-11 21:43:504006 input_api.json.loads(contents)
4007 except ValueError as e:
4008 return e
Andrew Grieve4deedb12022-02-03 21:34:504009 return None
4010
4011
Sam Maiera6e76d72022-02-11 21:43:504012def _GetIDLParseError(input_api, filename):
4013 try:
4014 contents = input_api.ReadFile(filename)
Devlin Croninf7582a12022-04-21 21:14:284015 for i, char in enumerate(contents):
Daniel Chenga37c03db2022-05-12 17:20:344016 if not char.isascii():
4017 return (
4018 'Non-ascii character "%s" (ord %d) found at offset %d.' %
4019 (char, ord(char), i))
Sam Maiera6e76d72022-02-11 21:43:504020 idl_schema = input_api.os_path.join(input_api.PresubmitLocalPath(),
4021 'tools', 'json_schema_compiler',
4022 'idl_schema.py')
4023 process = input_api.subprocess.Popen(
Bruce Dawson679fb082022-04-14 00:47:284024 [input_api.python3_executable, idl_schema],
Sam Maiera6e76d72022-02-11 21:43:504025 stdin=input_api.subprocess.PIPE,
4026 stdout=input_api.subprocess.PIPE,
4027 stderr=input_api.subprocess.PIPE,
4028 universal_newlines=True)
4029 (_, error) = process.communicate(input=contents)
4030 return error or None
4031 except ValueError as e:
4032 return e
agrievef32bcc72016-04-04 14:57:404033
agrievef32bcc72016-04-04 14:57:404034
Sam Maiera6e76d72022-02-11 21:43:504035def CheckParseErrors(input_api, output_api):
4036 """Check that IDL and JSON files do not contain syntax errors."""
4037 actions = {
4038 '.idl': _GetIDLParseError,
4039 '.json': _GetJSONParseError,
4040 }
4041 # Most JSON files are preprocessed and support comments, but these do not.
4042 json_no_comments_patterns = [
Bruce Dawson40fece62022-09-16 19:58:314043 r'^testing/',
Sam Maiera6e76d72022-02-11 21:43:504044 ]
4045 # Only run IDL checker on files in these directories.
4046 idl_included_patterns = [
Bruce Dawson40fece62022-09-16 19:58:314047 r'^chrome/common/extensions/api/',
4048 r'^extensions/common/api/',
Sam Maiera6e76d72022-02-11 21:43:504049 ]
agrievef32bcc72016-04-04 14:57:404050
Sam Maiera6e76d72022-02-11 21:43:504051 def get_action(affected_file):
4052 filename = affected_file.LocalPath()
4053 return actions.get(input_api.os_path.splitext(filename)[1])
agrievef32bcc72016-04-04 14:57:404054
Sam Maiera6e76d72022-02-11 21:43:504055 def FilterFile(affected_file):
4056 action = get_action(affected_file)
4057 if not action:
4058 return False
4059 path = affected_file.LocalPath()
agrievef32bcc72016-04-04 14:57:404060
Sam Maiera6e76d72022-02-11 21:43:504061 if _MatchesFile(input_api,
4062 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS, path):
4063 return False
4064
4065 if (action == _GetIDLParseError
4066 and not _MatchesFile(input_api, idl_included_patterns, path)):
4067 return False
4068 return True
4069
4070 results = []
4071 for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
4072 include_deletes=False):
4073 action = get_action(affected_file)
4074 kwargs = {}
4075 if (action == _GetJSONParseError
4076 and _MatchesFile(input_api, json_no_comments_patterns,
4077 affected_file.LocalPath())):
4078 kwargs['eat_comments'] = False
4079 parse_error = action(input_api, affected_file.AbsoluteLocalPath(),
4080 **kwargs)
4081 if parse_error:
4082 results.append(
4083 output_api.PresubmitError(
4084 '%s could not be parsed: %s' %
4085 (affected_file.LocalPath(), parse_error)))
4086 return results
4087
4088
4089def CheckJavaStyle(input_api, output_api):
4090 """Runs checkstyle on changed java files and returns errors if any exist."""
4091
4092 # Return early if no java files were modified.
4093 if not any(
4094 _IsJavaFile(input_api, f.LocalPath())
4095 for f in input_api.AffectedFiles()):
4096 return []
4097
4098 import sys
4099 original_sys_path = sys.path
4100 try:
4101 sys.path = sys.path + [
4102 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4103 'android', 'checkstyle')
4104 ]
4105 import checkstyle
4106 finally:
4107 # Restore sys.path to what it was before.
4108 sys.path = original_sys_path
4109
Andrew Grieve4f88e3ca2022-11-22 19:09:204110 return checkstyle.run_presubmit(
Sam Maiera6e76d72022-02-11 21:43:504111 input_api,
4112 output_api,
Sam Maiera6e76d72022-02-11 21:43:504113 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
4114
4115
4116def CheckPythonDevilInit(input_api, output_api):
4117 """Checks to make sure devil is initialized correctly in python scripts."""
4118 script_common_initialize_pattern = input_api.re.compile(
4119 r'script_common\.InitializeEnvironment\(')
4120 devil_env_config_initialize = input_api.re.compile(
4121 r'devil_env\.config\.Initialize\(')
4122
4123 errors = []
4124
4125 sources = lambda affected_file: input_api.FilterSourceFile(
4126 affected_file,
4127 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314128 r'^build/android/devil_chromium\.py',
Sven Zheng8e079562024-05-10 20:11:064129 r'^tools/bisect-builds\.py',
Bruce Dawson40fece62022-09-16 19:58:314130 r'^third_party/.*',
Sam Maiera6e76d72022-02-11 21:43:504131 )),
4132 files_to_check=[r'.*\.py$'])
4133
4134 for f in input_api.AffectedSourceFiles(sources):
4135 for line_num, line in f.ChangedContents():
4136 if (script_common_initialize_pattern.search(line)
4137 or devil_env_config_initialize.search(line)):
4138 errors.append("%s:%d" % (f.LocalPath(), line_num))
4139
4140 results = []
4141
4142 if errors:
4143 results.append(
4144 output_api.PresubmitError(
4145 'Devil initialization should always be done using '
4146 'devil_chromium.Initialize() in the chromium project, to use better '
4147 'defaults for dependencies (ex. up-to-date version of adb).',
4148 errors))
4149
4150 return results
4151
4152
4153def _MatchesFile(input_api, patterns, path):
Bruce Dawson40fece62022-09-16 19:58:314154 # Consistently use / as path separator to simplify the writing of regex
4155 # expressions.
4156 path = path.replace(input_api.os_path.sep, '/')
Sam Maiera6e76d72022-02-11 21:43:504157 for pattern in patterns:
4158 if input_api.re.search(pattern, path):
4159 return True
4160 return False
4161
4162
Daniel Chenga37c03db2022-05-12 17:20:344163def _ChangeHasSecurityReviewer(input_api, owners_file):
4164 """Returns True iff the CL has a reviewer from SECURITY_OWNERS.
Sam Maiera6e76d72022-02-11 21:43:504165
Daniel Chenga37c03db2022-05-12 17:20:344166 Args:
4167 input_api: The presubmit input API.
4168 owners_file: OWNERS file with required reviewers. Typically, this is
4169 something like ipc/SECURITY_OWNERS.
4170
4171 Note: if the presubmit is running for commit rather than for upload, this
4172 only returns True if a security reviewer has also approved the CL.
Sam Maiera6e76d72022-02-11 21:43:504173 """
Daniel Chengd88244472022-05-16 09:08:474174 # Owners-Override should bypass all additional OWNERS enforcement checks.
4175 # A CR+1 vote will still be required to land this change.
4176 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
4177 input_api.change.issue)):
4178 return True
4179
Daniel Chenga37c03db2022-05-12 17:20:344180 owner_email, reviewers = (
4181 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
Daniel Cheng3008dc12022-05-13 04:02:114182 input_api,
4183 None,
4184 approval_needed=input_api.is_committing and not input_api.dry_run))
Sam Maiera6e76d72022-02-11 21:43:504185
Daniel Chenga37c03db2022-05-12 17:20:344186 security_owners = input_api.owners_client.ListOwners(owners_file)
4187 return any(owner in reviewers for owner in security_owners)
Sam Maiera6e76d72022-02-11 21:43:504188
Daniel Chenga37c03db2022-05-12 17:20:344189
4190@dataclass
Daniel Cheng171dad8d2022-05-21 00:40:254191class _SecurityProblemWithItems:
4192 problem: str
4193 items: Sequence[str]
4194
4195
4196@dataclass
Daniel Chenga37c03db2022-05-12 17:20:344197class _MissingSecurityOwnersResult:
Daniel Cheng171dad8d2022-05-21 00:40:254198 owners_file_problems: Sequence[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:344199 has_security_sensitive_files: bool
Daniel Cheng171dad8d2022-05-21 00:40:254200 missing_reviewer_problem: Optional[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:344201
4202
4203def _FindMissingSecurityOwners(input_api,
4204 output_api,
4205 file_patterns: Sequence[str],
4206 excluded_patterns: Sequence[str],
4207 required_owners_file: str,
4208 custom_rule_function: Optional[Callable] = None
4209 ) -> _MissingSecurityOwnersResult:
4210 """Find OWNERS files missing per-file rules for security-sensitive files.
4211
4212 Args:
4213 input_api: the PRESUBMIT input API object.
4214 output_api: the PRESUBMIT output API object.
4215 file_patterns: basename patterns that require a corresponding per-file
4216 security restriction.
4217 excluded_patterns: path patterns that should be exempted from
4218 requiring a security restriction.
4219 required_owners_file: path to the required OWNERS file, e.g.
4220 ipc/SECURITY_OWNERS
4221 cc_alias: If not None, email that will be CCed automatically if the
4222 change contains security-sensitive files, as determined by
4223 `file_patterns` and `excluded_patterns`.
4224 custom_rule_function: If not None, will be called with `input_api` and
4225 the current file under consideration. Returning True will add an
4226 exact match per-file rule check for the current file.
4227 """
4228
4229 # `to_check` is a mapping of an OWNERS file path to Patterns.
4230 #
4231 # Patterns is a dictionary mapping glob patterns (suitable for use in
4232 # per-file rules) to a PatternEntry.
4233 #
Sam Maiera6e76d72022-02-11 21:43:504234 # PatternEntry is a dictionary with two keys:
4235 # - 'files': the files that are matched by this pattern
4236 # - 'rules': the per-file rules needed for this pattern
Daniel Chenga37c03db2022-05-12 17:20:344237 #
Sam Maiera6e76d72022-02-11 21:43:504238 # For example, if we expect OWNERS file to contain rules for *.mojom and
4239 # *_struct_traits*.*, Patterns might look like this:
4240 # {
4241 # '*.mojom': {
4242 # 'files': ...,
4243 # 'rules': [
4244 # 'per-file *.mojom=set noparent',
4245 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
4246 # ],
4247 # },
4248 # '*_struct_traits*.*': {
4249 # 'files': ...,
4250 # 'rules': [
4251 # 'per-file *_struct_traits*.*=set noparent',
4252 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
4253 # ],
4254 # },
4255 # }
4256 to_check = {}
Daniel Chenga37c03db2022-05-12 17:20:344257 files_to_review = []
Sam Maiera6e76d72022-02-11 21:43:504258
Daniel Chenga37c03db2022-05-12 17:20:344259 def AddPatternToCheck(file, pattern):
Sam Maiera6e76d72022-02-11 21:43:504260 owners_file = input_api.os_path.join(
Daniel Chengd88244472022-05-16 09:08:474261 input_api.os_path.dirname(file.LocalPath()), 'OWNERS')
Sam Maiera6e76d72022-02-11 21:43:504262 if owners_file not in to_check:
4263 to_check[owners_file] = {}
4264 if pattern not in to_check[owners_file]:
4265 to_check[owners_file][pattern] = {
4266 'files': [],
4267 'rules': [
Daniel Chenga37c03db2022-05-12 17:20:344268 f'per-file {pattern}=set noparent',
4269 f'per-file {pattern}=file://{required_owners_file}',
Sam Maiera6e76d72022-02-11 21:43:504270 ]
4271 }
Daniel Chenged57a162022-05-25 02:56:344272 to_check[owners_file][pattern]['files'].append(file.LocalPath())
Daniel Chenga37c03db2022-05-12 17:20:344273 files_to_review.append(file.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:504274
Daniel Chenga37c03db2022-05-12 17:20:344275 # Only enforce security OWNERS rules for a directory if that directory has a
4276 # file that matches `file_patterns`. For example, if a directory only
4277 # contains *.mojom files and no *_messages*.h files, the check should only
4278 # ensure that rules for *.mojom files are present.
4279 for file in input_api.AffectedFiles(include_deletes=False):
4280 file_basename = input_api.os_path.basename(file.LocalPath())
4281 if custom_rule_function is not None and custom_rule_function(
4282 input_api, file):
4283 AddPatternToCheck(file, file_basename)
4284 continue
Sam Maiera6e76d72022-02-11 21:43:504285
Daniel Chenga37c03db2022-05-12 17:20:344286 if any(
4287 input_api.fnmatch.fnmatch(file.LocalPath(), pattern)
4288 for pattern in excluded_patterns):
Sam Maiera6e76d72022-02-11 21:43:504289 continue
4290
4291 for pattern in file_patterns:
Daniel Chenga37c03db2022-05-12 17:20:344292 # Unlike `excluded_patterns`, `file_patterns` is checked only against the
4293 # file's basename.
4294 if input_api.fnmatch.fnmatch(file_basename, pattern):
4295 AddPatternToCheck(file, pattern)
Sam Maiera6e76d72022-02-11 21:43:504296 break
4297
Daniel Chenga37c03db2022-05-12 17:20:344298 has_security_sensitive_files = bool(to_check)
Daniel Cheng171dad8d2022-05-21 00:40:254299
4300 # Check if any newly added lines in OWNERS files intersect with required
4301 # per-file OWNERS lines. If so, ensure that a security reviewer is included.
4302 # This is a hack, but is needed because the OWNERS check (by design) ignores
4303 # new OWNERS entries; otherwise, a non-owner could add someone as a new
4304 # OWNER and have that newly-added OWNER self-approve their own addition.
4305 newly_covered_files = []
4306 for file in input_api.AffectedFiles(include_deletes=False):
4307 if not file.LocalPath() in to_check:
4308 continue
4309 for _, line in file.ChangedContents():
4310 for _, entry in to_check[file.LocalPath()].items():
4311 if line in entry['rules']:
4312 newly_covered_files.extend(entry['files'])
4313
4314 missing_reviewer_problems = None
4315 if newly_covered_files and not _ChangeHasSecurityReviewer(
Daniel Chenga37c03db2022-05-12 17:20:344316 input_api, required_owners_file):
Daniel Cheng171dad8d2022-05-21 00:40:254317 missing_reviewer_problems = _SecurityProblemWithItems(
4318 f'Review from an owner in {required_owners_file} is required for '
4319 'the following newly-added files:',
4320 [f'{file}' for file in sorted(set(newly_covered_files))])
Sam Maiera6e76d72022-02-11 21:43:504321
4322 # Go through the OWNERS files to check, filtering out rules that are already
4323 # present in that OWNERS file.
4324 for owners_file, patterns in to_check.items():
4325 try:
Daniel Cheng171dad8d2022-05-21 00:40:254326 lines = set(
4327 input_api.ReadFile(
4328 input_api.os_path.join(input_api.change.RepositoryRoot(),
4329 owners_file)).splitlines())
4330 for entry in patterns.values():
4331 entry['rules'] = [
4332 rule for rule in entry['rules'] if rule not in lines
4333 ]
Sam Maiera6e76d72022-02-11 21:43:504334 except IOError:
4335 # No OWNERS file, so all the rules are definitely missing.
4336 continue
4337
4338 # All the remaining lines weren't found in OWNERS files, so emit an error.
Daniel Cheng171dad8d2022-05-21 00:40:254339 owners_file_problems = []
Daniel Chenga37c03db2022-05-12 17:20:344340
Sam Maiera6e76d72022-02-11 21:43:504341 for owners_file, patterns in to_check.items():
4342 missing_lines = []
4343 files = []
4344 for _, entry in patterns.items():
Daniel Chenged57a162022-05-25 02:56:344345 files.extend(entry['files'])
Sam Maiera6e76d72022-02-11 21:43:504346 missing_lines.extend(entry['rules'])
Sam Maiera6e76d72022-02-11 21:43:504347 if missing_lines:
Daniel Cheng171dad8d2022-05-21 00:40:254348 joined_missing_lines = '\n'.join(line for line in missing_lines)
4349 owners_file_problems.append(
4350 _SecurityProblemWithItems(
4351 'Found missing OWNERS lines for security-sensitive files. '
4352 f'Please add the following lines to {owners_file}:\n'
4353 f'{joined_missing_lines}\n\nTo ensure security review for:',
4354 files))
Daniel Chenga37c03db2022-05-12 17:20:344355
Daniel Cheng171dad8d2022-05-21 00:40:254356 return _MissingSecurityOwnersResult(owners_file_problems,
Daniel Chenga37c03db2022-05-12 17:20:344357 has_security_sensitive_files,
Daniel Cheng171dad8d2022-05-21 00:40:254358 missing_reviewer_problems)
Daniel Chenga37c03db2022-05-12 17:20:344359
4360
4361def _CheckChangeForIpcSecurityOwners(input_api, output_api):
4362 # Whether or not a file affects IPC is (mostly) determined by a simple list
4363 # of filename patterns.
4364 file_patterns = [
4365 # Legacy IPC:
4366 '*_messages.cc',
4367 '*_messages*.h',
4368 '*_param_traits*.*',
4369 # Mojo IPC:
4370 '*.mojom',
4371 '*_mojom_traits*.*',
4372 '*_type_converter*.*',
4373 # Android native IPC:
4374 '*.aidl',
4375 ]
4376
Daniel Chenga37c03db2022-05-12 17:20:344377 excluded_patterns = [
Daniel Cheng518943f2022-05-12 22:15:464378 # These third_party directories do not contain IPCs, but contain files
4379 # matching the above patterns, which trigger false positives.
Daniel Chenga37c03db2022-05-12 17:20:344380 'third_party/crashpad/*',
4381 'third_party/blink/renderer/platform/bindings/*',
4382 'third_party/protobuf/benchmarks/python/*',
4383 'third_party/win_build_output/*',
Daniel Chengd88244472022-05-16 09:08:474384 # Enum-only mojoms used for web metrics, so no security review needed.
4385 'third_party/blink/public/mojom/use_counter/metrics/*',
Daniel Chenga37c03db2022-05-12 17:20:344386 # These files are just used to communicate between class loaders running
4387 # in the same process.
4388 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
4389 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
4390 ]
4391
4392 def IsMojoServiceManifestFile(input_api, file):
4393 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
4394 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
4395 if not manifest_pattern.search(file.LocalPath()):
4396 return False
4397
4398 if test_manifest_pattern.search(file.LocalPath()):
4399 return False
4400
4401 # All actual service manifest files should contain at least one
4402 # qualified reference to service_manager::Manifest.
4403 return any('service_manager::Manifest' in line
4404 for line in file.NewContents())
4405
4406 return _FindMissingSecurityOwners(
4407 input_api,
4408 output_api,
4409 file_patterns,
4410 excluded_patterns,
4411 'ipc/SECURITY_OWNERS',
4412 custom_rule_function=IsMojoServiceManifestFile)
4413
4414
4415def _CheckChangeForFuchsiaSecurityOwners(input_api, output_api):
4416 file_patterns = [
4417 # Component specifications.
4418 '*.cml', # Component Framework v2.
4419 '*.cmx', # Component Framework v1.
4420
4421 # Fuchsia IDL protocol specifications.
4422 '*.fidl',
4423 ]
4424
4425 # Don't check for owners files for changes in these directories.
4426 excluded_patterns = [
4427 'third_party/crashpad/*',
4428 ]
4429
4430 return _FindMissingSecurityOwners(input_api, output_api, file_patterns,
4431 excluded_patterns,
4432 'build/fuchsia/SECURITY_OWNERS')
4433
4434
4435def CheckSecurityOwners(input_api, output_api):
4436 """Checks that various security-sensitive files have an IPC OWNERS rule."""
4437 ipc_results = _CheckChangeForIpcSecurityOwners(input_api, output_api)
4438 fuchsia_results = _CheckChangeForFuchsiaSecurityOwners(
4439 input_api, output_api)
4440
4441 if ipc_results.has_security_sensitive_files:
4442 output_api.AppendCC('[email protected]')
Sam Maiera6e76d72022-02-11 21:43:504443
4444 results = []
Daniel Chenga37c03db2022-05-12 17:20:344445
Daniel Cheng171dad8d2022-05-21 00:40:254446 missing_reviewer_problems = []
4447 if ipc_results.missing_reviewer_problem:
4448 missing_reviewer_problems.append(ipc_results.missing_reviewer_problem)
4449 if fuchsia_results.missing_reviewer_problem:
4450 missing_reviewer_problems.append(
4451 fuchsia_results.missing_reviewer_problem)
Daniel Chenga37c03db2022-05-12 17:20:344452
Daniel Cheng171dad8d2022-05-21 00:40:254453 # Missing reviewers are an error unless there's no issue number
4454 # associated with this branch; in that case, the presubmit is being run
4455 # with --all or --files.
4456 #
4457 # Note that upload should never be an error; otherwise, it would be
4458 # impossible to upload changes at all.
4459 if input_api.is_committing and input_api.change.issue:
4460 make_presubmit_message = output_api.PresubmitError
4461 else:
4462 make_presubmit_message = output_api.PresubmitNotifyResult
4463 for problem in missing_reviewer_problems:
Sam Maiera6e76d72022-02-11 21:43:504464 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:254465 make_presubmit_message(problem.problem, items=problem.items))
Daniel Chenga37c03db2022-05-12 17:20:344466
Daniel Cheng171dad8d2022-05-21 00:40:254467 owners_file_problems = []
4468 owners_file_problems.extend(ipc_results.owners_file_problems)
4469 owners_file_problems.extend(fuchsia_results.owners_file_problems)
Daniel Chenga37c03db2022-05-12 17:20:344470
Daniel Cheng171dad8d2022-05-21 00:40:254471 for problem in owners_file_problems:
Daniel Cheng3008dc12022-05-13 04:02:114472 # Missing per-file rules are always an error. While swarming and caching
4473 # means that uploading a patchset with updated OWNERS files and sending
4474 # it to the CQ again should not have a large incremental cost, it is
4475 # still frustrating to discover the error only after the change has
4476 # already been uploaded.
Daniel Chenga37c03db2022-05-12 17:20:344477 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:254478 output_api.PresubmitError(problem.problem, items=problem.items))
Sam Maiera6e76d72022-02-11 21:43:504479
4480 return results
4481
4482
4483def _GetFilesUsingSecurityCriticalFunctions(input_api):
4484 """Checks affected files for changes to security-critical calls. This
4485 function checks the full change diff, to catch both additions/changes
4486 and removals.
4487
4488 Returns a dict keyed by file name, and the value is a set of detected
4489 functions.
4490 """
4491 # Map of function pretty name (displayed in an error) to the pattern to
4492 # match it with.
4493 _PATTERNS_TO_CHECK = {
4494 'content::GetServiceSandboxType<>()': 'GetServiceSandboxType\\<'
4495 }
4496 _PATTERNS_TO_CHECK = {
4497 k: input_api.re.compile(v)
4498 for k, v in _PATTERNS_TO_CHECK.items()
4499 }
4500
Sam Maiera6e76d72022-02-11 21:43:504501 # We don't want to trigger on strings within this file.
4502 def presubmit_file_filter(f):
Daniel Chenga37c03db2022-05-12 17:20:344503 return 'PRESUBMIT.py' != input_api.os_path.split(f.LocalPath())[1]
Sam Maiera6e76d72022-02-11 21:43:504504
4505 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
4506 files_to_functions = {}
4507 for f in input_api.AffectedFiles(file_filter=presubmit_file_filter):
4508 diff = f.GenerateScmDiff()
4509 for line in diff.split('\n'):
4510 # Not using just RightHandSideLines() because removing a
4511 # call to a security-critical function can be just as important
4512 # as adding or changing the arguments.
4513 if line.startswith('-') or (line.startswith('+')
4514 and not line.startswith('++')):
4515 for name, pattern in _PATTERNS_TO_CHECK.items():
4516 if pattern.search(line):
4517 path = f.LocalPath()
4518 if not path in files_to_functions:
4519 files_to_functions[path] = set()
4520 files_to_functions[path].add(name)
4521 return files_to_functions
4522
4523
4524def CheckSecurityChanges(input_api, output_api):
4525 """Checks that changes involving security-critical functions are reviewed
4526 by the security team.
4527 """
4528 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
4529 if not len(files_to_functions):
4530 return []
4531
Sam Maiera6e76d72022-02-11 21:43:504532 owners_file = 'ipc/SECURITY_OWNERS'
Daniel Chenga37c03db2022-05-12 17:20:344533 if _ChangeHasSecurityReviewer(input_api, owners_file):
Sam Maiera6e76d72022-02-11 21:43:504534 return []
4535
Daniel Chenga37c03db2022-05-12 17:20:344536 msg = 'The following files change calls to security-sensitive functions\n' \
Sam Maiera6e76d72022-02-11 21:43:504537 'that need to be reviewed by {}.\n'.format(owners_file)
4538 for path, names in files_to_functions.items():
4539 msg += ' {}\n'.format(path)
4540 for name in names:
4541 msg += ' {}\n'.format(name)
4542 msg += '\n'
4543
4544 if input_api.is_committing:
4545 output = output_api.PresubmitError
Mohamed Heikale217fc852020-07-06 19:44:034546 else:
Sam Maiera6e76d72022-02-11 21:43:504547 output = output_api.PresubmitNotifyResult
4548 return [output(msg)]
4549
4550
4551def CheckSetNoParent(input_api, output_api):
4552 """Checks that set noparent is only used together with an OWNERS file in
4553 //build/OWNERS.setnoparent (see also
4554 //docs/code_reviews.md#owners-files-details)
4555 """
4556 # Return early if no OWNERS files were modified.
4557 if not any(f.LocalPath().endswith('OWNERS')
4558 for f in input_api.AffectedFiles(include_deletes=False)):
4559 return []
4560
4561 errors = []
4562
4563 allowed_owners_files_file = 'build/OWNERS.setnoparent'
4564 allowed_owners_files = set()
Bruce Dawson58a45d22023-02-27 11:24:164565 with open(allowed_owners_files_file, 'r', encoding='utf-8') as f:
Sam Maiera6e76d72022-02-11 21:43:504566 for line in f:
4567 line = line.strip()
4568 if not line or line.startswith('#'):
4569 continue
4570 allowed_owners_files.add(line)
4571
4572 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
4573
4574 for f in input_api.AffectedFiles(include_deletes=False):
4575 if not f.LocalPath().endswith('OWNERS'):
4576 continue
4577
4578 found_owners_files = set()
4579 found_set_noparent_lines = dict()
4580
4581 # Parse the OWNERS file.
4582 for lineno, line in enumerate(f.NewContents(), 1):
4583 line = line.strip()
4584 if line.startswith('set noparent'):
4585 found_set_noparent_lines[''] = lineno
4586 if line.startswith('file://'):
4587 if line in allowed_owners_files:
4588 found_owners_files.add('')
4589 if line.startswith('per-file'):
4590 match = per_file_pattern.match(line)
4591 if match:
4592 glob = match.group(1).strip()
4593 directive = match.group(2).strip()
4594 if directive == 'set noparent':
4595 found_set_noparent_lines[glob] = lineno
4596 if directive.startswith('file://'):
4597 if directive in allowed_owners_files:
4598 found_owners_files.add(glob)
4599
4600 # Check that every set noparent line has a corresponding file:// line
4601 # listed in build/OWNERS.setnoparent. An exception is made for top level
4602 # directories since src/OWNERS shouldn't review them.
Bruce Dawson6bb0d672022-04-06 15:13:494603 linux_path = f.LocalPath().replace(input_api.os_path.sep, '/')
4604 if (linux_path.count('/') != 1
4605 and (not linux_path in _EXCLUDED_SET_NO_PARENT_PATHS)):
Sam Maiera6e76d72022-02-11 21:43:504606 for set_noparent_line in found_set_noparent_lines:
4607 if set_noparent_line in found_owners_files:
4608 continue
4609 errors.append(' %s:%d' %
Bruce Dawson6bb0d672022-04-06 15:13:494610 (linux_path,
Sam Maiera6e76d72022-02-11 21:43:504611 found_set_noparent_lines[set_noparent_line]))
4612
4613 results = []
4614 if errors:
4615 if input_api.is_committing:
4616 output = output_api.PresubmitError
4617 else:
4618 output = output_api.PresubmitPromptWarning
4619 results.append(
4620 output(
4621 'Found the following "set noparent" restrictions in OWNERS files that '
4622 'do not include owners from build/OWNERS.setnoparent:',
4623 long_text='\n\n'.join(errors)))
4624 return results
4625
4626
4627def CheckUselessForwardDeclarations(input_api, output_api):
4628 """Checks that added or removed lines in non third party affected
4629 header files do not lead to new useless class or struct forward
4630 declaration.
4631 """
4632 results = []
4633 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
4634 input_api.re.MULTILINE)
4635 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
4636 input_api.re.MULTILINE)
4637 for f in input_api.AffectedFiles(include_deletes=False):
4638 if (f.LocalPath().startswith('third_party')
4639 and not f.LocalPath().startswith('third_party/blink')
4640 and not f.LocalPath().startswith('third_party\\blink')):
4641 continue
4642
4643 if not f.LocalPath().endswith('.h'):
4644 continue
4645
4646 contents = input_api.ReadFile(f)
4647 fwd_decls = input_api.re.findall(class_pattern, contents)
4648 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
4649
4650 useless_fwd_decls = []
4651 for decl in fwd_decls:
4652 count = sum(1 for _ in input_api.re.finditer(
4653 r'\b%s\b' % input_api.re.escape(decl), contents))
4654 if count == 1:
4655 useless_fwd_decls.append(decl)
4656
4657 if not useless_fwd_decls:
4658 continue
4659
4660 for line in f.GenerateScmDiff().splitlines():
4661 if (line.startswith('-') and not line.startswith('--')
4662 or line.startswith('+') and not line.startswith('++')):
4663 for decl in useless_fwd_decls:
4664 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
4665 results.append(
4666 output_api.PresubmitPromptWarning(
4667 '%s: %s forward declaration is no longer needed'
4668 % (f.LocalPath(), decl)))
4669 useless_fwd_decls.remove(decl)
4670
4671 return results
4672
4673
4674def _CheckAndroidDebuggableBuild(input_api, output_api):
4675 """Checks that code uses BuildInfo.isDebugAndroid() instead of
4676 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
4677 this is a debuggable build of Android.
4678 """
4679 build_type_check_pattern = input_api.re.compile(
4680 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
4681
4682 errors = []
4683
4684 sources = lambda affected_file: input_api.FilterSourceFile(
4685 affected_file,
4686 files_to_skip=(
4687 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4688 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314689 r"^android_webview/support_library/boundary_interfaces/",
4690 r"^chrome/android/webapk/.*",
4691 r'^third_party/.*',
4692 r"tools/android/customtabs_benchmark/.*",
4693 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504694 )),
4695 files_to_check=[r'.*\.java$'])
4696
4697 for f in input_api.AffectedSourceFiles(sources):
4698 for line_num, line in f.ChangedContents():
4699 if build_type_check_pattern.search(line):
4700 errors.append("%s:%d" % (f.LocalPath(), line_num))
4701
4702 results = []
4703
4704 if errors:
4705 results.append(
4706 output_api.PresubmitPromptWarning(
4707 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
4708 ' Please use BuildInfo.isDebugAndroid() instead.', errors))
4709
4710 return results
4711
4712# TODO: add unit tests
4713def _CheckAndroidToastUsage(input_api, output_api):
4714 """Checks that code uses org.chromium.ui.widget.Toast instead of
4715 android.widget.Toast (Chromium Toast doesn't force hardware
4716 acceleration on low-end devices, saving memory).
4717 """
4718 toast_import_pattern = input_api.re.compile(
4719 r'^import android\.widget\.Toast;$')
4720
4721 errors = []
4722
4723 sources = lambda affected_file: input_api.FilterSourceFile(
4724 affected_file,
4725 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
Bruce Dawson40fece62022-09-16 19:58:314726 DEFAULT_FILES_TO_SKIP + (r'^chromecast/.*',
4727 r'^remoting/.*')),
Sam Maiera6e76d72022-02-11 21:43:504728 files_to_check=[r'.*\.java$'])
4729
4730 for f in input_api.AffectedSourceFiles(sources):
4731 for line_num, line in f.ChangedContents():
4732 if toast_import_pattern.search(line):
4733 errors.append("%s:%d" % (f.LocalPath(), line_num))
4734
4735 results = []
4736
4737 if errors:
4738 results.append(
4739 output_api.PresubmitError(
4740 'android.widget.Toast usage is detected. Android toasts use hardware'
4741 ' acceleration, and can be\ncostly on low-end devices. Please use'
4742 ' org.chromium.ui.widget.Toast instead.\n'
4743 'Contact [email protected] if you have any questions.',
4744 errors))
4745
4746 return results
4747
4748
4749def _CheckAndroidCrLogUsage(input_api, output_api):
4750 """Checks that new logs using org.chromium.base.Log:
4751 - Are using 'TAG' as variable name for the tags (warn)
4752 - Are using a tag that is shorter than 20 characters (error)
4753 """
4754
4755 # Do not check format of logs in the given files
4756 cr_log_check_excluded_paths = [
4757 # //chrome/android/webapk cannot depend on //base
Bruce Dawson40fece62022-09-16 19:58:314758 r"^chrome/android/webapk/.*",
Sam Maiera6e76d72022-02-11 21:43:504759 # WebView license viewer code cannot depend on //base; used in stub APK.
Bruce Dawson40fece62022-09-16 19:58:314760 r"^android_webview/glue/java/src/com/android/"
4761 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504762 # The customtabs_benchmark is a small app that does not depend on Chromium
4763 # java pieces.
Bruce Dawson40fece62022-09-16 19:58:314764 r"tools/android/customtabs_benchmark/.*",
Sam Maiera6e76d72022-02-11 21:43:504765 ]
4766
4767 cr_log_import_pattern = input_api.re.compile(
4768 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
4769 class_in_base_pattern = input_api.re.compile(
4770 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
4771 has_some_log_import_pattern = input_api.re.compile(r'^import .*\.Log;$',
4772 input_api.re.MULTILINE)
4773 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
4774 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
4775 log_decl_pattern = input_api.re.compile(
4776 r'static final String TAG = "(?P<name>(.*))"')
4777 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
4778
4779 REF_MSG = ('See docs/android_logging.md for more info.')
4780 sources = lambda x: input_api.FilterSourceFile(
4781 x,
4782 files_to_check=[r'.*\.java$'],
4783 files_to_skip=cr_log_check_excluded_paths)
4784
4785 tag_decl_errors = []
Andrew Grieved3a35d82024-01-02 21:24:384786 tag_length_errors = []
Sam Maiera6e76d72022-02-11 21:43:504787 tag_errors = []
4788 tag_with_dot_errors = []
4789 util_log_errors = []
4790
4791 for f in input_api.AffectedSourceFiles(sources):
4792 file_content = input_api.ReadFile(f)
4793 has_modified_logs = False
4794 # Per line checks
4795 if (cr_log_import_pattern.search(file_content)
4796 or (class_in_base_pattern.search(file_content)
4797 and not has_some_log_import_pattern.search(file_content))):
4798 # Checks to run for files using cr log
4799 for line_num, line in f.ChangedContents():
4800 if rough_log_decl_pattern.search(line):
4801 has_modified_logs = True
4802
4803 # Check if the new line is doing some logging
4804 match = log_call_pattern.search(line)
4805 if match:
4806 has_modified_logs = True
4807
4808 # Make sure it uses "TAG"
4809 if not match.group('tag') == 'TAG':
4810 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
4811 else:
4812 # Report non cr Log function calls in changed lines
4813 for line_num, line in f.ChangedContents():
4814 if log_call_pattern.search(line):
4815 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
4816
4817 # Per file checks
4818 if has_modified_logs:
4819 # Make sure the tag is using the "cr" prefix and is not too long
4820 match = log_decl_pattern.search(file_content)
4821 tag_name = match.group('name') if match else None
4822 if not tag_name:
4823 tag_decl_errors.append(f.LocalPath())
Andrew Grieved3a35d82024-01-02 21:24:384824 elif len(tag_name) > 20:
4825 tag_length_errors.append(f.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:504826 elif '.' in tag_name:
4827 tag_with_dot_errors.append(f.LocalPath())
4828
4829 results = []
4830 if tag_decl_errors:
4831 results.append(
4832 output_api.PresubmitPromptWarning(
4833 'Please define your tags using the suggested format: .\n'
4834 '"private static final String TAG = "<package tag>".\n'
4835 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
4836 tag_decl_errors))
4837
Andrew Grieved3a35d82024-01-02 21:24:384838 if tag_length_errors:
4839 results.append(
4840 output_api.PresubmitError(
4841 'The tag length is restricted by the system to be at most '
4842 '20 characters.\n' + REF_MSG, tag_length_errors))
4843
Sam Maiera6e76d72022-02-11 21:43:504844 if tag_errors:
4845 results.append(
4846 output_api.PresubmitPromptWarning(
4847 'Please use a variable named "TAG" for your log tags.\n' +
4848 REF_MSG, tag_errors))
4849
4850 if util_log_errors:
4851 results.append(
4852 output_api.PresubmitPromptWarning(
4853 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
4854 util_log_errors))
4855
4856 if tag_with_dot_errors:
4857 results.append(
4858 output_api.PresubmitPromptWarning(
4859 'Dot in log tags cause them to be elided in crash reports.\n' +
4860 REF_MSG, tag_with_dot_errors))
4861
4862 return results
4863
4864
Sam Maiera6e76d72022-02-11 21:43:504865def _CheckAndroidTestAnnotationUsage(input_api, output_api):
4866 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
4867 deprecated_annotation_import_pattern = input_api.re.compile(
4868 r'^import android\.test\.suitebuilder\.annotation\..*;',
4869 input_api.re.MULTILINE)
4870 sources = lambda x: input_api.FilterSourceFile(
4871 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
4872 errors = []
4873 for f in input_api.AffectedFiles(file_filter=sources):
4874 for line_num, line in f.ChangedContents():
4875 if deprecated_annotation_import_pattern.search(line):
4876 errors.append("%s:%d" % (f.LocalPath(), line_num))
4877
4878 results = []
4879 if errors:
4880 results.append(
4881 output_api.PresubmitError(
4882 'Annotations in android.test.suitebuilder.annotation have been'
Mohamed Heikal3d7a94c2023-03-28 16:55:244883 ' deprecated since API level 24. Please use androidx.test.filters'
4884 ' from //third_party/androidx:androidx_test_runner_java instead.'
Sam Maiera6e76d72022-02-11 21:43:504885 ' Contact [email protected] if you have any questions.',
4886 errors))
4887 return results
4888
4889
4890def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
4891 """Checks if MDPI assets are placed in a correct directory."""
Bruce Dawson6c05e852022-07-21 15:48:514892 file_filter = lambda f: (f.LocalPath().endswith(
4893 '.png') and ('/res/drawable/'.replace('/', input_api.os_path.sep) in f.
4894 LocalPath() or '/res/drawable-ldrtl/'.replace(
4895 '/', input_api.os_path.sep) in f.LocalPath()))
Sam Maiera6e76d72022-02-11 21:43:504896 errors = []
4897 for f in input_api.AffectedFiles(include_deletes=False,
4898 file_filter=file_filter):
4899 errors.append(' %s' % f.LocalPath())
4900
4901 results = []
4902 if errors:
4903 results.append(
4904 output_api.PresubmitError(
4905 'MDPI assets should be placed in /res/drawable-mdpi/ or '
4906 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
4907 '/res/drawable-ldrtl/.\n'
4908 'Contact [email protected] if you have questions.', errors))
4909 return results
4910
4911
4912def _CheckAndroidWebkitImports(input_api, output_api):
4913 """Checks that code uses org.chromium.base.Callback instead of
4914 android.webview.ValueCallback except in the WebView glue layer
4915 and WebLayer.
4916 """
4917 valuecallback_import_pattern = input_api.re.compile(
4918 r'^import android\.webkit\.ValueCallback;$')
4919
4920 errors = []
4921
4922 sources = lambda affected_file: input_api.FilterSourceFile(
4923 affected_file,
4924 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4925 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314926 r'^android_webview/glue/.*',
elabadysayedcbbaea72024-08-01 16:10:424927 r'^android_webview/support_library/.*',
Bruce Dawson40fece62022-09-16 19:58:314928 r'^weblayer/.*',
Sam Maiera6e76d72022-02-11 21:43:504929 )),
4930 files_to_check=[r'.*\.java$'])
4931
4932 for f in input_api.AffectedSourceFiles(sources):
4933 for line_num, line in f.ChangedContents():
4934 if valuecallback_import_pattern.search(line):
4935 errors.append("%s:%d" % (f.LocalPath(), line_num))
4936
4937 results = []
4938
4939 if errors:
4940 results.append(
4941 output_api.PresubmitError(
4942 'android.webkit.ValueCallback usage is detected outside of the glue'
4943 ' layer. To stay compatible with the support library, android.webkit.*'
4944 ' classes should only be used inside the glue layer and'
4945 ' org.chromium.base.Callback should be used instead.', errors))
4946
4947 return results
4948
4949
4950def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
4951 """Checks Android XML styles """
4952
4953 # Return early if no relevant files were modified.
4954 if not any(
4955 _IsXmlOrGrdFile(input_api, f.LocalPath())
4956 for f in input_api.AffectedFiles(include_deletes=False)):
4957 return []
4958
4959 import sys
4960 original_sys_path = sys.path
4961 try:
4962 sys.path = sys.path + [
4963 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4964 'android', 'checkxmlstyle')
4965 ]
4966 import checkxmlstyle
4967 finally:
4968 # Restore sys.path to what it was before.
4969 sys.path = original_sys_path
4970
4971 if is_check_on_upload:
4972 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
4973 else:
4974 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
4975
4976
4977def _CheckAndroidInfoBarDeprecation(input_api, output_api):
4978 """Checks Android Infobar Deprecation """
4979
4980 import sys
4981 original_sys_path = sys.path
4982 try:
4983 sys.path = sys.path + [
4984 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4985 'android', 'infobar_deprecation')
4986 ]
4987 import infobar_deprecation
4988 finally:
4989 # Restore sys.path to what it was before.
4990 sys.path = original_sys_path
4991
4992 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
4993
4994
4995class _PydepsCheckerResult:
4996 def __init__(self, cmd, pydeps_path, process, old_contents):
4997 self._cmd = cmd
4998 self._pydeps_path = pydeps_path
4999 self._process = process
5000 self._old_contents = old_contents
5001
5002 def GetError(self):
5003 """Returns an error message, or None."""
5004 import difflib
Andrew Grieved27620b62023-07-13 16:35:075005 new_contents = self._process.stdout.read().splitlines()[2:]
Sam Maiera6e76d72022-02-11 21:43:505006 if self._process.wait() != 0:
5007 # STDERR should already be printed.
5008 return 'Command failed: ' + self._cmd
Sam Maiera6e76d72022-02-11 21:43:505009 if self._old_contents != new_contents:
5010 diff = '\n'.join(
5011 difflib.context_diff(self._old_contents, new_contents))
5012 return ('File is stale: {}\n'
5013 'Diff (apply to fix):\n'
5014 '{}\n'
5015 'To regenerate, run:\n\n'
5016 ' {}').format(self._pydeps_path, diff, self._cmd)
5017 return None
5018
5019
5020class PydepsChecker:
5021 def __init__(self, input_api, pydeps_files):
5022 self._file_cache = {}
5023 self._input_api = input_api
5024 self._pydeps_files = pydeps_files
5025
5026 def _LoadFile(self, path):
5027 """Returns the list of paths within a .pydeps file relative to //."""
5028 if path not in self._file_cache:
5029 with open(path, encoding='utf-8') as f:
5030 self._file_cache[path] = f.read()
5031 return self._file_cache[path]
5032
5033 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
Gao Shenga79ebd42022-08-08 17:25:595034 """Returns an iterable of paths within the .pydep, relativized to //."""
Sam Maiera6e76d72022-02-11 21:43:505035 pydeps_data = self._LoadFile(pydeps_path)
5036 uses_gn_paths = '--gn-paths' in pydeps_data
5037 entries = (l for l in pydeps_data.splitlines()
5038 if not l.startswith('#'))
5039 if uses_gn_paths:
5040 # Paths look like: //foo/bar/baz
5041 return (e[2:] for e in entries)
5042 else:
5043 # Paths look like: path/relative/to/file.pydeps
5044 os_path = self._input_api.os_path
5045 pydeps_dir = os_path.dirname(pydeps_path)
5046 return (os_path.normpath(os_path.join(pydeps_dir, e))
5047 for e in entries)
5048
5049 def _CreateFilesToPydepsMap(self):
5050 """Returns a map of local_path -> list_of_pydeps."""
5051 ret = {}
5052 for pydep_local_path in self._pydeps_files:
5053 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
5054 ret.setdefault(path, []).append(pydep_local_path)
5055 return ret
5056
5057 def ComputeAffectedPydeps(self):
5058 """Returns an iterable of .pydeps files that might need regenerating."""
5059 affected_pydeps = set()
5060 file_to_pydeps_map = None
5061 for f in self._input_api.AffectedFiles(include_deletes=True):
5062 local_path = f.LocalPath()
5063 # Changes to DEPS can lead to .pydeps changes if any .py files are in
5064 # subrepositories. We can't figure out which files change, so re-check
5065 # all files.
5066 # Changes to print_python_deps.py affect all .pydeps.
5067 if local_path in ('DEPS', 'PRESUBMIT.py'
5068 ) or local_path.endswith('print_python_deps.py'):
5069 return self._pydeps_files
5070 elif local_path.endswith('.pydeps'):
5071 if local_path in self._pydeps_files:
5072 affected_pydeps.add(local_path)
5073 elif local_path.endswith('.py'):
5074 if file_to_pydeps_map is None:
5075 file_to_pydeps_map = self._CreateFilesToPydepsMap()
5076 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
5077 return affected_pydeps
5078
5079 def DetermineIfStaleAsync(self, pydeps_path):
5080 """Runs print_python_deps.py to see if the files is stale."""
5081 import os
5082
5083 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
5084 if old_pydeps_data:
5085 cmd = old_pydeps_data[1][1:].strip()
5086 if '--output' not in cmd:
5087 cmd += ' --output ' + pydeps_path
5088 old_contents = old_pydeps_data[2:]
5089 else:
5090 # A default cmd that should work in most cases (as long as pydeps filename
5091 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
5092 # file is empty/new.
5093 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
5094 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
5095 old_contents = []
5096 env = dict(os.environ)
5097 env['PYTHONDONTWRITEBYTECODE'] = '1'
5098 process = self._input_api.subprocess.Popen(
5099 cmd + ' --output ""',
5100 shell=True,
5101 env=env,
5102 stdout=self._input_api.subprocess.PIPE,
5103 encoding='utf-8')
5104 return _PydepsCheckerResult(cmd, pydeps_path, process, old_contents)
agrievef32bcc72016-04-04 14:57:405105
5106
Tibor Goldschwendt360793f72019-06-25 18:23:495107def _ParseGclientArgs():
Sam Maiera6e76d72022-02-11 21:43:505108 args = {}
5109 with open('build/config/gclient_args.gni', 'r') as f:
5110 for line in f:
5111 line = line.strip()
5112 if not line or line.startswith('#'):
5113 continue
5114 attribute, value = line.split('=')
5115 args[attribute.strip()] = value.strip()
5116 return args
Tibor Goldschwendt360793f72019-06-25 18:23:495117
5118
Saagar Sanghavifceeaae2020-08-12 16:40:365119def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
Sam Maiera6e76d72022-02-11 21:43:505120 """Checks if a .pydeps file needs to be regenerated."""
5121 # This check is for Python dependency lists (.pydeps files), and involves
5122 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
5123 # doesn't work on Windows and Mac, so skip it on other platforms.
5124 if not input_api.platform.startswith('linux'):
5125 return []
Erik Staabc734cd7a2021-11-23 03:11:525126
Sam Maiera6e76d72022-02-11 21:43:505127 results = []
5128 # First, check for new / deleted .pydeps.
5129 for f in input_api.AffectedFiles(include_deletes=True):
5130 # Check whether we are running the presubmit check for a file in src.
5131 # f.LocalPath is relative to repo (src, or internal repo).
5132 # os_path.exists is relative to src repo.
5133 # Therefore if os_path.exists is true, it means f.LocalPath is relative
5134 # to src and we can conclude that the pydeps is in src.
5135 if f.LocalPath().endswith('.pydeps'):
5136 if input_api.os_path.exists(f.LocalPath()):
5137 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
5138 results.append(
5139 output_api.PresubmitError(
5140 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
5141 'remove %s' % f.LocalPath()))
5142 elif f.Action() != 'D' and f.LocalPath(
5143 ) not in _ALL_PYDEPS_FILES:
5144 results.append(
5145 output_api.PresubmitError(
5146 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
5147 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:405148
Sam Maiera6e76d72022-02-11 21:43:505149 if results:
5150 return results
5151
Gavin Mak23884402024-07-25 20:39:265152 try:
5153 parsed_args = _ParseGclientArgs()
5154 except FileNotFoundError:
5155 message = (
5156 'build/config/gclient_args.gni not found. Please make sure your '
5157 'workspace has been initialized with gclient sync.'
5158 )
5159 import sys
5160 original_sys_path = sys.path
5161 try:
5162 sys.path = sys.path + [
5163 input_api.os_path.join(input_api.PresubmitLocalPath(),
5164 'third_party', 'depot_tools')
5165 ]
5166 import gclient_utils
5167 if gclient_utils.IsEnvCog():
5168 # Users will always hit this when they run presubmits before cog
5169 # workspace initialization finishes. The check shouldn't fail in
5170 # this case. This is an unavoidable workaround that's needed for
5171 # good presubmit UX for cog.
5172 results.append(output_api.PresubmitPromptWarning(message))
5173 else:
5174 results.append(output_api.PresubmitError(message))
5175 return results
5176 finally:
5177 # Restore sys.path to what it was before.
5178 sys.path = original_sys_path
5179
5180 is_android = parsed_args.get('checkout_android', 'false') == 'true'
Sam Maiera6e76d72022-02-11 21:43:505181 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
5182 affected_pydeps = set(checker.ComputeAffectedPydeps())
5183 affected_android_pydeps = affected_pydeps.intersection(
5184 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
5185 if affected_android_pydeps and not is_android:
5186 results.append(
5187 output_api.PresubmitPromptOrNotify(
5188 'You have changed python files that may affect pydeps for android\n'
Gao Shenga79ebd42022-08-08 17:25:595189 'specific scripts. However, the relevant presubmit check cannot be\n'
Sam Maiera6e76d72022-02-11 21:43:505190 'run because you are not using an Android checkout. To validate that\n'
5191 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
5192 'use the android-internal-presubmit optional trybot.\n'
5193 'Possibly stale pydeps files:\n{}'.format(
5194 '\n'.join(affected_android_pydeps))))
5195
5196 all_pydeps = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
5197 pydeps_to_check = affected_pydeps.intersection(all_pydeps)
5198 # Process these concurrently, as each one takes 1-2 seconds.
5199 pydep_results = [checker.DetermineIfStaleAsync(p) for p in pydeps_to_check]
5200 for result in pydep_results:
5201 error_msg = result.GetError()
5202 if error_msg:
5203 results.append(output_api.PresubmitError(error_msg))
5204
agrievef32bcc72016-04-04 14:57:405205 return results
5206
agrievef32bcc72016-04-04 14:57:405207
Saagar Sanghavifceeaae2020-08-12 16:40:365208def CheckSingletonInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505209 """Checks to make sure no header files have |Singleton<|."""
5210
5211 def FileFilter(affected_file):
5212 # It's ok for base/memory/singleton.h to have |Singleton<|.
5213 files_to_skip = (_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
Bruce Dawson40fece62022-09-16 19:58:315214 (r"^base/memory/singleton\.h$",
5215 r"^net/quic/platform/impl/quic_singleton_impl\.h$"))
Sam Maiera6e76d72022-02-11 21:43:505216 return input_api.FilterSourceFile(affected_file,
5217 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:435218
Sam Maiera6e76d72022-02-11 21:43:505219 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
5220 files = []
5221 for f in input_api.AffectedSourceFiles(FileFilter):
5222 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx')
5223 or f.LocalPath().endswith('.hpp')
5224 or f.LocalPath().endswith('.inl')):
5225 contents = input_api.ReadFile(f)
5226 for line in contents.splitlines(False):
5227 if (not line.lstrip().startswith('//')
5228 and # Strip C++ comment.
5229 pattern.search(line)):
5230 files.append(f)
5231 break
glidere61efad2015-02-18 17:39:435232
Sam Maiera6e76d72022-02-11 21:43:505233 if files:
5234 return [
5235 output_api.PresubmitError(
5236 'Found base::Singleton<T> in the following header files.\n' +
5237 'Please move them to an appropriate source file so that the ' +
5238 'template gets instantiated in a single compilation unit.',
5239 files)
5240 ]
5241 return []
glidere61efad2015-02-18 17:39:435242
5243
[email protected]fd20b902014-05-09 02:14:535244_DEPRECATED_CSS = [
5245 # Values
5246 ( "-webkit-box", "flex" ),
5247 ( "-webkit-inline-box", "inline-flex" ),
5248 ( "-webkit-flex", "flex" ),
5249 ( "-webkit-inline-flex", "inline-flex" ),
5250 ( "-webkit-min-content", "min-content" ),
5251 ( "-webkit-max-content", "max-content" ),
5252
5253 # Properties
5254 ( "-webkit-background-clip", "background-clip" ),
5255 ( "-webkit-background-origin", "background-origin" ),
5256 ( "-webkit-background-size", "background-size" ),
5257 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:445258 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:535259
5260 # Functions
5261 ( "-webkit-gradient", "gradient" ),
5262 ( "-webkit-repeating-gradient", "repeating-gradient" ),
5263 ( "-webkit-linear-gradient", "linear-gradient" ),
5264 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
5265 ( "-webkit-radial-gradient", "radial-gradient" ),
5266 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
5267]
5268
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:205269
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:495270# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:365271def CheckNoDeprecatedCss(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505272 """ Make sure that we don't use deprecated CSS
5273 properties, functions or values. Our external
5274 documentation and iOS CSS for dom distiller
5275 (reader mode) are ignored by the hooks as it
5276 needs to be consumed by WebKit. """
5277 results = []
5278 file_inclusion_pattern = [r".+\.css$"]
5279 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
5280 input_api.DEFAULT_FILES_TO_SKIP +
5281 (r"^chrome/common/extensions/docs", r"^chrome/docs",
Teresa Mao1d910882024-04-26 21:06:255282 r"^native_client_sdk",
5283 # The NTP team prefers reserving -webkit-line-clamp for
5284 # ellipsis effect which can only be used with -webkit-box.
5285 r"ui/webui/resources/cr_components/most_visited/.*\.css$"))
Sam Maiera6e76d72022-02-11 21:43:505286 file_filter = lambda f: input_api.FilterSourceFile(
5287 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
5288 for fpath in input_api.AffectedFiles(file_filter=file_filter):
5289 for line_num, line in fpath.ChangedContents():
5290 for (deprecated_value, value) in _DEPRECATED_CSS:
5291 if deprecated_value in line:
5292 results.append(
5293 output_api.PresubmitError(
5294 "%s:%d: Use of deprecated CSS %s, use %s instead" %
5295 (fpath.LocalPath(), line_num, deprecated_value,
5296 value)))
5297 return results
[email protected]fd20b902014-05-09 02:14:535298
mohan.reddyf21db962014-10-16 12:26:475299
Saagar Sanghavifceeaae2020-08-12 16:40:365300def CheckForRelativeIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505301 bad_files = {}
5302 for f in input_api.AffectedFiles(include_deletes=False):
5303 if (f.LocalPath().startswith('third_party')
5304 and not f.LocalPath().startswith('third_party/blink')
5305 and not f.LocalPath().startswith('third_party\\blink')):
5306 continue
rlanday6802cf632017-05-30 17:48:365307
Sam Maiera6e76d72022-02-11 21:43:505308 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
5309 continue
rlanday6802cf632017-05-30 17:48:365310
Sam Maiera6e76d72022-02-11 21:43:505311 relative_includes = [
5312 line for _, line in f.ChangedContents()
5313 if "#include" in line and "../" in line
5314 ]
5315 if not relative_includes:
5316 continue
5317 bad_files[f.LocalPath()] = relative_includes
rlanday6802cf632017-05-30 17:48:365318
Sam Maiera6e76d72022-02-11 21:43:505319 if not bad_files:
5320 return []
rlanday6802cf632017-05-30 17:48:365321
Sam Maiera6e76d72022-02-11 21:43:505322 error_descriptions = []
5323 for file_path, bad_lines in bad_files.items():
5324 error_description = file_path
5325 for line in bad_lines:
5326 error_description += '\n ' + line
5327 error_descriptions.append(error_description)
rlanday6802cf632017-05-30 17:48:365328
Sam Maiera6e76d72022-02-11 21:43:505329 results = []
5330 results.append(
5331 output_api.PresubmitError(
5332 'You added one or more relative #include paths (including "../").\n'
5333 'These shouldn\'t be used because they can be used to include headers\n'
5334 'from code that\'s not correctly specified as a dependency in the\n'
5335 'relevant BUILD.gn file(s).', error_descriptions))
rlanday6802cf632017-05-30 17:48:365336
Sam Maiera6e76d72022-02-11 21:43:505337 return results
rlanday6802cf632017-05-30 17:48:365338
Takeshi Yoshinoe387aa32017-08-02 13:16:135339
Saagar Sanghavifceeaae2020-08-12 16:40:365340def CheckForCcIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505341 """Check that nobody tries to include a cc file. It's a relatively
5342 common error which results in duplicate symbols in object
5343 files. This may not always break the build until someone later gets
5344 very confusing linking errors."""
5345 results = []
5346 for f in input_api.AffectedFiles(include_deletes=False):
5347 # We let third_party code do whatever it wants
5348 if (f.LocalPath().startswith('third_party')
5349 and not f.LocalPath().startswith('third_party/blink')
5350 and not f.LocalPath().startswith('third_party\\blink')):
5351 continue
Daniel Bratell65b033262019-04-23 08:17:065352
Sam Maiera6e76d72022-02-11 21:43:505353 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
5354 continue
Daniel Bratell65b033262019-04-23 08:17:065355
Sam Maiera6e76d72022-02-11 21:43:505356 for _, line in f.ChangedContents():
5357 if line.startswith('#include "'):
5358 included_file = line.split('"')[1]
5359 if _IsCPlusPlusFile(input_api, included_file):
5360 # The most common naming for external files with C++ code,
5361 # apart from standard headers, is to call them foo.inc, but
5362 # Chromium sometimes uses foo-inc.cc so allow that as well.
5363 if not included_file.endswith(('.h', '-inc.cc')):
5364 results.append(
5365 output_api.PresubmitError(
5366 'Only header files or .inc files should be included in other\n'
5367 'C++ files. Compiling the contents of a cc file more than once\n'
5368 'will cause duplicate information in the build which may later\n'
5369 'result in strange link_errors.\n' +
5370 f.LocalPath() + ':\n ' + line))
Daniel Bratell65b033262019-04-23 08:17:065371
Sam Maiera6e76d72022-02-11 21:43:505372 return results
Daniel Bratell65b033262019-04-23 08:17:065373
5374
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205375def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
Sam Maiera6e76d72022-02-11 21:43:505376 if not isinstance(key, ast.Str):
5377 return 'Key at line %d must be a string literal' % key.lineno
5378 if not isinstance(value, ast.Dict):
5379 return 'Value at line %d must be a dict' % value.lineno
5380 if len(value.keys) != 1:
5381 return 'Dict at line %d must have single entry' % value.lineno
5382 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
5383 return (
5384 'Entry at line %d must have a string literal \'filepath\' as key' %
5385 value.lineno)
5386 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:135387
Takeshi Yoshinoe387aa32017-08-02 13:16:135388
Sergey Ulanov4af16052018-11-08 02:41:465389def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Sam Maiera6e76d72022-02-11 21:43:505390 if not isinstance(key, ast.Str):
5391 return 'Key at line %d must be a string literal' % key.lineno
5392 if not isinstance(value, ast.List):
5393 return 'Value at line %d must be a list' % value.lineno
5394 for element in value.elts:
5395 if not isinstance(element, ast.Str):
5396 return 'Watchlist elements on line %d is not a string' % key.lineno
5397 if not email_regex.match(element.s):
5398 return ('Watchlist element on line %d doesn\'t look like a valid '
5399 + 'email: %s') % (key.lineno, element.s)
5400 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:135401
Takeshi Yoshinoe387aa32017-08-02 13:16:135402
Sergey Ulanov4af16052018-11-08 02:41:465403def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Sam Maiera6e76d72022-02-11 21:43:505404 mismatch_template = (
5405 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
5406 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:135407
Sam Maiera6e76d72022-02-11 21:43:505408 email_regex = input_api.re.compile(
5409 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
Sergey Ulanov4af16052018-11-08 02:41:465410
Sam Maiera6e76d72022-02-11 21:43:505411 ast = input_api.ast
5412 i = 0
5413 last_key = ''
5414 while True:
5415 if i >= len(wd_dict.keys):
5416 if i >= len(w_dict.keys):
5417 return None
5418 return mismatch_template % ('missing',
5419 'line %d' % w_dict.keys[i].lineno)
5420 elif i >= len(w_dict.keys):
5421 return (mismatch_template %
5422 ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:135423
Sam Maiera6e76d72022-02-11 21:43:505424 wd_key = wd_dict.keys[i]
5425 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:135426
Sam Maiera6e76d72022-02-11 21:43:505427 result = _CheckWatchlistDefinitionsEntrySyntax(wd_key,
5428 wd_dict.values[i], ast)
5429 if result is not None:
5430 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:135431
Sam Maiera6e76d72022-02-11 21:43:505432 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast,
5433 email_regex)
5434 if result is not None:
5435 return 'Bad entry in WATCHLISTS dict: %s' % result
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205436
Sam Maiera6e76d72022-02-11 21:43:505437 if wd_key.s != w_key.s:
5438 return mismatch_template % ('%s at line %d' %
5439 (wd_key.s, wd_key.lineno),
5440 '%s at line %d' %
5441 (w_key.s, w_key.lineno))
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205442
Sam Maiera6e76d72022-02-11 21:43:505443 if wd_key.s < last_key:
5444 return (
5445 'WATCHLISTS dict is not sorted lexicographically at line %d and %d'
5446 % (wd_key.lineno, w_key.lineno))
5447 last_key = wd_key.s
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205448
Sam Maiera6e76d72022-02-11 21:43:505449 i = i + 1
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205450
5451
Sergey Ulanov4af16052018-11-08 02:41:465452def _CheckWATCHLISTSSyntax(expression, input_api):
Sam Maiera6e76d72022-02-11 21:43:505453 ast = input_api.ast
5454 if not isinstance(expression, ast.Expression):
5455 return 'WATCHLISTS file must contain a valid expression'
5456 dictionary = expression.body
5457 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
5458 return 'WATCHLISTS file must have single dict with exactly two entries'
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205459
Sam Maiera6e76d72022-02-11 21:43:505460 first_key = dictionary.keys[0]
5461 first_value = dictionary.values[0]
5462 second_key = dictionary.keys[1]
5463 second_value = dictionary.values[1]
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205464
Sam Maiera6e76d72022-02-11 21:43:505465 if (not isinstance(first_key, ast.Str)
5466 or first_key.s != 'WATCHLIST_DEFINITIONS'
5467 or not isinstance(first_value, ast.Dict)):
5468 return ('The first entry of the dict in WATCHLISTS file must be '
5469 'WATCHLIST_DEFINITIONS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205470
Sam Maiera6e76d72022-02-11 21:43:505471 if (not isinstance(second_key, ast.Str) or second_key.s != 'WATCHLISTS'
5472 or not isinstance(second_value, ast.Dict)):
5473 return ('The second entry of the dict in WATCHLISTS file must be '
5474 'WATCHLISTS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:205475
Sam Maiera6e76d72022-02-11 21:43:505476 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:135477
5478
Saagar Sanghavifceeaae2020-08-12 16:40:365479def CheckWATCHLISTS(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505480 for f in input_api.AffectedFiles(include_deletes=False):
5481 if f.LocalPath() == 'WATCHLISTS':
5482 contents = input_api.ReadFile(f, 'r')
Takeshi Yoshinoe387aa32017-08-02 13:16:135483
Sam Maiera6e76d72022-02-11 21:43:505484 try:
5485 # First, make sure that it can be evaluated.
5486 input_api.ast.literal_eval(contents)
5487 # Get an AST tree for it and scan the tree for detailed style checking.
5488 expression = input_api.ast.parse(contents,
5489 filename='WATCHLISTS',
5490 mode='eval')
5491 except ValueError as e:
5492 return [
5493 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5494 long_text=repr(e))
5495 ]
5496 except SyntaxError as e:
5497 return [
5498 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5499 long_text=repr(e))
5500 ]
5501 except TypeError as e:
5502 return [
5503 output_api.PresubmitError('Cannot parse WATCHLISTS file',
5504 long_text=repr(e))
5505 ]
Takeshi Yoshinoe387aa32017-08-02 13:16:135506
Sam Maiera6e76d72022-02-11 21:43:505507 result = _CheckWATCHLISTSSyntax(expression, input_api)
5508 if result is not None:
5509 return [output_api.PresubmitError(result)]
5510 break
Takeshi Yoshinoe387aa32017-08-02 13:16:135511
Sam Maiera6e76d72022-02-11 21:43:505512 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:135513
Sean Kaucb7c9b32022-10-25 21:25:525514def CheckGnRebasePath(input_api, output_api):
5515 """Checks that target_gen_dir is not used wtih "//" in rebase_path().
5516
5517 Developers should use root_build_dir instead of "//" when using target_gen_dir because
5518 Chromium is sometimes built outside of the source tree.
5519 """
5520
5521 def gn_files(f):
5522 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
5523
5524 rebase_path_regex = input_api.re.compile(r'rebase_path\(("\$target_gen_dir"|target_gen_dir), ("/"|"//")\)')
5525 problems = []
5526 for f in input_api.AffectedSourceFiles(gn_files):
5527 for line_num, line in f.ChangedContents():
5528 if rebase_path_regex.search(line):
5529 problems.append(
5530 'Absolute path in rebase_path() in %s:%d' %
5531 (f.LocalPath(), line_num))
5532
5533 if problems:
5534 return [
5535 output_api.PresubmitPromptWarning(
5536 'Using an absolute path in rebase_path()',
5537 items=sorted(problems),
5538 long_text=(
5539 'rebase_path() should use root_build_dir instead of "/" ',
5540 'since builds can be initiated from outside of the source ',
5541 'root.'))
5542 ]
5543 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:135544
Andrew Grieve1b290e4a22020-11-24 20:07:015545def CheckGnGlobForward(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505546 """Checks that forward_variables_from(invoker, "*") follows best practices.
Andrew Grieve1b290e4a22020-11-24 20:07:015547
Sam Maiera6e76d72022-02-11 21:43:505548 As documented at //build/docs/writing_gn_templates.md
5549 """
Andrew Grieve1b290e4a22020-11-24 20:07:015550
Sam Maiera6e76d72022-02-11 21:43:505551 def gn_files(f):
5552 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
Andrew Grieve1b290e4a22020-11-24 20:07:015553
Sam Maiera6e76d72022-02-11 21:43:505554 problems = []
5555 for f in input_api.AffectedSourceFiles(gn_files):
5556 for line_num, line in f.ChangedContents():
5557 if 'forward_variables_from(invoker, "*")' in line:
5558 problems.append(
5559 'Bare forward_variables_from(invoker, "*") in %s:%d' %
5560 (f.LocalPath(), line_num))
5561
5562 if problems:
5563 return [
5564 output_api.PresubmitPromptWarning(
5565 'forward_variables_from("*") without exclusions',
5566 items=sorted(problems),
5567 long_text=(
Gao Shenga79ebd42022-08-08 17:25:595568 'The variables "visibility" and "test_only" should be '
Sam Maiera6e76d72022-02-11 21:43:505569 'explicitly listed in forward_variables_from(). For more '
5570 'details, see:\n'
5571 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
5572 'build/docs/writing_gn_templates.md'
5573 '#Using-forward_variables_from'))
5574 ]
5575 return []
Andrew Grieve1b290e4a22020-11-24 20:07:015576
Saagar Sanghavifceeaae2020-08-12 16:40:365577def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505578 """Checks that newly added header files have corresponding GN changes.
5579 Note that this is only a heuristic. To be precise, run script:
5580 build/check_gn_headers.py.
5581 """
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195582
Sam Maiera6e76d72022-02-11 21:43:505583 def headers(f):
5584 return input_api.FilterSourceFile(
5585 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195586
Sam Maiera6e76d72022-02-11 21:43:505587 new_headers = []
5588 for f in input_api.AffectedSourceFiles(headers):
5589 if f.Action() != 'A':
5590 continue
5591 new_headers.append(f.LocalPath())
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195592
Sam Maiera6e76d72022-02-11 21:43:505593 def gn_files(f):
5594 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195595
Sam Maiera6e76d72022-02-11 21:43:505596 all_gn_changed_contents = ''
5597 for f in input_api.AffectedSourceFiles(gn_files):
5598 for _, line in f.ChangedContents():
5599 all_gn_changed_contents += line
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195600
Sam Maiera6e76d72022-02-11 21:43:505601 problems = []
5602 for header in new_headers:
5603 basename = input_api.os_path.basename(header)
5604 if basename not in all_gn_changed_contents:
5605 problems.append(header)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195606
Sam Maiera6e76d72022-02-11 21:43:505607 if problems:
5608 return [
5609 output_api.PresubmitPromptWarning(
5610 'Missing GN changes for new header files',
5611 items=sorted(problems),
5612 long_text=
5613 'Please double check whether newly added header files need '
5614 'corresponding changes in gn or gni files.\nThis checking is only a '
5615 'heuristic. Run build/check_gn_headers.py to be precise.\n'
5616 'Read https://crbug.com/661774 for more info.')
5617 ]
5618 return []
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195619
5620
Saagar Sanghavifceeaae2020-08-12 16:40:365621def CheckCorrectProductNameInMessages(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505622 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
Michael Giuffridad3bc8672018-10-25 22:48:025623
Sam Maiera6e76d72022-02-11 21:43:505624 This assumes we won't intentionally reference one product from the other
5625 product.
5626 """
5627 all_problems = []
5628 test_cases = [{
5629 "filename_postfix": "google_chrome_strings.grd",
5630 "correct_name": "Chrome",
5631 "incorrect_name": "Chromium",
5632 }, {
Thiago Perrotta099034f2023-06-05 18:10:205633 "filename_postfix": "google_chrome_strings.grd",
5634 "correct_name": "Chrome",
5635 "incorrect_name": "Chrome for Testing",
5636 }, {
Sam Maiera6e76d72022-02-11 21:43:505637 "filename_postfix": "chromium_strings.grd",
5638 "correct_name": "Chromium",
5639 "incorrect_name": "Chrome",
5640 }]
Michael Giuffridad3bc8672018-10-25 22:48:025641
Sam Maiera6e76d72022-02-11 21:43:505642 for test_case in test_cases:
5643 problems = []
5644 filename_filter = lambda x: x.LocalPath().endswith(test_case[
5645 "filename_postfix"])
Michael Giuffridad3bc8672018-10-25 22:48:025646
Sam Maiera6e76d72022-02-11 21:43:505647 # Check each new line. Can yield false positives in multiline comments, but
5648 # easier than trying to parse the XML because messages can have nested
5649 # children, and associating message elements with affected lines is hard.
5650 for f in input_api.AffectedSourceFiles(filename_filter):
5651 for line_num, line in f.ChangedContents():
5652 if "<message" in line or "<!--" in line or "-->" in line:
5653 continue
5654 if test_case["incorrect_name"] in line:
Thiago Perrotta099034f2023-06-05 18:10:205655 # Chrome for Testing is a special edge case: https://goo.gle/chrome-for-testing#bookmark=id.n1rat320av91
5656 if (test_case["correct_name"] == "Chromium" and line.count("Chrome") == line.count("Chrome for Testing")):
5657 continue
Sam Maiera6e76d72022-02-11 21:43:505658 problems.append("Incorrect product name in %s:%d" %
5659 (f.LocalPath(), line_num))
Michael Giuffridad3bc8672018-10-25 22:48:025660
Sam Maiera6e76d72022-02-11 21:43:505661 if problems:
5662 message = (
5663 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
5664 % (test_case["correct_name"], test_case["correct_name"],
5665 test_case["incorrect_name"]))
5666 all_problems.append(
5667 output_api.PresubmitPromptWarning(message, items=problems))
Michael Giuffridad3bc8672018-10-25 22:48:025668
Sam Maiera6e76d72022-02-11 21:43:505669 return all_problems
Michael Giuffridad3bc8672018-10-25 22:48:025670
5671
Saagar Sanghavifceeaae2020-08-12 16:40:365672def CheckForTooLargeFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505673 """Avoid large files, especially binary files, in the repository since
5674 git doesn't scale well for those. They will be in everyone's repo
5675 clones forever, forever making Chromium slower to clone and work
5676 with."""
Daniel Bratell93eb6c62019-04-29 20:13:365677
Sam Maiera6e76d72022-02-11 21:43:505678 # Uploading files to cloud storage is not trivial so we don't want
5679 # to set the limit too low, but the upper limit for "normal" large
5680 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
5681 # anything over 20 MB is exceptional.
Bruce Dawsonbb414db2022-12-27 20:21:255682 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024
Daniel Bratell93eb6c62019-04-29 20:13:365683
Sam Maiera6e76d72022-02-11 21:43:505684 too_large_files = []
5685 for f in input_api.AffectedFiles():
5686 # Check both added and modified files (but not deleted files).
5687 if f.Action() in ('A', 'M'):
5688 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Joe DeBlasio10a832f2023-04-21 20:20:185689 if size > TOO_LARGE_FILE_SIZE_LIMIT:
Sam Maiera6e76d72022-02-11 21:43:505690 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
Daniel Bratell93eb6c62019-04-29 20:13:365691
Sam Maiera6e76d72022-02-11 21:43:505692 if too_large_files:
5693 message = (
5694 'Do not commit large files to git since git scales badly for those.\n'
5695 +
5696 'Instead put the large files in cloud storage and use DEPS to\n' +
5697 'fetch them.\n' + '\n'.join(too_large_files))
5698 return [
5699 output_api.PresubmitError('Too large files found in commit',
5700 long_text=message + '\n')
5701 ]
5702 else:
5703 return []
Daniel Bratell93eb6c62019-04-29 20:13:365704
Max Morozb47503b2019-08-08 21:03:275705
Saagar Sanghavifceeaae2020-08-12 16:40:365706def CheckFuzzTargetsOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505707 """Checks specific for fuzz target sources."""
5708 EXPORTED_SYMBOLS = [
5709 'LLVMFuzzerInitialize',
5710 'LLVMFuzzerCustomMutator',
5711 'LLVMFuzzerCustomCrossOver',
5712 'LLVMFuzzerMutate',
5713 ]
Max Morozb47503b2019-08-08 21:03:275714
Sam Maiera6e76d72022-02-11 21:43:505715 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
Max Morozb47503b2019-08-08 21:03:275716
Sam Maiera6e76d72022-02-11 21:43:505717 def FilterFile(affected_file):
5718 """Ignore libFuzzer source code."""
5719 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
Bruce Dawson40fece62022-09-16 19:58:315720 files_to_skip = r"^third_party/libFuzzer"
Max Morozb47503b2019-08-08 21:03:275721
Sam Maiera6e76d72022-02-11 21:43:505722 return input_api.FilterSourceFile(affected_file,
5723 files_to_check=[files_to_check],
5724 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:275725
Sam Maiera6e76d72022-02-11 21:43:505726 files_with_missing_header = []
5727 for f in input_api.AffectedSourceFiles(FilterFile):
5728 contents = input_api.ReadFile(f, 'r')
5729 if REQUIRED_HEADER in contents:
5730 continue
Max Morozb47503b2019-08-08 21:03:275731
Sam Maiera6e76d72022-02-11 21:43:505732 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
5733 files_with_missing_header.append(f.LocalPath())
Max Morozb47503b2019-08-08 21:03:275734
Sam Maiera6e76d72022-02-11 21:43:505735 if not files_with_missing_header:
5736 return []
Max Morozb47503b2019-08-08 21:03:275737
Sam Maiera6e76d72022-02-11 21:43:505738 long_text = (
5739 'If you define any of the libFuzzer optional functions (%s), it is '
5740 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
5741 'work incorrectly on Mac (crbug.com/687076).\nNote that '
5742 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
5743 'to access command line arguments passed to the fuzzer. Instead, prefer '
5744 'static initialization and shared resources as documented in '
5745 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
5746 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n'
5747 % (', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER))
Max Morozb47503b2019-08-08 21:03:275748
Sam Maiera6e76d72022-02-11 21:43:505749 return [
5750 output_api.PresubmitPromptWarning(message="Missing '%s' in:" %
5751 REQUIRED_HEADER,
5752 items=files_with_missing_header,
5753 long_text=long_text)
5754 ]
Max Morozb47503b2019-08-08 21:03:275755
5756
Mohamed Heikald048240a2019-11-12 16:57:375757def _CheckNewImagesWarning(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505758 """
5759 Warns authors who add images into the repo to make sure their images are
5760 optimized before committing.
5761 """
5762 images_added = False
5763 image_paths = []
5764 errors = []
5765 filter_lambda = lambda x: input_api.FilterSourceFile(
5766 x,
5767 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
5768 DEFAULT_FILES_TO_SKIP),
5769 files_to_check=[r'.*\/(drawable|mipmap)'])
5770 for f in input_api.AffectedFiles(include_deletes=False,
5771 file_filter=filter_lambda):
5772 local_path = f.LocalPath().lower()
5773 if any(
5774 local_path.endswith(extension)
5775 for extension in _IMAGE_EXTENSIONS):
5776 images_added = True
5777 image_paths.append(f)
5778 if images_added:
5779 errors.append(
5780 output_api.PresubmitPromptWarning(
5781 'It looks like you are trying to commit some images. If these are '
5782 'non-test-only images, please make sure to read and apply the tips in '
5783 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
5784 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
5785 'FYI only and will not block your CL on the CQ.', image_paths))
5786 return errors
Mohamed Heikald048240a2019-11-12 16:57:375787
5788
Saagar Sanghavifceeaae2020-08-12 16:40:365789def ChecksAndroidSpecificOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505790 """Groups upload checks that target android code."""
5791 results = []
5792 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
5793 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
5794 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
5795 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505796 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
5797 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
5798 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
5799 results.extend(_CheckNewImagesWarning(input_api, output_api))
5800 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
5801 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
5802 return results
5803
Becky Zhou7c69b50992018-12-10 19:37:575804
Saagar Sanghavifceeaae2020-08-12 16:40:365805def ChecksAndroidSpecificOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505806 """Groups commit checks that target android code."""
5807 results = []
5808 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
5809 return results
dgnaa68d5e2015-06-10 10:08:225810
Chris Hall59f8d0c72020-05-01 07:31:195811# TODO(chrishall): could we additionally match on any path owned by
5812# ui/accessibility/OWNERS ?
5813_ACCESSIBILITY_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:315814 r"^chrome/browser.*/accessibility/",
5815 r"^chrome/browser/extensions/api/automation.*/",
5816 r"^chrome/renderer/extensions/accessibility_.*",
5817 r"^chrome/tests/data/accessibility/",
5818 r"^content/browser/accessibility/",
5819 r"^content/renderer/accessibility/",
5820 r"^content/tests/data/accessibility/",
5821 r"^extensions/renderer/api/automation/",
Katie Dektar58ef07b2022-09-27 13:19:175822 r"^services/accessibility/",
Abigail Klein7a63c572024-02-28 20:45:095823 r"^services/screen_ai/",
Bruce Dawson40fece62022-09-16 19:58:315824 r"^ui/accessibility/",
5825 r"^ui/views/accessibility/",
Chris Hall59f8d0c72020-05-01 07:31:195826)
5827
Saagar Sanghavifceeaae2020-08-12 16:40:365828def CheckAccessibilityRelnotesField(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505829 """Checks that commits to accessibility code contain an AX-Relnotes field in
5830 their commit message."""
Chris Hall59f8d0c72020-05-01 07:31:195831
Sam Maiera6e76d72022-02-11 21:43:505832 def FileFilter(affected_file):
5833 paths = _ACCESSIBILITY_PATHS
5834 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:195835
Sam Maiera6e76d72022-02-11 21:43:505836 # Only consider changes affecting accessibility paths.
5837 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
5838 return []
Akihiro Ota08108e542020-05-20 15:30:535839
Sam Maiera6e76d72022-02-11 21:43:505840 # AX-Relnotes can appear in either the description or the footer.
5841 # When searching the description, require 'AX-Relnotes:' to appear at the
5842 # beginning of a line.
5843 ax_regex = input_api.re.compile('ax-relnotes[:=]')
5844 description_has_relnotes = any(
5845 ax_regex.match(line)
5846 for line in input_api.change.DescriptionText().lower().splitlines())
Chris Hall59f8d0c72020-05-01 07:31:195847
Sam Maiera6e76d72022-02-11 21:43:505848 footer_relnotes = input_api.change.GitFootersFromDescription().get(
5849 'AX-Relnotes', [])
5850 if description_has_relnotes or footer_relnotes:
5851 return []
Chris Hall59f8d0c72020-05-01 07:31:195852
Sam Maiera6e76d72022-02-11 21:43:505853 # TODO(chrishall): link to Relnotes documentation in message.
5854 message = (
5855 "Missing 'AX-Relnotes:' field required for accessibility changes"
5856 "\n please add 'AX-Relnotes: [release notes].' to describe any "
5857 "user-facing changes"
5858 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
5859 "user-facing effects"
5860 "\n if this is confusing or annoying then please contact members "
5861 "of ui/accessibility/OWNERS.")
5862
5863 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:225864
Mark Schillacie5a0be22022-01-19 00:38:395865
5866_ACCESSIBILITY_EVENTS_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315867 r"^content/test/data/accessibility/event/.*\.html",
Mark Schillacie5a0be22022-01-19 00:38:395868)
5869
5870_ACCESSIBILITY_TREE_TEST_PATH = (
Aaron Leventhal267119f2023-08-18 22:45:345871 r"^content/test/data/accessibility/accname/"
5872 ".*-expected-(mac|win|uia-win|auralinux).txt",
5873 r"^content/test/data/accessibility/aria/"
5874 ".*-expected-(mac|win|uia-win|auralinux).txt",
5875 r"^content/test/data/accessibility/css/"
5876 ".*-expected-(mac|win|uia-win|auralinux).txt",
5877 r"^content/test/data/accessibility/event/"
5878 ".*-expected-(mac|win|uia-win|auralinux).txt",
5879 r"^content/test/data/accessibility/html/"
5880 ".*-expected-(mac|win|uia-win|auralinux).txt",
Mark Schillacie5a0be22022-01-19 00:38:395881)
5882
5883_ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315884 r"^.*/WebContentsAccessibilityEventsTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:395885)
5886
5887_ACCESSIBILITY_ANDROID_TREE_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315888 r"^.*/WebContentsAccessibilityTreeTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:395889)
5890
5891def CheckAccessibilityEventsTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505892 """Checks that commits that include a newly added, renamed/moved, or deleted
5893 test in the DumpAccessibilityEventsTest suite also includes a corresponding
5894 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:395895
Sam Maiera6e76d72022-02-11 21:43:505896 def FilePathFilter(affected_file):
5897 paths = _ACCESSIBILITY_EVENTS_TEST_PATH
5898 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395899
Sam Maiera6e76d72022-02-11 21:43:505900 def AndroidFilePathFilter(affected_file):
5901 paths = _ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH
5902 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395903
Sam Maiera6e76d72022-02-11 21:43:505904 # Only consider changes in the events test data path with html type.
5905 if not any(
5906 input_api.AffectedFiles(include_deletes=True,
5907 file_filter=FilePathFilter)):
5908 return []
Mark Schillacie5a0be22022-01-19 00:38:395909
Sam Maiera6e76d72022-02-11 21:43:505910 # If the commit contains any change to the Android test file, ignore.
5911 if any(
5912 input_api.AffectedFiles(include_deletes=True,
5913 file_filter=AndroidFilePathFilter)):
5914 return []
Mark Schillacie5a0be22022-01-19 00:38:395915
Sam Maiera6e76d72022-02-11 21:43:505916 # Only consider changes that are adding/renaming or deleting a file
5917 message = []
5918 for f in input_api.AffectedFiles(include_deletes=True,
5919 file_filter=FilePathFilter):
Aaron Leventhal267119f2023-08-18 22:45:345920 if f.Action() == 'A':
Sam Maiera6e76d72022-02-11 21:43:505921 message = (
Aaron Leventhal267119f2023-08-18 22:45:345922 "It appears that you are adding platform expectations for a"
Aaron Leventhal0de81072023-08-21 21:26:525923 "\ndump_accessibility_events* test, but have not included"
Sam Maiera6e76d72022-02-11 21:43:505924 "\na corresponding change for Android."
Aaron Leventhal267119f2023-08-18 22:45:345925 "\nPlease include the test from:"
Sam Maiera6e76d72022-02-11 21:43:505926 "\n content/public/android/javatests/src/org/chromium/"
5927 "content/browser/accessibility/"
5928 "WebContentsAccessibilityEventsTest.java"
5929 "\nIf this message is confusing or annoying, please contact"
5930 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:395931
Sam Maiera6e76d72022-02-11 21:43:505932 # If no message was set, return empty.
5933 if not len(message):
5934 return []
5935
5936 return [output_api.PresubmitPromptWarning(message)]
5937
Mark Schillacie5a0be22022-01-19 00:38:395938
5939def CheckAccessibilityTreeTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505940 """Checks that commits that include a newly added, renamed/moved, or deleted
5941 test in the DumpAccessibilityTreeTest suite also includes a corresponding
5942 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:395943
Sam Maiera6e76d72022-02-11 21:43:505944 def FilePathFilter(affected_file):
5945 paths = _ACCESSIBILITY_TREE_TEST_PATH
5946 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395947
Sam Maiera6e76d72022-02-11 21:43:505948 def AndroidFilePathFilter(affected_file):
5949 paths = _ACCESSIBILITY_ANDROID_TREE_TEST_PATH
5950 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395951
Sam Maiera6e76d72022-02-11 21:43:505952 # Only consider changes in the various tree test data paths with html type.
5953 if not any(
5954 input_api.AffectedFiles(include_deletes=True,
5955 file_filter=FilePathFilter)):
5956 return []
Mark Schillacie5a0be22022-01-19 00:38:395957
Sam Maiera6e76d72022-02-11 21:43:505958 # If the commit contains any change to the Android test file, ignore.
5959 if any(
5960 input_api.AffectedFiles(include_deletes=True,
5961 file_filter=AndroidFilePathFilter)):
5962 return []
Mark Schillacie5a0be22022-01-19 00:38:395963
Sam Maiera6e76d72022-02-11 21:43:505964 # Only consider changes that are adding/renaming or deleting a file
5965 message = []
5966 for f in input_api.AffectedFiles(include_deletes=True,
5967 file_filter=FilePathFilter):
Aaron Leventhal0de81072023-08-21 21:26:525968 if f.Action() == 'A':
Sam Maiera6e76d72022-02-11 21:43:505969 message = (
Aaron Leventhal0de81072023-08-21 21:26:525970 "It appears that you are adding platform expectations for a"
5971 "\ndump_accessibility_tree* test, but have not included"
Sam Maiera6e76d72022-02-11 21:43:505972 "\na corresponding change for Android."
5973 "\nPlease include (or remove) the test from:"
5974 "\n content/public/android/javatests/src/org/chromium/"
5975 "content/browser/accessibility/"
5976 "WebContentsAccessibilityTreeTest.java"
5977 "\nIf this message is confusing or annoying, please contact"
5978 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:395979
Sam Maiera6e76d72022-02-11 21:43:505980 # If no message was set, return empty.
5981 if not len(message):
5982 return []
5983
5984 return [output_api.PresubmitPromptWarning(message)]
Mark Schillacie5a0be22022-01-19 00:38:395985
5986
Bruce Dawson33806592022-11-16 01:44:515987def CheckEsLintConfigChanges(input_api, output_api):
5988 """Suggest using "git cl presubmit --files" when .eslintrc.js files are
5989 modified. This is important because enabling an error in .eslintrc.js can
5990 trigger errors in any .js or .ts files in its directory, leading to hidden
5991 presubmit errors."""
5992 results = []
5993 eslint_filter = lambda f: input_api.FilterSourceFile(
5994 f, files_to_check=[r'.*\.eslintrc\.js$'])
5995 for f in input_api.AffectedFiles(include_deletes=False,
5996 file_filter=eslint_filter):
5997 local_dir = input_api.os_path.dirname(f.LocalPath())
5998 # Use / characters so that the commands printed work on any OS.
5999 local_dir = local_dir.replace(input_api.os_path.sep, '/')
6000 if local_dir:
6001 local_dir += '/'
6002 results.append(
6003 output_api.PresubmitNotifyResult(
6004 '%(file)s modified. Consider running \'git cl presubmit --files '
6005 '"%(dir)s*.js;%(dir)s*.ts"\' in order to check and fix the affected '
6006 'files before landing this change.' %
6007 { 'file' : f.LocalPath(), 'dir' : local_dir}))
6008 return results
6009
6010
seanmccullough4a9356252021-04-08 19:54:096011# string pattern, sequence of strings to show when pattern matches,
6012# error flag. True if match is a presubmit error, otherwise it's a warning.
6013_NON_INCLUSIVE_TERMS = (
6014 (
6015 # Note that \b pattern in python re is pretty particular. In this
6016 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
6017 # ...' will not. This may require some tweaking to catch these cases
6018 # without triggering a lot of false positives. Leaving it naive and
6019 # less matchy for now.
Josip Sokcevic9d2806a02023-12-13 03:04:026020 r'/(?i)\b((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:096021 (
6022 'Please don\'t use blacklist, whitelist, ' # nocheck
6023 'or slave in your', # nocheck
6024 'code and make every effort to use other terms. Using "// nocheck"',
6025 '"# nocheck" or "<!-- nocheck -->"',
6026 'at the end of the offending line will bypass this PRESUBMIT error',
6027 'but avoid using this whenever possible. Reach out to',
6028 '[email protected] if you have questions'),
6029 True),)
6030
Saagar Sanghavifceeaae2020-08-12 16:40:366031def ChecksCommon(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506032 """Checks common to both upload and commit."""
6033 results = []
Eric Boren6fd2b932018-01-25 15:05:086034 results.extend(
Sam Maiera6e76d72022-02-11 21:43:506035 input_api.canned_checks.PanProjectChecks(
6036 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:086037
Sam Maiera6e76d72022-02-11 21:43:506038 author = input_api.change.author_email
6039 if author and author not in _KNOWN_ROBOTS:
6040 results.extend(
6041 input_api.canned_checks.CheckAuthorizedAuthor(
6042 input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:246043
Sam Maiera6e76d72022-02-11 21:43:506044 results.extend(
6045 input_api.canned_checks.CheckChangeHasNoTabs(
6046 input_api,
6047 output_api,
6048 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
6049 results.extend(
6050 input_api.RunTests(
6051 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Edward Lesmesce51df52020-08-04 22:10:176052
Bruce Dawsonc8054482022-03-28 15:33:376053 dirmd = 'dirmd.bat' if input_api.is_windows else 'dirmd'
Sam Maiera6e76d72022-02-11 21:43:506054 dirmd_bin = input_api.os_path.join(input_api.PresubmitLocalPath(),
Bruce Dawsonc8054482022-03-28 15:33:376055 'third_party', 'depot_tools', dirmd)
Sam Maiera6e76d72022-02-11 21:43:506056 results.extend(
6057 input_api.RunTests(
6058 input_api.canned_checks.CheckDirMetadataFormat(
6059 input_api, output_api, dirmd_bin)))
6060 results.extend(
6061 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
6062 input_api, output_api))
6063 results.extend(
6064 input_api.canned_checks.CheckNoNewMetadataInOwners(
6065 input_api, output_api))
6066 results.extend(
6067 input_api.canned_checks.CheckInclusiveLanguage(
6068 input_api,
6069 output_api,
6070 excluded_directories_relative_path=[
6071 'infra', 'inclusive_language_presubmit_exempt_dirs.txt'
6072 ],
6073 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Dirk Prankee3c9c62d2021-05-18 18:35:596074
Aleksey Khoroshilov2978c942022-06-13 16:14:126075 presubmit_py_filter = lambda f: input_api.FilterSourceFile(
Bruce Dawson696963f2022-09-13 01:15:476076 f, files_to_check=[r'.*PRESUBMIT\.py$'])
Aleksey Khoroshilov2978c942022-06-13 16:14:126077 for f in input_api.AffectedFiles(include_deletes=False,
6078 file_filter=presubmit_py_filter):
6079 full_path = input_api.os_path.dirname(f.AbsoluteLocalPath())
6080 test_file = input_api.os_path.join(full_path, 'PRESUBMIT_test.py')
6081 # The PRESUBMIT.py file (and the directory containing it) might have
6082 # been affected by being moved or removed, so only try to run the tests
6083 # if they still exist.
6084 if not input_api.os_path.exists(test_file):
6085 continue
Sam Maiera6e76d72022-02-11 21:43:506086
Aleksey Khoroshilov2978c942022-06-13 16:14:126087 results.extend(
6088 input_api.canned_checks.RunUnitTestsInDirectory(
6089 input_api,
6090 output_api,
6091 full_path,
Takuto Ikuta40def482023-06-02 02:23:496092 files_to_check=[r'^PRESUBMIT_test\.py$']))
Sam Maiera6e76d72022-02-11 21:43:506093 return results
[email protected]1f7b4172010-01-28 01:17:346094
[email protected]b337cb5b2011-01-23 21:24:056095
Saagar Sanghavifceeaae2020-08-12 16:40:366096def CheckPatchFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506097 problems = [
6098 f.LocalPath() for f in input_api.AffectedFiles()
6099 if f.LocalPath().endswith(('.orig', '.rej'))
6100 ]
6101 # Cargo.toml.orig files are part of third-party crates downloaded from
6102 # crates.io and should be included.
6103 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
6104 if problems:
6105 return [
6106 output_api.PresubmitError("Don't commit .rej and .orig files.",
6107 problems)
6108 ]
6109 else:
6110 return []
[email protected]b8079ae4a2012-12-05 19:56:496111
6112
Saagar Sanghavifceeaae2020-08-12 16:40:366113def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506114 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
6115 macro_re = input_api.re.compile(
6116 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
6117 include_re = input_api.re.compile(r'^#include\s+"build/build_config.h"',
6118 input_api.re.MULTILINE)
6119 extension_re = input_api.re.compile(r'\.[a-z]+$')
6120 errors = []
Bruce Dawsonf7679202022-08-09 20:24:006121 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:506122 for f in input_api.AffectedFiles(include_deletes=False):
Bruce Dawsonf7679202022-08-09 20:24:006123 # The build-config macros are allowed to be used in build_config.h
6124 # without including itself.
6125 if f.LocalPath() == config_h_file:
6126 continue
Sam Maiera6e76d72022-02-11 21:43:506127 if not f.LocalPath().endswith(
6128 ('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
6129 continue
Arthur Sonzognia3dec412024-04-29 12:05:376130
Sam Maiera6e76d72022-02-11 21:43:506131 found_line_number = None
6132 found_macro = None
6133 all_lines = input_api.ReadFile(f, 'r').splitlines()
6134 for line_num, line in enumerate(all_lines):
6135 match = macro_re.search(line)
6136 if match:
6137 found_line_number = line_num
6138 found_macro = match.group(2)
6139 break
6140 if not found_line_number:
6141 continue
Kent Tamura5a8755d2017-06-29 23:37:076142
Sam Maiera6e76d72022-02-11 21:43:506143 found_include_line = -1
6144 for line_num, line in enumerate(all_lines):
6145 if include_re.search(line):
6146 found_include_line = line_num
6147 break
6148 if found_include_line >= 0 and found_include_line < found_line_number:
6149 continue
Kent Tamura5a8755d2017-06-29 23:37:076150
Sam Maiera6e76d72022-02-11 21:43:506151 if not f.LocalPath().endswith('.h'):
6152 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
6153 try:
6154 content = input_api.ReadFile(primary_header_path, 'r')
6155 if include_re.search(content):
6156 continue
6157 except IOError:
6158 pass
6159 errors.append('%s:%d %s macro is used without first including build/'
6160 'build_config.h.' %
6161 (f.LocalPath(), found_line_number, found_macro))
6162 if errors:
6163 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
6164 return []
Kent Tamura5a8755d2017-06-29 23:37:076165
6166
Lei Zhang1c12a22f2021-05-12 11:28:456167def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506168 stl_include_re = input_api.re.compile(r'^#include\s+<('
6169 r'algorithm|'
6170 r'array|'
6171 r'limits|'
6172 r'list|'
6173 r'map|'
6174 r'memory|'
6175 r'queue|'
6176 r'set|'
6177 r'string|'
6178 r'unordered_map|'
6179 r'unordered_set|'
6180 r'utility|'
6181 r'vector)>')
6182 std_namespace_re = input_api.re.compile(r'std::')
6183 errors = []
6184 for f in input_api.AffectedFiles():
6185 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
6186 continue
Lei Zhang1c12a22f2021-05-12 11:28:456187
Sam Maiera6e76d72022-02-11 21:43:506188 uses_std_namespace = False
6189 has_stl_include = False
6190 for line in f.NewContents():
6191 if has_stl_include and uses_std_namespace:
6192 break
Lei Zhang1c12a22f2021-05-12 11:28:456193
Sam Maiera6e76d72022-02-11 21:43:506194 if not has_stl_include and stl_include_re.search(line):
6195 has_stl_include = True
6196 continue
Lei Zhang1c12a22f2021-05-12 11:28:456197
Bruce Dawson4a5579a2022-04-08 17:11:366198 if not uses_std_namespace and (std_namespace_re.search(line)
6199 or 'no-std-usage-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:506200 uses_std_namespace = True
6201 continue
Lei Zhang1c12a22f2021-05-12 11:28:456202
Sam Maiera6e76d72022-02-11 21:43:506203 if has_stl_include and not uses_std_namespace:
6204 errors.append(
6205 '%s: Includes STL header(s) but does not reference std::' %
6206 f.LocalPath())
6207 if errors:
6208 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
6209 return []
Lei Zhang1c12a22f2021-05-12 11:28:456210
6211
Xiaohan Wang42d96c22022-01-20 17:23:116212def _CheckForDeprecatedOSMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:506213 """Check for sensible looking, totally invalid OS macros."""
6214 preprocessor_statement = input_api.re.compile(r'^\s*#')
6215 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
6216 results = []
6217 for lnum, line in f.ChangedContents():
6218 if preprocessor_statement.search(line):
6219 for match in os_macro.finditer(line):
6220 results.append(
6221 ' %s:%d: %s' %
6222 (f.LocalPath(), lnum, 'defined(OS_' + match.group(1) +
6223 ') -> BUILDFLAG(IS_' + match.group(1) + ')'))
6224 return results
[email protected]b00342e7f2013-03-26 16:21:546225
6226
Xiaohan Wang42d96c22022-01-20 17:23:116227def CheckForDeprecatedOSMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506228 """Check all affected files for invalid OS macros."""
6229 bad_macros = []
Bruce Dawsonf7679202022-08-09 20:24:006230 # The OS_ macros are allowed to be used in build/build_config.h.
6231 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:506232 for f in input_api.AffectedSourceFiles(None):
Bruce Dawsonf7679202022-08-09 20:24:006233 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')) \
6234 and f.LocalPath() != config_h_file:
Sam Maiera6e76d72022-02-11 21:43:506235 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
[email protected]b00342e7f2013-03-26 16:21:546236
Sam Maiera6e76d72022-02-11 21:43:506237 if not bad_macros:
6238 return []
[email protected]b00342e7f2013-03-26 16:21:546239
Sam Maiera6e76d72022-02-11 21:43:506240 return [
6241 output_api.PresubmitError(
6242 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
6243 'defined in build_config.h):', bad_macros)
6244 ]
[email protected]b00342e7f2013-03-26 16:21:546245
lliabraa35bab3932014-10-01 12:16:446246
6247def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:506248 """Check all affected files for invalid "if defined" macros."""
6249 ALWAYS_DEFINED_MACROS = (
6250 "TARGET_CPU_PPC",
6251 "TARGET_CPU_PPC64",
6252 "TARGET_CPU_68K",
6253 "TARGET_CPU_X86",
6254 "TARGET_CPU_ARM",
6255 "TARGET_CPU_MIPS",
6256 "TARGET_CPU_SPARC",
6257 "TARGET_CPU_ALPHA",
6258 "TARGET_IPHONE_SIMULATOR",
6259 "TARGET_OS_EMBEDDED",
6260 "TARGET_OS_IPHONE",
6261 "TARGET_OS_MAC",
6262 "TARGET_OS_UNIX",
6263 "TARGET_OS_WIN32",
6264 )
6265 ifdef_macro = input_api.re.compile(
6266 r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
6267 results = []
6268 for lnum, line in f.ChangedContents():
6269 for match in ifdef_macro.finditer(line):
6270 if match.group(1) in ALWAYS_DEFINED_MACROS:
6271 always_defined = ' %s is always defined. ' % match.group(1)
6272 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
6273 results.append(
6274 ' %s:%d %s\n\t%s' %
6275 (f.LocalPath(), lnum, always_defined, did_you_mean))
6276 return results
lliabraa35bab3932014-10-01 12:16:446277
6278
Saagar Sanghavifceeaae2020-08-12 16:40:366279def CheckForInvalidIfDefinedMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506280 """Check all affected files for invalid "if defined" macros."""
Arthur Sonzogni4fd14fd2024-06-02 18:42:526281 SKIPPED_PATHS = [
6282 'base/allocator/partition_allocator/src/partition_alloc/build_config.h',
6283 'build/build_config.h',
6284 'third_party/abseil-cpp/',
6285 'third_party/sqlite/',
6286 ]
6287 def affected_files_filter(f):
6288 # Normalize the local path to Linux-style path separators so that the
6289 # path comparisons work on Windows as well.
6290 path = f.LocalPath().replace('\\', '/')
6291
6292 for skipped_path in SKIPPED_PATHS:
6293 if path.startswith(skipped_path):
6294 return False
6295
6296 return path.endswith(('.h', '.c', '.cc', '.m', '.mm'))
6297
Sam Maiera6e76d72022-02-11 21:43:506298 bad_macros = []
Arthur Sonzogni4fd14fd2024-06-02 18:42:526299 for f in input_api.AffectedSourceFiles(affected_files_filter):
6300 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
lliabraa35bab3932014-10-01 12:16:446301
Sam Maiera6e76d72022-02-11 21:43:506302 if not bad_macros:
6303 return []
lliabraa35bab3932014-10-01 12:16:446304
Sam Maiera6e76d72022-02-11 21:43:506305 return [
6306 output_api.PresubmitError(
6307 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
6308 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
6309 bad_macros)
6310 ]
lliabraa35bab3932014-10-01 12:16:446311
Saagar Sanghavifceeaae2020-08-12 16:40:366312def CheckForIPCRules(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506313 """Check for same IPC rules described in
6314 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
6315 """
6316 base_pattern = r'IPC_ENUM_TRAITS\('
6317 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
6318 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
mlamouria82272622014-09-16 18:45:046319
Sam Maiera6e76d72022-02-11 21:43:506320 problems = []
6321 for f in input_api.AffectedSourceFiles(None):
6322 local_path = f.LocalPath()
6323 if not local_path.endswith('.h'):
6324 continue
6325 for line_number, line in f.ChangedContents():
6326 if inclusion_pattern.search(
6327 line) and not comment_pattern.search(line):
6328 problems.append('%s:%d\n %s' %
6329 (local_path, line_number, line.strip()))
mlamouria82272622014-09-16 18:45:046330
Sam Maiera6e76d72022-02-11 21:43:506331 if problems:
6332 return [
6333 output_api.PresubmitPromptWarning(_IPC_ENUM_TRAITS_DEPRECATED,
6334 problems)
6335 ]
6336 else:
6337 return []
mlamouria82272622014-09-16 18:45:046338
[email protected]b00342e7f2013-03-26 16:21:546339
Saagar Sanghavifceeaae2020-08-12 16:40:366340def CheckForLongPathnames(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506341 """Check to make sure no files being submitted have long paths.
6342 This causes issues on Windows.
6343 """
6344 problems = []
6345 for f in input_api.AffectedTestableFiles():
6346 local_path = f.LocalPath()
6347 # Windows has a path limit of 260 characters. Limit path length to 200 so
6348 # that we have some extra for the prefix on dev machines and the bots.
Weizhong Xia8b461f12024-06-21 21:46:336349 if (local_path.startswith('third_party/blink/web_tests/platform/') and
6350 not local_path.startswith('third_party/blink/web_tests/platform/win')):
6351 # Do not check length of the path for files not used by Windows
6352 continue
Sam Maiera6e76d72022-02-11 21:43:506353 if len(local_path) > 200:
6354 problems.append(local_path)
Stephen Martinis97a394142018-06-07 23:06:056355
Sam Maiera6e76d72022-02-11 21:43:506356 if problems:
6357 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
6358 else:
6359 return []
Stephen Martinis97a394142018-06-07 23:06:056360
6361
Saagar Sanghavifceeaae2020-08-12 16:40:366362def CheckForIncludeGuards(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506363 """Check that header files have proper guards against multiple inclusion.
6364 If a file should not have such guards (and it probably should) then it
Bruce Dawson4a5579a2022-04-08 17:11:366365 should include the string "no-include-guard-because-multiply-included" or
6366 "no-include-guard-because-pch-file".
Sam Maiera6e76d72022-02-11 21:43:506367 """
Daniel Bratell8ba52722018-03-02 16:06:146368
Sam Maiera6e76d72022-02-11 21:43:506369 def is_chromium_header_file(f):
6370 # We only check header files under the control of the Chromium
mikt84d6c712024-03-27 13:29:036371 # project. This excludes:
6372 # - third_party/*, except blink.
6373 # - base/allocator/partition_allocator/: PartitionAlloc is a standalone
6374 # library used outside of Chrome. Includes are referenced from its
6375 # own base directory. It has its own `CheckForIncludeGuards`
6376 # PRESUBMIT.py check.
6377 # - *_message_generator.h: They use include guards in a special,
6378 # non-typical way.
Sam Maiera6e76d72022-02-11 21:43:506379 file_with_path = input_api.os_path.normpath(f.LocalPath())
6380 return (file_with_path.endswith('.h')
6381 and not file_with_path.endswith('_message_generator.h')
Bruce Dawson4c4c2922022-05-02 18:07:336382 and not file_with_path.endswith('com_imported_mstscax.h')
mikt84d6c712024-03-27 13:29:036383 and not file_with_path.startswith('base/allocator/partition_allocator')
Sam Maiera6e76d72022-02-11 21:43:506384 and (not file_with_path.startswith('third_party')
6385 or file_with_path.startswith(
6386 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:146387
Sam Maiera6e76d72022-02-11 21:43:506388 def replace_special_with_underscore(string):
6389 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:146390
Sam Maiera6e76d72022-02-11 21:43:506391 errors = []
Daniel Bratell8ba52722018-03-02 16:06:146392
Sam Maiera6e76d72022-02-11 21:43:506393 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
6394 guard_name = None
6395 guard_line_number = None
6396 seen_guard_end = False
Lei Zhangd84f9512024-05-28 19:43:306397 bypass_checks_at_end_of_file = False
Daniel Bratell8ba52722018-03-02 16:06:146398
Sam Maiera6e76d72022-02-11 21:43:506399 file_with_path = input_api.os_path.normpath(f.LocalPath())
6400 base_file_name = input_api.os_path.splitext(
6401 input_api.os_path.basename(file_with_path))[0]
6402 upper_base_file_name = base_file_name.upper()
Daniel Bratell8ba52722018-03-02 16:06:146403
Sam Maiera6e76d72022-02-11 21:43:506404 expected_guard = replace_special_with_underscore(
6405 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:146406
Sam Maiera6e76d72022-02-11 21:43:506407 # For "path/elem/file_name.h" we should really only accept
6408 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
6409 # are too many (1000+) files with slight deviations from the
6410 # coding style. The most important part is that the include guard
6411 # is there, and that it's unique, not the name so this check is
6412 # forgiving for existing files.
6413 #
6414 # As code becomes more uniform, this could be made stricter.
Daniel Bratell8ba52722018-03-02 16:06:146415
Sam Maiera6e76d72022-02-11 21:43:506416 guard_name_pattern_list = [
6417 # Anything with the right suffix (maybe with an extra _).
6418 r'\w+_H__?',
Daniel Bratell8ba52722018-03-02 16:06:146419
Sam Maiera6e76d72022-02-11 21:43:506420 # To cover include guards with old Blink style.
6421 r'\w+_h',
Daniel Bratell8ba52722018-03-02 16:06:146422
Sam Maiera6e76d72022-02-11 21:43:506423 # Anything including the uppercase name of the file.
6424 r'\w*' + input_api.re.escape(
6425 replace_special_with_underscore(upper_base_file_name)) +
6426 r'\w*',
6427 ]
6428 guard_name_pattern = '|'.join(guard_name_pattern_list)
6429 guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
6430 guard_name_pattern + ')')
Daniel Bratell8ba52722018-03-02 16:06:146431
Sam Maiera6e76d72022-02-11 21:43:506432 for line_number, line in enumerate(f.NewContents()):
Bruce Dawson4a5579a2022-04-08 17:11:366433 if ('no-include-guard-because-multiply-included' in line
6434 or 'no-include-guard-because-pch-file' in line):
Lei Zhangd84f9512024-05-28 19:43:306435 bypass_checks_at_end_of_file = True
Sam Maiera6e76d72022-02-11 21:43:506436 break
Daniel Bratell8ba52722018-03-02 16:06:146437
Sam Maiera6e76d72022-02-11 21:43:506438 if guard_name is None:
6439 match = guard_pattern.match(line)
6440 if match:
6441 guard_name = match.group(1)
6442 guard_line_number = line_number
Daniel Bratell8ba52722018-03-02 16:06:146443
Sam Maiera6e76d72022-02-11 21:43:506444 # We allow existing files to use include guards whose names
6445 # don't match the chromium style guide, but new files should
6446 # get it right.
Bruce Dawson6cc154e2022-04-12 20:39:496447 if guard_name != expected_guard:
Bruce Dawson95eb7562022-09-14 15:27:166448 if f.Action() == 'A': # If file was just 'A'dded
Sam Maiera6e76d72022-02-11 21:43:506449 errors.append(
6450 output_api.PresubmitPromptWarning(
6451 'Header using the wrong include guard name %s'
6452 % guard_name, [
6453 '%s:%d' %
6454 (f.LocalPath(), line_number + 1)
6455 ], 'Expected: %r\nFound: %r' %
6456 (expected_guard, guard_name)))
6457 else:
6458 # The line after #ifndef should have a #define of the same name.
6459 if line_number == guard_line_number + 1:
6460 expected_line = '#define %s' % guard_name
6461 if line != expected_line:
6462 errors.append(
6463 output_api.PresubmitPromptWarning(
6464 'Missing "%s" for include guard' %
6465 expected_line,
6466 ['%s:%d' % (f.LocalPath(), line_number + 1)],
6467 'Expected: %r\nGot: %r' %
6468 (expected_line, line)))
Daniel Bratell8ba52722018-03-02 16:06:146469
Sam Maiera6e76d72022-02-11 21:43:506470 if not seen_guard_end and line == '#endif // %s' % guard_name:
6471 seen_guard_end = True
6472 elif seen_guard_end:
6473 if line.strip() != '':
6474 errors.append(
6475 output_api.PresubmitPromptWarning(
6476 'Include guard %s not covering the whole file'
6477 % (guard_name), [f.LocalPath()]))
6478 break # Nothing else to check and enough to warn once.
Daniel Bratell8ba52722018-03-02 16:06:146479
Lei Zhangd84f9512024-05-28 19:43:306480 if bypass_checks_at_end_of_file:
6481 continue
6482
Sam Maiera6e76d72022-02-11 21:43:506483 if guard_name is None:
6484 errors.append(
6485 output_api.PresubmitPromptWarning(
Bruce Dawson32114b62022-04-11 16:45:496486 'Missing include guard in %s\n'
Sam Maiera6e76d72022-02-11 21:43:506487 'Recommended name: %s\n'
6488 'This check can be disabled by having the string\n'
Bruce Dawson4a5579a2022-04-08 17:11:366489 '"no-include-guard-because-multiply-included" or\n'
6490 '"no-include-guard-because-pch-file" in the header.'
Sam Maiera6e76d72022-02-11 21:43:506491 % (f.LocalPath(), expected_guard)))
Lei Zhangd84f9512024-05-28 19:43:306492 elif not seen_guard_end:
6493 errors.append(
6494 output_api.PresubmitPromptWarning(
6495 'Incorrect or missing include guard #endif in %s\n'
6496 'Recommended #endif comment: // %s'
6497 % (f.LocalPath(), expected_guard)))
Sam Maiera6e76d72022-02-11 21:43:506498
6499 return errors
Daniel Bratell8ba52722018-03-02 16:06:146500
6501
Saagar Sanghavifceeaae2020-08-12 16:40:366502def CheckForWindowsLineEndings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506503 """Check source code and known ascii text files for Windows style line
6504 endings.
6505 """
Bruce Dawson5efbdc652022-04-11 19:29:516506 known_text_files = r'.*\.(txt|html|htm|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:236507
Sam Maiera6e76d72022-02-11 21:43:506508 file_inclusion_pattern = (known_text_files,
6509 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
6510 r'.+%s' % _HEADER_EXTENSIONS)
mostynbb639aca52015-01-07 20:31:236511
Sam Maiera6e76d72022-02-11 21:43:506512 problems = []
6513 source_file_filter = lambda f: input_api.FilterSourceFile(
6514 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
6515 for f in input_api.AffectedSourceFiles(source_file_filter):
Bruce Dawson5efbdc652022-04-11 19:29:516516 # Ignore test files that contain crlf intentionally.
6517 if f.LocalPath().endswith('crlf.txt'):
Daniel Chenga37c03db2022-05-12 17:20:346518 continue
Sam Maiera6e76d72022-02-11 21:43:506519 include_file = False
6520 for line in input_api.ReadFile(f, 'r').splitlines(True):
6521 if line.endswith('\r\n'):
6522 include_file = True
6523 if include_file:
6524 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:236525
Sam Maiera6e76d72022-02-11 21:43:506526 if problems:
6527 return [
6528 output_api.PresubmitPromptWarning(
6529 'Are you sure that you want '
6530 'these files to contain Windows style line endings?\n' +
6531 '\n'.join(problems))
6532 ]
mostynbb639aca52015-01-07 20:31:236533
Sam Maiera6e76d72022-02-11 21:43:506534 return []
6535
mostynbb639aca52015-01-07 20:31:236536
Evan Stade6cfc964c12021-05-18 20:21:166537def CheckIconFilesForLicenseHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506538 """Check that .icon files (which are fragments of C++) have license headers.
6539 """
Evan Stade6cfc964c12021-05-18 20:21:166540
Sam Maiera6e76d72022-02-11 21:43:506541 icon_files = (r'.*\.icon$', )
Evan Stade6cfc964c12021-05-18 20:21:166542
Sam Maiera6e76d72022-02-11 21:43:506543 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
6544 return input_api.canned_checks.CheckLicense(input_api,
6545 output_api,
6546 source_file_filter=icons)
6547
Evan Stade6cfc964c12021-05-18 20:21:166548
Jose Magana2b456f22021-03-09 23:26:406549def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506550 """Check source code for use of Chrome App technologies being
6551 deprecated.
6552 """
Jose Magana2b456f22021-03-09 23:26:406553
Sam Maiera6e76d72022-02-11 21:43:506554 def _CheckForDeprecatedTech(input_api,
6555 output_api,
6556 detection_list,
6557 files_to_check=None,
6558 files_to_skip=None):
Jose Magana2b456f22021-03-09 23:26:406559
Sam Maiera6e76d72022-02-11 21:43:506560 if (files_to_check or files_to_skip):
6561 source_file_filter = lambda f: input_api.FilterSourceFile(
6562 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
6563 else:
6564 source_file_filter = None
6565
6566 problems = []
6567
6568 for f in input_api.AffectedSourceFiles(source_file_filter):
6569 if f.Action() == 'D':
6570 continue
6571 for _, line in f.ChangedContents():
6572 if any(detect in line for detect in detection_list):
6573 problems.append(f.LocalPath())
6574
6575 return problems
6576
6577 # to avoid this presubmit script triggering warnings
6578 files_to_skip = ['PRESUBMIT.py', 'PRESUBMIT_test.py']
Jose Magana2b456f22021-03-09 23:26:406579
6580 problems = []
6581
Sam Maiera6e76d72022-02-11 21:43:506582 # NMF: any files with extensions .nmf or NMF
6583 _NMF_FILES = r'\.(nmf|NMF)$'
6584 problems += _CheckForDeprecatedTech(
6585 input_api,
6586 output_api,
6587 detection_list=[''], # any change to the file will trigger warning
6588 files_to_check=[r'.+%s' % _NMF_FILES])
Jose Magana2b456f22021-03-09 23:26:406589
Sam Maiera6e76d72022-02-11 21:43:506590 # MANIFEST: any manifest.json that in its diff includes "app":
6591 _MANIFEST_FILES = r'(manifest\.json)$'
6592 problems += _CheckForDeprecatedTech(
6593 input_api,
6594 output_api,
6595 detection_list=['"app":'],
6596 files_to_check=[r'.*%s' % _MANIFEST_FILES])
Jose Magana2b456f22021-03-09 23:26:406597
Sam Maiera6e76d72022-02-11 21:43:506598 # NaCl / PNaCl: any file that in its diff contains the strings in the list
6599 problems += _CheckForDeprecatedTech(
6600 input_api,
6601 output_api,
6602 detection_list=['config=nacl', 'enable-nacl', 'cpu=pnacl', 'nacl_io'],
Bruce Dawson40fece62022-09-16 19:58:316603 files_to_skip=files_to_skip + [r"^native_client_sdk/"])
Jose Magana2b456f22021-03-09 23:26:406604
Gao Shenga79ebd42022-08-08 17:25:596605 # PPAPI: any C/C++ file that in its diff includes a ppapi library
Sam Maiera6e76d72022-02-11 21:43:506606 problems += _CheckForDeprecatedTech(
6607 input_api,
6608 output_api,
6609 detection_list=['#include "ppapi', '#include <ppapi'],
6610 files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,
6611 r'.+%s' % _IMPLEMENTATION_EXTENSIONS),
Bruce Dawson40fece62022-09-16 19:58:316612 files_to_skip=[r"^ppapi/"])
Jose Magana2b456f22021-03-09 23:26:406613
Sam Maiera6e76d72022-02-11 21:43:506614 if problems:
6615 return [
6616 output_api.PresubmitPromptWarning(
6617 'You are adding/modifying code'
6618 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
6619 ' PNaCl, PPAPI). See this blog post for more details:\n'
6620 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
6621 'and this documentation for options to replace these technologies:\n'
6622 'https://developer.chrome.com/docs/apps/migration/\n' +
6623 '\n'.join(problems))
6624 ]
Jose Magana2b456f22021-03-09 23:26:406625
Sam Maiera6e76d72022-02-11 21:43:506626 return []
Jose Magana2b456f22021-03-09 23:26:406627
mostynbb639aca52015-01-07 20:31:236628
Saagar Sanghavifceeaae2020-08-12 16:40:366629def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
Sam Maiera6e76d72022-02-11 21:43:506630 """Checks that all source files use SYSLOG properly."""
6631 syslog_files = []
6632 for f in input_api.AffectedSourceFiles(src_file_filter):
6633 for line_number, line in f.ChangedContents():
6634 if 'SYSLOG' in line:
6635 syslog_files.append(f.LocalPath() + ':' + str(line_number))
pastarmovj032ba5bc2017-01-12 10:41:566636
Sam Maiera6e76d72022-02-11 21:43:506637 if syslog_files:
6638 return [
6639 output_api.PresubmitPromptWarning(
6640 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
6641 ' calls.\nFiles to check:\n',
6642 items=syslog_files)
6643 ]
6644 return []
pastarmovj89f7ee12016-09-20 14:58:136645
6646
[email protected]1f7b4172010-01-28 01:17:346647def CheckChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506648 if input_api.version < [2, 0, 0]:
6649 return [
6650 output_api.PresubmitError(
6651 "Your depot_tools is out of date. "
6652 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
6653 "but your version is %d.%d.%d" % tuple(input_api.version))
6654 ]
6655 results = []
6656 results.extend(
6657 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
6658 return results
[email protected]ca8d1982009-02-19 16:33:126659
6660
6661def CheckChangeOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506662 if input_api.version < [2, 0, 0]:
6663 return [
6664 output_api.PresubmitError(
6665 "Your depot_tools is out of date. "
6666 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
6667 "but your version is %d.%d.%d" % tuple(input_api.version))
6668 ]
Saagar Sanghavifceeaae2020-08-12 16:40:366669
Sam Maiera6e76d72022-02-11 21:43:506670 results = []
6671 # Make sure the tree is 'open'.
6672 results.extend(
6673 input_api.canned_checks.CheckTreeIsOpen(
6674 input_api,
6675 output_api,
6676 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:276677
Sam Maiera6e76d72022-02-11 21:43:506678 results.extend(
6679 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
6680 results.extend(
6681 input_api.canned_checks.CheckChangeHasBugField(input_api, output_api))
6682 results.extend(
6683 input_api.canned_checks.CheckChangeHasNoUnwantedTags(
6684 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:506685 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146686
6687
Saagar Sanghavifceeaae2020-08-12 16:40:366688def CheckStrings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506689 """Check string ICU syntax validity and if translation screenshots exist."""
6690 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
6691 # footer is set to true.
6692 git_footers = input_api.change.GitFootersFromDescription()
6693 skip_screenshot_check_footer = [
6694 footer.lower() for footer in git_footers.get(
6695 u'Skip-Translation-Screenshots-Check', [])
6696 ]
6697 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:026698
Sam Maiera6e76d72022-02-11 21:43:506699 import os
6700 import re
6701 import sys
6702 from io import StringIO
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146703
Sam Maiera6e76d72022-02-11 21:43:506704 new_or_added_paths = set(f.LocalPath() for f in input_api.AffectedFiles()
6705 if (f.Action() == 'A' or f.Action() == 'M'))
6706 removed_paths = set(f.LocalPath()
6707 for f in input_api.AffectedFiles(include_deletes=True)
6708 if f.Action() == 'D')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146709
Sam Maiera6e76d72022-02-11 21:43:506710 affected_grds = [
6711 f for f in input_api.AffectedFiles()
6712 if f.LocalPath().endswith(('.grd', '.grdp'))
6713 ]
6714 affected_grds = [
6715 f for f in affected_grds if not 'testdata' in f.LocalPath()
6716 ]
6717 if not affected_grds:
6718 return []
meacer8c0d3832019-12-26 21:46:166719
Sam Maiera6e76d72022-02-11 21:43:506720 affected_png_paths = [
6721 f.AbsoluteLocalPath() for f in input_api.AffectedFiles()
6722 if (f.LocalPath().endswith('.png'))
6723 ]
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146724
Sam Maiera6e76d72022-02-11 21:43:506725 # Check for screenshots. Developers can upload screenshots using
6726 # tools/translation/upload_screenshots.py which finds and uploads
6727 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
6728 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
6729 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
6730 #
6731 # The logic here is as follows:
6732 #
6733 # - If the CL has a .png file under the screenshots directory for a grd
6734 # file, warn the developer. Actual images should never be checked into the
6735 # Chrome repo.
6736 #
6737 # - If the CL contains modified or new messages in grd files and doesn't
6738 # contain the corresponding .sha1 files, warn the developer to add images
6739 # and upload them via tools/translation/upload_screenshots.py.
6740 #
6741 # - If the CL contains modified or new messages in grd files and the
6742 # corresponding .sha1 files, everything looks good.
6743 #
6744 # - If the CL contains removed messages in grd files but the corresponding
6745 # .sha1 files aren't removed, warn the developer to remove them.
6746 unnecessary_screenshots = []
Jens Mueller054652c2023-05-10 15:12:306747 invalid_sha1 = []
Sam Maiera6e76d72022-02-11 21:43:506748 missing_sha1 = []
Bruce Dawson55776c42022-12-09 17:23:476749 missing_sha1_modified = []
Sam Maiera6e76d72022-02-11 21:43:506750 unnecessary_sha1_files = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146751
Sam Maiera6e76d72022-02-11 21:43:506752 # This checks verifies that the ICU syntax of messages this CL touched is
6753 # valid, and reports any found syntax errors.
6754 # Without this presubmit check, ICU syntax errors in Chromium strings can land
6755 # without developers being aware of them. Later on, such ICU syntax errors
6756 # break message extraction for translation, hence would block Chromium
6757 # translations until they are fixed.
6758 icu_syntax_errors = []
Jens Mueller054652c2023-05-10 15:12:306759 sha1_pattern = input_api.re.compile(r'^[a-fA-F0-9]{40}$',
6760 input_api.re.MULTILINE)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146761
Sam Maiera6e76d72022-02-11 21:43:506762 def _CheckScreenshotAdded(screenshots_dir, message_id):
6763 sha1_path = input_api.os_path.join(screenshots_dir,
6764 message_id + '.png.sha1')
6765 if sha1_path not in new_or_added_paths:
6766 missing_sha1.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306767 elif not _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256768 invalid_sha1.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146769
Bruce Dawson55776c42022-12-09 17:23:476770 def _CheckScreenshotModified(screenshots_dir, message_id):
6771 sha1_path = input_api.os_path.join(screenshots_dir,
6772 message_id + '.png.sha1')
6773 if sha1_path not in new_or_added_paths:
6774 missing_sha1_modified.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306775 elif not _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256776 invalid_sha1.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306777
6778 def _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256779 return sha1_pattern.search(
6780 next("\n".join(f.NewContents()) for f in input_api.AffectedFiles()
6781 if f.LocalPath() == sha1_path))
Bruce Dawson55776c42022-12-09 17:23:476782
Sam Maiera6e76d72022-02-11 21:43:506783 def _CheckScreenshotRemoved(screenshots_dir, message_id):
6784 sha1_path = input_api.os_path.join(screenshots_dir,
6785 message_id + '.png.sha1')
6786 if input_api.os_path.exists(
6787 sha1_path) and sha1_path not in removed_paths:
6788 unnecessary_sha1_files.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146789
Sam Maiera6e76d72022-02-11 21:43:506790 def _ValidateIcuSyntax(text, level, signatures):
6791 """Validates ICU syntax of a text string.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146792
Sam Maiera6e76d72022-02-11 21:43:506793 Check if text looks similar to ICU and checks for ICU syntax correctness
6794 in this case. Reports various issues with ICU syntax and values of
6795 variants. Supports checking of nested messages. Accumulate information of
6796 each ICU messages found in the text for further checking.
Rainhard Findlingfc31844c52020-05-15 09:58:266797
Sam Maiera6e76d72022-02-11 21:43:506798 Args:
6799 text: a string to check.
6800 level: a number of current nesting level.
6801 signatures: an accumulator, a list of tuple of (level, variable,
6802 kind, variants).
Rainhard Findlingfc31844c52020-05-15 09:58:266803
Sam Maiera6e76d72022-02-11 21:43:506804 Returns:
6805 None if a string is not ICU or no issue detected.
6806 A tuple of (message, start index, end index) if an issue detected.
6807 """
6808 valid_types = {
6809 'plural': (frozenset(
Rainhard Findling3cde3ef02024-02-05 18:40:326810 ['=0', '=1', '=2', '=3', 'zero', 'one', 'two', 'few', 'many',
Sam Maiera6e76d72022-02-11 21:43:506811 'other']), frozenset(['=1', 'other'])),
6812 'selectordinal': (frozenset(
Rainhard Findling3cde3ef02024-02-05 18:40:326813 ['=0', '=1', '=2', '=3', 'zero', 'one', 'two', 'few', 'many',
Sam Maiera6e76d72022-02-11 21:43:506814 'other']), frozenset(['one', 'other'])),
6815 'select': (frozenset(), frozenset(['other'])),
6816 }
Rainhard Findlingfc31844c52020-05-15 09:58:266817
Sam Maiera6e76d72022-02-11 21:43:506818 # Check if the message looks like an attempt to use ICU
6819 # plural. If yes - check if its syntax strictly matches ICU format.
6820 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b',
6821 text)
6822 if not like:
6823 signatures.append((level, None, None, None))
6824 return
Rainhard Findlingfc31844c52020-05-15 09:58:266825
Sam Maiera6e76d72022-02-11 21:43:506826 # Check for valid prefix and suffix
6827 m = re.match(
6828 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
6829 r'(plural|selectordinal|select),\s*'
6830 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
6831 if not m:
6832 return (('This message looks like an ICU plural, '
6833 'but does not follow ICU syntax.'), like.start(),
6834 like.end())
6835 starting, variable, kind, variant_pairs = m.groups()
6836 variants, depth, last_pos = _ParseIcuVariants(variant_pairs,
6837 m.start(4))
6838 if depth:
6839 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
6840 len(text))
6841 first = text[0]
6842 ending = text[last_pos:]
6843 if not starting:
6844 return ('Invalid ICU format. No initial opening bracket',
6845 last_pos - 1, last_pos)
6846 if not ending or '}' not in ending:
6847 return ('Invalid ICU format. No final closing bracket',
6848 last_pos - 1, last_pos)
6849 elif first != '{':
6850 return ((
6851 'Invalid ICU format. Extra characters at the start of a complex '
6852 'message (go/icu-message-migration): "%s"') % starting, 0,
6853 len(starting))
6854 elif ending != '}':
6855 return ((
6856 'Invalid ICU format. Extra characters at the end of a complex '
6857 'message (go/icu-message-migration): "%s"') % ending,
6858 last_pos - 1, len(text) - 1)
6859 if kind not in valid_types:
6860 return (('Unknown ICU message type %s. '
6861 'Valid types are: plural, select, selectordinal') % kind,
6862 0, 0)
6863 known, required = valid_types[kind]
6864 defined_variants = set()
6865 for variant, variant_range, value, value_range in variants:
6866 start, end = variant_range
6867 if variant in defined_variants:
6868 return ('Variant "%s" is defined more than once' % variant,
6869 start, end)
6870 elif known and variant not in known:
6871 return ('Variant "%s" is not valid for %s message' %
6872 (variant, kind), start, end)
6873 defined_variants.add(variant)
6874 # Check for nested structure
6875 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
6876 if res:
6877 return (res[0], res[1] + value_range[0] + 1,
6878 res[2] + value_range[0] + 1)
6879 missing = required - defined_variants
6880 if missing:
6881 return ('Required variants missing: %s' % ', '.join(missing), 0,
6882 len(text))
6883 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:266884
Sam Maiera6e76d72022-02-11 21:43:506885 def _ParseIcuVariants(text, offset=0):
6886 """Parse variants part of ICU complex message.
Rainhard Findlingfc31844c52020-05-15 09:58:266887
Sam Maiera6e76d72022-02-11 21:43:506888 Builds a tuple of variant names and values, as well as
6889 their offsets in the input string.
Rainhard Findlingfc31844c52020-05-15 09:58:266890
Sam Maiera6e76d72022-02-11 21:43:506891 Args:
6892 text: a string to parse
6893 offset: additional offset to add to positions in the text to get correct
6894 position in the complete ICU string.
Rainhard Findlingfc31844c52020-05-15 09:58:266895
Sam Maiera6e76d72022-02-11 21:43:506896 Returns:
6897 List of tuples, each tuple consist of four fields: variant name,
6898 variant name span (tuple of two integers), variant value, value
6899 span (tuple of two integers).
6900 """
6901 depth, start, end = 0, -1, -1
6902 variants = []
6903 key = None
6904 for idx, char in enumerate(text):
6905 if char == '{':
6906 if not depth:
6907 start = idx
6908 chunk = text[end + 1:start]
6909 key = chunk.strip()
6910 pos = offset + end + 1 + chunk.find(key)
6911 span = (pos, pos + len(key))
6912 depth += 1
6913 elif char == '}':
6914 if not depth:
6915 return variants, depth, offset + idx
6916 depth -= 1
6917 if not depth:
6918 end = idx
6919 variants.append((key, span, text[start:end + 1],
6920 (offset + start, offset + end + 1)))
6921 return variants, depth, offset + end + 1
Rainhard Findlingfc31844c52020-05-15 09:58:266922
Sam Maiera6e76d72022-02-11 21:43:506923 try:
6924 old_sys_path = sys.path
6925 sys.path = sys.path + [
6926 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
6927 'translation')
6928 ]
6929 from helper import grd_helper
6930 finally:
6931 sys.path = old_sys_path
Rainhard Findlingfc31844c52020-05-15 09:58:266932
Sam Maiera6e76d72022-02-11 21:43:506933 for f in affected_grds:
6934 file_path = f.LocalPath()
6935 old_id_to_msg_map = {}
6936 new_id_to_msg_map = {}
6937 # Note that this code doesn't check if the file has been deleted. This is
6938 # OK because it only uses the old and new file contents and doesn't load
6939 # the file via its path.
6940 # It's also possible that a file's content refers to a renamed or deleted
6941 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
6942 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
6943 # .grdp files.
6944 if file_path.endswith('.grdp'):
6945 if f.OldContents():
6946 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6947 '\n'.join(f.OldContents()))
6948 if f.NewContents():
6949 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6950 '\n'.join(f.NewContents()))
6951 else:
6952 file_dir = input_api.os_path.dirname(file_path) or '.'
6953 if f.OldContents():
6954 old_id_to_msg_map = grd_helper.GetGrdMessages(
6955 StringIO('\n'.join(f.OldContents())), file_dir)
6956 if f.NewContents():
6957 new_id_to_msg_map = grd_helper.GetGrdMessages(
6958 StringIO('\n'.join(f.NewContents())), file_dir)
Rainhard Findlingfc31844c52020-05-15 09:58:266959
Sam Maiera6e76d72022-02-11 21:43:506960 grd_name, ext = input_api.os_path.splitext(
6961 input_api.os_path.basename(file_path))
6962 screenshots_dir = input_api.os_path.join(
6963 input_api.os_path.dirname(file_path),
6964 grd_name + ext.replace('.', '_'))
Rainhard Findlingfc31844c52020-05-15 09:58:266965
Sam Maiera6e76d72022-02-11 21:43:506966 # Compute added, removed and modified message IDs.
6967 old_ids = set(old_id_to_msg_map)
6968 new_ids = set(new_id_to_msg_map)
6969 added_ids = new_ids - old_ids
6970 removed_ids = old_ids - new_ids
6971 modified_ids = set([])
6972 for key in old_ids.intersection(new_ids):
6973 if (old_id_to_msg_map[key].ContentsAsXml('', True) !=
6974 new_id_to_msg_map[key].ContentsAsXml('', True)):
6975 # The message content itself changed. Require an updated screenshot.
6976 modified_ids.add(key)
6977 elif old_id_to_msg_map[key].attrs['meaning'] != \
6978 new_id_to_msg_map[key].attrs['meaning']:
Jens Mueller054652c2023-05-10 15:12:306979 # The message meaning changed. We later check for a screenshot.
6980 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146981
Sam Maiera6e76d72022-02-11 21:43:506982 if run_screenshot_check:
6983 # Check the screenshot directory for .png files. Warn if there is any.
6984 for png_path in affected_png_paths:
6985 if png_path.startswith(screenshots_dir):
6986 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146987
Sam Maiera6e76d72022-02-11 21:43:506988 for added_id in added_ids:
6989 _CheckScreenshotAdded(screenshots_dir, added_id)
Rainhard Findlingd8d04372020-08-13 13:30:096990
Sam Maiera6e76d72022-02-11 21:43:506991 for modified_id in modified_ids:
Bruce Dawson55776c42022-12-09 17:23:476992 _CheckScreenshotModified(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146993
Sam Maiera6e76d72022-02-11 21:43:506994 for removed_id in removed_ids:
6995 _CheckScreenshotRemoved(screenshots_dir, removed_id)
6996
6997 # Check new and changed strings for ICU syntax errors.
6998 for key in added_ids.union(modified_ids):
6999 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
7000 err = _ValidateIcuSyntax(msg, 0, [])
7001 if err is not None:
7002 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
7003
7004 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:267005 if run_screenshot_check:
Sam Maiera6e76d72022-02-11 21:43:507006 if unnecessary_screenshots:
7007 results.append(
7008 output_api.PresubmitError(
7009 'Do not include actual screenshots in the changelist. Run '
7010 'tools/translate/upload_screenshots.py to upload them instead:',
7011 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147012
Sam Maiera6e76d72022-02-11 21:43:507013 if missing_sha1:
7014 results.append(
7015 output_api.PresubmitError(
Bruce Dawson55776c42022-12-09 17:23:477016 'You are adding UI strings.\n'
Sam Maiera6e76d72022-02-11 21:43:507017 'To ensure the best translations, take screenshots of the relevant UI '
7018 '(https://g.co/chrome/translation) and add these files to your '
7019 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147020
Jens Mueller054652c2023-05-10 15:12:307021 if invalid_sha1:
7022 results.append(
7023 output_api.PresubmitError(
7024 'The following files do not seem to contain valid sha1 hashes. '
7025 'Make sure they contain hashes created by '
7026 'tools/translate/upload_screenshots.py:', sorted(invalid_sha1)))
7027
Bruce Dawson55776c42022-12-09 17:23:477028 if missing_sha1_modified:
7029 results.append(
7030 output_api.PresubmitError(
7031 'You are modifying UI strings or their meanings.\n'
7032 'To ensure the best translations, take screenshots of the relevant UI '
7033 '(https://g.co/chrome/translation) and add these files to your '
7034 'changelist:', sorted(missing_sha1_modified)))
7035
Sam Maiera6e76d72022-02-11 21:43:507036 if unnecessary_sha1_files:
7037 results.append(
7038 output_api.PresubmitError(
7039 'You removed strings associated with these files. Remove:',
7040 sorted(unnecessary_sha1_files)))
7041 else:
7042 results.append(
7043 output_api.PresubmitPromptOrNotify('Skipping translation '
7044 'screenshots check.'))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:147045
Sam Maiera6e76d72022-02-11 21:43:507046 if icu_syntax_errors:
7047 results.append(
7048 output_api.PresubmitPromptWarning(
7049 'ICU syntax errors were found in the following strings (problems or '
7050 'feedback? Contact [email protected]):',
7051 items=icu_syntax_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:267052
Sam Maiera6e76d72022-02-11 21:43:507053 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:127054
7055
Saagar Sanghavifceeaae2020-08-12 16:40:367056def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:127057 repo_root=None,
7058 translation_expectations_path=None,
7059 grd_files=None):
Sam Maiera6e76d72022-02-11 21:43:507060 import sys
7061 affected_grds = [
7062 f for f in input_api.AffectedFiles()
7063 if (f.LocalPath().endswith('.grd') or f.LocalPath().endswith('.grdp'))
7064 ]
7065 if not affected_grds:
7066 return []
7067
7068 try:
7069 old_sys_path = sys.path
7070 sys.path = sys.path + [
7071 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
7072 'translation')
7073 ]
7074 from helper import git_helper
7075 from helper import translation_helper
7076 finally:
7077 sys.path = old_sys_path
7078
7079 # Check that translation expectations can be parsed and we can get a list of
7080 # translatable grd files. |repo_root| and |translation_expectations_path| are
7081 # only passed by tests.
7082 if not repo_root:
7083 repo_root = input_api.PresubmitLocalPath()
7084 if not translation_expectations_path:
7085 translation_expectations_path = input_api.os_path.join(
7086 repo_root, 'tools', 'gritsettings', 'translation_expectations.pyl')
7087 if not grd_files:
7088 grd_files = git_helper.list_grds_in_repository(repo_root)
7089
7090 # Ignore bogus grd files used only for testing
Gao Shenga79ebd42022-08-08 17:25:597091 # ui/webui/resources/tools/generate_grd.py.
Sam Maiera6e76d72022-02-11 21:43:507092 ignore_path = input_api.os_path.join('ui', 'webui', 'resources', 'tools',
7093 'tests')
7094 grd_files = [p for p in grd_files if ignore_path not in p]
7095
7096 try:
7097 translation_helper.get_translatable_grds(
7098 repo_root, grd_files, translation_expectations_path)
7099 except Exception as e:
7100 return [
7101 output_api.PresubmitNotifyResult(
7102 'Failed to get a list of translatable grd files. This happens when:\n'
7103 ' - One of the modified grd or grdp files cannot be parsed or\n'
7104 ' - %s is not updated.\n'
7105 'Stack:\n%s' % (translation_expectations_path, str(e)))
7106 ]
Mustafa Emre Acer51f2f742020-03-09 19:41:127107 return []
7108
Ken Rockotc31f4832020-05-29 18:58:517109
Saagar Sanghavifceeaae2020-08-12 16:40:367110def CheckStableMojomChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507111 """Changes to [Stable] mojom types must preserve backward-compatibility."""
7112 changed_mojoms = input_api.AffectedFiles(
7113 include_deletes=True,
7114 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:527115
Bruce Dawson344ab262022-06-04 11:35:107116 if not changed_mojoms or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:507117 return []
7118
7119 delta = []
7120 for mojom in changed_mojoms:
Sam Maiera6e76d72022-02-11 21:43:507121 delta.append({
7122 'filename': mojom.LocalPath(),
7123 'old': '\n'.join(mojom.OldContents()) or None,
7124 'new': '\n'.join(mojom.NewContents()) or None,
7125 })
7126
7127 process = input_api.subprocess.Popen([
Takuto Ikutadca10222022-04-13 02:51:217128 input_api.python3_executable,
Sam Maiera6e76d72022-02-11 21:43:507129 input_api.os_path.join(
7130 input_api.PresubmitLocalPath(), 'mojo', 'public', 'tools', 'mojom',
7131 'check_stable_mojom_compatibility.py'), '--src-root',
7132 input_api.PresubmitLocalPath()
7133 ],
7134 stdin=input_api.subprocess.PIPE,
7135 stdout=input_api.subprocess.PIPE,
7136 stderr=input_api.subprocess.PIPE,
7137 universal_newlines=True)
7138 (x, error) = process.communicate(input=input_api.json.dumps(delta))
7139 if process.returncode:
7140 return [
7141 output_api.PresubmitError(
7142 'One or more [Stable] mojom definitions appears to have been changed '
Alex Goughc99921652024-02-15 22:59:127143 'in a way that is not backward-compatible. See '
7144 'https://chromium.googlesource.com/chromium/src/+/HEAD/mojo/public/tools/bindings/README.md#versioning'
7145 ' for details.',
Sam Maiera6e76d72022-02-11 21:43:507146 long_text=error)
7147 ]
Erik Staabc734cd7a2021-11-23 03:11:527148 return []
7149
Dominic Battre645d42342020-12-04 16:14:107150def CheckDeprecationOfPreferences(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507151 """Removing a preference should come with a deprecation."""
Dominic Battre645d42342020-12-04 16:14:107152
Sam Maiera6e76d72022-02-11 21:43:507153 def FilterFile(affected_file):
7154 """Accept only .cc files and the like."""
7155 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
7156 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
7157 input_api.DEFAULT_FILES_TO_SKIP)
7158 return input_api.FilterSourceFile(
7159 affected_file,
7160 files_to_check=file_inclusion_pattern,
7161 files_to_skip=files_to_skip)
Dominic Battre645d42342020-12-04 16:14:107162
Sam Maiera6e76d72022-02-11 21:43:507163 def ModifiedLines(affected_file):
7164 """Returns a list of tuples (line number, line text) of added and removed
7165 lines.
Dominic Battre645d42342020-12-04 16:14:107166
Sam Maiera6e76d72022-02-11 21:43:507167 Deleted lines share the same line number as the previous line.
Dominic Battre645d42342020-12-04 16:14:107168
Sam Maiera6e76d72022-02-11 21:43:507169 This relies on the scm diff output describing each changed code section
7170 with a line of the form
Dominic Battre645d42342020-12-04 16:14:107171
Sam Maiera6e76d72022-02-11 21:43:507172 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
7173 """
7174 line_num = 0
7175 modified_lines = []
7176 for line in affected_file.GenerateScmDiff().splitlines():
7177 # Extract <new line num> of the patch fragment (see format above).
7178 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@',
7179 line)
7180 if m:
7181 line_num = int(m.groups(1)[0])
7182 continue
7183 if ((line.startswith('+') and not line.startswith('++'))
7184 or (line.startswith('-') and not line.startswith('--'))):
7185 modified_lines.append((line_num, line))
Dominic Battre645d42342020-12-04 16:14:107186
Sam Maiera6e76d72022-02-11 21:43:507187 if not line.startswith('-'):
7188 line_num += 1
7189 return modified_lines
Dominic Battre645d42342020-12-04 16:14:107190
Sam Maiera6e76d72022-02-11 21:43:507191 def FindLineWith(lines, needle):
7192 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
Dominic Battre645d42342020-12-04 16:14:107193
Sam Maiera6e76d72022-02-11 21:43:507194 If 0 or >1 lines contain `needle`, -1 is returned.
7195 """
7196 matching_line_numbers = [
7197 # + 1 for 1-based counting of line numbers.
7198 i + 1 for i, line in enumerate(lines) if needle in line
7199 ]
7200 return matching_line_numbers[0] if len(
7201 matching_line_numbers) == 1 else -1
Dominic Battre645d42342020-12-04 16:14:107202
Sam Maiera6e76d72022-02-11 21:43:507203 def ModifiedPrefMigration(affected_file):
7204 """Returns whether the MigrateObsolete.*Pref functions were modified."""
7205 # Determine first and last lines of MigrateObsolete.*Pref functions.
7206 new_contents = affected_file.NewContents()
7207 range_1 = (FindLineWith(new_contents,
7208 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
7209 FindLineWith(new_contents,
7210 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
7211 range_2 = (FindLineWith(new_contents,
7212 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
7213 FindLineWith(new_contents,
7214 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
7215 if (-1 in range_1 + range_2):
7216 raise Exception(
7217 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.'
7218 )
Dominic Battre645d42342020-12-04 16:14:107219
Sam Maiera6e76d72022-02-11 21:43:507220 # Check whether any of the modified lines are part of the
7221 # MigrateObsolete.*Pref functions.
7222 for line_nr, line in ModifiedLines(affected_file):
7223 if (range_1[0] <= line_nr <= range_1[1]
7224 or range_2[0] <= line_nr <= range_2[1]):
7225 return True
7226 return False
Dominic Battre645d42342020-12-04 16:14:107227
Sam Maiera6e76d72022-02-11 21:43:507228 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
7229 browser_prefs_file_pattern = input_api.re.compile(
7230 r'chrome/browser/prefs/browser_prefs.cc')
Dominic Battre645d42342020-12-04 16:14:107231
Sam Maiera6e76d72022-02-11 21:43:507232 changes = input_api.AffectedFiles(include_deletes=True,
7233 file_filter=FilterFile)
7234 potential_problems = []
7235 for f in changes:
7236 for line in f.GenerateScmDiff().splitlines():
7237 # Check deleted lines for pref registrations.
7238 if (line.startswith('-') and not line.startswith('--')
7239 and register_pref_pattern.search(line)):
7240 potential_problems.append('%s: %s' % (f.LocalPath(), line))
Dominic Battre645d42342020-12-04 16:14:107241
Sam Maiera6e76d72022-02-11 21:43:507242 if browser_prefs_file_pattern.search(f.LocalPath()):
7243 # If the developer modified the MigrateObsolete.*Prefs() functions, we
7244 # assume that they knew that they have to deprecate preferences and don't
7245 # warn.
7246 try:
7247 if ModifiedPrefMigration(f):
7248 return []
7249 except Exception as e:
7250 return [output_api.PresubmitError(str(e))]
Dominic Battre645d42342020-12-04 16:14:107251
Sam Maiera6e76d72022-02-11 21:43:507252 if potential_problems:
7253 return [
7254 output_api.PresubmitPromptWarning(
7255 'Discovered possible removal of preference registrations.\n\n'
7256 'Please make sure to properly deprecate preferences by clearing their\n'
7257 'value for a couple of milestones before finally removing the code.\n'
7258 'Otherwise data may stay in the preferences files forever. See\n'
7259 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
7260 'chrome/browser/prefs/README.md for examples.\n'
7261 'This may be a false positive warning (e.g. if you move preference\n'
7262 'registrations to a different place).\n', potential_problems)
7263 ]
7264 return []
7265
Matt Stark6ef08872021-07-29 01:21:467266
7267def CheckConsistentGrdChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507268 """Changes to GRD files must be consistent for tools to read them."""
7269 changed_grds = input_api.AffectedFiles(
7270 include_deletes=False,
7271 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
7272 errors = []
7273 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
7274 for matcher, msg in _INVALID_GRD_FILE_LINE]
7275 for grd in changed_grds:
7276 for i, line in enumerate(grd.NewContents()):
7277 for matcher, msg in invalid_file_regexes:
7278 if matcher.search(line):
7279 errors.append(
7280 output_api.PresubmitError(
7281 'Problem on {grd}:{i} - {msg}'.format(
7282 grd=grd.LocalPath(), i=i + 1, msg=msg)))
7283 return errors
7284
Kevin McNee967dd2d22021-11-15 16:09:297285
Henrique Ferreiro2a4b55942021-11-29 23:45:367286def CheckAssertAshOnlyCode(input_api, output_api):
7287 """Errors if a BUILD.gn file in an ash/ directory doesn't include
7288 assert(is_chromeos_ash).
7289 """
7290
7291 def FileFilter(affected_file):
7292 """Includes directories known to be Ash only."""
7293 return input_api.FilterSourceFile(
7294 affected_file,
7295 files_to_check=(
7296 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
7297 r'.*/ash/.*BUILD\.gn'), # Any path component.
7298 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
7299
7300 errors = []
7301 pattern = input_api.re.compile(r'assert\(is_chromeos_ash')
Jameson Thies0ce669f2021-12-09 15:56:567302 for f in input_api.AffectedFiles(include_deletes=False,
7303 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:367304 if (not pattern.search(input_api.ReadFile(f))):
7305 errors.append(
7306 output_api.PresubmitError(
7307 'Please add assert(is_chromeos_ash) to %s. If that\'s not '
7308 'possible, please create and issue and add a comment such '
Alison Galed6b25fe2024-04-17 13:59:047309 'as:\n # TODO(crbug.com/XXX): add '
Henrique Ferreiro2a4b55942021-11-29 23:45:367310 'assert(is_chromeos_ash) when ...' % f.LocalPath()))
7311 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:277312
7313
Kalvin Lee84ad17a2023-09-25 11:14:417314def _IsMiraclePtrDisallowed(input_api, affected_file):
Sam Maiera6e76d72022-02-11 21:43:507315 path = affected_file.LocalPath()
7316 if not _IsCPlusPlusFile(input_api, path):
7317 return False
7318
Bartek Nowierski49b1a452024-06-08 00:24:357319 # Renderer-only code is generally allowed to use MiraclePtr. These
7320 # directories, however, are specifically disallowed, for perf reasons.
Kalvin Lee84ad17a2023-09-25 11:14:417321 if ("third_party/blink/renderer/core/" in path
7322 or "third_party/blink/renderer/platform/heap/" in path
Bartek Nowierski49b1a452024-06-08 00:24:357323 or "third_party/blink/renderer/platform/wtf/" in path
7324 or "third_party/blink/renderer/platform/fonts/" in path):
7325 return True
7326
7327 # The below paths are an explicitly listed subset of Renderer-only code,
7328 # because the plan is to Oilpanize it.
7329 # TODO(crbug.com/330759291): Remove once Oilpanization is completed or
7330 # abandoned.
7331 if ("third_party/blink/renderer/core/paint/" in path
7332 or "third_party/blink/renderer/platform/graphics/compositing/" in path
7333 or "third_party/blink/renderer/platform/graphics/paint/" in path):
Sam Maiera6e76d72022-02-11 21:43:507334 return True
7335
Sam Maiera6e76d72022-02-11 21:43:507336 # We assume that everything else may be used outside of Renderer processes.
Lukasz Anforowicz7016d05e2021-11-30 03:56:277337 return False
7338
Alison Galed6b25fe2024-04-17 13:59:047339# TODO(crbug.com/40206238): Remove these checks, once they are replaced
Lukasz Anforowicz7016d05e2021-11-30 03:56:277340# by the Chromium Clang Plugin (which will be preferable because it will
7341# 1) report errors earlier - at compile-time and 2) cover more rules).
7342def CheckRawPtrUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:507343 """Rough checks that raw_ptr<T> usage guidelines are followed."""
7344 errors = []
7345 # The regex below matches "raw_ptr<" following a word boundary, but not in a
7346 # C++ comment.
7347 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
Kalvin Lee84ad17a2023-09-25 11:14:417348 file_filter = lambda f: _IsMiraclePtrDisallowed(input_api, f)
Sam Maiera6e76d72022-02-11 21:43:507349 for f, line_num, line in input_api.RightHandSideLines(file_filter):
7350 if raw_ptr_matcher.search(line):
7351 errors.append(
7352 output_api.PresubmitError(
7353 'Problem on {path}:{line} - '\
Kalvin Lee84ad17a2023-09-25 11:14:417354 'raw_ptr<T> should not be used in this renderer code '\
Sam Maiera6e76d72022-02-11 21:43:507355 '(as documented in the "Pointers to unprotected memory" '\
7356 'section in //base/memory/raw_ptr.md)'.format(
7357 path=f.LocalPath(), line=line_num)))
7358 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:567359
mikt9337567c2023-09-08 18:38:177360def CheckAdvancedMemorySafetyChecksUsage(input_api, output_api):
7361 """Checks that ADVANCED_MEMORY_SAFETY_CHECKS() macro is neither added nor
7362 removed as it is managed by the memory safety team internally.
7363 Do not add / remove it manually."""
7364 paths = set([])
7365 # The regex below matches "ADVANCED_MEMORY_SAFETY_CHECKS(" following a word
7366 # boundary, but not in a C++ comment.
7367 macro_matcher = input_api.re.compile(
7368 r'^((?!//).)*\bADVANCED_MEMORY_SAFETY_CHECKS\(', input_api.re.MULTILINE)
7369 for f in input_api.AffectedFiles():
7370 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
7371 continue
7372 if macro_matcher.search(f.GenerateScmDiff()):
7373 paths.add(f.LocalPath())
7374 if not paths:
7375 return []
7376 return [output_api.PresubmitPromptWarning(
7377 'ADVANCED_MEMORY_SAFETY_CHECKS() macro is managed by ' \
7378 'the memory safety team (chrome-memory-safety@). ' \
7379 'Please contact us to add/delete the uses of the macro.',
7380 paths)]
Henrique Ferreirof9819f2e32021-11-30 13:31:567381
7382def CheckPythonShebang(input_api, output_api):
7383 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
7384 system-wide python.
7385 """
7386 errors = []
7387 sources = lambda affected_file: input_api.FilterSourceFile(
7388 affected_file,
7389 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
7390 r'third_party/blink/web_tests/external/') + input_api.
7391 DEFAULT_FILES_TO_SKIP),
7392 files_to_check=[r'.*\.py$'])
7393 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:277394 for line_num, line in f.ChangedContents():
7395 if line_num == 1 and line.startswith('#!/usr/bin/python'):
7396 errors.append(f.LocalPath())
7397 break
Henrique Ferreirof9819f2e32021-11-30 13:31:567398
7399 result = []
7400 for file in errors:
7401 result.append(
7402 output_api.PresubmitError(
7403 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
7404 file))
7405 return result
James Shen81cc0e22022-06-15 21:10:457406
7407
7408def CheckBatchAnnotation(input_api, output_api):
7409 """Checks that tests have either @Batch or @DoNotBatch annotation. If this
7410 is not an instrumentation test, disregard."""
7411
7412 batch_annotation = input_api.re.compile(r'^\s*@Batch')
7413 do_not_batch_annotation = input_api.re.compile(r'^\s*@DoNotBatch')
7414 robolectric_test = input_api.re.compile(r'[rR]obolectric')
7415 test_class_declaration = input_api.re.compile(r'^\s*public\sclass.*Test')
7416 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
Mark Schillaci8ef0d872023-07-18 22:07:597417 test_annotation_declaration = input_api.re.compile(r'^\s*public\s@interface\s.*{')
James Shen81cc0e22022-06-15 21:10:457418
ckitagawae8fd23b2022-06-17 15:29:387419 missing_annotation_errors = []
7420 extra_annotation_errors = []
James Shen81cc0e22022-06-15 21:10:457421
7422 def _FilterFile(affected_file):
7423 return input_api.FilterSourceFile(
7424 affected_file,
7425 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
7426 files_to_check=[r'.*Test\.java$'])
7427
7428 for f in input_api.AffectedSourceFiles(_FilterFile):
7429 batch_matched = None
7430 do_not_batch_matched = None
7431 is_instrumentation_test = True
Mark Schillaci8ef0d872023-07-18 22:07:597432 test_annotation_declaration_matched = None
James Shen81cc0e22022-06-15 21:10:457433 for line in f.NewContents():
7434 if robolectric_test.search(line) or uiautomator_test.search(line):
7435 # Skip Robolectric and UiAutomator tests.
7436 is_instrumentation_test = False
7437 break
7438 if not batch_matched:
7439 batch_matched = batch_annotation.search(line)
7440 if not do_not_batch_matched:
7441 do_not_batch_matched = do_not_batch_annotation.search(line)
7442 test_class_declaration_matched = test_class_declaration.search(
7443 line)
Mark Schillaci8ef0d872023-07-18 22:07:597444 test_annotation_declaration_matched = test_annotation_declaration.search(line)
7445 if test_class_declaration_matched or test_annotation_declaration_matched:
James Shen81cc0e22022-06-15 21:10:457446 break
Mark Schillaci8ef0d872023-07-18 22:07:597447 if test_annotation_declaration_matched:
7448 continue
James Shen81cc0e22022-06-15 21:10:457449 if (is_instrumentation_test and
7450 not batch_matched and
7451 not do_not_batch_matched):
Sam Maier4cef9242022-10-03 14:21:247452 missing_annotation_errors.append(str(f.LocalPath()))
ckitagawae8fd23b2022-06-17 15:29:387453 if (not is_instrumentation_test and
7454 (batch_matched or
7455 do_not_batch_matched)):
Sam Maier4cef9242022-10-03 14:21:247456 extra_annotation_errors.append(str(f.LocalPath()))
James Shen81cc0e22022-06-15 21:10:457457
7458 results = []
7459
ckitagawae8fd23b2022-06-17 15:29:387460 if missing_annotation_errors:
James Shen81cc0e22022-06-15 21:10:457461 results.append(
7462 output_api.PresubmitPromptWarning(
7463 """
Andrew Grieve43a5cf82023-09-08 15:09:467464A change was made to an on-device test that has neither been annotated with
7465@Batch nor @DoNotBatch. If this is a new test, please add the annotation. If
7466this is an existing test, please consider adding it if you are sufficiently
7467familiar with the test (but do so as a separate change).
7468
Jens Mueller2085ff82023-02-27 11:54:497469See https://source.chromium.org/chromium/chromium/src/+/main:docs/testing/batching_instrumentation_tests.md
ckitagawae8fd23b2022-06-17 15:29:387470""", missing_annotation_errors))
7471 if extra_annotation_errors:
7472 results.append(
7473 output_api.PresubmitPromptWarning(
7474 """
7475Robolectric tests do not need a @Batch or @DoNotBatch annotations.
7476""", extra_annotation_errors))
James Shen81cc0e22022-06-15 21:10:457477
7478 return results
Sam Maier4cef9242022-10-03 14:21:247479
7480
7481def CheckMockAnnotation(input_api, output_api):
7482 """Checks that we have annotated all Mockito.mock()-ed or Mockito.spy()-ed
7483 classes with @Mock or @Spy. If this is not an instrumentation test,
7484 disregard."""
7485
7486 # This is just trying to be approximately correct. We are not writing a
7487 # Java parser, so special cases like statically importing mock() then
7488 # calling an unrelated non-mockito spy() function will cause a false
7489 # positive.
7490 package_name = input_api.re.compile(r'^package\s+(\w+(?:\.\w+)+);')
7491 mock_static_import = input_api.re.compile(
7492 r'^import\s+static\s+org.mockito.Mockito.(?:mock|spy);')
7493 import_class = input_api.re.compile(r'import\s+((?:\w+\.)+)(\w+);')
7494 mock_annotation = input_api.re.compile(r'^\s*@(?:Mock|Spy)')
7495 field_type = input_api.re.compile(r'(\w+)(?:<\w+>)?\s+\w+\s*(?:;|=)')
7496 mock_or_spy_function_call = r'(?:mock|spy)\(\s*(?:new\s*)?(\w+)(?:\.class|\()'
7497 fully_qualified_mock_function = input_api.re.compile(
7498 r'Mockito\.' + mock_or_spy_function_call)
7499 statically_imported_mock_function = input_api.re.compile(
7500 r'\W' + mock_or_spy_function_call)
7501 robolectric_test = input_api.re.compile(r'[rR]obolectric')
7502 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
7503
7504 def _DoClassLookup(class_name, class_name_map, package):
7505 found = class_name_map.get(class_name)
7506 if found is not None:
7507 return found
7508 else:
7509 return package + '.' + class_name
7510
7511 def _FilterFile(affected_file):
7512 return input_api.FilterSourceFile(
7513 affected_file,
7514 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
7515 files_to_check=[r'.*Test\.java$'])
7516
7517 mocked_by_function_classes = set()
7518 mocked_by_annotation_classes = set()
7519 class_to_filename = {}
7520 for f in input_api.AffectedSourceFiles(_FilterFile):
7521 mock_function_regex = fully_qualified_mock_function
7522 next_line_is_annotated = False
7523 fully_qualified_class_map = {}
7524 package = None
7525
7526 for line in f.NewContents():
7527 if robolectric_test.search(line) or uiautomator_test.search(line):
7528 # Skip Robolectric and UiAutomator tests.
7529 break
7530
7531 m = package_name.search(line)
7532 if m:
7533 package = m.group(1)
7534 continue
7535
7536 if mock_static_import.search(line):
7537 mock_function_regex = statically_imported_mock_function
7538 continue
7539
7540 m = import_class.search(line)
7541 if m:
7542 fully_qualified_class_map[m.group(2)] = m.group(1) + m.group(2)
7543 continue
7544
7545 if next_line_is_annotated:
7546 next_line_is_annotated = False
7547 fully_qualified_class = _DoClassLookup(
7548 field_type.search(line).group(1), fully_qualified_class_map,
7549 package)
7550 mocked_by_annotation_classes.add(fully_qualified_class)
7551 continue
7552
7553 if mock_annotation.search(line):
Sam Maierb8a66a02023-10-10 13:50:557554 field_type_search = field_type.search(line)
7555 if field_type_search:
7556 fully_qualified_class = _DoClassLookup(
7557 field_type_search.group(1), fully_qualified_class_map,
7558 package)
7559 mocked_by_annotation_classes.add(fully_qualified_class)
7560 else:
7561 next_line_is_annotated = True
Sam Maier4cef9242022-10-03 14:21:247562 continue
7563
7564 m = mock_function_regex.search(line)
7565 if m:
7566 fully_qualified_class = _DoClassLookup(m.group(1),
7567 fully_qualified_class_map, package)
7568 # Skipping builtin classes, since they don't get optimized.
7569 if fully_qualified_class.startswith(
7570 'android.') or fully_qualified_class.startswith(
7571 'java.'):
7572 continue
7573 class_to_filename[fully_qualified_class] = str(f.LocalPath())
7574 mocked_by_function_classes.add(fully_qualified_class)
7575
7576 results = []
7577 missed_classes = mocked_by_function_classes - mocked_by_annotation_classes
7578 if missed_classes:
7579 error_locations = []
7580 for c in missed_classes:
7581 error_locations.append(c + ' in ' + class_to_filename[c])
7582 results.append(
7583 output_api.PresubmitPromptWarning(
7584 """
7585Mockito.mock()/spy() cause issues with our Java optimizer. You have 3 options:
75861) If the mocked variable can be a class member, annotate the member with
7587 @Mock/@Spy.
75882) If the mocked variable cannot be a class member, create a dummy member
7589 variable of that type, annotated with @Mock/@Spy. This dummy does not need
7590 to be used or initialized in any way.
75913) If the mocked type is definitely not going to be optimized, whether it's a
7592 builtin type which we don't ship, or a class you know R8 will treat
7593 specially, you can ignore this warning.
7594""", error_locations))
7595
7596 return results
Mike Dougherty1b8be712022-10-20 00:15:137597
7598def CheckNoJsInIos(input_api, output_api):
7599 """Checks to make sure that JavaScript files are not used on iOS."""
7600
7601 def _FilterFile(affected_file):
7602 return input_api.FilterSourceFile(
7603 affected_file,
7604 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP +
Daniel White44b8bd02023-08-22 16:20:367605 (r'^ios/third_party/*', r'^ios/tools/*', r'^third_party/*',
7606 r'^components/autofill/ios/form_util/resources/*'),
Mike Dougherty1b8be712022-10-20 00:15:137607 files_to_check=[r'^ios/.*\.js$', r'.*/ios/.*\.js$'])
7608
Mike Dougherty4d1050b2023-03-14 15:59:537609 deleted_files = []
7610
7611 # Collect filenames of all removed JS files.
Arthur Sonzognic66e9c82024-04-23 07:53:047612 for f in input_api.AffectedFiles(file_filter=_FilterFile):
Mike Dougherty4d1050b2023-03-14 15:59:537613 local_path = f.LocalPath()
7614
7615 if input_api.os_path.splitext(local_path)[1] == '.js' and f.Action() == 'D':
7616 deleted_files.append(input_api.os_path.basename(local_path))
7617
Mike Dougherty1b8be712022-10-20 00:15:137618 error_paths = []
Mike Dougherty4d1050b2023-03-14 15:59:537619 moved_paths = []
Mike Dougherty1b8be712022-10-20 00:15:137620 warning_paths = []
7621
7622 for f in input_api.AffectedSourceFiles(_FilterFile):
7623 local_path = f.LocalPath()
7624
7625 if input_api.os_path.splitext(local_path)[1] == '.js':
7626 if f.Action() == 'A':
Mike Dougherty4d1050b2023-03-14 15:59:537627 if input_api.os_path.basename(local_path) in deleted_files:
7628 # This script was probably moved rather than newly created.
7629 # Present a warning instead of an error for these cases.
7630 moved_paths.append(local_path)
7631 else:
7632 error_paths.append(local_path)
Mike Dougherty1b8be712022-10-20 00:15:137633 elif f.Action() != 'D':
7634 warning_paths.append(local_path)
7635
7636 results = []
7637
7638 if warning_paths:
7639 results.append(output_api.PresubmitPromptWarning(
7640 'TypeScript is now fully supported for iOS feature scripts. '
7641 'Consider converting JavaScript files to TypeScript. See '
7642 '//ios/web/public/js_messaging/README.md for more details.',
7643 warning_paths))
7644
Mike Dougherty4d1050b2023-03-14 15:59:537645 if moved_paths:
7646 results.append(output_api.PresubmitPromptWarning(
7647 'Do not use JavaScript on iOS for new files as TypeScript is '
7648 'fully supported. (If this is a moved file, you may leave the '
7649 'script unconverted.) See //ios/web/public/js_messaging/README.md '
7650 'for help using scripts on iOS.', moved_paths))
7651
Mike Dougherty1b8be712022-10-20 00:15:137652 if error_paths:
7653 results.append(output_api.PresubmitError(
7654 'Do not use JavaScript on iOS as TypeScript is fully supported. '
7655 'See //ios/web/public/js_messaging/README.md for help using '
7656 'scripts on iOS.', error_paths))
7657
7658 return results
Hans Wennborg23a81d52023-03-24 16:38:137659
7660def CheckLibcxxRevisionsMatch(input_api, output_api):
7661 """Check to make sure the libc++ version matches across deps files."""
Andrew Grieve21bb6792023-03-27 19:06:487662 # Disable check for changes to sub-repositories.
7663 if input_api.PresubmitLocalPath() != input_api.change.RepositoryRoot():
Sam Maierb926c58c2023-08-08 19:58:257664 return []
Hans Wennborg23a81d52023-03-24 16:38:137665
7666 DEPS_FILES = [ 'DEPS', 'buildtools/deps_revisions.gni' ]
7667
7668 file_filter = lambda f: f.LocalPath().replace(
7669 input_api.os_path.sep, '/') in DEPS_FILES
7670 changed_deps_files = input_api.AffectedFiles(file_filter=file_filter)
7671 if not changed_deps_files:
7672 return []
7673
7674 def LibcxxRevision(file):
7675 file = input_api.os_path.join(input_api.PresubmitLocalPath(),
7676 *file.split('/'))
7677 return input_api.re.search(
7678 r'libcxx_revision.*[:=].*[\'"](\w+)[\'"]',
7679 input_api.ReadFile(file)).group(1)
7680
7681 if len(set([LibcxxRevision(f) for f in DEPS_FILES])) == 1:
7682 return []
7683
7684 return [output_api.PresubmitError(
7685 'libcxx_revision not equal across %s' % ', '.join(DEPS_FILES),
7686 changed_deps_files)]
Arthur Sonzogni7109bd32023-10-03 10:34:427687
7688
7689def CheckDanglingUntriaged(input_api, output_api):
7690 """Warn developers adding DanglingUntriaged raw_ptr."""
7691
7692 # Ignore during git presubmit --all.
7693 #
7694 # This would be too costly, because this would check every lines of every
7695 # C++ files. Check from _BANNED_CPP_FUNCTIONS are also reading the whole
7696 # source code, but only once to apply every checks. It seems the bots like
7697 # `win-presubmit` are particularly sensitive to reading the files. Adding
7698 # this check caused the bot to run 2x longer. See https://crbug.com/1486612.
7699 if input_api.no_diffs:
Arthur Sonzogni9eafd222023-11-10 08:50:397700 return []
Arthur Sonzogni7109bd32023-10-03 10:34:427701
7702 def FilterFile(file):
7703 return input_api.FilterSourceFile(
7704 file,
7705 files_to_check=[r".*\.(h|cc|cpp|cxx|m|mm)$"],
7706 files_to_skip=[r"^base/allocator.*"],
7707 )
7708
7709 count = 0
Arthur Sonzognic66e9c82024-04-23 07:53:047710 for f in input_api.AffectedFiles(file_filter=FilterFile):
Arthur Sonzogni9eafd222023-11-10 08:50:397711 count -= sum([l.count("DanglingUntriaged") for l in f.OldContents()])
7712 count += sum([l.count("DanglingUntriaged") for l in f.NewContents()])
Arthur Sonzogni7109bd32023-10-03 10:34:427713
7714 # Most likely, nothing changed:
7715 if count == 0:
7716 return []
7717
7718 # Congrats developers for improving it:
7719 if count < 0:
Arthur Sonzogni9eafd222023-11-10 08:50:397720 message = f"DanglingUntriaged pointers removed: {-count}\nThank you!"
Arthur Sonzogni7109bd32023-10-03 10:34:427721 return [output_api.PresubmitNotifyResult(message)]
7722
7723 # Check for 'DanglingUntriaged-notes' in the description:
7724 notes_regex = input_api.re.compile("DanglingUntriaged-notes[:=]")
7725 if any(
7726 notes_regex.match(line)
7727 for line in input_api.change.DescriptionText().splitlines()):
7728 return []
7729
7730 # Check for DanglingUntriaged-notes in the git footer:
7731 if input_api.change.GitFootersFromDescription().get(
7732 "DanglingUntriaged-notes", []):
7733 return []
7734
7735 message = (
Arthur Sonzogni9eafd222023-11-10 08:50:397736 "Unexpected new occurrences of `DanglingUntriaged` detected. Please\n" +
7737 "avoid adding new ones\n" +
7738 "\n" +
7739 "See documentation:\n" +
7740 "https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr.md\n" +
7741 "\n" +
7742 "See also the guide to fix dangling pointers:\n" +
7743 "https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr_guide.md\n" +
7744 "\n" +
7745 "To disable this warning, please add in the commit description:\n" +
Alex Gough26dcd852023-12-22 16:47:197746 "DanglingUntriaged-notes: <rationale for new untriaged dangling " +
Arthur Sonzogni9eafd222023-11-10 08:50:397747 "pointers>"
Arthur Sonzogni7109bd32023-10-03 10:34:427748 )
7749 return [output_api.PresubmitPromptWarning(message)]
Jan Keitel77be7522023-10-12 20:40:497750
7751def CheckInlineConstexprDefinitionsInHeaders(input_api, output_api):
7752 """Checks that non-static constexpr definitions in headers are inline."""
7753 # In a properly formatted file, constexpr definitions inside classes or
7754 # structs will have additional whitespace at the beginning of the line.
7755 # The pattern looks for variables initialized as constexpr kVar = ...; or
7756 # constexpr kVar{...};
7757 # The pattern does not match expressions that have braces in kVar to avoid
7758 # matching constexpr functions.
7759 pattern = input_api.re.compile(r'^constexpr (?!inline )[^\(\)]*[={]')
7760 attribute_pattern = input_api.re.compile(r'(\[\[[a-zA-Z_:]+\]\]|[A-Z]+[A-Z_]+) ')
7761 problems = []
7762 for f in input_api.AffectedFiles():
7763 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
7764 continue
7765
7766 for line_number, line in f.ChangedContents():
7767 line = attribute_pattern.sub('', line)
7768 if pattern.search(line):
7769 problems.append(
7770 f"{f.LocalPath()}: {line_number}\n {line}")
7771
7772 if problems:
7773 return [
7774 output_api.PresubmitPromptWarning(
7775 'Consider inlining constexpr variable definitions in headers '
7776 'outside of classes to avoid unnecessary copies of the '
7777 'constant. See https://abseil.io/tips/168 for more details.',
7778 problems)
7779 ]
7780 else:
7781 return []
Alison Galed6b25fe2024-04-17 13:59:047782
7783def CheckTodoBugReferences(input_api, output_api):
7784 """Checks that bugs in TODOs use updated issue tracker IDs."""
7785
7786 files_to_skip = ['PRESUBMIT_test.py']
7787
7788 def _FilterFile(affected_file):
7789 return input_api.FilterSourceFile(
7790 affected_file,
7791 files_to_skip=files_to_skip)
7792
7793 # Monorail bug IDs are all less than or equal to 1524553 so check that all
7794 # bugs in TODOs are greater than that value.
7795 pattern = input_api.re.compile(r'.*TODO\([^\)0-9]*([0-9]+)\).*')
7796 problems = []
7797 for f in input_api.AffectedSourceFiles(_FilterFile):
7798 for line_number, line in f.ChangedContents():
7799 match = pattern.match(line)
7800 if match and int(match.group(1)) <= 1524553:
7801 problems.append(
7802 f"{f.LocalPath()}: {line_number}\n {line}")
7803
7804 if problems:
7805 return [
7806 output_api.PresubmitPromptWarning(
Alison Galecb598de52024-04-26 17:03:257807 'TODOs should use the new Chromium Issue Tracker IDs which can '
7808 'be found by navigating to the bug. See '
7809 'https://crbug.com/336778624 for more details.',
Alison Galed6b25fe2024-04-17 13:59:047810 problems)
7811 ]
7812 else:
7813 return []