blob: ae1232a7d1a9517d1b0c7756a02957eba85a75be [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# This line is 'magic' in that git-cl looks for it to decide whether to
19# use Python3 instead of Python2 when running the code in this file.
20USE_PYTHON3 = True
21
[email protected]379e7dd2010-01-28 17:39:2122_EXCLUDED_PATHS = (
Bruce Dawson7f8566b2022-05-06 16:22:1823 # Generated file
Bruce Dawson40fece62022-09-16 19:58:3124 (r"chrome/android/webapk/shell_apk/src/org/chromium"
25 r"/webapk/lib/runtime_library/IWebApkApi.java"),
Mila Greene3aa7222021-09-07 16:34:0826 # File needs to write to stdout to emulate a tool it's replacing.
Bruce Dawson40fece62022-09-16 19:58:3127 r"chrome/updater/mac/keystone/ksadmin.mm",
Ilya Shermane8a7d2d2020-07-25 04:33:4728 # Generated file.
Bruce Dawson40fece62022-09-16 19:58:3129 (r"^components/variations/proto/devtools/"
Ilya Shermanc167a962020-08-18 18:40:2630 r"client_variations.js"),
Bruce Dawson3bd976c2022-05-06 22:47:5231 # These are video files, not typescript.
Bruce Dawson40fece62022-09-16 19:58:3132 r"^media/test/data/.*.ts",
33 r"^native_client_sdksrc/build_tools/make_rules.py",
34 r"^native_client_sdk/src/build_tools/make_simple.py",
35 r"^native_client_sdk/src/tools/.*.mk",
36 r"^net/tools/spdyshark/.*",
37 r"^skia/.*",
38 r"^third_party/blink/.*",
39 r"^third_party/breakpad/.*",
Darwin Huangd74a9d32019-07-17 17:58:4640 # sqlite is an imported third party dependency.
Bruce Dawson40fece62022-09-16 19:58:3141 r"^third_party/sqlite/.*",
42 r"^v8/.*",
[email protected]3e4eb112011-01-18 03:29:5443 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5344 r".+_autogen\.h$",
Yue Shecf1380552022-08-23 20:59:2045 r".+_pb2(_grpc)?\.py$",
Bruce Dawson40fece62022-09-16 19:58:3146 r".+/pnacl_shim\.c$",
47 r"^gpu/config/.*_list_json\.cc$",
48 r"tools/md_browser/.*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1449 # Test pages for Maps telemetry tests.
Bruce Dawson40fece62022-09-16 19:58:3150 r"tools/perf/page_sets/maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5451 # Test pages for WebRTC telemetry tests.
Bruce Dawson40fece62022-09-16 19:58:3152 r"tools/perf/page_sets/webrtc_cases.*",
dpapad2efd4452023-04-06 01:43:4553 # Test file compared with generated output.
54 r"tools/polymer/tests/html_to_wrapper/.*.html.ts$",
[email protected]4306417642009-06-11 00:33:4055)
[email protected]ca8d1982009-02-19 16:33:1256
John Abd-El-Malek759fea62021-03-13 03:41:1457_EXCLUDED_SET_NO_PARENT_PATHS = (
58 # It's for historical reasons that blink isn't a top level directory, where
59 # it would be allowed to have "set noparent" to avoid top level owners
60 # accidentally +1ing changes.
61 'third_party/blink/OWNERS',
62)
63
wnwenbdc444e2016-05-25 13:44:1564
[email protected]06e6d0ff2012-12-11 01:36:4465# Fragment of a regular expression that matches C++ and Objective-C++
66# implementation files.
67_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
68
wnwenbdc444e2016-05-25 13:44:1569
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1970# Fragment of a regular expression that matches C++ and Objective-C++
71# header files.
72_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
73
74
Aleksey Khoroshilov9b28c032022-06-03 16:35:3275# Paths with sources that don't use //base.
76_NON_BASE_DEPENDENT_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:3177 r"^chrome/browser/browser_switcher/bho/",
78 r"^tools/win/",
Aleksey Khoroshilov9b28c032022-06-03 16:35:3279)
80
81
[email protected]06e6d0ff2012-12-11 01:36:4482# Regular expression that matches code only used for test binaries
83# (best effort).
84_TEST_CODE_EXCLUDED_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:3185 r'.*/(fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4486 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
James Cook1b4dc132021-03-09 22:45:1387 # Test suite files, like:
88 # foo_browsertest.cc
89 # bar_unittest_mac.cc (suffix)
90 # baz_unittests.cc (plural)
91 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(s)?(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1292 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1893 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
Victor Hugo Vianna Silvac22e0202021-06-09 19:46:2194 r'.+sync_service_impl_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Bruce Dawson40fece62022-09-16 19:58:3195 r'.*/(test|tool(s)?)/.*',
danakj89f47082020-09-02 17:53:4396 # content_shell is used for running content_browsertests.
Bruce Dawson40fece62022-09-16 19:58:3197 r'content/shell/.*',
danakj89f47082020-09-02 17:53:4398 # Web test harness.
Bruce Dawson40fece62022-09-16 19:58:3199 r'content/web_test/.*',
[email protected]7b054982013-11-27 00:44:47100 # Non-production example code.
Bruce Dawson40fece62022-09-16 19:58:31101 r'mojo/examples/.*',
[email protected]8176de12014-06-20 19:07:08102 # Launcher for running iOS tests on the simulator.
Bruce Dawson40fece62022-09-16 19:58:31103 r'testing/iossim/iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:41104 # EarlGrey app side code for tests.
Bruce Dawson40fece62022-09-16 19:58:31105 r'ios/.*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:17106 # Views Examples code
Bruce Dawson40fece62022-09-16 19:58:31107 r'ui/views/examples/.*',
Austin Sullivan33da70a2020-10-07 15:39:41108 # Chromium Codelab
Bruce Dawson40fece62022-09-16 19:58:31109 r'codelabs/*'
[email protected]06e6d0ff2012-12-11 01:36:44110)
[email protected]ca8d1982009-02-19 16:33:12111
Daniel Bratell609102be2019-03-27 20:53:21112_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:15113
[email protected]eea609a2011-11-18 13:10:12114_TEST_ONLY_WARNING = (
115 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:55116 'production code. If you are doing this from inside another method\n'
117 'named as *ForTesting(), then consider exposing things to have tests\n'
118 'make that same call directly.\n'
119 'If that is not possible, you may put a comment on the same line with\n'
120 ' // IN-TEST \n'
121 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
122 'method and can be ignored. Do not do this inside production code.\n'
123 'The android-binary-size trybot will block if the method exists in the\n'
124 'release apk.')
[email protected]eea609a2011-11-18 13:10:12125
126
Daniel Chenga44a1bcd2022-03-15 20:00:15127@dataclass
128class BanRule:
Daniel Chenga37c03db2022-05-12 17:20:34129 # String pattern. If the pattern begins with a slash, the pattern will be
130 # treated as a regular expression instead.
131 pattern: str
132 # Explanation as a sequence of strings. Each string in the sequence will be
133 # printed on its own line.
134 explanation: Sequence[str]
135 # Whether or not to treat this ban as a fatal error. If unspecified,
136 # defaults to true.
137 treat_as_error: Optional[bool] = None
138 # Paths that should be excluded from the ban check. Each string is a regular
139 # expression that will be matched against the path of the file being checked
140 # relative to the root of the source tree.
141 excluded_paths: Optional[Sequence[str]] = None
[email protected]cf9b78f2012-11-14 11:40:28142
Daniel Chenga44a1bcd2022-03-15 20:00:15143
Daniel Cheng917ce542022-03-15 20:46:57144_BANNED_JAVA_IMPORTS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15145 BanRule(
146 'import java.net.URI;',
147 (
148 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
149 ),
150 excluded_paths=(
151 (r'net/android/javatests/src/org/chromium/net/'
152 'AndroidProxySelectorTest\.java'),
153 r'components/cronet/',
154 r'third_party/robolectric/local/',
155 ),
Michael Thiessen44457642020-02-06 00:24:15156 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15157 BanRule(
158 'import android.annotation.TargetApi;',
159 (
160 'Do not use TargetApi, use @androidx.annotation.RequiresApi instead. '
161 'RequiresApi ensures that any calls are guarded by the appropriate '
162 'SDK_INT check. See https://crbug.com/1116486.',
163 ),
164 ),
165 BanRule(
Mohamed Heikal3d7a94c2023-03-28 16:55:24166 'import androidx.test.rule.UiThreadTestRule;',
Daniel Chenga44a1bcd2022-03-15 20:00:15167 (
168 'Do not use UiThreadTestRule, just use '
169 '@org.chromium.base.test.UiThreadTest on test methods that should run '
170 'on the UI thread. See https://crbug.com/1111893.',
171 ),
172 ),
173 BanRule(
Mohamed Heikal3d7a94c2023-03-28 16:55:24174 'import androidx.test.annotation.UiThreadTest;',
175 ('Do not use androidx.test.annotation.UiThreadTest, use '
Daniel Chenga44a1bcd2022-03-15 20:00:15176 'org.chromium.base.test.UiThreadTest instead. See '
177 'https://crbug.com/1111893.',
178 ),
179 ),
180 BanRule(
Mohamed Heikal3d7a94c2023-03-28 16:55:24181 'import androidx.test.rule.ActivityTestRule;',
Daniel Chenga44a1bcd2022-03-15 20:00:15182 (
183 'Do not use ActivityTestRule, use '
184 'org.chromium.base.test.BaseActivityTestRule instead.',
185 ),
186 excluded_paths=(
187 'components/cronet/',
188 ),
189 ),
Min Qinbc44383c2023-02-22 17:25:26190 BanRule(
191 'import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;',
192 (
193 'Do not use VectorDrawableCompat, use getResources().getDrawable() to '
194 'avoid extra indirections. Please also add trace event as the call '
195 'might take more than 20 ms to complete.',
196 ),
197 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15198)
wnwenbdc444e2016-05-25 13:44:15199
Daniel Cheng917ce542022-03-15 20:46:57200_BANNED_JAVA_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15201 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41202 'StrictMode.allowThreadDiskReads()',
203 (
204 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
205 'directly.',
206 ),
207 False,
208 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15209 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41210 'StrictMode.allowThreadDiskWrites()',
211 (
212 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
213 'directly.',
214 ),
215 False,
216 ),
Daniel Cheng917ce542022-03-15 20:46:57217 BanRule(
Michael Thiessen0f2547e2020-07-27 21:55:36218 '.waitForIdleSync()',
219 (
220 'Do not use waitForIdleSync as it masks underlying issues. There is '
221 'almost always something else you should wait on instead.',
222 ),
223 False,
224 ),
Ashley Newson09cbd602022-10-26 11:40:14225 BanRule(
Ashley Newsoneb6f5ced2022-10-26 14:45:42226 r'/(?<!\bsuper\.)(?<!\bIntent )\bregisterReceiver\(',
Ashley Newson09cbd602022-10-26 11:40:14227 (
228 'Do not call android.content.Context.registerReceiver (or an override) '
229 'directly. Use one of the wrapper methods defined in '
230 'org.chromium.base.ContextUtils, such as '
231 'registerProtectedBroadcastReceiver, '
232 'registerExportedBroadcastReceiver, or '
233 'registerNonExportedBroadcastReceiver. See their documentation for '
234 'which one to use.',
235 ),
236 True,
237 excluded_paths=(
Ashley Newson22bc26d2022-11-01 20:30:57238 r'.*Test[^a-z]',
239 r'third_party/',
Ashley Newson09cbd602022-10-26 11:40:14240 'base/android/java/src/org/chromium/base/ContextUtils.java',
Brandon Mousseau7e76a9c2022-12-08 22:08:38241 'chromecast/browser/android/apk/src/org/chromium/chromecast/shell/BroadcastReceiverScope.java',
Ashley Newson09cbd602022-10-26 11:40:14242 ),
243 ),
Ted Chocd5b327b12022-11-05 02:13:22244 BanRule(
245 r'/(?:extends|new)\s*(?:android.util.)?Property<[A-Za-z.]+,\s*(?:Integer|Float)>',
246 (
247 'Do not use Property<..., Integer|Float>, but use FloatProperty or '
248 'IntProperty because it will avoid unnecessary autoboxing of '
249 'primitives.',
250 ),
251 ),
Peilin Wangbba4a8652022-11-10 16:33:57252 BanRule(
253 'requestLayout()',
254 (
255 'Layouts can be expensive. Prefer using ViewUtils.requestLayout(), '
256 'which emits a trace event with additional information to help with '
257 'scroll jank investigations. See http://crbug.com/1354176.',
258 ),
259 False,
260 excluded_paths=(
261 'ui/android/java/src/org/chromium/ui/base/ViewUtils.java',
262 ),
263 ),
Ted Chocf40ea9152023-02-14 19:02:39264 BanRule(
265 'Profile.getLastUsedRegularProfile()',
266 (
267 'Prefer passing in the Profile reference instead of relying on the '
268 'static getLastUsedRegularProfile() call. Only top level entry points '
269 '(e.g. Activities) should call this method. Otherwise, the Profile '
270 'should either be passed in explicitly or retreived from an existing '
271 'entity with a reference to the Profile (e.g. WebContents).',
272 ),
273 False,
274 excluded_paths=(
275 r'.*Test[A-Z]?.*\.java',
276 ),
277 ),
Min Qinbc44383c2023-02-22 17:25:26278 BanRule(
279 r'/(ResourcesCompat|getResources\(\))\.getDrawable\(\)',
280 (
281 'getDrawable() can be expensive. If you have a lot of calls to '
282 'GetDrawable() or your code may introduce janks, please put your calls '
283 'inside a trace().',
284 ),
285 False,
286 excluded_paths=(
287 r'.*Test[A-Z]?.*\.java',
288 ),
289 ),
Henrique Nakashimabbf2b262023-03-10 17:21:39290 BanRule(
291 r'/RecordHistogram\.getHistogram(ValueCount|TotalCount|Samples)ForTesting\(',
292 (
293 'Raw histogram counts are easy to misuse; for example they don\'t reset '
294 'between batched tests. Use HistogramWatcher to check histogram records instead.',
295 ),
296 False,
297 excluded_paths=(
298 'base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java',
299 'base/test/android/javatests/src/org/chromium/base/test/util/HistogramWatcher.java',
300 ),
301 ),
Eric Stevensona9a980972017-09-23 00:04:41302)
303
Clement Yan9b330cb2022-11-17 05:25:29304_BANNED_JAVASCRIPT_FUNCTIONS : Sequence [BanRule] = (
305 BanRule(
306 r'/\bchrome\.send\b',
307 (
308 '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).',
309 'Please use mojo instead for new webuis. https://docs.google.com/document/d/1RF-GSUoveYa37eoyZ9EhwMtaIwoW7Z88pIgNZ9YzQi4/edit#heading=h.gkk22wgk6wff',
310 ),
311 True,
312 (
313 r'^(?!ash\/webui).+',
314 # TODO(crbug.com/1385601): pre-existing violations still need to be
315 # cleaned up.
Rebekah Potter57aa94df2022-12-13 20:30:58316 'ash/webui/common/resources/cr.m.js',
Clement Yan9b330cb2022-11-17 05:25:29317 'ash/webui/common/resources/multidevice_setup/multidevice_setup_browser_proxy.js',
318 'ash/webui/common/resources/quick_unlock/lock_screen_constants.js',
319 'ash/webui/common/resources/smb_shares/smb_browser_proxy.js',
320 'ash/webui/connectivity_diagnostics/resources/connectivity_diagnostics.js',
321 'ash/webui/diagnostics_ui/resources/diagnostics_browser_proxy.ts',
322 'ash/webui/multidevice_debug/resources/logs.js',
323 'ash/webui/multidevice_debug/resources/webui.js',
324 'ash/webui/projector_app/resources/annotator/trusted/annotator_browser_proxy.js',
325 'ash/webui/projector_app/resources/app/trusted/projector_browser_proxy.js',
326 'ash/webui/scanning/resources/scanning_browser_proxy.js',
327 ),
328 ),
329)
330
Daniel Cheng917ce542022-03-15 20:46:57331_BANNED_OBJC_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15332 BanRule(
[email protected]127f18ec2012-06-16 05:05:59333 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20334 (
335 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59336 'prohibited. Please use CrTrackingArea instead.',
337 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
338 ),
339 False,
340 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15341 BanRule(
[email protected]eaae1972014-04-16 04:17:26342 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20343 (
344 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59345 'instead.',
346 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
347 ),
348 False,
349 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15350 BanRule(
[email protected]127f18ec2012-06-16 05:05:59351 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20352 (
353 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59354 'Please use |convertPoint:(point) fromView:nil| instead.',
355 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
356 ),
357 True,
358 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15359 BanRule(
[email protected]127f18ec2012-06-16 05:05:59360 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20361 (
362 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59363 'Please use |convertPoint:(point) toView:nil| instead.',
364 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
365 ),
366 True,
367 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15368 BanRule(
[email protected]127f18ec2012-06-16 05:05:59369 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20370 (
371 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59372 'Please use |convertRect:(point) fromView:nil| instead.',
373 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
374 ),
375 True,
376 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15377 BanRule(
[email protected]127f18ec2012-06-16 05:05:59378 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20379 (
380 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59381 'Please use |convertRect:(point) toView:nil| instead.',
382 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
383 ),
384 True,
385 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15386 BanRule(
[email protected]127f18ec2012-06-16 05:05:59387 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20388 (
389 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59390 'Please use |convertSize:(point) fromView:nil| instead.',
391 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
392 ),
393 True,
394 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15395 BanRule(
[email protected]127f18ec2012-06-16 05:05:59396 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20397 (
398 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59399 'Please use |convertSize:(point) toView:nil| instead.',
400 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
401 ),
402 True,
403 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15404 BanRule(
jif65398702016-10-27 10:19:48405 r"/\s+UTF8String\s*]",
406 (
407 'The use of -[NSString UTF8String] is dangerous as it can return null',
408 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
409 'Please use |SysNSStringToUTF8| instead.',
410 ),
411 True,
412 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15413 BanRule(
Sylvain Defresne4cf1d182017-09-18 14:16:34414 r'__unsafe_unretained',
415 (
416 'The use of __unsafe_unretained is almost certainly wrong, unless',
417 'when interacting with NSFastEnumeration or NSInvocation.',
418 'Please use __weak in files build with ARC, nothing otherwise.',
419 ),
420 False,
421 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15422 BanRule(
Avi Drissman7382afa02019-04-29 23:27:13423 'freeWhenDone:NO',
424 (
425 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
426 'Foundation types is prohibited.',
427 ),
428 True,
429 ),
[email protected]127f18ec2012-06-16 05:05:59430)
431
Sylvain Defresnea8b73d252018-02-28 15:45:54432_BANNED_IOS_OBJC_FUNCTIONS = (
Daniel Chenga44a1bcd2022-03-15 20:00:15433 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54434 r'/\bTEST[(]',
435 (
436 'TEST() macro should not be used in Objective-C++ code as it does not ',
437 'drain the autorelease pool at the end of the test. Use TEST_F() ',
438 'macro instead with a fixture inheriting from PlatformTest (or a ',
439 'typedef).'
440 ),
441 True,
442 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15443 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54444 r'/\btesting::Test\b',
445 (
446 'testing::Test should not be used in Objective-C++ code as it does ',
447 'not drain the autorelease pool at the end of the test. Use ',
448 'PlatformTest instead.'
449 ),
450 True,
451 ),
Ewann2ecc8d72022-07-18 07:41:23452 BanRule(
453 ' systemImageNamed:',
454 (
455 '+[UIImage systemImageNamed:] should not be used to create symbols.',
456 'Instead use a wrapper defined in:',
Victor Vianna77a40f62023-01-31 19:04:53457 'ios/chrome/browser/ui/icons/symbol_helpers.h'
Ewann2ecc8d72022-07-18 07:41:23458 ),
459 True,
Ewann450a2ef2022-07-19 14:38:23460 excluded_paths=(
Gauthier Ambard4d8756b2023-04-07 17:26:41461 'ios/chrome/browser/shared/ui/symbols/symbol_helpers.mm',
Gauthier Ambardd36c10b12023-03-16 08:45:03462 'ios/chrome/search_widget_extension/',
Ewann450a2ef2022-07-19 14:38:23463 ),
Ewann2ecc8d72022-07-18 07:41:23464 ),
Sylvain Defresnea8b73d252018-02-28 15:45:54465)
466
Daniel Cheng917ce542022-03-15 20:46:57467_BANNED_IOS_EGTEST_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15468 BanRule(
Peter K. Lee6c03ccff2019-07-15 14:40:05469 r'/\bEXPECT_OCMOCK_VERIFY\b',
470 (
471 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
472 'it is meant for GTests. Use [mock verify] instead.'
473 ),
474 True,
475 ),
476)
477
Daniel Cheng917ce542022-03-15 20:46:57478_BANNED_CPP_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15479 BanRule(
Peter Kasting94a56c42019-10-25 21:54:04480 r'/\busing namespace ',
481 (
482 'Using directives ("using namespace x") are banned by the Google Style',
483 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
484 'Explicitly qualify symbols or use using declarations ("using x::foo").',
485 ),
486 True,
487 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
488 ),
Antonio Gomes07300d02019-03-13 20:59:57489 # Make sure that gtest's FRIEND_TEST() macro is not used; the
490 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
491 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
Daniel Chenga44a1bcd2022-03-15 20:00:15492 BanRule(
[email protected]23e6cbc2012-06-16 18:51:20493 'FRIEND_TEST(',
494 (
[email protected]e3c945502012-06-26 20:01:49495 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20496 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
497 ),
498 False,
[email protected]7345da02012-11-27 14:31:49499 (),
[email protected]23e6cbc2012-06-16 18:51:20500 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15501 BanRule(
tomhudsone2c14d552016-05-26 17:07:46502 'setMatrixClip',
503 (
504 'Overriding setMatrixClip() is prohibited; ',
505 'the base function is deprecated. ',
506 ),
507 True,
508 (),
509 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15510 BanRule(
[email protected]52657f62013-05-20 05:30:31511 'SkRefPtr',
512 (
513 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22514 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31515 ),
516 True,
517 (),
518 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15519 BanRule(
[email protected]52657f62013-05-20 05:30:31520 'SkAutoRef',
521 (
522 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22523 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31524 ),
525 True,
526 (),
527 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15528 BanRule(
[email protected]52657f62013-05-20 05:30:31529 'SkAutoTUnref',
530 (
531 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22532 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31533 ),
534 True,
535 (),
536 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15537 BanRule(
[email protected]52657f62013-05-20 05:30:31538 'SkAutoUnref',
539 (
540 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
541 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22542 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31543 ),
544 True,
545 (),
546 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15547 BanRule(
[email protected]d89eec82013-12-03 14:10:59548 r'/HANDLE_EINTR\(.*close',
549 (
550 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
551 'descriptor will be closed, and it is incorrect to retry the close.',
552 'Either call close directly and ignore its return value, or wrap close',
553 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
554 ),
555 True,
556 (),
557 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15558 BanRule(
[email protected]d89eec82013-12-03 14:10:59559 r'/IGNORE_EINTR\((?!.*close)',
560 (
561 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
562 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
563 ),
564 True,
565 (
566 # Files that #define IGNORE_EINTR.
Bruce Dawson40fece62022-09-16 19:58:31567 r'^base/posix/eintr_wrapper\.h$',
568 r'^ppapi/tests/test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59569 ),
570 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15571 BanRule(
[email protected]ec5b3f02014-04-04 18:43:43572 r'/v8::Extension\(',
573 (
574 'Do not introduce new v8::Extensions into the code base, use',
575 'gin::Wrappable instead. See http://crbug.com/334679',
576 ),
577 True,
[email protected]f55c90ee62014-04-12 00:50:03578 (
Bruce Dawson40fece62022-09-16 19:58:31579 r'extensions/renderer/safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03580 ),
[email protected]ec5b3f02014-04-04 18:43:43581 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15582 BanRule(
jame2d1a952016-04-02 00:27:10583 '#pragma comment(lib,',
584 (
585 'Specify libraries to link with in build files and not in the source.',
586 ),
587 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41588 (
Bruce Dawson40fece62022-09-16 19:58:31589 r'^base/third_party/symbolize/.*',
590 r'^third_party/abseil-cpp/.*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41591 ),
jame2d1a952016-04-02 00:27:10592 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15593 BanRule(
Gabriel Charette7cc6c432018-04-25 20:52:02594 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59595 (
596 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
597 ),
598 False,
599 (),
600 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15601 BanRule(
Gabriel Charette7cc6c432018-04-25 20:52:02602 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59603 (
604 'Consider using THREAD_CHECKER macros instead of the class directly.',
605 ),
606 False,
607 (),
608 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15609 BanRule(
Sean Maher03efef12022-09-23 22:43:13610 r'/\b(?!(Sequenced|SingleThread))\w*TaskRunner::(GetCurrentDefault|CurrentDefaultHandle)',
611 (
612 'It is not allowed to call these methods from the subclasses ',
613 'of Sequenced or SingleThread task runners.',
614 ),
615 True,
616 (),
617 ),
618 BanRule(
Yuri Wiitala2f8de5c2017-07-21 00:11:06619 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
620 (
621 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
622 'deprecated (http://crbug.com/634507). Please avoid converting away',
623 'from the Time types in Chromium code, especially if any math is',
624 'being done on time values. For interfacing with platform/library',
625 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
626 'type converter methods instead. For faking TimeXXX values (for unit',
Peter Kasting53fd6ee2021-10-05 20:40:48627 'testing only), use TimeXXX() + Microseconds(N). For',
Yuri Wiitala2f8de5c2017-07-21 00:11:06628 'other use cases, please contact base/time/OWNERS.',
629 ),
630 False,
631 (),
632 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15633 BanRule(
dbeamb6f4fde2017-06-15 04:03:06634 'CallJavascriptFunctionUnsafe',
635 (
636 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
637 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
638 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
639 ),
640 False,
641 (
Bruce Dawson40fece62022-09-16 19:58:31642 r'^content/browser/webui/web_ui_impl\.(cc|h)$',
643 r'^content/public/browser/web_ui\.h$',
644 r'^content/public/test/test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06645 ),
646 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15647 BanRule(
dskiba1474c2bfd62017-07-20 02:19:24648 'leveldb::DB::Open',
649 (
650 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
651 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
652 "Chrome's tracing, making their memory usage visible.",
653 ),
654 True,
655 (
656 r'^third_party/leveldatabase/.*\.(cc|h)$',
657 ),
Gabriel Charette0592c3a2017-07-26 12:02:04658 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15659 BanRule(
Chris Mumfordc38afb62017-10-09 17:55:08660 'leveldb::NewMemEnv',
661 (
662 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58663 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
664 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08665 ),
666 True,
667 (
668 r'^third_party/leveldatabase/.*\.(cc|h)$',
669 ),
670 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15671 BanRule(
Gabriel Charetted9839bc2017-07-29 14:17:47672 'RunLoop::QuitCurrent',
673 (
Robert Liao64b7ab22017-08-04 23:03:43674 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
675 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47676 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41677 False,
Gabriel Charetted9839bc2017-07-29 14:17:47678 (),
Gabriel Charettea44975052017-08-21 23:14:04679 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15680 BanRule(
Gabriel Charettea44975052017-08-21 23:14:04681 'base::ScopedMockTimeMessageLoopTaskRunner',
682 (
Gabriel Charette87cc1af2018-04-25 20:52:51683 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11684 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51685 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
686 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
687 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04688 ),
Gabriel Charette87cc1af2018-04-25 20:52:51689 False,
Gabriel Charettea44975052017-08-21 23:14:04690 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57691 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15692 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44693 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57694 (
695 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02696 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57697 ),
698 True,
Danil Chapovalov7bc42a72020-12-09 18:20:16699 # Abseil's benchmarks never linked into chrome.
700 ['third_party/abseil-cpp/.*_benchmark.cc'],
Francois Doray43670e32017-09-27 12:40:38701 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15702 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:08703 r'/\bstd::sto(i|l|ul|ll|ull)\b',
Peter Kasting991618a62019-06-17 22:00:09704 (
Peter Kastinge2c5ee82023-02-15 17:23:08705 'std::sto{i,l,ul,ll,ull}() use exceptions to communicate results. ',
706 'Use base::StringTo[U]Int[64]() instead.',
Peter Kasting991618a62019-06-17 22:00:09707 ),
708 True,
709 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
710 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15711 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:08712 r'/\bstd::sto(f|d|ld)\b',
Peter Kasting991618a62019-06-17 22:00:09713 (
Peter Kastinge2c5ee82023-02-15 17:23:08714 'std::sto{f,d,ld}() use exceptions to communicate results. ',
Peter Kasting991618a62019-06-17 22:00:09715 'For locale-independent values, e.g. reading numbers from disk',
716 'profiles, use base::StringToDouble().',
717 'For user-visible values, parse using ICU.',
718 ),
719 True,
720 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
721 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15722 BanRule(
Daniel Bratell69334cc2019-03-26 11:07:45723 r'/\bstd::to_string\b',
724 (
Peter Kastinge2c5ee82023-02-15 17:23:08725 'std::to_string() is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09726 'For locale-independent strings, e.g. writing numbers to disk',
727 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45728 'For user-visible strings, use base::FormatNumber() and',
729 'the related functions in base/i18n/number_formatting.h.',
730 ),
Peter Kasting991618a62019-06-17 22:00:09731 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21732 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45733 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15734 BanRule(
Daniel Bratell69334cc2019-03-26 11:07:45735 r'/\bstd::shared_ptr\b',
736 (
Peter Kastinge2c5ee82023-02-15 17:23:08737 'std::shared_ptr is banned. Use scoped_refptr instead.',
Daniel Bratell69334cc2019-03-26 11:07:45738 ),
739 True,
Ulan Degenbaev947043882021-02-10 14:02:31740 [
741 # Needed for interop with third-party library.
742 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
Alex Chau9eb03cdd52020-07-13 21:04:57743 'array_buffer_contents\.(cc|h)',
Ben Kelly39bf6bef2021-10-04 22:54:58744 '^third_party/blink/renderer/bindings/core/v8/' +
745 'v8_wasm_response_extensions.cc',
Wez5f56be52021-05-04 09:30:58746 '^gin/array_buffer\.(cc|h)',
747 '^chrome/services/sharing/nearby/',
Stephen Nuskoe09c8ef22022-09-29 00:47:28748 # Needed for interop with third-party library libunwindstack.
Stephen Nuskoe51c1382022-09-26 15:49:03749 '^base/profiler/libunwindstack_unwinder_android\.(cc|h)',
Bob Beck03509d282022-12-07 21:49:05750 # Needed for interop with third-party boringssl cert verifier
751 '^third_party/boringssl/',
752 '^net/cert/',
753 '^net/tools/cert_verify_tool/',
754 '^services/cert_verifier/',
755 '^components/certificate_transparency/',
756 '^components/media_router/common/providers/cast/certificate/',
Meilin Wang00efc7c2021-05-13 01:12:42757 # gRPC provides some C++ libraries that use std::shared_ptr<>.
Yeunjoo Choi1b644402022-08-25 02:36:10758 '^chromeos/ash/services/libassistant/grpc/',
Vigen Issahhanjanfdf9de52021-12-22 21:13:59759 '^chromecast/cast_core/grpc',
760 '^chromecast/cast_core/runtime/browser',
Yue Shef83d95202022-09-26 20:23:45761 '^ios/chrome/test/earl_grey/chrome_egtest_plugin_client\.(mm|h)',
Wez5f56be52021-05-04 09:30:58762 # Fuchsia provides C++ libraries that use std::shared_ptr<>.
Wez6da2e412022-11-23 11:28:48763 '^base/fuchsia/.*\.(cc|h)',
Wez5f56be52021-05-04 09:30:58764 '.*fuchsia.*test\.(cc|h)',
Will Cassella64da6c52022-01-06 18:13:57765 # Needed for clang plugin tests
766 '^tools/clang/plugins/tests/',
Alex Chau9eb03cdd52020-07-13 21:04:57767 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21768 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15769 BanRule(
Peter Kasting991618a62019-06-17 22:00:09770 r'/\bstd::weak_ptr\b',
771 (
Peter Kastinge2c5ee82023-02-15 17:23:08772 'std::weak_ptr is banned. Use base::WeakPtr instead.',
Peter Kasting991618a62019-06-17 22:00:09773 ),
774 True,
775 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
776 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15777 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21778 r'/\blong long\b',
779 (
Peter Kastinge2c5ee82023-02-15 17:23:08780 'long long is banned. Use [u]int64_t instead.',
Daniel Bratell609102be2019-03-27 20:53:21781 ),
782 False, # Only a warning since it is already used.
783 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
784 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15785 BanRule(
Daniel Cheng192683f2022-11-01 20:52:44786 r'/\b(absl|std)::any\b',
Daniel Chengc05fcc62022-01-12 16:54:29787 (
Peter Kastinge2c5ee82023-02-15 17:23:08788 '{absl,std}::any are banned due to incompatibility with the component ',
789 'build.',
Daniel Chengc05fcc62022-01-12 16:54:29790 ),
791 True,
792 # Not an error in third party folders, though it probably should be :)
793 [_THIRD_PARTY_EXCEPT_BLINK],
794 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15795 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21796 r'/\bstd::bind\b',
797 (
Peter Kastinge2c5ee82023-02-15 17:23:08798 'std::bind() is banned because of lifetime risks. Use ',
799 'base::Bind{Once,Repeating}() instead.',
Daniel Bratell609102be2019-03-27 20:53:21800 ),
801 True,
802 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
803 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15804 BanRule(
Daniel Cheng192683f2022-11-01 20:52:44805 (
Peter Kastingc7460d982023-03-14 21:01:42806 r'/\bstd::(?:'
807 r'linear_congruential_engine|mersenne_twister_engine|'
808 r'subtract_with_carry_engine|discard_block_engine|'
809 r'independent_bits_engine|shuffle_order_engine|'
810 r'minstd_rand0?|mt19937(_64)?|ranlux(24|48)(_base)?|knuth_b|'
811 r'default_random_engine|'
812 r'random_device|'
813 r'seed_seq'
Daniel Cheng192683f2022-11-01 20:52:44814 r')\b'
815 ),
816 (
817 'STL random number engines and generators are banned. Use the ',
818 'helpers in base/rand_util.h instead, e.g. base::RandBytes() or ',
819 'base::RandomBitGenerator.'
820 ),
821 True,
822 [
823 # Not an error in third_party folders.
824 _THIRD_PARTY_EXCEPT_BLINK,
825 # Various tools which build outside of Chrome.
826 r'testing/libfuzzer',
827 r'tools/android/io_benchmark/',
828 # Fuzzers are allowed to use standard library random number generators
829 # since fuzzing speed + reproducibility is important.
830 r'tools/ipc_fuzzer/',
831 r'.+_fuzzer\.cc$',
832 r'.+_fuzzertest\.cc$',
833 # TODO(https://crbug.com/1380528): These are all unsanctioned uses of
834 # the standard library's random number generators, and should be
835 # migrated to the //base equivalent.
836 r'ash/ambient/model/ambient_topic_queue\.cc',
837 r'base/allocator/partition_allocator/partition_alloc_unittest\.cc',
838 r'base/ranges/algorithm_unittest\.cc',
839 r'base/test/launcher/test_launcher\.cc',
840 r'cc/metrics/video_playback_roughness_reporter_unittest\.cc',
841 r'chrome/browser/apps/app_service/metrics/website_metrics\.cc',
842 r'chrome/browser/ash/power/auto_screen_brightness/monotone_cubic_spline_unittest\.cc',
843 r'chrome/browser/ash/printing/zeroconf_printer_detector_unittest\.cc',
844 r'chrome/browser/nearby_sharing/contacts/nearby_share_contact_manager_impl_unittest\.cc',
845 r'chrome/browser/nearby_sharing/contacts/nearby_share_contacts_sorter_unittest\.cc',
846 r'chrome/browser/privacy_budget/mesa_distribution_unittest\.cc',
847 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
848 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
849 r'chrome/browser/win/conflicts/module_blocklist_cache_util_unittest\.cc',
850 r'chrome/chrome_cleaner/logging/detailed_info_sampler\.cc',
851 r'chromeos/ash/components/memory/userspace_swap/swap_storage_unittest\.cc',
852 r'chromeos/ash/components/memory/userspace_swap/userspace_swap\.cc',
853 r'components/metrics/metrics_state_manager\.cc',
854 r'components/omnibox/browser/history_quick_provider_performance_unittest\.cc',
855 r'components/zucchini/disassembler_elf_unittest\.cc',
856 r'content/browser/webid/federated_auth_request_impl\.cc',
857 r'content/browser/webid/federated_auth_request_impl\.cc',
858 r'media/cast/test/utility/udp_proxy\.h',
859 r'sql/recover_module/module_unittest\.cc',
860 ],
861 ),
862 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:08863 r'/\b(absl,std)::bind_front\b',
Peter Kasting4f35bfc2022-10-18 18:39:12864 (
Peter Kastinge2c5ee82023-02-15 17:23:08865 '{absl,std}::bind_front() are banned. Use base::Bind{Once,Repeating}() '
866 'instead.',
Peter Kasting4f35bfc2022-10-18 18:39:12867 ),
868 True,
869 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
870 ),
871 BanRule(
872 r'/\bABSL_FLAG\b',
873 (
874 'ABSL_FLAG is banned. Use base::CommandLine instead.',
875 ),
876 True,
877 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
878 ),
879 BanRule(
880 r'/\babsl::c_',
881 (
Peter Kastinge2c5ee82023-02-15 17:23:08882 'Abseil container utilities are banned. Use base/ranges/algorithm.h ',
Peter Kasting4f35bfc2022-10-18 18:39:12883 'instead.',
884 ),
885 True,
886 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
887 ),
888 BanRule(
889 r'/\babsl::FunctionRef\b',
890 (
891 'absl::FunctionRef is banned. Use base::FunctionRef instead.',
892 ),
893 True,
894 [
895 # base::Bind{Once,Repeating} references absl::FunctionRef to disallow
896 # interoperability.
897 r'^base/functional/bind_internal\.h',
898 # base::FunctionRef is implemented on top of absl::FunctionRef.
899 r'^base/functional/function_ref.*\..+',
900 # Not an error in third_party folders.
901 _THIRD_PARTY_EXCEPT_BLINK,
902 ],
903 ),
904 BanRule(
905 r'/\babsl::(Insecure)?BitGen\b',
906 (
Daniel Cheng192683f2022-11-01 20:52:44907 'absl random number generators are banned. Use the helpers in '
908 'base/rand_util.h instead, e.g. base::RandBytes() or ',
909 'base::RandomBitGenerator.'
Peter Kasting4f35bfc2022-10-18 18:39:12910 ),
911 True,
912 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
913 ),
914 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:08915 r'/(\babsl::Span\b|#include <span>)',
Peter Kasting4f35bfc2022-10-18 18:39:12916 (
Peter Kastinge2c5ee82023-02-15 17:23:08917 'absl::Span is banned and <span> is not allowed yet ',
918 '(https://crbug.com/1414652). Use base::span instead.',
Peter Kasting4f35bfc2022-10-18 18:39:12919 ),
920 True,
Victor Vasiliev23b9ea6a2023-01-05 19:42:29921 [
922 # Needed to use QUICHE API.
923 r'services/network/web_transport\.cc',
924 # Not an error in third_party folders.
925 _THIRD_PARTY_EXCEPT_BLINK
926 ],
Peter Kasting4f35bfc2022-10-18 18:39:12927 ),
928 BanRule(
929 r'/\babsl::StatusOr\b',
930 (
931 'absl::StatusOr is banned. Use base::expected instead.',
932 ),
933 True,
Adithya Srinivasanb2041882022-10-21 19:34:20934 [
935 # Needed to use liburlpattern API.
936 r'third_party/blink/renderer/core/url_pattern/.*',
Louise Brettc6d23872023-04-11 02:48:32937 r'third_party/blink/renderer/modules/manifest/manifest_parser\.cc',
Adithya Srinivasanb2041882022-10-21 19:34:20938 # Not an error in third_party folders.
939 _THIRD_PARTY_EXCEPT_BLINK
940 ],
Peter Kasting4f35bfc2022-10-18 18:39:12941 ),
942 BanRule(
943 r'/\babsl::StrFormat\b',
944 (
Peter Kastinge2c5ee82023-02-15 17:23:08945 'absl::StrFormat() is not allowed yet (https://crbug.com/1371963). ',
946 'Use base::StringPrintf() instead.',
Peter Kasting4f35bfc2022-10-18 18:39:12947 ),
948 True,
949 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
950 ),
951 BanRule(
David Benjaminea985a22023-04-18 22:05:01952 r'/\babsl::string_view\b',
Peter Kasting4f35bfc2022-10-18 18:39:12953 (
David Benjaminea985a22023-04-18 22:05:01954 'absl::string_view is a legacy spelling of std::string_view, which is ',
955 'not allowed yet (https://crbug.com/691162). Use base::StringPiece ',
956 'instead, unless std::string_view is needed to use with an external ',
957 'API.',
958 ),
959 True,
960 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
961 ),
962 BanRule(
963 r'/\bstd::(u16)?string_view\b',
964 (
965 'std::[u16]string_view is not yet allowed (crbug.com/691162). Use ',
966 'base::StringPiece[16] instead, unless std::[u16]string_view is ',
967 'needed to use an external API.',
Peter Kasting4f35bfc2022-10-18 18:39:12968 ),
969 True,
Adithya Srinivasanb2041882022-10-21 19:34:20970 [
David Benjaminea985a22023-04-18 22:05:01971 # Needed to implement and test std::string_view interoperability.
972 r'base/strings/string_piece.*',
Xiaochen Zhouf19c97f2023-04-28 13:04:32973 # Needed to use re2::RE2 regular expression library.
974 r'third_party/blink/common/interest_group/ad_display_size_utils.cc',
Adithya Srinivasanb2041882022-10-21 19:34:20975 # Needed to use liburlpattern API.
976 r'third_party/blink/renderer/core/url_pattern/.*',
Louise Brettc6d23872023-04-11 02:48:32977 r'third_party/blink/renderer/modules/manifest/manifest_parser\.cc',
David Benjamin3a305f12022-11-19 00:10:03978 # Needed to use QUICHE API.
Victor Vasilieva13f1932022-12-02 15:27:24979 r'net/quic/.*',
980 r'net/spdy/.*',
David Benjamin3a305f12022-11-19 00:10:03981 r'net/test/embedded_test_server/.*',
Victor Vasilieva13f1932022-12-02 15:27:24982 r'net/third_party/quiche/.*',
983 r'services/network/web_transport\.cc',
David Benjaminea985a22023-04-18 22:05:01984 # This code is in the process of being extracted into an external
985 # library, where //base will be unavailable.
986 r'net/cert/pki/.*',
987 r'net/der/.*',
988 # Needed to use APIs from the above.
989 r'net/cert/.*',
Adithya Srinivasanb2041882022-10-21 19:34:20990 # Not an error in third_party folders.
991 _THIRD_PARTY_EXCEPT_BLINK
992 ],
Peter Kasting4f35bfc2022-10-18 18:39:12993 ),
994 BanRule(
995 r'/\babsl::(StrSplit|StrJoin|StrCat|StrAppend|Substitute|StrContains)\b',
996 (
997 'Abseil string utilities are banned. Use base/strings instead.',
998 ),
999 True,
1000 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1001 ),
1002 BanRule(
1003 r'/\babsl::(Mutex|CondVar|Notification|Barrier|BlockingCounter)\b',
1004 (
1005 'Abseil synchronization primitives are banned. Use',
1006 'base/synchronization instead.',
1007 ),
1008 True,
1009 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1010 ),
1011 BanRule(
1012 r'/\babsl::(Duration|Time|TimeZone|CivilDay)\b',
1013 (
1014 'Abseil\'s time library is banned. Use base/time instead.',
1015 ),
1016 True,
1017 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1018 ),
1019 BanRule(
Avi Drissman48ee39e2022-02-16 16:31:031020 r'/\bstd::optional\b',
1021 (
Peter Kastinge2c5ee82023-02-15 17:23:081022 'std::optional is not allowed yet (https://crbug.com/1373619). Use ',
1023 'absl::optional instead.',
Avi Drissman48ee39e2022-02-16 16:31:031024 ),
1025 True,
1026 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1027 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151028 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081029 r'/#include <chrono>',
Daniel Bratell609102be2019-03-27 20:53:211030 (
Peter Kastinge2c5ee82023-02-15 17:23:081031 '<chrono> is banned. Use base/time instead.',
Daniel Bratell609102be2019-03-27 20:53:211032 ),
1033 True,
1034 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1035 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151036 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081037 r'/#include <exception>',
Daniel Bratell609102be2019-03-27 20:53:211038 (
1039 'Exceptions are banned and disabled in Chromium.',
1040 ),
1041 True,
1042 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1043 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151044 BanRule(
Daniel Bratell609102be2019-03-27 20:53:211045 r'/\bstd::function\b',
1046 (
Peter Kastinge2c5ee82023-02-15 17:23:081047 'std::function is banned. Use base::{Once,Repeating}Callback instead.',
Daniel Bratell609102be2019-03-27 20:53:211048 ),
Daniel Chenge5583e3c2022-09-22 00:19:411049 True,
Daniel Chengcd23b8b2022-09-16 17:16:241050 [
1051 # Has tests that template trait helpers don't unintentionally match
1052 # std::function.
Daniel Chenge5583e3c2022-09-22 00:19:411053 r'base/functional/callback_helpers_unittest\.cc',
1054 # Required to implement interfaces from the third-party perfetto
1055 # library.
1056 r'base/tracing/perfetto_task_runner\.cc',
1057 r'base/tracing/perfetto_task_runner\.h',
1058 # Needed for interop with the third-party nearby library type
1059 # location::nearby::connections::ResultCallback.
1060 'chrome/services/sharing/nearby/nearby_connections_conversions\.cc'
1061 # Needed for interop with the internal libassistant library.
1062 'chromeos/ash/services/libassistant/callback_utils\.h',
1063 # Needed for interop with Fuchsia fidl APIs.
1064 'fuchsia_web/webengine/browser/context_impl_browsertest\.cc',
1065 'fuchsia_web/webengine/browser/cookie_manager_impl_unittest\.cc',
1066 'fuchsia_web/webengine/browser/media_player_impl_unittest\.cc',
1067 # Required to interop with interfaces from the third-party perfetto
1068 # library.
1069 'services/tracing/public/cpp/perfetto/custom_event_recorder\.cc',
1070 'services/tracing/public/cpp/perfetto/perfetto_traced_process\.cc',
1071 'services/tracing/public/cpp/perfetto/perfetto_traced_process\.h',
1072 'services/tracing/public/cpp/perfetto/perfetto_tracing_backend\.cc',
1073 'services/tracing/public/cpp/perfetto/producer_client\.cc',
1074 'services/tracing/public/cpp/perfetto/producer_client\.h',
1075 'services/tracing/public/cpp/perfetto/producer_test_utils\.cc',
1076 'services/tracing/public/cpp/perfetto/producer_test_utils\.h',
1077 # Required for interop with the third-party webrtc library.
1078 'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.cc',
1079 'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.h',
Bob Beck5fc0be82022-12-12 23:32:521080 # This code is in the process of being extracted into a third-party library.
1081 # See https://crbug.com/1322914
1082 '^net/cert/pki/path_builder_unittest\.cc',
Daniel Chenge5583e3c2022-09-22 00:19:411083 # TODO(https://crbug.com/1364577): Various uses that should be
1084 # migrated to something else.
1085 # Should use base::OnceCallback or base::RepeatingCallback.
1086 'base/allocator/dispatcher/initializer_unittest\.cc',
1087 'chrome/browser/ash/accessibility/speech_monitor\.cc',
1088 'chrome/browser/ash/accessibility/speech_monitor\.h',
1089 'chrome/browser/ash/login/ash_hud_login_browsertest\.cc',
1090 'chromecast/base/observer_unittest\.cc',
1091 'chromecast/browser/cast_web_view\.h',
1092 'chromecast/public/cast_media_shlib\.h',
1093 'device/bluetooth/floss/exported_callback_manager\.h',
1094 'device/bluetooth/floss/floss_dbus_client\.h',
1095 'device/fido/cable/v2_handshake_unittest\.cc',
1096 'device/fido/pin\.cc',
1097 'services/tracing/perfetto/test_utils\.h',
1098 # Should use base::FunctionRef.
1099 'chrome/browser/media/webrtc/test_stats_dictionary\.cc',
1100 'chrome/browser/media/webrtc/test_stats_dictionary\.h',
1101 'chromeos/ash/services/libassistant/device_settings_controller\.cc',
1102 'components/browser_ui/client_certificate/android/ssl_client_certificate_request\.cc',
1103 'components/gwp_asan/client/sampling_malloc_shims_unittest\.cc',
1104 'content/browser/font_unique_name_lookup/font_unique_name_lookup_unittest\.cc',
1105 # Does not need std::function at all.
1106 'components/omnibox/browser/autocomplete_result\.cc',
1107 'device/fido/win/webauthn_api\.cc',
1108 'media/audio/alsa/alsa_util\.cc',
1109 'media/remoting/stream_provider\.h',
1110 'sql/vfs_wrapper\.cc',
1111 # TODO(https://crbug.com/1364585): Remove usage and exception list
1112 # entries.
1113 'extensions/renderer/api/automation/automation_internal_custom_bindings\.cc',
1114 'extensions/renderer/api/automation/automation_internal_custom_bindings\.h',
1115 # TODO(https://crbug.com/1364579): Remove usage and exception list
1116 # entry.
1117 'ui/views/controls/focus_ring\.h',
1118
1119 # Various pre-existing uses in //tools that is low-priority to fix.
1120 'tools/binary_size/libsupersize/viewer/caspian/diff\.cc',
1121 'tools/binary_size/libsupersize/viewer/caspian/model\.cc',
1122 'tools/binary_size/libsupersize/viewer/caspian/model\.h',
1123 'tools/binary_size/libsupersize/viewer/caspian/tree_builder\.h',
1124 'tools/clang/base_bind_rewriters/BaseBindRewriters\.cpp',
1125
Daniel Chengcd23b8b2022-09-16 17:16:241126 # Not an error in third_party folders.
1127 _THIRD_PARTY_EXCEPT_BLINK
1128 ],
Daniel Bratell609102be2019-03-27 20:53:211129 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151130 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081131 r'/#include <X11/',
Tom Andersona95e12042020-09-09 23:08:001132 (
1133 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
1134 ),
1135 True,
1136 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1137 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151138 BanRule(
Daniel Bratell609102be2019-03-27 20:53:211139 r'/\bstd::ratio\b',
1140 (
1141 'std::ratio is banned by the Google Style Guide.',
1142 ),
1143 True,
1144 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:451145 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151146 BanRule(
Peter Kasting6d77e9d2023-02-09 21:58:181147 r'/\bstd::aligned_alloc\b',
1148 (
Peter Kastinge2c5ee82023-02-15 17:23:081149 'std::aligned_alloc() is not yet allowed (crbug.com/1412818). Use ',
1150 'base::AlignedAlloc() instead.',
Peter Kasting6d77e9d2023-02-09 21:58:181151 ),
1152 True,
1153 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1154 ),
1155 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081156 r'/#include <(barrier|latch|semaphore|stop_token)>',
Peter Kasting6d77e9d2023-02-09 21:58:181157 (
Peter Kastinge2c5ee82023-02-15 17:23:081158 'The thread support library is banned. Use base/synchronization '
1159 'instead.',
Peter Kasting6d77e9d2023-02-09 21:58:181160 ),
1161 True,
1162 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1163 ),
1164 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081165 r'/\bstd::(c8rtomb|mbrtoc8)\b',
Peter Kasting6d77e9d2023-02-09 21:58:181166 (
Peter Kastinge2c5ee82023-02-15 17:23:081167 'std::c8rtomb() and std::mbrtoc8() are banned.',
Peter Kasting6d77e9d2023-02-09 21:58:181168 ),
1169 True,
1170 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1171 ),
1172 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081173 r'/\bchar8_t|std::u8string\b',
Peter Kasting6d77e9d2023-02-09 21:58:181174 (
Peter Kastinge2c5ee82023-02-15 17:23:081175 'char8_t and std::u8string are not yet allowed. Can you use [unsigned]',
1176 ' char and std::string instead?',
1177 ),
1178 True,
Daniel Cheng893c563f2023-04-21 09:54:521179 [
1180 # The demangler does not use this type but needs to know about it.
1181 'base/third_party/symbolize/demangle\.cc',
1182 # Don't warn in third_party folders.
1183 _THIRD_PARTY_EXCEPT_BLINK
1184 ],
Peter Kastinge2c5ee82023-02-15 17:23:081185 ),
1186 BanRule(
1187 r'/(\b(co_await|co_return|co_yield)\b|#include <coroutine>)',
1188 (
1189 'Coroutines are not yet allowed (https://crbug.com/1403840).',
1190 ),
1191 True,
1192 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1193 ),
1194 BanRule(
Peter Kastingcc152522023-03-22 20:17:371195 r'/^\s*(export\s|import\s+["<:\w]|module(;|\s+[:\w]))',
Peter Kasting69357dc2023-03-14 01:34:291196 (
1197 'Modules are disallowed for now due to lack of toolchain support.',
1198 ),
1199 True,
1200 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1201 ),
1202 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081203 r'/\[\[(un)?likely\]\]',
1204 (
1205 '[[likely]] and [[unlikely]] are not yet allowed ',
1206 '(https://crbug.com/1414620). Use [UN]LIKELY instead.',
1207 ),
1208 True,
1209 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1210 ),
1211 BanRule(
1212 r'/#include <format>',
1213 (
1214 '<format> is not yet allowed. Use base::StringPrintf() instead.',
1215 ),
1216 True,
1217 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1218 ),
1219 BanRule(
1220 r'/#include <ranges>',
1221 (
1222 '<ranges> is not yet allowed. Use base/ranges/algorithm.h instead.',
1223 ),
1224 True,
1225 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1226 ),
1227 BanRule(
1228 r'/#include <source_location>',
1229 (
1230 '<source_location> is not yet allowed. Use base/location.h instead.',
1231 ),
1232 True,
1233 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1234 ),
1235 BanRule(
1236 r'/#include <syncstream>',
1237 (
1238 '<syncstream> is banned.',
Peter Kasting6d77e9d2023-02-09 21:58:181239 ),
1240 True,
1241 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1242 ),
1243 BanRule(
Michael Giuffrida7f93d6922019-04-19 14:39:581244 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:191245 (
1246 'RunMessageLoop is deprecated, use RunLoop instead.',
1247 ),
1248 False,
1249 (),
1250 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151251 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441252 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:191253 (
1254 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
1255 "if you're convinced you need this.",
1256 ),
1257 False,
1258 (),
1259 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151260 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441261 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:191262 (
1263 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:041264 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:191265 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
1266 'async events instead of flushing threads.',
1267 ),
1268 False,
1269 (),
1270 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151271 BanRule(
Gabriel Charette147335ea2018-03-22 15:59:191272 r'MessageLoopRunner',
1273 (
1274 'MessageLoopRunner is deprecated, use RunLoop instead.',
1275 ),
1276 False,
1277 (),
1278 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151279 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441280 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:191281 (
1282 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
1283 "gab@ if you found a use case where this is the only solution.",
1284 ),
1285 False,
1286 (),
1287 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151288 BanRule(
Victor Costane48a2e82019-03-15 22:02:341289 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:161290 (
Victor Costane48a2e82019-03-15 22:02:341291 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:161292 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
1293 ),
1294 True,
1295 (
1296 r'^sql/initialization\.(cc|h)$',
1297 r'^third_party/sqlite/.*\.(c|cc|h)$',
1298 ),
1299 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151300 BanRule(
Austin Sullivand661ab52022-11-16 08:55:151301 'CREATE VIEW',
1302 (
1303 'SQL views are disabled in Chromium feature code',
1304 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-views',
1305 ),
1306 True,
1307 (
1308 _THIRD_PARTY_EXCEPT_BLINK,
1309 # sql/ itself uses views when using memory-mapped IO.
1310 r'^sql/.*',
1311 # Various performance tools that do not build as part of Chrome.
1312 r'^infra/.*',
1313 r'^tools/perf.*',
1314 r'.*perfetto.*',
1315 ),
1316 ),
1317 BanRule(
1318 'CREATE VIRTUAL TABLE',
1319 (
1320 'SQL virtual tables are disabled in Chromium feature code',
1321 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-virtual-tables',
1322 ),
1323 True,
1324 (
1325 _THIRD_PARTY_EXCEPT_BLINK,
1326 # sql/ itself uses virtual tables in the recovery module and tests.
1327 r'^sql/.*',
1328 # TODO(https://crbug.com/695592): Remove once WebSQL is deprecated.
1329 r'third_party/blink/web_tests/storage/websql/.*'
1330 # Various performance tools that do not build as part of Chrome.
1331 r'^tools/perf.*',
1332 r'.*perfetto.*',
1333 ),
1334 ),
1335 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441336 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:471337 (
1338 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
1339 'base::RandomShuffle instead.'
1340 ),
1341 True,
1342 (),
1343 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151344 BanRule(
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:241345 'ios/web/public/test/http_server',
1346 (
1347 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
1348 ),
1349 False,
1350 (),
1351 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151352 BanRule(
Robert Liao764c9492019-01-24 18:46:281353 'GetAddressOf',
1354 (
1355 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:531356 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:111357 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:531358 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:281359 ),
1360 True,
1361 (),
1362 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151363 BanRule(
Ben Lewisa9514602019-04-29 17:53:051364 'SHFileOperation',
1365 (
1366 'SHFileOperation was deprecated in Windows Vista, and there are less ',
1367 'complex functions to achieve the same goals. Use IFileOperation for ',
1368 'any esoteric actions instead.'
1369 ),
1370 True,
1371 (),
1372 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151373 BanRule(
Cliff Smolinsky81951642019-04-30 21:39:511374 'StringFromGUID2',
1375 (
1376 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241377 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511378 ),
1379 True,
1380 (
Daniel Chenga44a1bcd2022-03-15 20:00:151381 r'/base/win/win_util_unittest.cc',
Cliff Smolinsky81951642019-04-30 21:39:511382 ),
1383 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151384 BanRule(
Cliff Smolinsky81951642019-04-30 21:39:511385 'StringFromCLSID',
1386 (
1387 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241388 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511389 ),
1390 True,
1391 (
Daniel Chenga44a1bcd2022-03-15 20:00:151392 r'/base/win/win_util_unittest.cc',
Cliff Smolinsky81951642019-04-30 21:39:511393 ),
1394 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151395 BanRule(
Avi Drissman7382afa02019-04-29 23:27:131396 'kCFAllocatorNull',
1397 (
1398 'The use of kCFAllocatorNull with the NoCopy creation of ',
1399 'CoreFoundation types is prohibited.',
1400 ),
1401 True,
1402 (),
1403 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151404 BanRule(
Oksana Zhuravlovafd247772019-05-16 16:57:291405 'mojo::ConvertTo',
1406 (
1407 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1408 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1409 'StringTraits if you would like to convert between custom types and',
1410 'the wire format of mojom types.'
1411 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221412 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291413 (
David Dorwin13dc48b2022-06-03 21:18:421414 r'^fuchsia_web/webengine/browser/url_request_rewrite_rules_manager\.cc$',
1415 r'^fuchsia_web/webengine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291416 r'^third_party/blink/.*\.(cc|h)$',
1417 r'^content/renderer/.*\.(cc|h)$',
1418 ),
1419 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151420 BanRule(
Oksana Zhuravlovac8222d22019-12-19 19:21:161421 'GetInterfaceProvider',
1422 (
1423 'InterfaceProvider is deprecated.',
1424 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1425 'or Platform::GetBrowserInterfaceBroker.'
1426 ),
1427 False,
1428 (),
1429 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151430 BanRule(
Robert Liao1d78df52019-11-11 20:02:011431 'CComPtr',
1432 (
1433 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1434 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1435 'details.'
1436 ),
1437 False,
1438 (),
1439 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151440 BanRule(
Xiaohan Wang72bd2ba2020-02-18 21:38:201441 r'/\b(IFACE|STD)METHOD_?\(',
1442 (
1443 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1444 'Instead, always use IFACEMETHODIMP in the declaration.'
1445 ),
1446 False,
1447 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1448 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151449 BanRule(
Allen Bauer53b43fb12020-03-12 17:21:471450 'set_owned_by_client',
1451 (
1452 'set_owned_by_client is deprecated.',
1453 'views::View already owns the child views by default. This introduces ',
1454 'a competing ownership model which makes the code difficult to reason ',
1455 'about. See http://crbug.com/1044687 for more details.'
1456 ),
1457 False,
1458 (),
1459 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151460 BanRule(
Peter Boström7ff41522021-07-29 03:43:271461 'RemoveAllChildViewsWithoutDeleting',
1462 (
1463 'RemoveAllChildViewsWithoutDeleting is deprecated.',
1464 'This method is deemed dangerous as, unless raw pointers are re-added,',
1465 'calls to this method introduce memory leaks.'
1466 ),
1467 False,
1468 (),
1469 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151470 BanRule(
Eric Secklerbe6f48d2020-05-06 18:09:121471 r'/\bTRACE_EVENT_ASYNC_',
1472 (
1473 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1474 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1475 ),
1476 False,
1477 (
1478 r'^base/trace_event/.*',
1479 r'^base/tracing/.*',
1480 ),
1481 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151482 BanRule(
Aditya Kushwah5a286b72022-02-10 04:54:431483 r'/\bbase::debug::DumpWithoutCrashingUnthrottled[(][)]',
1484 (
1485 'base::debug::DumpWithoutCrashingUnthrottled() does not throttle',
1486 'dumps and may spam crash reports. Consider if the throttled',
1487 'variants suffice instead.',
1488 ),
1489 False,
1490 (),
1491 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151492 BanRule(
Robert Liao22f66a52021-04-10 00:57:521493 'RoInitialize',
1494 (
Robert Liao48018922021-04-16 23:03:021495 'Improper use of [base::win]::RoInitialize() has been implicated in a ',
Robert Liao22f66a52021-04-10 00:57:521496 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
1497 'instead. See http://crbug.com/1197722 for more information.'
1498 ),
1499 True,
Robert Liao48018922021-04-16 23:03:021500 (
Bruce Dawson40fece62022-09-16 19:58:311501 r'^base/win/scoped_winrt_initializer\.cc$',
Robert Liao48018922021-04-16 23:03:021502 ),
Robert Liao22f66a52021-04-10 00:57:521503 ),
Patrick Monettec343bb982022-06-01 17:18:451504 BanRule(
1505 r'base::Watchdog',
1506 (
1507 'base::Watchdog is deprecated because it creates its own thread.',
1508 'Instead, manually start a timer on a SequencedTaskRunner.',
1509 ),
1510 False,
1511 (),
1512 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091513 BanRule(
1514 'base::Passed',
1515 (
1516 'Do not use base::Passed. It is a legacy helper for capturing ',
1517 'move-only types with base::BindRepeating, but invoking the ',
1518 'resulting RepeatingCallback moves the captured value out of ',
1519 'the callback storage, and subsequent invocations may pass the ',
1520 'value in a valid but undefined state. Prefer base::BindOnce().',
1521 'See http://crbug.com/1326449 for context.'
1522 ),
1523 False,
Daniel Cheng91f6fbaf2022-09-16 12:07:481524 (
1525 # False positive, but it is also fine to let bind internals reference
1526 # base::Passed.
Daniel Chengcd23b8b2022-09-16 17:16:241527 r'^base[\\/]functional[\\/]bind\.h',
Daniel Cheng91f6fbaf2022-09-16 12:07:481528 r'^base[\\/]functional[\\/]bind_internal\.h',
1529 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091530 ),
Daniel Cheng2248b332022-07-27 06:16:591531 BanRule(
Daniel Chengba3bc2e2022-10-03 02:45:431532 r'base::Feature k',
1533 (
1534 'Please use BASE_DECLARE_FEATURE() or BASE_FEATURE() instead of ',
1535 'directly declaring/defining features.'
1536 ),
1537 True,
1538 [
1539 _THIRD_PARTY_EXCEPT_BLINK,
1540 ],
1541 ),
Robert Ogden92101dcb2022-10-19 23:49:361542 BanRule(
Arthur Sonzogni1da65fa2023-03-27 16:01:521543 r'/\bchartorune\b',
Robert Ogden92101dcb2022-10-19 23:49:361544 (
1545 'chartorune is not memory-safe, unless you can guarantee the input ',
1546 'string is always null-terminated. Otherwise, please use charntorune ',
1547 'from libphonenumber instead.'
1548 ),
1549 True,
1550 [
1551 _THIRD_PARTY_EXCEPT_BLINK,
1552 # Exceptions to this rule should have a fuzzer.
1553 ],
1554 ),
Arthur Sonzogni1da65fa2023-03-27 16:01:521555 BanRule(
1556 r'/\b#include "base/atomicops\.h"\b',
1557 (
1558 'Do not use base::subtle atomics, but std::atomic, which are simpler '
1559 'to use, have better understood, clearer and richer semantics, and are '
1560 'harder to mis-use. See details in base/atomicops.h.',
1561 ),
1562 False,
1563 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Benoit Lize79cf0592023-01-27 10:01:571564 ),
Arthur Sonzogni60348572e2023-04-07 10:22:521565 BanRule(
1566 r'CrossThreadPersistent<',
1567 (
1568 'Do not use blink::CrossThreadPersistent, but '
1569 'blink::CrossThreadHandle. It is harder to mis-use.',
1570 'More info: '
1571 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1572 'Please contact platform-architecture-dev@ before adding new instances.'
1573 ),
1574 False,
1575 []
1576 ),
1577 BanRule(
1578 r'CrossThreadWeakPersistent<',
1579 (
1580 'Do not use blink::CrossThreadWeakPersistent, but '
1581 'blink::CrossThreadWeakHandle. It is harder to mis-use.',
1582 'More info: '
1583 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1584 'Please contact platform-architecture-dev@ before adding new instances.'
1585 ),
1586 False,
1587 []
1588 ),
Avi Drissman491617c2023-04-13 17:33:151589 BanRule(
1590 r'objc/objc.h',
1591 (
1592 'Do not include <objc/objc.h>. It defines away ARC lifetime '
1593 'annotations, and is thus dangerous.',
1594 'Please use the pimpl pattern; search for `ObjCStorage` for examples.',
1595 'For further reading on how to safely mix C++ and Obj-C, see',
1596 'https://chromium.googlesource.com/chromium/src/+/main/docs/mac/mixing_cpp_and_objc.md'
1597 ),
1598 True,
1599 []
1600 ),
Grace Park8d59b54b2023-04-26 17:53:351601 BanRule(
1602 r'/#include <filesystem>',
1603 (
1604 'libc++ <filesystem> is banned per the Google C++ styleguide.',
1605 ),
1606 True,
1607 # This fuzzing framework is a standalone open source project and
1608 # cannot rely on Chromium base.
1609 (r'third_party/centipede'),
1610 ),
[email protected]127f18ec2012-06-16 05:05:591611)
1612
Daniel Cheng92c15e32022-03-16 17:48:221613_BANNED_MOJOM_PATTERNS : Sequence[BanRule] = (
1614 BanRule(
1615 'handle<shared_buffer>',
1616 (
1617 'Please use one of the more specific shared memory types instead:',
1618 ' mojo_base.mojom.ReadOnlySharedMemoryRegion',
1619 ' mojo_base.mojom.WritableSharedMemoryRegion',
1620 ' mojo_base.mojom.UnsafeSharedMemoryRegion',
1621 ),
1622 True,
1623 ),
1624)
1625
mlamouria82272622014-09-16 18:45:041626_IPC_ENUM_TRAITS_DEPRECATED = (
1627 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501628 'See http://www.chromium.org/Home/chromium-security/education/'
1629 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041630
Stephen Martinis97a394142018-06-07 23:06:051631_LONG_PATH_ERROR = (
1632 'Some files included in this CL have file names that are too long (> 200'
1633 ' characters). If committed, these files will cause issues on Windows. See'
1634 ' https://crbug.com/612667 for more details.'
1635)
1636
Shenghua Zhangbfaa38b82017-11-16 21:58:021637_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Bruce Dawson40fece62022-09-16 19:58:311638 r".*/AppHooksImpl\.java",
1639 r".*/BuildHooksAndroidImpl\.java",
1640 r".*/LicenseContentProvider\.java",
1641 r".*/PlatformServiceBridgeImpl.java",
1642 r".*chrome/android/feed/dummy/.*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021643]
[email protected]127f18ec2012-06-16 05:05:591644
Mohamed Heikald048240a2019-11-12 16:57:371645# List of image extensions that are used as resources in chromium.
1646_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1647
Sean Kau46e29bc2017-08-28 16:31:161648# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401649_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Bruce Dawson40fece62022-09-16 19:58:311650 r'test/data/',
1651 r'testing/buildbot/',
1652 r'^components/policy/resources/policy_templates\.json$',
1653 r'^third_party/protobuf/',
1654 r'^third_party/blink/perf_tests/speedometer/resources/todomvc/learn.json',
1655 r'^third_party/blink/renderer/devtools/protocol\.json$',
1656 r'^third_party/blink/web_tests/external/wpt/',
1657 r'^tools/perf/',
1658 r'^tools/traceline/svgui/startup-release.json',
Daniel Cheng2d4c2d192022-07-01 01:38:311659 # vscode configuration files allow comments
Bruce Dawson40fece62022-09-16 19:58:311660 r'^tools/vscode/',
Sean Kau46e29bc2017-08-28 16:31:161661]
1662
Andrew Grieveb773bad2020-06-05 18:00:381663# These are not checked on the public chromium-presubmit trybot.
1664# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041665# checkouts.
agrievef32bcc72016-04-04 14:57:401666_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381667 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381668]
1669
1670
1671_GENERIC_PYDEPS_FILES = [
Bruce Dawson853b739e62022-05-03 23:03:101672 'android_webview/test/components/run_webview_component_smoketest.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041673 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361674 'base/android/jni_generator/jni_generator.pydeps',
1675 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361676 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041677 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361678 'build/android/gyp/aar.pydeps',
1679 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271680 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361681 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381682 'build/android/gyp/assert_static_initializers.pydeps',
Mohamed Heikal133e1f22023-04-18 20:04:371683 'build/android/gyp/binary_baseline_profile.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361684 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021685 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:221686 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111687 'build/android/gyp/compile_java.pydeps',
Peter Weneaa963f2023-01-20 19:40:301688 'build/android/gyp/compile_kt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361689 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361690 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361691 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111692 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041693 'build/android/gyp/create_app_bundle_apks.pydeps',
1694 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361695 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121696 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091697 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221698 'build/android/gyp/create_size_info_files.pydeps',
Peter Wene6e017e2022-07-27 21:40:401699 'build/android/gyp/create_test_apk_wrapper_script.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001700 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361701 'build/android/gyp/dex.pydeps',
1702 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361703 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:211704 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361705 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361706 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361707 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581708 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361709 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141710 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261711 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:471712 'build/android/gyp/java_google_api_keys.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041713 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361714 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361715 'build/android/gyp/merge_manifest.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:101716 'build/android/gyp/optimize_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361717 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221718 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361719 'build/android/gyp/proguard.pydeps',
Andrew Grievee3a775ab2022-05-16 15:59:221720 'build/android/gyp/system_image_apks.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:101721 'build/android/gyp/trace_event_bytecode_rewriter.pydeps',
Peter Wen578730b2020-03-19 19:55:461722 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:301723 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241724 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361725 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461726 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561727 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361728 'build/android/incremental_install/generate_android_manifest.pydeps',
1729 'build/android/incremental_install/write_installer_json.pydeps',
Stephanie Kim392913b452022-06-15 17:25:321730 'build/android/pylib/results/presentation/test_results_presentation.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041731 'build/android/resource_sizes.pydeps',
1732 'build/android/test_runner.pydeps',
1733 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361734 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361735 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321736 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271737 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1738 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:041739 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001740 'components/cronet/tools/generate_javadoc.pydeps',
1741 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381742 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001743 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381744 'net/tools/testserver/testserver.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181745 'testing/scripts/run_isolated_script_test.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411746 'testing/merge_scripts/standard_isolated_script_merge.pydeps',
1747 'testing/merge_scripts/standard_gtest_merge.pydeps',
1748 'testing/merge_scripts/code_coverage/merge_results.pydeps',
1749 'testing/merge_scripts/code_coverage/merge_steps.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041750 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421751 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
Yuki Shiino38eeaad12022-08-11 06:40:251752 'third_party/blink/renderer/bindings/scripts/check_generated_file_list.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421753 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131754 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:501755 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411756 'third_party/blink/tools/blinkpy/web_tests/merge_results.pydeps',
1757 'third_party/blink/tools/merge_web_test_results.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061758 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221759 'tools/binary_size/supersize.pydeps',
Ben Pastene028104a2022-08-10 19:17:451760 'tools/perf/process_perf_results.pydeps',
agrievef32bcc72016-04-04 14:57:401761]
1762
wnwenbdc444e2016-05-25 13:44:151763
agrievef32bcc72016-04-04 14:57:401764_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1765
1766
Eric Boren6fd2b932018-01-25 15:05:081767# Bypass the AUTHORS check for these accounts.
1768_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591769 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451770 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591771 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521772 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:231773 'wpt-autoroller', 'chrome-weblayer-builder',
Garrett Beaty4d4fcf62021-11-24 17:57:471774 'lacros-version-skew-roller', 'skylab-test-cros-roller',
Sven Zheng722960ba2022-07-18 16:40:461775 'infra-try-recipes-tester', 'lacros-tracking-roller',
Brian Sheedy1c951e62022-10-27 01:16:181776 'lacros-sdk-version-roller', 'chrome-automated-expectation',
Stephanie Kimb49bdd242023-04-28 16:46:041777 'chromium-automated-expectation', 'chrome-branch-day',
1778 'chromium-autosharder')
Eric Boren835d71f2018-09-07 21:09:041779 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271780 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041781 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:161782 for s in ('chromium-internal-autoroll',)
1783 ) | set('%[email protected]' % s
Chong Gub277e342022-10-15 03:30:551784 for s in ('swarming-tasks',)
1785 ) | set('%[email protected]' % s
1786 for s in ('global-integration-try-builder',
1787 'global-integration-ci-builder'))
Eric Boren6fd2b932018-01-25 15:05:081788
Matt Stark6ef08872021-07-29 01:21:461789_INVALID_GRD_FILE_LINE = [
1790 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
1791]
Eric Boren6fd2b932018-01-25 15:05:081792
Daniel Bratell65b033262019-04-23 08:17:061793def _IsCPlusPlusFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501794 """Returns True if this file contains C++-like code (and not Python,
1795 Go, Java, MarkDown, ...)"""
Daniel Bratell65b033262019-04-23 08:17:061796
Sam Maiera6e76d72022-02-11 21:43:501797 ext = input_api.os_path.splitext(file_path)[1]
1798 # This list is compatible with CppChecker.IsCppFile but we should
1799 # consider adding ".c" to it. If we do that we can use this function
1800 # at more places in the code.
1801 return ext in (
1802 '.h',
1803 '.cc',
1804 '.cpp',
1805 '.m',
1806 '.mm',
1807 )
1808
Daniel Bratell65b033262019-04-23 08:17:061809
1810def _IsCPlusPlusHeaderFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501811 return input_api.os_path.splitext(file_path)[1] == ".h"
Daniel Bratell65b033262019-04-23 08:17:061812
1813
1814def _IsJavaFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501815 return input_api.os_path.splitext(file_path)[1] == ".java"
Daniel Bratell65b033262019-04-23 08:17:061816
1817
1818def _IsProtoFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501819 return input_api.os_path.splitext(file_path)[1] == ".proto"
Daniel Bratell65b033262019-04-23 08:17:061820
Mohamed Heikal5e5b7922020-10-29 18:57:591821
Erik Staabc734cd7a2021-11-23 03:11:521822def _IsXmlOrGrdFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501823 ext = input_api.os_path.splitext(file_path)[1]
1824 return ext in ('.grd', '.xml')
Erik Staabc734cd7a2021-11-23 03:11:521825
1826
Sven Zheng76a79ea2022-12-21 21:25:241827def _IsMojomFile(input_api, file_path):
1828 return input_api.os_path.splitext(file_path)[1] == ".mojom"
1829
1830
Mohamed Heikal5e5b7922020-10-29 18:57:591831def CheckNoUpstreamDepsOnClank(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501832 """Prevent additions of dependencies from the upstream repo on //clank."""
1833 # clank can depend on clank
1834 if input_api.change.RepositoryRoot().endswith('clank'):
1835 return []
1836 build_file_patterns = [
1837 r'(.+/)?BUILD\.gn',
1838 r'.+\.gni',
1839 ]
1840 excluded_files = [r'build[/\\]config[/\\]android[/\\]config\.gni']
1841 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
Mohamed Heikal5e5b7922020-10-29 18:57:591842
Sam Maiera6e76d72022-02-11 21:43:501843 error_message = 'Disallowed import on //clank in an upstream build file:'
Mohamed Heikal5e5b7922020-10-29 18:57:591844
Sam Maiera6e76d72022-02-11 21:43:501845 def FilterFile(affected_file):
1846 return input_api.FilterSourceFile(affected_file,
1847 files_to_check=build_file_patterns,
1848 files_to_skip=excluded_files)
Mohamed Heikal5e5b7922020-10-29 18:57:591849
Sam Maiera6e76d72022-02-11 21:43:501850 problems = []
1851 for f in input_api.AffectedSourceFiles(FilterFile):
1852 local_path = f.LocalPath()
1853 for line_number, line in f.ChangedContents():
1854 if (bad_pattern.search(line)):
1855 problems.append('%s:%d\n %s' %
1856 (local_path, line_number, line.strip()))
1857 if problems:
1858 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1859 else:
1860 return []
Mohamed Heikal5e5b7922020-10-29 18:57:591861
1862
Saagar Sanghavifceeaae2020-08-12 16:40:361863def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501864 """Attempts to prevent use of functions intended only for testing in
1865 non-testing code. For now this is just a best-effort implementation
1866 that ignores header files and may have some false positives. A
1867 better implementation would probably need a proper C++ parser.
1868 """
1869 # We only scan .cc files and the like, as the declaration of
1870 # for-testing functions in header files are hard to distinguish from
1871 # calls to such functions without a proper C++ parser.
1872 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191873
Sam Maiera6e76d72022-02-11 21:43:501874 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
1875 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' %
1876 base_function_pattern)
1877 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
1878 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
1879 exclusion_pattern = input_api.re.compile(
1880 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' %
1881 (base_function_pattern, base_function_pattern))
1882 # Avoid a false positive in this case, where the method name, the ::, and
1883 # the closing { are all on different lines due to line wrapping.
1884 # HelperClassForTesting::
1885 # HelperClassForTesting(
1886 # args)
1887 # : member(0) {}
1888 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191889
Sam Maiera6e76d72022-02-11 21:43:501890 def FilterFile(affected_file):
1891 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1892 input_api.DEFAULT_FILES_TO_SKIP)
1893 return input_api.FilterSourceFile(
1894 affected_file,
1895 files_to_check=file_inclusion_pattern,
1896 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191897
Sam Maiera6e76d72022-02-11 21:43:501898 problems = []
1899 for f in input_api.AffectedSourceFiles(FilterFile):
1900 local_path = f.LocalPath()
1901 in_method_defn = False
1902 for line_number, line in f.ChangedContents():
1903 if (inclusion_pattern.search(line)
1904 and not comment_pattern.search(line)
1905 and not exclusion_pattern.search(line)
1906 and not allowlist_pattern.search(line)
1907 and not in_method_defn):
1908 problems.append('%s:%d\n %s' %
1909 (local_path, line_number, line.strip()))
1910 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191911
Sam Maiera6e76d72022-02-11 21:43:501912 if problems:
1913 return [
1914 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
1915 ]
1916 else:
1917 return []
[email protected]55459852011-08-10 15:17:191918
1919
Saagar Sanghavifceeaae2020-08-12 16:40:361920def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501921 """This is a simplified version of
1922 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
1923 """
1924 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1925 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1926 name_pattern = r'ForTest(s|ing)?'
1927 # Describes an occurrence of "ForTest*" inside a // comment.
1928 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
1929 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
1930 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
1931 # Catch calls.
1932 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1933 # Ignore definitions. (Comments are ignored separately.)
1934 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
Vaclav Brozek7dbc28c2018-03-27 08:35:231935
Sam Maiera6e76d72022-02-11 21:43:501936 problems = []
1937 sources = lambda x: input_api.FilterSourceFile(
1938 x,
1939 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
1940 DEFAULT_FILES_TO_SKIP),
1941 files_to_check=[r'.*\.java$'])
1942 for f in input_api.AffectedFiles(include_deletes=False,
1943 file_filter=sources):
1944 local_path = f.LocalPath()
Vaclav Brozek7dbc28c2018-03-27 08:35:231945 is_inside_javadoc = False
Sam Maiera6e76d72022-02-11 21:43:501946 for line_number, line in f.ChangedContents():
1947 if is_inside_javadoc and javadoc_end_re.search(line):
1948 is_inside_javadoc = False
1949 if not is_inside_javadoc and javadoc_start_re.search(line):
1950 is_inside_javadoc = True
1951 if is_inside_javadoc:
1952 continue
1953 if (inclusion_re.search(line) and not comment_re.search(line)
1954 and not annotation_re.search(line)
1955 and not exclusion_re.search(line)):
1956 problems.append('%s:%d\n %s' %
1957 (local_path, line_number, line.strip()))
Vaclav Brozek7dbc28c2018-03-27 08:35:231958
Sam Maiera6e76d72022-02-11 21:43:501959 if problems:
1960 return [
1961 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
1962 ]
1963 else:
1964 return []
Vaclav Brozek7dbc28c2018-03-27 08:35:231965
1966
Saagar Sanghavifceeaae2020-08-12 16:40:361967def CheckNoIOStreamInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501968 """Checks to make sure no .h files include <iostream>."""
1969 files = []
1970 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1971 input_api.re.MULTILINE)
1972 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1973 if not f.LocalPath().endswith('.h'):
1974 continue
1975 contents = input_api.ReadFile(f)
1976 if pattern.search(contents):
1977 files.append(f)
[email protected]10689ca2011-09-02 02:31:541978
Sam Maiera6e76d72022-02-11 21:43:501979 if len(files):
1980 return [
1981 output_api.PresubmitError(
1982 'Do not #include <iostream> in header files, since it inserts static '
1983 'initialization into every file including the header. Instead, '
1984 '#include <ostream>. See http://crbug.com/94794', files)
1985 ]
1986 return []
1987
[email protected]10689ca2011-09-02 02:31:541988
Aleksey Khoroshilov9b28c032022-06-03 16:35:321989def CheckNoStrCatRedefines(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501990 """Checks no windows headers with StrCat redefined are included directly."""
1991 files = []
Aleksey Khoroshilov9b28c032022-06-03 16:35:321992 files_to_check = (r'.+%s' % _HEADER_EXTENSIONS,
1993 r'.+%s' % _IMPLEMENTATION_EXTENSIONS)
1994 files_to_skip = (input_api.DEFAULT_FILES_TO_SKIP +
1995 _NON_BASE_DEPENDENT_PATHS)
1996 sources_filter = lambda f: input_api.FilterSourceFile(
1997 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
1998
Sam Maiera6e76d72022-02-11 21:43:501999 pattern_deny = input_api.re.compile(
2000 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
2001 input_api.re.MULTILINE)
2002 pattern_allow = input_api.re.compile(
2003 r'^#include\s"base/win/windows_defines.inc"', input_api.re.MULTILINE)
Aleksey Khoroshilov9b28c032022-06-03 16:35:322004 for f in input_api.AffectedSourceFiles(sources_filter):
Sam Maiera6e76d72022-02-11 21:43:502005 contents = input_api.ReadFile(f)
2006 if pattern_deny.search(
2007 contents) and not pattern_allow.search(contents):
2008 files.append(f.LocalPath())
Danil Chapovalov3518f362018-08-11 16:13:432009
Sam Maiera6e76d72022-02-11 21:43:502010 if len(files):
2011 return [
2012 output_api.PresubmitError(
2013 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
2014 'directly since they pollute code with StrCat macro. Instead, '
2015 'include matching header from base/win. See http://crbug.com/856536',
2016 files)
2017 ]
2018 return []
Danil Chapovalov3518f362018-08-11 16:13:432019
[email protected]10689ca2011-09-02 02:31:542020
Saagar Sanghavifceeaae2020-08-12 16:40:362021def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502022 """Checks to make sure no source files use UNIT_TEST."""
2023 problems = []
2024 for f in input_api.AffectedFiles():
2025 if (not f.LocalPath().endswith(('.cc', '.mm'))):
2026 continue
[email protected]72df4e782012-06-21 16:28:182027
Sam Maiera6e76d72022-02-11 21:43:502028 for line_num, line in f.ChangedContents():
2029 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
2030 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]72df4e782012-06-21 16:28:182031
Sam Maiera6e76d72022-02-11 21:43:502032 if not problems:
2033 return []
2034 return [
2035 output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
2036 '\n'.join(problems))
2037 ]
2038
[email protected]72df4e782012-06-21 16:28:182039
Saagar Sanghavifceeaae2020-08-12 16:40:362040def CheckNoDISABLETypoInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502041 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
Dominic Battre033531052018-09-24 15:45:342042
Sam Maiera6e76d72022-02-11 21:43:502043 This test warns if somebody tries to disable a test with the DISABLE_ prefix
2044 instead of DISABLED_. To filter false positives, reports are only generated
2045 if a corresponding MAYBE_ line exists.
2046 """
2047 problems = []
Dominic Battre033531052018-09-24 15:45:342048
Sam Maiera6e76d72022-02-11 21:43:502049 # The following two patterns are looked for in tandem - is a test labeled
2050 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
2051 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
2052 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
Dominic Battre033531052018-09-24 15:45:342053
Sam Maiera6e76d72022-02-11 21:43:502054 # This is for the case that a test is disabled on all platforms.
2055 full_disable_pattern = input_api.re.compile(
2056 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
2057 input_api.re.MULTILINE)
Dominic Battre033531052018-09-24 15:45:342058
Sam Maiera6e76d72022-02-11 21:43:502059 for f in input_api.AffectedFiles(False):
2060 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2061 continue
Dominic Battre033531052018-09-24 15:45:342062
Sam Maiera6e76d72022-02-11 21:43:502063 # Search for MABYE_, DISABLE_ pairs.
2064 disable_lines = {} # Maps of test name to line number.
2065 maybe_lines = {}
2066 for line_num, line in f.ChangedContents():
2067 disable_match = disable_pattern.search(line)
2068 if disable_match:
2069 disable_lines[disable_match.group(1)] = line_num
2070 maybe_match = maybe_pattern.search(line)
2071 if maybe_match:
2072 maybe_lines[maybe_match.group(1)] = line_num
Dominic Battre033531052018-09-24 15:45:342073
Sam Maiera6e76d72022-02-11 21:43:502074 # Search for DISABLE_ occurrences within a TEST() macro.
2075 disable_tests = set(disable_lines.keys())
2076 maybe_tests = set(maybe_lines.keys())
2077 for test in disable_tests.intersection(maybe_tests):
2078 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
Dominic Battre033531052018-09-24 15:45:342079
Sam Maiera6e76d72022-02-11 21:43:502080 contents = input_api.ReadFile(f)
2081 full_disable_match = full_disable_pattern.search(contents)
2082 if full_disable_match:
2083 problems.append(' %s' % f.LocalPath())
Dominic Battre033531052018-09-24 15:45:342084
Sam Maiera6e76d72022-02-11 21:43:502085 if not problems:
2086 return []
2087 return [
2088 output_api.PresubmitPromptWarning(
2089 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
2090 '\n'.join(problems))
2091 ]
2092
Dominic Battre033531052018-09-24 15:45:342093
Nina Satragnof7660532021-09-20 18:03:352094def CheckForgettingMAYBEInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502095 """Checks to make sure tests disabled conditionally are not missing a
2096 corresponding MAYBE_ prefix.
2097 """
2098 # Expect at least a lowercase character in the test name. This helps rule out
2099 # false positives with macros wrapping the actual tests name.
2100 define_maybe_pattern = input_api.re.compile(
2101 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
Bruce Dawsonffc55292022-04-20 04:18:192102 # The test_maybe_pattern needs to handle all of these forms. The standard:
2103 # IN_PROC_TEST_F(SyncTest, MAYBE_Start) {
2104 # With a wrapper macro around the test name:
2105 # IN_PROC_TEST_F(SyncTest, E2E_ENABLED(MAYBE_Start)) {
2106 # And the odd-ball NACL_BROWSER_TEST_f format:
2107 # NACL_BROWSER_TEST_F(NaClBrowserTest, SimpleLoad, {
2108 # The optional E2E_ENABLED-style is handled with (\w*\()?
2109 # The NACL_BROWSER_TEST_F pattern is handled by allowing a trailing comma or
2110 # trailing ')'.
2111 test_maybe_pattern = (
2112 r'^\s*\w*TEST[^(]*\(\s*\w+,\s*(\w*\()?MAYBE_{test_name}[\),]')
Sam Maiera6e76d72022-02-11 21:43:502113 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
2114 warnings = []
Nina Satragnof7660532021-09-20 18:03:352115
Sam Maiera6e76d72022-02-11 21:43:502116 # Read the entire files. We can't just read the affected lines, forgetting to
2117 # add MAYBE_ on a change would not show up otherwise.
2118 for f in input_api.AffectedFiles(False):
2119 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2120 continue
2121 contents = input_api.ReadFile(f)
2122 lines = contents.splitlines(True)
2123 current_position = 0
2124 warning_test_names = set()
2125 for line_num, line in enumerate(lines, start=1):
2126 current_position += len(line)
2127 maybe_match = define_maybe_pattern.search(line)
2128 if maybe_match:
2129 test_name = maybe_match.group('test_name')
2130 # Do not warn twice for the same test.
2131 if (test_name in warning_test_names):
2132 continue
2133 warning_test_names.add(test_name)
Nina Satragnof7660532021-09-20 18:03:352134
Sam Maiera6e76d72022-02-11 21:43:502135 # Attempt to find the corresponding MAYBE_ test or suite, starting from
2136 # the current position.
2137 test_match = input_api.re.compile(
2138 test_maybe_pattern.format(test_name=test_name),
2139 input_api.re.MULTILINE).search(contents, current_position)
2140 suite_match = input_api.re.compile(
2141 suite_maybe_pattern.format(test_name=test_name),
2142 input_api.re.MULTILINE).search(contents, current_position)
2143 if not test_match and not suite_match:
2144 warnings.append(
2145 output_api.PresubmitPromptWarning(
2146 '%s:%d found MAYBE_ defined without corresponding test %s'
2147 % (f.LocalPath(), line_num, test_name)))
2148 return warnings
2149
[email protected]72df4e782012-06-21 16:28:182150
Saagar Sanghavifceeaae2020-08-12 16:40:362151def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502152 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
2153 errors = []
Kalvin Lee4a3b79de2022-05-26 16:00:162154 pattern = input_api.re.compile(r'\bDCHECK_IS_ON\b(?!\(\))',
Sam Maiera6e76d72022-02-11 21:43:502155 input_api.re.MULTILINE)
2156 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2157 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
2158 continue
2159 for lnum, line in f.ChangedContents():
2160 if input_api.re.search(pattern, line):
2161 errors.append(
2162 output_api.PresubmitError((
2163 '%s:%d: Use of DCHECK_IS_ON() must be written as "#if '
2164 + 'DCHECK_IS_ON()", not forgetting the parentheses.') %
2165 (f.LocalPath(), lnum)))
2166 return errors
danakj61c1aa22015-10-26 19:55:522167
2168
Weilun Shia487fad2020-10-28 00:10:342169# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
2170# more reliable way. See
2171# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:192172
wnwenbdc444e2016-05-25 13:44:152173
Saagar Sanghavifceeaae2020-08-12 16:40:362174def CheckFlakyTestUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502175 """Check that FlakyTest annotation is our own instead of the android one"""
2176 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
2177 files = []
2178 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2179 if f.LocalPath().endswith('Test.java'):
2180 if pattern.search(input_api.ReadFile(f)):
2181 files.append(f)
2182 if len(files):
2183 return [
2184 output_api.PresubmitError(
2185 'Use org.chromium.base.test.util.FlakyTest instead of '
2186 'android.test.FlakyTest', files)
2187 ]
2188 return []
mcasasb7440c282015-02-04 14:52:192189
wnwenbdc444e2016-05-25 13:44:152190
Saagar Sanghavifceeaae2020-08-12 16:40:362191def CheckNoDEPSGIT(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502192 """Make sure .DEPS.git is never modified manually."""
2193 if any(f.LocalPath().endswith('.DEPS.git')
2194 for f in input_api.AffectedFiles()):
2195 return [
2196 output_api.PresubmitError(
2197 'Never commit changes to .DEPS.git. This file is maintained by an\n'
2198 'automated system based on what\'s in DEPS and your changes will be\n'
2199 'overwritten.\n'
2200 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
2201 'get-the-code#Rolling_DEPS\n'
2202 'for more information')
2203 ]
2204 return []
[email protected]2a8ac9c2011-10-19 17:20:442205
2206
Sven Zheng76a79ea2022-12-21 21:25:242207def CheckCrosApiNeedBrowserTest(input_api, output_api):
2208 """Check new crosapi should add browser test."""
2209 has_new_crosapi = False
2210 has_browser_test = False
2211 for f in input_api.AffectedFiles():
2212 path = f.LocalPath()
2213 if (path.startswith('chromeos/crosapi/mojom') and
2214 _IsMojomFile(input_api, path) and f.Action() == 'A'):
2215 has_new_crosapi = True
2216 if path.endswith('browsertest.cc') or path.endswith('browser_test.cc'):
2217 has_browser_test = True
2218 if has_new_crosapi and not has_browser_test:
2219 return [
2220 output_api.PresubmitPromptWarning(
2221 'You are adding a new crosapi, but there is no file ends with '
2222 'browsertest.cc file being added or modified. It is important '
2223 'to add crosapi browser test coverage to avoid version '
2224 ' skew issues.\n'
2225 'Check //docs/lacros/test_instructions.md for more information.'
2226 )
2227 ]
2228 return []
2229
2230
Saagar Sanghavifceeaae2020-08-12 16:40:362231def CheckValidHostsInDEPSOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502232 """Checks that DEPS file deps are from allowed_hosts."""
2233 # Run only if DEPS file has been modified to annoy fewer bystanders.
2234 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
2235 return []
2236 # Outsource work to gclient verify
2237 try:
2238 gclient_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
2239 'third_party', 'depot_tools',
2240 'gclient.py')
2241 input_api.subprocess.check_output(
Bruce Dawson8a43cf72022-05-13 17:10:322242 [input_api.python3_executable, gclient_path, 'verify'],
Sam Maiera6e76d72022-02-11 21:43:502243 stderr=input_api.subprocess.STDOUT)
2244 return []
2245 except input_api.subprocess.CalledProcessError as error:
2246 return [
2247 output_api.PresubmitError(
2248 'DEPS file must have only git dependencies.',
2249 long_text=error.output)
2250 ]
tandriief664692014-09-23 14:51:472251
2252
Mario Sanchez Prada2472cab2019-09-18 10:58:312253def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152254 ban_rule):
Allen Bauer84778682022-09-22 16:28:562255 """Helper method for checking for banned constructs.
Mario Sanchez Prada2472cab2019-09-18 10:58:312256
Sam Maiera6e76d72022-02-11 21:43:502257 Returns an string composed of the name of the file, the line number where the
2258 match has been found and the additional text passed as |message| in case the
2259 target type name matches the text inside the line passed as parameter.
2260 """
2261 result = []
Peng Huang9c5949a02020-06-11 19:20:542262
Daniel Chenga44a1bcd2022-03-15 20:00:152263 # Ignore comments about banned types.
2264 if input_api.re.search(r"^ *//", line):
Sam Maiera6e76d72022-02-11 21:43:502265 return result
Daniel Chenga44a1bcd2022-03-15 20:00:152266 # A // nocheck comment will bypass this error.
2267 if line.endswith(" nocheck"):
Sam Maiera6e76d72022-02-11 21:43:502268 return result
2269
2270 matched = False
Daniel Chenga44a1bcd2022-03-15 20:00:152271 if ban_rule.pattern[0:1] == '/':
2272 regex = ban_rule.pattern[1:]
Sam Maiera6e76d72022-02-11 21:43:502273 if input_api.re.search(regex, line):
2274 matched = True
Daniel Chenga44a1bcd2022-03-15 20:00:152275 elif ban_rule.pattern in line:
Sam Maiera6e76d72022-02-11 21:43:502276 matched = True
2277
2278 if matched:
2279 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
Daniel Chenga44a1bcd2022-03-15 20:00:152280 for line in ban_rule.explanation:
2281 result.append(' %s' % line)
Sam Maiera6e76d72022-02-11 21:43:502282
danakjd18e8892020-12-17 17:42:012283 return result
Mario Sanchez Prada2472cab2019-09-18 10:58:312284
2285
Saagar Sanghavifceeaae2020-08-12 16:40:362286def CheckNoBannedFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502287 """Make sure that banned functions are not used."""
2288 warnings = []
2289 errors = []
[email protected]127f18ec2012-06-16 05:05:592290
Sam Maiera6e76d72022-02-11 21:43:502291 def IsExcludedFile(affected_file, excluded_paths):
Daniel Chenga44a1bcd2022-03-15 20:00:152292 if not excluded_paths:
2293 return False
2294
Sam Maiera6e76d72022-02-11 21:43:502295 local_path = affected_file.LocalPath()
Bruce Dawson40fece62022-09-16 19:58:312296 # Consistently use / as path separator to simplify the writing of regex
2297 # expressions.
2298 local_path = local_path.replace(input_api.os_path.sep, '/')
Sam Maiera6e76d72022-02-11 21:43:502299 for item in excluded_paths:
2300 if input_api.re.match(item, local_path):
2301 return True
2302 return False
wnwenbdc444e2016-05-25 13:44:152303
Sam Maiera6e76d72022-02-11 21:43:502304 def IsIosObjcFile(affected_file):
2305 local_path = affected_file.LocalPath()
2306 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m',
2307 '.h'):
2308 return False
2309 basename = input_api.os_path.basename(local_path)
2310 if 'ios' in basename.split('_'):
2311 return True
2312 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
2313 if sep and 'ios' in local_path.split(sep):
2314 return True
2315 return False
Sylvain Defresnea8b73d252018-02-28 15:45:542316
Daniel Chenga44a1bcd2022-03-15 20:00:152317 def CheckForMatch(affected_file, line_num: int, line: str,
2318 ban_rule: BanRule):
2319 if IsExcludedFile(affected_file, ban_rule.excluded_paths):
2320 return
2321
Sam Maiera6e76d72022-02-11 21:43:502322 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152323 ban_rule)
Sam Maiera6e76d72022-02-11 21:43:502324 if problems:
Daniel Chenga44a1bcd2022-03-15 20:00:152325 if ban_rule.treat_as_error is not None and ban_rule.treat_as_error:
Sam Maiera6e76d72022-02-11 21:43:502326 errors.extend(problems)
2327 else:
2328 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:152329
Sam Maiera6e76d72022-02-11 21:43:502330 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2331 for f in input_api.AffectedFiles(file_filter=file_filter):
2332 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152333 for ban_rule in _BANNED_JAVA_FUNCTIONS:
2334 CheckForMatch(f, line_num, line, ban_rule)
Eric Stevensona9a980972017-09-23 00:04:412335
Clement Yan9b330cb2022-11-17 05:25:292336 file_filter = lambda f: f.LocalPath().endswith(('.js', '.ts'))
2337 for f in input_api.AffectedFiles(file_filter=file_filter):
2338 for line_num, line in f.ChangedContents():
2339 for ban_rule in _BANNED_JAVASCRIPT_FUNCTIONS:
2340 CheckForMatch(f, line_num, line, ban_rule)
2341
Sam Maiera6e76d72022-02-11 21:43:502342 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
2343 for f in input_api.AffectedFiles(file_filter=file_filter):
2344 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152345 for ban_rule in _BANNED_OBJC_FUNCTIONS:
2346 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:592347
Sam Maiera6e76d72022-02-11 21:43:502348 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
2349 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152350 for ban_rule in _BANNED_IOS_OBJC_FUNCTIONS:
2351 CheckForMatch(f, line_num, line, ban_rule)
Sylvain Defresnea8b73d252018-02-28 15:45:542352
Sam Maiera6e76d72022-02-11 21:43:502353 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
2354 for f in input_api.AffectedFiles(file_filter=egtest_filter):
2355 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152356 for ban_rule in _BANNED_IOS_EGTEST_FUNCTIONS:
2357 CheckForMatch(f, line_num, line, ban_rule)
Peter K. Lee6c03ccff2019-07-15 14:40:052358
Sam Maiera6e76d72022-02-11 21:43:502359 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
2360 for f in input_api.AffectedFiles(file_filter=file_filter):
2361 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152362 for ban_rule in _BANNED_CPP_FUNCTIONS:
2363 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:592364
Daniel Cheng92c15e32022-03-16 17:48:222365 file_filter = lambda f: f.LocalPath().endswith(('.mojom'))
2366 for f in input_api.AffectedFiles(file_filter=file_filter):
2367 for line_num, line in f.ChangedContents():
2368 for ban_rule in _BANNED_MOJOM_PATTERNS:
2369 CheckForMatch(f, line_num, line, ban_rule)
2370
2371
Sam Maiera6e76d72022-02-11 21:43:502372 result = []
2373 if (warnings):
2374 result.append(
2375 output_api.PresubmitPromptWarning('Banned functions were used.\n' +
2376 '\n'.join(warnings)))
2377 if (errors):
2378 result.append(
2379 output_api.PresubmitError('Banned functions were used.\n' +
2380 '\n'.join(errors)))
2381 return result
[email protected]127f18ec2012-06-16 05:05:592382
Allen Bauer84778682022-09-22 16:28:562383def CheckNoLayoutCallsInTests(input_api, output_api):
2384 """Make sure there are no explicit calls to View::Layout() in tests"""
2385 warnings = []
2386 ban_rule = BanRule(
2387 r'/(\.|->)Layout\(\);',
2388 (
2389 'Direct calls to View::Layout() are not allowed in tests. '
2390 'If the view must be laid out here, use RunScheduledLayout(view). It '
2391 'is found in //ui/views/test/views_test_utils.h. '
2392 'See http://crbug.com/1350521 for more details.',
2393 ),
2394 False,
2395 )
2396 file_filter = lambda f: input_api.re.search(
2397 r'_(unittest|browsertest|ui_test).*\.(cc|mm)$', f.LocalPath())
2398 for f in input_api.AffectedFiles(file_filter = file_filter):
2399 for line_num, line in f.ChangedContents():
2400 problems = _GetMessageForMatchingType(input_api, f,
2401 line_num, line,
2402 ban_rule)
2403 if problems:
2404 warnings.extend(problems)
2405 result = []
2406 if (warnings):
2407 result.append(
2408 output_api.PresubmitPromptWarning(
2409 'Banned call to View::Layout() in tests.\n\n'.join(warnings)))
2410 return result
[email protected]127f18ec2012-06-16 05:05:592411
Michael Thiessen44457642020-02-06 00:24:152412def _CheckAndroidNoBannedImports(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502413 """Make sure that banned java imports are not used."""
2414 errors = []
Michael Thiessen44457642020-02-06 00:24:152415
Sam Maiera6e76d72022-02-11 21:43:502416 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2417 for f in input_api.AffectedFiles(file_filter=file_filter):
2418 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152419 for ban_rule in _BANNED_JAVA_IMPORTS:
2420 # Consider merging this into the above function. There is no
2421 # real difference anymore other than helping with a little
2422 # bit of boilerplate text. Doing so means things like
2423 # `treat_as_error` will also be uniformly handled.
Sam Maiera6e76d72022-02-11 21:43:502424 problems = _GetMessageForMatchingType(input_api, f, line_num,
Daniel Chenga44a1bcd2022-03-15 20:00:152425 line, ban_rule)
Sam Maiera6e76d72022-02-11 21:43:502426 if problems:
2427 errors.extend(problems)
2428 result = []
2429 if (errors):
2430 result.append(
2431 output_api.PresubmitError('Banned imports were used.\n' +
2432 '\n'.join(errors)))
2433 return result
Michael Thiessen44457642020-02-06 00:24:152434
2435
Saagar Sanghavifceeaae2020-08-12 16:40:362436def CheckNoPragmaOnce(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502437 """Make sure that banned functions are not used."""
2438 files = []
2439 pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
2440 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2441 if not f.LocalPath().endswith('.h'):
2442 continue
Bruce Dawson4c4c2922022-05-02 18:07:332443 if f.LocalPath().endswith('com_imported_mstscax.h'):
2444 continue
Sam Maiera6e76d72022-02-11 21:43:502445 contents = input_api.ReadFile(f)
2446 if pattern.search(contents):
2447 files.append(f)
[email protected]6c063c62012-07-11 19:11:062448
Sam Maiera6e76d72022-02-11 21:43:502449 if files:
2450 return [
2451 output_api.PresubmitError(
2452 'Do not use #pragma once in header files.\n'
2453 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
2454 files)
2455 ]
2456 return []
[email protected]6c063c62012-07-11 19:11:062457
[email protected]127f18ec2012-06-16 05:05:592458
Saagar Sanghavifceeaae2020-08-12 16:40:362459def CheckNoTrinaryTrueFalse(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502460 """Checks to make sure we don't introduce use of foo ? true : false."""
2461 problems = []
2462 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
2463 for f in input_api.AffectedFiles():
2464 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2465 continue
[email protected]e7479052012-09-19 00:26:122466
Sam Maiera6e76d72022-02-11 21:43:502467 for line_num, line in f.ChangedContents():
2468 if pattern.match(line):
2469 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]e7479052012-09-19 00:26:122470
Sam Maiera6e76d72022-02-11 21:43:502471 if not problems:
2472 return []
2473 return [
2474 output_api.PresubmitPromptWarning(
2475 'Please consider avoiding the "? true : false" pattern if possible.\n'
2476 + '\n'.join(problems))
2477 ]
[email protected]e7479052012-09-19 00:26:122478
2479
Saagar Sanghavifceeaae2020-08-12 16:40:362480def CheckUnwantedDependencies(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502481 """Runs checkdeps on #include and import statements added in this
2482 change. Breaking - rules is an error, breaking ! rules is a
2483 warning.
2484 """
2485 # Return early if no relevant file types were modified.
2486 for f in input_api.AffectedFiles():
2487 path = f.LocalPath()
2488 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path)
2489 or _IsJavaFile(input_api, path)):
2490 break
[email protected]55f9f382012-07-31 11:02:182491 else:
Sam Maiera6e76d72022-02-11 21:43:502492 return []
rhalavati08acd232017-04-03 07:23:282493
Sam Maiera6e76d72022-02-11 21:43:502494 import sys
2495 # We need to wait until we have an input_api object and use this
2496 # roundabout construct to import checkdeps because this file is
2497 # eval-ed and thus doesn't have __file__.
2498 original_sys_path = sys.path
2499 try:
2500 sys.path = sys.path + [
2501 input_api.os_path.join(input_api.PresubmitLocalPath(),
2502 'buildtools', 'checkdeps')
2503 ]
2504 import checkdeps
2505 from rules import Rule
2506 finally:
2507 # Restore sys.path to what it was before.
2508 sys.path = original_sys_path
[email protected]55f9f382012-07-31 11:02:182509
Sam Maiera6e76d72022-02-11 21:43:502510 added_includes = []
2511 added_imports = []
2512 added_java_imports = []
2513 for f in input_api.AffectedFiles():
2514 if _IsCPlusPlusFile(input_api, f.LocalPath()):
2515 changed_lines = [line for _, line in f.ChangedContents()]
2516 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
2517 elif _IsProtoFile(input_api, f.LocalPath()):
2518 changed_lines = [line for _, line in f.ChangedContents()]
2519 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
2520 elif _IsJavaFile(input_api, f.LocalPath()):
2521 changed_lines = [line for _, line in f.ChangedContents()]
2522 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:242523
Sam Maiera6e76d72022-02-11 21:43:502524 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
2525
2526 error_descriptions = []
2527 warning_descriptions = []
2528 error_subjects = set()
2529 warning_subjects = set()
2530
2531 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2532 added_includes):
2533 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2534 description_with_path = '%s\n %s' % (path, rule_description)
2535 if rule_type == Rule.DISALLOW:
2536 error_descriptions.append(description_with_path)
2537 error_subjects.add("#includes")
2538 else:
2539 warning_descriptions.append(description_with_path)
2540 warning_subjects.add("#includes")
2541
2542 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2543 added_imports):
2544 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2545 description_with_path = '%s\n %s' % (path, rule_description)
2546 if rule_type == Rule.DISALLOW:
2547 error_descriptions.append(description_with_path)
2548 error_subjects.add("imports")
2549 else:
2550 warning_descriptions.append(description_with_path)
2551 warning_subjects.add("imports")
2552
2553 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
2554 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
2555 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2556 description_with_path = '%s\n %s' % (path, rule_description)
2557 if rule_type == Rule.DISALLOW:
2558 error_descriptions.append(description_with_path)
2559 error_subjects.add("imports")
2560 else:
2561 warning_descriptions.append(description_with_path)
2562 warning_subjects.add("imports")
2563
2564 results = []
2565 if error_descriptions:
2566 results.append(
2567 output_api.PresubmitError(
2568 'You added one or more %s that violate checkdeps rules.' %
2569 " and ".join(error_subjects), error_descriptions))
2570 if warning_descriptions:
2571 results.append(
2572 output_api.PresubmitPromptOrNotify(
2573 'You added one or more %s of files that are temporarily\n'
2574 'allowed but being removed. Can you avoid introducing the\n'
2575 '%s? See relevant DEPS file(s) for details and contacts.' %
2576 (" and ".join(warning_subjects), "/".join(warning_subjects)),
2577 warning_descriptions))
2578 return results
[email protected]55f9f382012-07-31 11:02:182579
2580
Saagar Sanghavifceeaae2020-08-12 16:40:362581def CheckFilePermissions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502582 """Check that all files have their permissions properly set."""
2583 if input_api.platform == 'win32':
2584 return []
2585 checkperms_tool = input_api.os_path.join(input_api.PresubmitLocalPath(),
2586 'tools', 'checkperms',
2587 'checkperms.py')
2588 args = [
Bruce Dawson8a43cf72022-05-13 17:10:322589 input_api.python3_executable, checkperms_tool, '--root',
Sam Maiera6e76d72022-02-11 21:43:502590 input_api.change.RepositoryRoot()
2591 ]
2592 with input_api.CreateTemporaryFile() as file_list:
2593 for f in input_api.AffectedFiles():
2594 # checkperms.py file/directory arguments must be relative to the
2595 # repository.
2596 file_list.write((f.LocalPath() + '\n').encode('utf8'))
2597 file_list.close()
2598 args += ['--file-list', file_list.name]
2599 try:
2600 input_api.subprocess.check_output(args)
2601 return []
2602 except input_api.subprocess.CalledProcessError as error:
2603 return [
2604 output_api.PresubmitError('checkperms.py failed:',
2605 long_text=error.output.decode(
2606 'utf-8', 'ignore'))
2607 ]
[email protected]fbcafe5a2012-08-08 15:31:222608
2609
Saagar Sanghavifceeaae2020-08-12 16:40:362610def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502611 """Makes sure we don't include ui/aura/window_property.h
2612 in header files.
2613 """
2614 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2615 errors = []
2616 for f in input_api.AffectedFiles():
2617 if not f.LocalPath().endswith('.h'):
2618 continue
2619 for line_num, line in f.ChangedContents():
2620 if pattern.match(line):
2621 errors.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]c8278b32012-10-30 20:35:492622
Sam Maiera6e76d72022-02-11 21:43:502623 results = []
2624 if errors:
2625 results.append(
2626 output_api.PresubmitError(
2627 'Header files should not include ui/aura/window_property.h',
2628 errors))
2629 return results
[email protected]c8278b32012-10-30 20:35:492630
2631
Omer Katzcc77ea92021-04-26 10:23:282632def CheckNoInternalHeapIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502633 """Makes sure we don't include any headers from
2634 third_party/blink/renderer/platform/heap/impl or
2635 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
2636 third_party/blink/renderer/platform/heap
2637 """
2638 impl_pattern = input_api.re.compile(
2639 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
2640 v8_wrapper_pattern = input_api.re.compile(
2641 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"'
2642 )
Bruce Dawson40fece62022-09-16 19:58:312643 # Consistently use / as path separator to simplify the writing of regex
2644 # expressions.
Sam Maiera6e76d72022-02-11 21:43:502645 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:312646 r"^third_party/blink/renderer/platform/heap/.*",
2647 f.LocalPath().replace(input_api.os_path.sep, '/'))
Sam Maiera6e76d72022-02-11 21:43:502648 errors = []
Omer Katzcc77ea92021-04-26 10:23:282649
Sam Maiera6e76d72022-02-11 21:43:502650 for f in input_api.AffectedFiles(file_filter=file_filter):
2651 for line_num, line in f.ChangedContents():
2652 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
2653 errors.append(' %s:%d' % (f.LocalPath(), line_num))
Omer Katzcc77ea92021-04-26 10:23:282654
Sam Maiera6e76d72022-02-11 21:43:502655 results = []
2656 if errors:
2657 results.append(
2658 output_api.PresubmitError(
2659 'Do not include files from third_party/blink/renderer/platform/heap/impl'
2660 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
2661 'relevant counterparts from third_party/blink/renderer/platform/heap',
2662 errors))
2663 return results
Omer Katzcc77ea92021-04-26 10:23:282664
2665
[email protected]70ca77752012-11-20 03:45:032666def _CheckForVersionControlConflictsInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:502667 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2668 errors = []
2669 for line_num, line in f.ChangedContents():
2670 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
2671 # First-level headers in markdown look a lot like version control
2672 # conflict markers. http://daringfireball.net/projects/markdown/basics
2673 continue
2674 if pattern.match(line):
2675 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2676 return errors
[email protected]70ca77752012-11-20 03:45:032677
2678
Saagar Sanghavifceeaae2020-08-12 16:40:362679def CheckForVersionControlConflicts(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502680 """Usually this is not intentional and will cause a compile failure."""
2681 errors = []
2682 for f in input_api.AffectedFiles():
2683 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
[email protected]70ca77752012-11-20 03:45:032684
Sam Maiera6e76d72022-02-11 21:43:502685 results = []
2686 if errors:
2687 results.append(
2688 output_api.PresubmitError(
2689 'Version control conflict markers found, please resolve.',
2690 errors))
2691 return results
[email protected]70ca77752012-11-20 03:45:032692
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202693
Saagar Sanghavifceeaae2020-08-12 16:40:362694def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502695 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2696 errors = []
2697 for f in input_api.AffectedFiles():
2698 for line_num, line in f.ChangedContents():
2699 if pattern.search(line):
2700 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
estadee17314a02017-01-12 16:22:162701
Sam Maiera6e76d72022-02-11 21:43:502702 results = []
2703 if errors:
2704 results.append(
2705 output_api.PresubmitPromptWarning(
2706 'Found Google support URL addressed by answer number. Please replace '
2707 'with a p= identifier instead. See crbug.com/679462\n',
2708 errors))
2709 return results
estadee17314a02017-01-12 16:22:162710
[email protected]70ca77752012-11-20 03:45:032711
Saagar Sanghavifceeaae2020-08-12 16:40:362712def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502713 def FilterFile(affected_file):
2714 """Filter function for use with input_api.AffectedSourceFiles,
2715 below. This filters out everything except non-test files from
2716 top-level directories that generally speaking should not hard-code
2717 service URLs (e.g. src/android_webview/, src/content/ and others).
2718 """
2719 return input_api.FilterSourceFile(
2720 affected_file,
Bruce Dawson40fece62022-09-16 19:58:312721 files_to_check=[r'^(android_webview|base|content|net)/.*'],
Sam Maiera6e76d72022-02-11 21:43:502722 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2723 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442724
Sam Maiera6e76d72022-02-11 21:43:502725 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2726 '\.(com|net)[^"]*"')
2727 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2728 pattern = input_api.re.compile(base_pattern)
2729 problems = [] # items are (filename, line_number, line)
2730 for f in input_api.AffectedSourceFiles(FilterFile):
2731 for line_num, line in f.ChangedContents():
2732 if not comment_pattern.search(line) and pattern.search(line):
2733 problems.append((f.LocalPath(), line_num, line))
[email protected]06e6d0ff2012-12-11 01:36:442734
Sam Maiera6e76d72022-02-11 21:43:502735 if problems:
2736 return [
2737 output_api.PresubmitPromptOrNotify(
2738 'Most layers below src/chrome/ should not hardcode service URLs.\n'
2739 'Are you sure this is correct?', [
2740 ' %s:%d: %s' % (problem[0], problem[1], problem[2])
2741 for problem in problems
2742 ])
2743 ]
2744 else:
2745 return []
[email protected]06e6d0ff2012-12-11 01:36:442746
2747
Saagar Sanghavifceeaae2020-08-12 16:40:362748def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502749 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
James Cook6b6597c2019-11-06 22:05:292750
Sam Maiera6e76d72022-02-11 21:43:502751 def FileFilter(affected_file):
2752 """Includes directories known to be Chrome OS only."""
2753 return input_api.FilterSourceFile(
2754 affected_file,
2755 files_to_check=(
2756 '^ash/',
2757 '^chromeos/', # Top-level src/chromeos.
2758 '.*/chromeos/', # Any path component.
2759 '^components/arc',
2760 '^components/exo'),
2761 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292762
Sam Maiera6e76d72022-02-11 21:43:502763 prefs = []
2764 priority_prefs = []
2765 for f in input_api.AffectedFiles(file_filter=FileFilter):
2766 for line_num, line in f.ChangedContents():
2767 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF',
2768 line):
2769 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2770 prefs.append(' %s' % line)
2771 if input_api.re.search(
2772 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2773 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2774 priority_prefs.append(' %s' % line)
2775
2776 results = []
2777 if (prefs):
2778 results.append(
2779 output_api.PresubmitPromptWarning(
2780 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2781 'by browser sync settings. If these prefs should be controlled by OS '
2782 'sync settings use SYNCABLE_OS_PREF instead.\n' +
2783 '\n'.join(prefs)))
2784 if (priority_prefs):
2785 results.append(
2786 output_api.PresubmitPromptWarning(
2787 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2788 'controlled by browser sync settings. If these prefs should be '
2789 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2790 'instead.\n' + '\n'.join(prefs)))
2791 return results
James Cook6b6597c2019-11-06 22:05:292792
2793
Saagar Sanghavifceeaae2020-08-12 16:40:362794def CheckNoAbbreviationInPngFileName(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502795 """Makes sure there are no abbreviations in the name of PNG files.
2796 The native_client_sdk directory is excluded because it has auto-generated PNG
2797 files for documentation.
2798 """
2799 errors = []
Yuanqing Zhu9eef02832022-12-04 14:42:172800 files_to_check = [r'.*\.png$']
Bruce Dawson40fece62022-09-16 19:58:312801 files_to_skip = [r'^native_client_sdk/',
2802 r'^services/test/',
2803 r'^third_party/blink/web_tests/',
Bruce Dawson3db456212022-05-02 05:34:182804 ]
Sam Maiera6e76d72022-02-11 21:43:502805 file_filter = lambda f: input_api.FilterSourceFile(
2806 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Yuanqing Zhu9eef02832022-12-04 14:42:172807 abbreviation = input_api.re.compile('.+_[a-z]\.png|.+_[a-z]_.*\.png')
Sam Maiera6e76d72022-02-11 21:43:502808 for f in input_api.AffectedFiles(include_deletes=False,
2809 file_filter=file_filter):
Yuanqing Zhu9eef02832022-12-04 14:42:172810 file_name = input_api.os_path.split(f.LocalPath())[1]
2811 if abbreviation.search(file_name):
2812 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272813
Sam Maiera6e76d72022-02-11 21:43:502814 results = []
2815 if errors:
2816 results.append(
2817 output_api.PresubmitError(
2818 'The name of PNG files should not have abbreviations. \n'
2819 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2820 'Contact [email protected] if you have questions.', errors))
2821 return results
[email protected]d2530012013-01-25 16:39:272822
Evan Stade7cd4a2c2022-08-04 23:37:252823def CheckNoProductIconsAddedToPublicRepo(input_api, output_api):
2824 """Heuristically identifies product icons based on their file name and reminds
2825 contributors not to add them to the Chromium repository.
2826 """
2827 errors = []
2828 files_to_check = [r'.*google.*\.png$|.*google.*\.svg$|.*google.*\.icon$']
2829 file_filter = lambda f: input_api.FilterSourceFile(
2830 f, files_to_check=files_to_check)
2831 for f in input_api.AffectedFiles(include_deletes=False,
2832 file_filter=file_filter):
2833 errors.append(' %s' % f.LocalPath())
2834
2835 results = []
2836 if errors:
Bruce Dawson3bcf0c92022-08-12 00:03:082837 # Give warnings instead of errors on presubmit --all and presubmit
2838 # --files.
2839 message_type = (output_api.PresubmitNotifyResult if input_api.no_diffs
2840 else output_api.PresubmitError)
Evan Stade7cd4a2c2022-08-04 23:37:252841 results.append(
Bruce Dawson3bcf0c92022-08-12 00:03:082842 message_type(
Evan Stade7cd4a2c2022-08-04 23:37:252843 'Trademarked images should not be added to the public repo. '
2844 'See crbug.com/944754', errors))
2845 return results
2846
[email protected]d2530012013-01-25 16:39:272847
Daniel Cheng4dcdb6b2017-04-13 08:30:172848def _ExtractAddRulesFromParsedDeps(parsed_deps):
Sam Maiera6e76d72022-02-11 21:43:502849 """Extract the rules that add dependencies from a parsed DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172850
Sam Maiera6e76d72022-02-11 21:43:502851 Args:
2852 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2853 add_rules = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172854 add_rules.update([
Sam Maiera6e76d72022-02-11 21:43:502855 rule[1:] for rule in parsed_deps.get('include_rules', [])
Daniel Cheng4dcdb6b2017-04-13 08:30:172856 if rule.startswith('+') or rule.startswith('!')
2857 ])
Sam Maiera6e76d72022-02-11 21:43:502858 for _, rules in parsed_deps.get('specific_include_rules', {}).items():
2859 add_rules.update([
2860 rule[1:] for rule in rules
2861 if rule.startswith('+') or rule.startswith('!')
2862 ])
2863 return add_rules
Daniel Cheng4dcdb6b2017-04-13 08:30:172864
2865
2866def _ParseDeps(contents):
Sam Maiera6e76d72022-02-11 21:43:502867 """Simple helper for parsing DEPS files."""
Daniel Cheng4dcdb6b2017-04-13 08:30:172868
Sam Maiera6e76d72022-02-11 21:43:502869 # Stubs for handling special syntax in the root DEPS file.
2870 class _VarImpl:
2871 def __init__(self, local_scope):
2872 self._local_scope = local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172873
Sam Maiera6e76d72022-02-11 21:43:502874 def Lookup(self, var_name):
2875 """Implements the Var syntax."""
2876 try:
2877 return self._local_scope['vars'][var_name]
2878 except KeyError:
2879 raise Exception('Var is not defined: %s' % var_name)
Daniel Cheng4dcdb6b2017-04-13 08:30:172880
Sam Maiera6e76d72022-02-11 21:43:502881 local_scope = {}
2882 global_scope = {
2883 'Var': _VarImpl(local_scope).Lookup,
2884 'Str': str,
2885 }
Dirk Pranke1b9e06382021-05-14 01:16:222886
Sam Maiera6e76d72022-02-11 21:43:502887 exec(contents, global_scope, local_scope)
2888 return local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172889
2890
2891def _CalculateAddedDeps(os_path, old_contents, new_contents):
Sam Maiera6e76d72022-02-11 21:43:502892 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
2893 a set of DEPS entries that we should look up.
[email protected]14a6131c2014-01-08 01:15:412894
Sam Maiera6e76d72022-02-11 21:43:502895 For a directory (rather than a specific filename) we fake a path to
2896 a specific filename by adding /DEPS. This is chosen as a file that
2897 will seldom or never be subject to per-file include_rules.
2898 """
2899 # We ignore deps entries on auto-generated directories.
2900 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082901
Sam Maiera6e76d72022-02-11 21:43:502902 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2903 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
Daniel Cheng4dcdb6b2017-04-13 08:30:172904
Sam Maiera6e76d72022-02-11 21:43:502905 added_deps = new_deps.difference(old_deps)
Daniel Cheng4dcdb6b2017-04-13 08:30:172906
Sam Maiera6e76d72022-02-11 21:43:502907 results = set()
2908 for added_dep in added_deps:
2909 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2910 continue
2911 # Assume that a rule that ends in .h is a rule for a specific file.
2912 if added_dep.endswith('.h'):
2913 results.add(added_dep)
2914 else:
2915 results.add(os_path.join(added_dep, 'DEPS'))
2916 return results
[email protected]f32e2d1e2013-07-26 21:39:082917
2918
Saagar Sanghavifceeaae2020-08-12 16:40:362919def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502920 """When a dependency prefixed with + is added to a DEPS file, we
2921 want to make sure that the change is reviewed by an OWNER of the
2922 target file or directory, to avoid layering violations from being
2923 introduced. This check verifies that this happens.
2924 """
2925 # We rely on Gerrit's code-owners to check approvals.
2926 # input_api.gerrit is always set for Chromium, but other projects
2927 # might not use Gerrit.
Bruce Dawson344ab262022-06-04 11:35:102928 if not input_api.gerrit or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:502929 return []
Bruce Dawsonb357aeb2022-08-09 15:38:302930 if 'PRESUBMIT_SKIP_NETWORK' in input_api.environ:
Sam Maiera6e76d72022-02-11 21:43:502931 return []
Bruce Dawsonb357aeb2022-08-09 15:38:302932 try:
2933 if (input_api.change.issue and
2934 input_api.gerrit.IsOwnersOverrideApproved(
2935 input_api.change.issue)):
2936 # Skip OWNERS check when Owners-Override label is approved. This is
2937 # intended for global owners, trusted bots, and on-call sheriffs.
2938 # Review is still required for these changes.
2939 return []
2940 except Exception as e:
Sam Maier4cef9242022-10-03 14:21:242941 return [output_api.PresubmitPromptWarning(
2942 'Failed to retrieve owner override status - %s' % str(e))]
Edward Lesmes6fba51082021-01-20 04:20:232943
Sam Maiera6e76d72022-02-11 21:43:502944 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242945
Bruce Dawson40fece62022-09-16 19:58:312946 # Consistently use / as path separator to simplify the writing of regex
2947 # expressions.
Sam Maiera6e76d72022-02-11 21:43:502948 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:312949 r"^third_party/blink/.*",
2950 f.LocalPath().replace(input_api.os_path.sep, '/'))
Sam Maiera6e76d72022-02-11 21:43:502951 for f in input_api.AffectedFiles(include_deletes=False,
2952 file_filter=file_filter):
2953 filename = input_api.os_path.basename(f.LocalPath())
2954 if filename == 'DEPS':
2955 virtual_depended_on_files.update(
2956 _CalculateAddedDeps(input_api.os_path,
2957 '\n'.join(f.OldContents()),
2958 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552959
Sam Maiera6e76d72022-02-11 21:43:502960 if not virtual_depended_on_files:
2961 return []
[email protected]e871964c2013-05-13 14:14:552962
Sam Maiera6e76d72022-02-11 21:43:502963 if input_api.is_committing:
2964 if input_api.tbr:
2965 return [
2966 output_api.PresubmitNotifyResult(
2967 '--tbr was specified, skipping OWNERS check for DEPS additions'
2968 )
2969 ]
Daniel Cheng3008dc12022-05-13 04:02:112970 # TODO(dcheng): Make this generate an error on dry runs if the reviewer
2971 # is not added, to prevent review serialization.
Sam Maiera6e76d72022-02-11 21:43:502972 if input_api.dry_run:
2973 return [
2974 output_api.PresubmitNotifyResult(
2975 'This is a dry run, skipping OWNERS check for DEPS additions'
2976 )
2977 ]
2978 if not input_api.change.issue:
2979 return [
2980 output_api.PresubmitError(
2981 "DEPS approval by OWNERS check failed: this change has "
2982 "no change number, so we can't check it for approvals.")
2983 ]
2984 output = output_api.PresubmitError
[email protected]14a6131c2014-01-08 01:15:412985 else:
Sam Maiera6e76d72022-02-11 21:43:502986 output = output_api.PresubmitNotifyResult
[email protected]e871964c2013-05-13 14:14:552987
Sam Maiera6e76d72022-02-11 21:43:502988 owner_email, reviewers = (
2989 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2990 input_api, None, approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552991
Sam Maiera6e76d72022-02-11 21:43:502992 owner_email = owner_email or input_api.change.author_email
2993
2994 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2995 virtual_depended_on_files, reviewers.union([owner_email]), [])
2996 missing_files = [
2997 f for f in virtual_depended_on_files
2998 if approval_status[f] != input_api.owners_client.APPROVED
2999 ]
3000
3001 # We strip the /DEPS part that was added by
3002 # _FilesToCheckForIncomingDeps to fake a path to a file in a
3003 # directory.
3004 def StripDeps(path):
3005 start_deps = path.rfind('/DEPS')
3006 if start_deps != -1:
3007 return path[:start_deps]
3008 else:
3009 return path
3010
3011 unapproved_dependencies = [
3012 "'+%s'," % StripDeps(path) for path in missing_files
3013 ]
3014
3015 if unapproved_dependencies:
3016 output_list = [
3017 output(
3018 'You need LGTM from owners of depends-on paths in DEPS that were '
3019 'modified in this CL:\n %s' %
3020 '\n '.join(sorted(unapproved_dependencies)))
3021 ]
3022 suggested_owners = input_api.owners_client.SuggestOwners(
3023 missing_files, exclude=[owner_email])
3024 output_list.append(
3025 output('Suggested missing target path OWNERS:\n %s' %
3026 '\n '.join(suggested_owners or [])))
3027 return output_list
3028
3029 return []
[email protected]e871964c2013-05-13 14:14:553030
3031
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493032# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:363033def CheckSpamLogging(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503034 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3035 files_to_skip = (
3036 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3037 input_api.DEFAULT_FILES_TO_SKIP + (
Jaewon Jung2f323bb2022-12-07 23:55:013038 r"^base/fuchsia/scoped_fx_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313039 r"^base/logging\.h$",
3040 r"^base/logging\.cc$",
3041 r"^base/task/thread_pool/task_tracker\.cc$",
3042 r"^chrome/app/chrome_main_delegate\.cc$",
Yao Li359937b2023-02-15 23:43:033043 r"^chrome/browser/ash/arc/enterprise/cert_store/arc_cert_installer\.cc$",
3044 r"^chrome/browser/ash/policy/remote_commands/user_command_arc_job\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313045 r"^chrome/browser/chrome_browser_main\.cc$",
3046 r"^chrome/browser/ui/startup/startup_browser_creator\.cc$",
3047 r"^chrome/browser/browser_switcher/bho/.*",
3048 r"^chrome/browser/diagnostics/diagnostics_writer\.cc$",
3049 r"^chrome/chrome_cleaner/.*",
3050 r"^chrome/chrome_elf/dll_hash/dll_hash_main\.cc$",
3051 r"^chrome/installer/setup/.*",
3052 r"^chromecast/",
Bruce Dawson40fece62022-09-16 19:58:313053 r"^components/media_control/renderer/media_playback_options\.cc$",
Salma Elmahallawy52976452023-01-27 17:04:493054 r"^components/policy/core/common/policy_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313055 r"^components/viz/service/display/"
Sam Maiera6e76d72022-02-11 21:43:503056 r"overlay_strategy_underlay_cast\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313057 r"^components/zucchini/.*",
Sam Maiera6e76d72022-02-11 21:43:503058 # TODO(peter): Remove exception. https://crbug.com/534537
Bruce Dawson40fece62022-09-16 19:58:313059 r"^content/browser/notifications/"
Sam Maiera6e76d72022-02-11 21:43:503060 r"notification_event_dispatcher_impl\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313061 r"^content/common/gpu/client/gl_helper_benchmark\.cc$",
3062 r"^courgette/courgette_minimal_tool\.cc$",
3063 r"^courgette/courgette_tool\.cc$",
3064 r"^extensions/renderer/logging_native_handler\.cc$",
3065 r"^fuchsia_web/common/init_logging\.cc$",
3066 r"^fuchsia_web/runners/common/web_component\.cc$",
Caroline Liua7050132023-02-13 22:23:153067 r"^fuchsia_web/shell/.*\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313068 r"^headless/app/headless_shell\.cc$",
3069 r"^ipc/ipc_logging\.cc$",
3070 r"^native_client_sdk/",
3071 r"^remoting/base/logging\.h$",
3072 r"^remoting/host/.*",
3073 r"^sandbox/linux/.*",
3074 r"^storage/browser/file_system/dump_file_system\.cc$",
3075 r"^tools/",
3076 r"^ui/base/resource/data_pack\.cc$",
3077 r"^ui/aura/bench/bench_main\.cc$",
3078 r"^ui/ozone/platform/cast/",
3079 r"^ui/base/x/xwmstartupcheck/"
Sam Maiera6e76d72022-02-11 21:43:503080 r"xwmstartupcheck\.cc$"))
3081 source_file_filter = lambda x: input_api.FilterSourceFile(
3082 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:403083
Sam Maiera6e76d72022-02-11 21:43:503084 log_info = set([])
3085 printf = set([])
[email protected]85218562013-11-22 07:41:403086
Sam Maiera6e76d72022-02-11 21:43:503087 for f in input_api.AffectedSourceFiles(source_file_filter):
3088 for _, line in f.ChangedContents():
3089 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
3090 log_info.add(f.LocalPath())
3091 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
3092 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:373093
Sam Maiera6e76d72022-02-11 21:43:503094 if input_api.re.search(r"\bprintf\(", line):
3095 printf.add(f.LocalPath())
3096 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
3097 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:403098
Sam Maiera6e76d72022-02-11 21:43:503099 if log_info:
3100 return [
3101 output_api.PresubmitError(
3102 'These files spam the console log with LOG(INFO):',
3103 items=log_info)
3104 ]
3105 if printf:
3106 return [
3107 output_api.PresubmitError(
3108 'These files spam the console log with printf/fprintf:',
3109 items=printf)
3110 ]
3111 return []
[email protected]85218562013-11-22 07:41:403112
3113
Saagar Sanghavifceeaae2020-08-12 16:40:363114def CheckForAnonymousVariables(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503115 """These types are all expected to hold locks while in scope and
3116 so should never be anonymous (which causes them to be immediately
3117 destroyed)."""
3118 they_who_must_be_named = [
3119 'base::AutoLock',
3120 'base::AutoReset',
3121 'base::AutoUnlock',
3122 'SkAutoAlphaRestore',
3123 'SkAutoBitmapShaderInstall',
3124 'SkAutoBlitterChoose',
3125 'SkAutoBounderCommit',
3126 'SkAutoCallProc',
3127 'SkAutoCanvasRestore',
3128 'SkAutoCommentBlock',
3129 'SkAutoDescriptor',
3130 'SkAutoDisableDirectionCheck',
3131 'SkAutoDisableOvalCheck',
3132 'SkAutoFree',
3133 'SkAutoGlyphCache',
3134 'SkAutoHDC',
3135 'SkAutoLockColors',
3136 'SkAutoLockPixels',
3137 'SkAutoMalloc',
3138 'SkAutoMaskFreeImage',
3139 'SkAutoMutexAcquire',
3140 'SkAutoPathBoundsUpdate',
3141 'SkAutoPDFRelease',
3142 'SkAutoRasterClipValidate',
3143 'SkAutoRef',
3144 'SkAutoTime',
3145 'SkAutoTrace',
3146 'SkAutoUnref',
3147 ]
3148 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
3149 # bad: base::AutoLock(lock.get());
3150 # not bad: base::AutoLock lock(lock.get());
3151 bad_pattern = input_api.re.compile(anonymous)
3152 # good: new base::AutoLock(lock.get())
3153 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
3154 errors = []
[email protected]49aa76a2013-12-04 06:59:163155
Sam Maiera6e76d72022-02-11 21:43:503156 for f in input_api.AffectedFiles():
3157 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
3158 continue
3159 for linenum, line in f.ChangedContents():
3160 if bad_pattern.search(line) and not good_pattern.search(line):
3161 errors.append('%s:%d' % (f.LocalPath(), linenum))
[email protected]49aa76a2013-12-04 06:59:163162
Sam Maiera6e76d72022-02-11 21:43:503163 if errors:
3164 return [
3165 output_api.PresubmitError(
3166 'These lines create anonymous variables that need to be named:',
3167 items=errors)
3168 ]
3169 return []
[email protected]49aa76a2013-12-04 06:59:163170
3171
Saagar Sanghavifceeaae2020-08-12 16:40:363172def CheckUniquePtrOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503173 # Returns whether |template_str| is of the form <T, U...> for some types T
3174 # and U. Assumes that |template_str| is already in the form <...>.
3175 def HasMoreThanOneArg(template_str):
3176 # Level of <...> nesting.
3177 nesting = 0
3178 for c in template_str:
3179 if c == '<':
3180 nesting += 1
3181 elif c == '>':
3182 nesting -= 1
3183 elif c == ',' and nesting == 1:
3184 return True
3185 return False
Vaclav Brozekb7fadb692018-08-30 06:39:533186
Sam Maiera6e76d72022-02-11 21:43:503187 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3188 sources = lambda affected_file: input_api.FilterSourceFile(
3189 affected_file,
3190 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3191 DEFAULT_FILES_TO_SKIP),
3192 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:553193
Sam Maiera6e76d72022-02-11 21:43:503194 # Pattern to capture a single "<...>" block of template arguments. It can
3195 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
3196 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
3197 # latter would likely require counting that < and > match, which is not
3198 # expressible in regular languages. Should the need arise, one can introduce
3199 # limited counting (matching up to a total number of nesting depth), which
3200 # should cover all practical cases for already a low nesting limit.
3201 template_arg_pattern = (
3202 r'<[^>]*' # Opening block of <.
3203 r'>([^<]*>)?') # Closing block of >.
3204 # Prefix expressing that whatever follows is not already inside a <...>
3205 # block.
3206 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
3207 null_construct_pattern = input_api.re.compile(
3208 not_inside_template_arg_pattern + r'\bstd::unique_ptr' +
3209 template_arg_pattern + r'\(\)')
Vaclav Brozeka54c528b2018-04-06 19:23:553210
Sam Maiera6e76d72022-02-11 21:43:503211 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
3212 template_arg_no_array_pattern = (
3213 r'<[^>]*[^]]' # Opening block of <.
3214 r'>([^(<]*[^]]>)?') # Closing block of >.
3215 # Prefix saying that what follows is the start of an expression.
3216 start_of_expr_pattern = r'(=|\breturn|^)\s*'
3217 # Suffix saying that what follows are call parentheses with a non-empty list
3218 # of arguments.
3219 nonempty_arg_list_pattern = r'\(([^)]|$)'
3220 # Put the template argument into a capture group for deeper examination later.
3221 return_construct_pattern = input_api.re.compile(
3222 start_of_expr_pattern + r'std::unique_ptr' + '(?P<template_arg>' +
3223 template_arg_no_array_pattern + ')' + nonempty_arg_list_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:553224
Sam Maiera6e76d72022-02-11 21:43:503225 problems_constructor = []
3226 problems_nullptr = []
3227 for f in input_api.AffectedSourceFiles(sources):
3228 for line_number, line in f.ChangedContents():
3229 # Disallow:
3230 # return std::unique_ptr<T>(foo);
3231 # bar = std::unique_ptr<T>(foo);
3232 # But allow:
3233 # return std::unique_ptr<T[]>(foo);
3234 # bar = std::unique_ptr<T[]>(foo);
3235 # And also allow cases when the second template argument is present. Those
3236 # cases cannot be handled by std::make_unique:
3237 # return std::unique_ptr<T, U>(foo);
3238 # bar = std::unique_ptr<T, U>(foo);
3239 local_path = f.LocalPath()
3240 return_construct_result = return_construct_pattern.search(line)
3241 if return_construct_result and not HasMoreThanOneArg(
3242 return_construct_result.group('template_arg')):
3243 problems_constructor.append(
3244 '%s:%d\n %s' % (local_path, line_number, line.strip()))
3245 # Disallow:
3246 # std::unique_ptr<T>()
3247 if null_construct_pattern.search(line):
3248 problems_nullptr.append(
3249 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Vaclav Brozek851d9602018-04-04 16:13:053250
Sam Maiera6e76d72022-02-11 21:43:503251 errors = []
3252 if problems_nullptr:
3253 errors.append(
3254 output_api.PresubmitPromptWarning(
3255 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
3256 problems_nullptr))
3257 if problems_constructor:
3258 errors.append(
3259 output_api.PresubmitError(
3260 'The following files use explicit std::unique_ptr constructor. '
3261 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
3262 'std::make_unique is not an option.', problems_constructor))
3263 return errors
Peter Kasting4844e46e2018-02-23 07:27:103264
3265
Saagar Sanghavifceeaae2020-08-12 16:40:363266def CheckUserActionUpdate(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503267 """Checks if any new user action has been added."""
3268 if any('actions.xml' == input_api.os_path.basename(f)
3269 for f in input_api.LocalPaths()):
3270 # If actions.xml is already included in the changelist, the PRESUBMIT
3271 # for actions.xml will do a more complete presubmit check.
3272 return []
3273
3274 file_inclusion_pattern = [r'.*\.(cc|mm)$']
3275 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3276 input_api.DEFAULT_FILES_TO_SKIP)
3277 file_filter = lambda f: input_api.FilterSourceFile(
3278 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
3279
3280 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
3281 current_actions = None
3282 for f in input_api.AffectedFiles(file_filter=file_filter):
3283 for line_num, line in f.ChangedContents():
3284 match = input_api.re.search(action_re, line)
3285 if match:
3286 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
3287 # loaded only once.
3288 if not current_actions:
Bruce Dawson6cb2d4d2023-03-01 21:35:093289 with open('tools/metrics/actions/actions.xml',
3290 encoding='utf-8') as actions_f:
Sam Maiera6e76d72022-02-11 21:43:503291 current_actions = actions_f.read()
3292 # Search for the matched user action name in |current_actions|.
3293 for action_name in match.groups():
3294 action = 'name="{0}"'.format(action_name)
3295 if action not in current_actions:
3296 return [
3297 output_api.PresubmitPromptWarning(
3298 'File %s line %d: %s is missing in '
3299 'tools/metrics/actions/actions.xml. Please run '
3300 'tools/metrics/actions/extract_actions.py to update.'
3301 % (f.LocalPath(), line_num, action_name))
3302 ]
[email protected]999261d2014-03-03 20:08:083303 return []
3304
[email protected]999261d2014-03-03 20:08:083305
Daniel Cheng13ca61a882017-08-25 15:11:253306def _ImportJSONCommentEater(input_api):
Sam Maiera6e76d72022-02-11 21:43:503307 import sys
3308 sys.path = sys.path + [
3309 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3310 'json_comment_eater')
3311 ]
3312 import json_comment_eater
3313 return json_comment_eater
Daniel Cheng13ca61a882017-08-25 15:11:253314
3315
[email protected]99171a92014-06-03 08:44:473316def _GetJSONParseError(input_api, filename, eat_comments=True):
dchenge07de812016-06-20 19:27:173317 try:
Sam Maiera6e76d72022-02-11 21:43:503318 contents = input_api.ReadFile(filename)
3319 if eat_comments:
3320 json_comment_eater = _ImportJSONCommentEater(input_api)
3321 contents = json_comment_eater.Nom(contents)
dchenge07de812016-06-20 19:27:173322
Sam Maiera6e76d72022-02-11 21:43:503323 input_api.json.loads(contents)
3324 except ValueError as e:
3325 return e
Andrew Grieve4deedb12022-02-03 21:34:503326 return None
3327
3328
Sam Maiera6e76d72022-02-11 21:43:503329def _GetIDLParseError(input_api, filename):
3330 try:
3331 contents = input_api.ReadFile(filename)
Devlin Croninf7582a12022-04-21 21:14:283332 for i, char in enumerate(contents):
Daniel Chenga37c03db2022-05-12 17:20:343333 if not char.isascii():
3334 return (
3335 'Non-ascii character "%s" (ord %d) found at offset %d.' %
3336 (char, ord(char), i))
Sam Maiera6e76d72022-02-11 21:43:503337 idl_schema = input_api.os_path.join(input_api.PresubmitLocalPath(),
3338 'tools', 'json_schema_compiler',
3339 'idl_schema.py')
3340 process = input_api.subprocess.Popen(
Bruce Dawson679fb082022-04-14 00:47:283341 [input_api.python3_executable, idl_schema],
Sam Maiera6e76d72022-02-11 21:43:503342 stdin=input_api.subprocess.PIPE,
3343 stdout=input_api.subprocess.PIPE,
3344 stderr=input_api.subprocess.PIPE,
3345 universal_newlines=True)
3346 (_, error) = process.communicate(input=contents)
3347 return error or None
3348 except ValueError as e:
3349 return e
agrievef32bcc72016-04-04 14:57:403350
agrievef32bcc72016-04-04 14:57:403351
Sam Maiera6e76d72022-02-11 21:43:503352def CheckParseErrors(input_api, output_api):
3353 """Check that IDL and JSON files do not contain syntax errors."""
3354 actions = {
3355 '.idl': _GetIDLParseError,
3356 '.json': _GetJSONParseError,
3357 }
3358 # Most JSON files are preprocessed and support comments, but these do not.
3359 json_no_comments_patterns = [
Bruce Dawson40fece62022-09-16 19:58:313360 r'^testing/',
Sam Maiera6e76d72022-02-11 21:43:503361 ]
3362 # Only run IDL checker on files in these directories.
3363 idl_included_patterns = [
Bruce Dawson40fece62022-09-16 19:58:313364 r'^chrome/common/extensions/api/',
3365 r'^extensions/common/api/',
Sam Maiera6e76d72022-02-11 21:43:503366 ]
agrievef32bcc72016-04-04 14:57:403367
Sam Maiera6e76d72022-02-11 21:43:503368 def get_action(affected_file):
3369 filename = affected_file.LocalPath()
3370 return actions.get(input_api.os_path.splitext(filename)[1])
agrievef32bcc72016-04-04 14:57:403371
Sam Maiera6e76d72022-02-11 21:43:503372 def FilterFile(affected_file):
3373 action = get_action(affected_file)
3374 if not action:
3375 return False
3376 path = affected_file.LocalPath()
agrievef32bcc72016-04-04 14:57:403377
Sam Maiera6e76d72022-02-11 21:43:503378 if _MatchesFile(input_api,
3379 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS, path):
3380 return False
3381
3382 if (action == _GetIDLParseError
3383 and not _MatchesFile(input_api, idl_included_patterns, path)):
3384 return False
3385 return True
3386
3387 results = []
3388 for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
3389 include_deletes=False):
3390 action = get_action(affected_file)
3391 kwargs = {}
3392 if (action == _GetJSONParseError
3393 and _MatchesFile(input_api, json_no_comments_patterns,
3394 affected_file.LocalPath())):
3395 kwargs['eat_comments'] = False
3396 parse_error = action(input_api, affected_file.AbsoluteLocalPath(),
3397 **kwargs)
3398 if parse_error:
3399 results.append(
3400 output_api.PresubmitError(
3401 '%s could not be parsed: %s' %
3402 (affected_file.LocalPath(), parse_error)))
3403 return results
3404
3405
3406def CheckJavaStyle(input_api, output_api):
3407 """Runs checkstyle on changed java files and returns errors if any exist."""
3408
3409 # Return early if no java files were modified.
3410 if not any(
3411 _IsJavaFile(input_api, f.LocalPath())
3412 for f in input_api.AffectedFiles()):
3413 return []
3414
3415 import sys
3416 original_sys_path = sys.path
3417 try:
3418 sys.path = sys.path + [
3419 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3420 'android', 'checkstyle')
3421 ]
3422 import checkstyle
3423 finally:
3424 # Restore sys.path to what it was before.
3425 sys.path = original_sys_path
3426
Andrew Grieve4f88e3ca2022-11-22 19:09:203427 return checkstyle.run_presubmit(
Sam Maiera6e76d72022-02-11 21:43:503428 input_api,
3429 output_api,
Sam Maiera6e76d72022-02-11 21:43:503430 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
3431
3432
3433def CheckPythonDevilInit(input_api, output_api):
3434 """Checks to make sure devil is initialized correctly in python scripts."""
3435 script_common_initialize_pattern = input_api.re.compile(
3436 r'script_common\.InitializeEnvironment\(')
3437 devil_env_config_initialize = input_api.re.compile(
3438 r'devil_env\.config\.Initialize\(')
3439
3440 errors = []
3441
3442 sources = lambda affected_file: input_api.FilterSourceFile(
3443 affected_file,
3444 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:313445 r'^build/android/devil_chromium\.py',
3446 r'^third_party/.*',
Sam Maiera6e76d72022-02-11 21:43:503447 )),
3448 files_to_check=[r'.*\.py$'])
3449
3450 for f in input_api.AffectedSourceFiles(sources):
3451 for line_num, line in f.ChangedContents():
3452 if (script_common_initialize_pattern.search(line)
3453 or devil_env_config_initialize.search(line)):
3454 errors.append("%s:%d" % (f.LocalPath(), line_num))
3455
3456 results = []
3457
3458 if errors:
3459 results.append(
3460 output_api.PresubmitError(
3461 'Devil initialization should always be done using '
3462 'devil_chromium.Initialize() in the chromium project, to use better '
3463 'defaults for dependencies (ex. up-to-date version of adb).',
3464 errors))
3465
3466 return results
3467
3468
3469def _MatchesFile(input_api, patterns, path):
Bruce Dawson40fece62022-09-16 19:58:313470 # Consistently use / as path separator to simplify the writing of regex
3471 # expressions.
3472 path = path.replace(input_api.os_path.sep, '/')
Sam Maiera6e76d72022-02-11 21:43:503473 for pattern in patterns:
3474 if input_api.re.search(pattern, path):
3475 return True
3476 return False
3477
3478
Daniel Chenga37c03db2022-05-12 17:20:343479def _ChangeHasSecurityReviewer(input_api, owners_file):
3480 """Returns True iff the CL has a reviewer from SECURITY_OWNERS.
Sam Maiera6e76d72022-02-11 21:43:503481
Daniel Chenga37c03db2022-05-12 17:20:343482 Args:
3483 input_api: The presubmit input API.
3484 owners_file: OWNERS file with required reviewers. Typically, this is
3485 something like ipc/SECURITY_OWNERS.
3486
3487 Note: if the presubmit is running for commit rather than for upload, this
3488 only returns True if a security reviewer has also approved the CL.
Sam Maiera6e76d72022-02-11 21:43:503489 """
Daniel Chengd88244472022-05-16 09:08:473490 # Owners-Override should bypass all additional OWNERS enforcement checks.
3491 # A CR+1 vote will still be required to land this change.
3492 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
3493 input_api.change.issue)):
3494 return True
3495
Daniel Chenga37c03db2022-05-12 17:20:343496 owner_email, reviewers = (
3497 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
Daniel Cheng3008dc12022-05-13 04:02:113498 input_api,
3499 None,
3500 approval_needed=input_api.is_committing and not input_api.dry_run))
Sam Maiera6e76d72022-02-11 21:43:503501
Daniel Chenga37c03db2022-05-12 17:20:343502 security_owners = input_api.owners_client.ListOwners(owners_file)
3503 return any(owner in reviewers for owner in security_owners)
Sam Maiera6e76d72022-02-11 21:43:503504
Daniel Chenga37c03db2022-05-12 17:20:343505
3506@dataclass
Daniel Cheng171dad8d2022-05-21 00:40:253507class _SecurityProblemWithItems:
3508 problem: str
3509 items: Sequence[str]
3510
3511
3512@dataclass
Daniel Chenga37c03db2022-05-12 17:20:343513class _MissingSecurityOwnersResult:
Daniel Cheng171dad8d2022-05-21 00:40:253514 owners_file_problems: Sequence[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:343515 has_security_sensitive_files: bool
Daniel Cheng171dad8d2022-05-21 00:40:253516 missing_reviewer_problem: Optional[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:343517
3518
3519def _FindMissingSecurityOwners(input_api,
3520 output_api,
3521 file_patterns: Sequence[str],
3522 excluded_patterns: Sequence[str],
3523 required_owners_file: str,
3524 custom_rule_function: Optional[Callable] = None
3525 ) -> _MissingSecurityOwnersResult:
3526 """Find OWNERS files missing per-file rules for security-sensitive files.
3527
3528 Args:
3529 input_api: the PRESUBMIT input API object.
3530 output_api: the PRESUBMIT output API object.
3531 file_patterns: basename patterns that require a corresponding per-file
3532 security restriction.
3533 excluded_patterns: path patterns that should be exempted from
3534 requiring a security restriction.
3535 required_owners_file: path to the required OWNERS file, e.g.
3536 ipc/SECURITY_OWNERS
3537 cc_alias: If not None, email that will be CCed automatically if the
3538 change contains security-sensitive files, as determined by
3539 `file_patterns` and `excluded_patterns`.
3540 custom_rule_function: If not None, will be called with `input_api` and
3541 the current file under consideration. Returning True will add an
3542 exact match per-file rule check for the current file.
3543 """
3544
3545 # `to_check` is a mapping of an OWNERS file path to Patterns.
3546 #
3547 # Patterns is a dictionary mapping glob patterns (suitable for use in
3548 # per-file rules) to a PatternEntry.
3549 #
Sam Maiera6e76d72022-02-11 21:43:503550 # PatternEntry is a dictionary with two keys:
3551 # - 'files': the files that are matched by this pattern
3552 # - 'rules': the per-file rules needed for this pattern
Daniel Chenga37c03db2022-05-12 17:20:343553 #
Sam Maiera6e76d72022-02-11 21:43:503554 # For example, if we expect OWNERS file to contain rules for *.mojom and
3555 # *_struct_traits*.*, Patterns might look like this:
3556 # {
3557 # '*.mojom': {
3558 # 'files': ...,
3559 # 'rules': [
3560 # 'per-file *.mojom=set noparent',
3561 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
3562 # ],
3563 # },
3564 # '*_struct_traits*.*': {
3565 # 'files': ...,
3566 # 'rules': [
3567 # 'per-file *_struct_traits*.*=set noparent',
3568 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
3569 # ],
3570 # },
3571 # }
3572 to_check = {}
Daniel Chenga37c03db2022-05-12 17:20:343573 files_to_review = []
Sam Maiera6e76d72022-02-11 21:43:503574
Daniel Chenga37c03db2022-05-12 17:20:343575 def AddPatternToCheck(file, pattern):
Sam Maiera6e76d72022-02-11 21:43:503576 owners_file = input_api.os_path.join(
Daniel Chengd88244472022-05-16 09:08:473577 input_api.os_path.dirname(file.LocalPath()), 'OWNERS')
Sam Maiera6e76d72022-02-11 21:43:503578 if owners_file not in to_check:
3579 to_check[owners_file] = {}
3580 if pattern not in to_check[owners_file]:
3581 to_check[owners_file][pattern] = {
3582 'files': [],
3583 'rules': [
Daniel Chenga37c03db2022-05-12 17:20:343584 f'per-file {pattern}=set noparent',
3585 f'per-file {pattern}=file://{required_owners_file}',
Sam Maiera6e76d72022-02-11 21:43:503586 ]
3587 }
Daniel Chenged57a162022-05-25 02:56:343588 to_check[owners_file][pattern]['files'].append(file.LocalPath())
Daniel Chenga37c03db2022-05-12 17:20:343589 files_to_review.append(file.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:503590
Daniel Chenga37c03db2022-05-12 17:20:343591 # Only enforce security OWNERS rules for a directory if that directory has a
3592 # file that matches `file_patterns`. For example, if a directory only
3593 # contains *.mojom files and no *_messages*.h files, the check should only
3594 # ensure that rules for *.mojom files are present.
3595 for file in input_api.AffectedFiles(include_deletes=False):
3596 file_basename = input_api.os_path.basename(file.LocalPath())
3597 if custom_rule_function is not None and custom_rule_function(
3598 input_api, file):
3599 AddPatternToCheck(file, file_basename)
3600 continue
Sam Maiera6e76d72022-02-11 21:43:503601
Daniel Chenga37c03db2022-05-12 17:20:343602 if any(
3603 input_api.fnmatch.fnmatch(file.LocalPath(), pattern)
3604 for pattern in excluded_patterns):
Sam Maiera6e76d72022-02-11 21:43:503605 continue
3606
3607 for pattern in file_patterns:
Daniel Chenga37c03db2022-05-12 17:20:343608 # Unlike `excluded_patterns`, `file_patterns` is checked only against the
3609 # file's basename.
3610 if input_api.fnmatch.fnmatch(file_basename, pattern):
3611 AddPatternToCheck(file, pattern)
Sam Maiera6e76d72022-02-11 21:43:503612 break
3613
Daniel Chenga37c03db2022-05-12 17:20:343614 has_security_sensitive_files = bool(to_check)
Daniel Cheng171dad8d2022-05-21 00:40:253615
3616 # Check if any newly added lines in OWNERS files intersect with required
3617 # per-file OWNERS lines. If so, ensure that a security reviewer is included.
3618 # This is a hack, but is needed because the OWNERS check (by design) ignores
3619 # new OWNERS entries; otherwise, a non-owner could add someone as a new
3620 # OWNER and have that newly-added OWNER self-approve their own addition.
3621 newly_covered_files = []
3622 for file in input_api.AffectedFiles(include_deletes=False):
3623 if not file.LocalPath() in to_check:
3624 continue
3625 for _, line in file.ChangedContents():
3626 for _, entry in to_check[file.LocalPath()].items():
3627 if line in entry['rules']:
3628 newly_covered_files.extend(entry['files'])
3629
3630 missing_reviewer_problems = None
3631 if newly_covered_files and not _ChangeHasSecurityReviewer(
Daniel Chenga37c03db2022-05-12 17:20:343632 input_api, required_owners_file):
Daniel Cheng171dad8d2022-05-21 00:40:253633 missing_reviewer_problems = _SecurityProblemWithItems(
3634 f'Review from an owner in {required_owners_file} is required for '
3635 'the following newly-added files:',
3636 [f'{file}' for file in sorted(set(newly_covered_files))])
Sam Maiera6e76d72022-02-11 21:43:503637
3638 # Go through the OWNERS files to check, filtering out rules that are already
3639 # present in that OWNERS file.
3640 for owners_file, patterns in to_check.items():
3641 try:
Daniel Cheng171dad8d2022-05-21 00:40:253642 lines = set(
3643 input_api.ReadFile(
3644 input_api.os_path.join(input_api.change.RepositoryRoot(),
3645 owners_file)).splitlines())
3646 for entry in patterns.values():
3647 entry['rules'] = [
3648 rule for rule in entry['rules'] if rule not in lines
3649 ]
Sam Maiera6e76d72022-02-11 21:43:503650 except IOError:
3651 # No OWNERS file, so all the rules are definitely missing.
3652 continue
3653
3654 # All the remaining lines weren't found in OWNERS files, so emit an error.
Daniel Cheng171dad8d2022-05-21 00:40:253655 owners_file_problems = []
Daniel Chenga37c03db2022-05-12 17:20:343656
Sam Maiera6e76d72022-02-11 21:43:503657 for owners_file, patterns in to_check.items():
3658 missing_lines = []
3659 files = []
3660 for _, entry in patterns.items():
Daniel Chenged57a162022-05-25 02:56:343661 files.extend(entry['files'])
Sam Maiera6e76d72022-02-11 21:43:503662 missing_lines.extend(entry['rules'])
Sam Maiera6e76d72022-02-11 21:43:503663 if missing_lines:
Daniel Cheng171dad8d2022-05-21 00:40:253664 joined_missing_lines = '\n'.join(line for line in missing_lines)
3665 owners_file_problems.append(
3666 _SecurityProblemWithItems(
3667 'Found missing OWNERS lines for security-sensitive files. '
3668 f'Please add the following lines to {owners_file}:\n'
3669 f'{joined_missing_lines}\n\nTo ensure security review for:',
3670 files))
Daniel Chenga37c03db2022-05-12 17:20:343671
Daniel Cheng171dad8d2022-05-21 00:40:253672 return _MissingSecurityOwnersResult(owners_file_problems,
Daniel Chenga37c03db2022-05-12 17:20:343673 has_security_sensitive_files,
Daniel Cheng171dad8d2022-05-21 00:40:253674 missing_reviewer_problems)
Daniel Chenga37c03db2022-05-12 17:20:343675
3676
3677def _CheckChangeForIpcSecurityOwners(input_api, output_api):
3678 # Whether or not a file affects IPC is (mostly) determined by a simple list
3679 # of filename patterns.
3680 file_patterns = [
3681 # Legacy IPC:
3682 '*_messages.cc',
3683 '*_messages*.h',
3684 '*_param_traits*.*',
3685 # Mojo IPC:
3686 '*.mojom',
3687 '*_mojom_traits*.*',
3688 '*_type_converter*.*',
3689 # Android native IPC:
3690 '*.aidl',
3691 ]
3692
Daniel Chenga37c03db2022-05-12 17:20:343693 excluded_patterns = [
Daniel Cheng518943f2022-05-12 22:15:463694 # These third_party directories do not contain IPCs, but contain files
3695 # matching the above patterns, which trigger false positives.
Daniel Chenga37c03db2022-05-12 17:20:343696 'third_party/crashpad/*',
3697 'third_party/blink/renderer/platform/bindings/*',
3698 'third_party/protobuf/benchmarks/python/*',
3699 'third_party/win_build_output/*',
Daniel Chengd88244472022-05-16 09:08:473700 # Enum-only mojoms used for web metrics, so no security review needed.
3701 'third_party/blink/public/mojom/use_counter/metrics/*',
Daniel Chenga37c03db2022-05-12 17:20:343702 # These files are just used to communicate between class loaders running
3703 # in the same process.
3704 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
3705 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
3706 ]
3707
3708 def IsMojoServiceManifestFile(input_api, file):
3709 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
3710 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
3711 if not manifest_pattern.search(file.LocalPath()):
3712 return False
3713
3714 if test_manifest_pattern.search(file.LocalPath()):
3715 return False
3716
3717 # All actual service manifest files should contain at least one
3718 # qualified reference to service_manager::Manifest.
3719 return any('service_manager::Manifest' in line
3720 for line in file.NewContents())
3721
3722 return _FindMissingSecurityOwners(
3723 input_api,
3724 output_api,
3725 file_patterns,
3726 excluded_patterns,
3727 'ipc/SECURITY_OWNERS',
3728 custom_rule_function=IsMojoServiceManifestFile)
3729
3730
3731def _CheckChangeForFuchsiaSecurityOwners(input_api, output_api):
3732 file_patterns = [
3733 # Component specifications.
3734 '*.cml', # Component Framework v2.
3735 '*.cmx', # Component Framework v1.
3736
3737 # Fuchsia IDL protocol specifications.
3738 '*.fidl',
3739 ]
3740
3741 # Don't check for owners files for changes in these directories.
3742 excluded_patterns = [
3743 'third_party/crashpad/*',
3744 ]
3745
3746 return _FindMissingSecurityOwners(input_api, output_api, file_patterns,
3747 excluded_patterns,
3748 'build/fuchsia/SECURITY_OWNERS')
3749
3750
3751def CheckSecurityOwners(input_api, output_api):
3752 """Checks that various security-sensitive files have an IPC OWNERS rule."""
3753 ipc_results = _CheckChangeForIpcSecurityOwners(input_api, output_api)
3754 fuchsia_results = _CheckChangeForFuchsiaSecurityOwners(
3755 input_api, output_api)
3756
3757 if ipc_results.has_security_sensitive_files:
3758 output_api.AppendCC('[email protected]')
Sam Maiera6e76d72022-02-11 21:43:503759
3760 results = []
Daniel Chenga37c03db2022-05-12 17:20:343761
Daniel Cheng171dad8d2022-05-21 00:40:253762 missing_reviewer_problems = []
3763 if ipc_results.missing_reviewer_problem:
3764 missing_reviewer_problems.append(ipc_results.missing_reviewer_problem)
3765 if fuchsia_results.missing_reviewer_problem:
3766 missing_reviewer_problems.append(
3767 fuchsia_results.missing_reviewer_problem)
Daniel Chenga37c03db2022-05-12 17:20:343768
Daniel Cheng171dad8d2022-05-21 00:40:253769 # Missing reviewers are an error unless there's no issue number
3770 # associated with this branch; in that case, the presubmit is being run
3771 # with --all or --files.
3772 #
3773 # Note that upload should never be an error; otherwise, it would be
3774 # impossible to upload changes at all.
3775 if input_api.is_committing and input_api.change.issue:
3776 make_presubmit_message = output_api.PresubmitError
3777 else:
3778 make_presubmit_message = output_api.PresubmitNotifyResult
3779 for problem in missing_reviewer_problems:
Sam Maiera6e76d72022-02-11 21:43:503780 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:253781 make_presubmit_message(problem.problem, items=problem.items))
Daniel Chenga37c03db2022-05-12 17:20:343782
Daniel Cheng171dad8d2022-05-21 00:40:253783 owners_file_problems = []
3784 owners_file_problems.extend(ipc_results.owners_file_problems)
3785 owners_file_problems.extend(fuchsia_results.owners_file_problems)
Daniel Chenga37c03db2022-05-12 17:20:343786
Daniel Cheng171dad8d2022-05-21 00:40:253787 for problem in owners_file_problems:
Daniel Cheng3008dc12022-05-13 04:02:113788 # Missing per-file rules are always an error. While swarming and caching
3789 # means that uploading a patchset with updated OWNERS files and sending
3790 # it to the CQ again should not have a large incremental cost, it is
3791 # still frustrating to discover the error only after the change has
3792 # already been uploaded.
Daniel Chenga37c03db2022-05-12 17:20:343793 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:253794 output_api.PresubmitError(problem.problem, items=problem.items))
Sam Maiera6e76d72022-02-11 21:43:503795
3796 return results
3797
3798
3799def _GetFilesUsingSecurityCriticalFunctions(input_api):
3800 """Checks affected files for changes to security-critical calls. This
3801 function checks the full change diff, to catch both additions/changes
3802 and removals.
3803
3804 Returns a dict keyed by file name, and the value is a set of detected
3805 functions.
3806 """
3807 # Map of function pretty name (displayed in an error) to the pattern to
3808 # match it with.
3809 _PATTERNS_TO_CHECK = {
3810 'content::GetServiceSandboxType<>()': 'GetServiceSandboxType\\<'
3811 }
3812 _PATTERNS_TO_CHECK = {
3813 k: input_api.re.compile(v)
3814 for k, v in _PATTERNS_TO_CHECK.items()
3815 }
3816
Sam Maiera6e76d72022-02-11 21:43:503817 # We don't want to trigger on strings within this file.
3818 def presubmit_file_filter(f):
Daniel Chenga37c03db2022-05-12 17:20:343819 return 'PRESUBMIT.py' != input_api.os_path.split(f.LocalPath())[1]
Sam Maiera6e76d72022-02-11 21:43:503820
3821 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3822 files_to_functions = {}
3823 for f in input_api.AffectedFiles(file_filter=presubmit_file_filter):
3824 diff = f.GenerateScmDiff()
3825 for line in diff.split('\n'):
3826 # Not using just RightHandSideLines() because removing a
3827 # call to a security-critical function can be just as important
3828 # as adding or changing the arguments.
3829 if line.startswith('-') or (line.startswith('+')
3830 and not line.startswith('++')):
3831 for name, pattern in _PATTERNS_TO_CHECK.items():
3832 if pattern.search(line):
3833 path = f.LocalPath()
3834 if not path in files_to_functions:
3835 files_to_functions[path] = set()
3836 files_to_functions[path].add(name)
3837 return files_to_functions
3838
3839
3840def CheckSecurityChanges(input_api, output_api):
3841 """Checks that changes involving security-critical functions are reviewed
3842 by the security team.
3843 """
3844 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3845 if not len(files_to_functions):
3846 return []
3847
Sam Maiera6e76d72022-02-11 21:43:503848 owners_file = 'ipc/SECURITY_OWNERS'
Daniel Chenga37c03db2022-05-12 17:20:343849 if _ChangeHasSecurityReviewer(input_api, owners_file):
Sam Maiera6e76d72022-02-11 21:43:503850 return []
3851
Daniel Chenga37c03db2022-05-12 17:20:343852 msg = 'The following files change calls to security-sensitive functions\n' \
Sam Maiera6e76d72022-02-11 21:43:503853 'that need to be reviewed by {}.\n'.format(owners_file)
3854 for path, names in files_to_functions.items():
3855 msg += ' {}\n'.format(path)
3856 for name in names:
3857 msg += ' {}\n'.format(name)
3858 msg += '\n'
3859
3860 if input_api.is_committing:
3861 output = output_api.PresubmitError
Mohamed Heikale217fc852020-07-06 19:44:033862 else:
Sam Maiera6e76d72022-02-11 21:43:503863 output = output_api.PresubmitNotifyResult
3864 return [output(msg)]
3865
3866
3867def CheckSetNoParent(input_api, output_api):
3868 """Checks that set noparent is only used together with an OWNERS file in
3869 //build/OWNERS.setnoparent (see also
3870 //docs/code_reviews.md#owners-files-details)
3871 """
3872 # Return early if no OWNERS files were modified.
3873 if not any(f.LocalPath().endswith('OWNERS')
3874 for f in input_api.AffectedFiles(include_deletes=False)):
3875 return []
3876
3877 errors = []
3878
3879 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3880 allowed_owners_files = set()
Bruce Dawson58a45d22023-02-27 11:24:163881 with open(allowed_owners_files_file, 'r', encoding='utf-8') as f:
Sam Maiera6e76d72022-02-11 21:43:503882 for line in f:
3883 line = line.strip()
3884 if not line or line.startswith('#'):
3885 continue
3886 allowed_owners_files.add(line)
3887
3888 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3889
3890 for f in input_api.AffectedFiles(include_deletes=False):
3891 if not f.LocalPath().endswith('OWNERS'):
3892 continue
3893
3894 found_owners_files = set()
3895 found_set_noparent_lines = dict()
3896
3897 # Parse the OWNERS file.
3898 for lineno, line in enumerate(f.NewContents(), 1):
3899 line = line.strip()
3900 if line.startswith('set noparent'):
3901 found_set_noparent_lines[''] = lineno
3902 if line.startswith('file://'):
3903 if line in allowed_owners_files:
3904 found_owners_files.add('')
3905 if line.startswith('per-file'):
3906 match = per_file_pattern.match(line)
3907 if match:
3908 glob = match.group(1).strip()
3909 directive = match.group(2).strip()
3910 if directive == 'set noparent':
3911 found_set_noparent_lines[glob] = lineno
3912 if directive.startswith('file://'):
3913 if directive in allowed_owners_files:
3914 found_owners_files.add(glob)
3915
3916 # Check that every set noparent line has a corresponding file:// line
3917 # listed in build/OWNERS.setnoparent. An exception is made for top level
3918 # directories since src/OWNERS shouldn't review them.
Bruce Dawson6bb0d672022-04-06 15:13:493919 linux_path = f.LocalPath().replace(input_api.os_path.sep, '/')
3920 if (linux_path.count('/') != 1
3921 and (not linux_path in _EXCLUDED_SET_NO_PARENT_PATHS)):
Sam Maiera6e76d72022-02-11 21:43:503922 for set_noparent_line in found_set_noparent_lines:
3923 if set_noparent_line in found_owners_files:
3924 continue
3925 errors.append(' %s:%d' %
Bruce Dawson6bb0d672022-04-06 15:13:493926 (linux_path,
Sam Maiera6e76d72022-02-11 21:43:503927 found_set_noparent_lines[set_noparent_line]))
3928
3929 results = []
3930 if errors:
3931 if input_api.is_committing:
3932 output = output_api.PresubmitError
3933 else:
3934 output = output_api.PresubmitPromptWarning
3935 results.append(
3936 output(
3937 'Found the following "set noparent" restrictions in OWNERS files that '
3938 'do not include owners from build/OWNERS.setnoparent:',
3939 long_text='\n\n'.join(errors)))
3940 return results
3941
3942
3943def CheckUselessForwardDeclarations(input_api, output_api):
3944 """Checks that added or removed lines in non third party affected
3945 header files do not lead to new useless class or struct forward
3946 declaration.
3947 """
3948 results = []
3949 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3950 input_api.re.MULTILINE)
3951 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3952 input_api.re.MULTILINE)
3953 for f in input_api.AffectedFiles(include_deletes=False):
3954 if (f.LocalPath().startswith('third_party')
3955 and not f.LocalPath().startswith('third_party/blink')
3956 and not f.LocalPath().startswith('third_party\\blink')):
3957 continue
3958
3959 if not f.LocalPath().endswith('.h'):
3960 continue
3961
3962 contents = input_api.ReadFile(f)
3963 fwd_decls = input_api.re.findall(class_pattern, contents)
3964 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3965
3966 useless_fwd_decls = []
3967 for decl in fwd_decls:
3968 count = sum(1 for _ in input_api.re.finditer(
3969 r'\b%s\b' % input_api.re.escape(decl), contents))
3970 if count == 1:
3971 useless_fwd_decls.append(decl)
3972
3973 if not useless_fwd_decls:
3974 continue
3975
3976 for line in f.GenerateScmDiff().splitlines():
3977 if (line.startswith('-') and not line.startswith('--')
3978 or line.startswith('+') and not line.startswith('++')):
3979 for decl in useless_fwd_decls:
3980 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3981 results.append(
3982 output_api.PresubmitPromptWarning(
3983 '%s: %s forward declaration is no longer needed'
3984 % (f.LocalPath(), decl)))
3985 useless_fwd_decls.remove(decl)
3986
3987 return results
3988
3989
3990def _CheckAndroidDebuggableBuild(input_api, output_api):
3991 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3992 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3993 this is a debuggable build of Android.
3994 """
3995 build_type_check_pattern = input_api.re.compile(
3996 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3997
3998 errors = []
3999
4000 sources = lambda affected_file: input_api.FilterSourceFile(
4001 affected_file,
4002 files_to_skip=(
4003 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4004 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314005 r"^android_webview/support_library/boundary_interfaces/",
4006 r"^chrome/android/webapk/.*",
4007 r'^third_party/.*',
4008 r"tools/android/customtabs_benchmark/.*",
4009 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504010 )),
4011 files_to_check=[r'.*\.java$'])
4012
4013 for f in input_api.AffectedSourceFiles(sources):
4014 for line_num, line in f.ChangedContents():
4015 if build_type_check_pattern.search(line):
4016 errors.append("%s:%d" % (f.LocalPath(), line_num))
4017
4018 results = []
4019
4020 if errors:
4021 results.append(
4022 output_api.PresubmitPromptWarning(
4023 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
4024 ' Please use BuildInfo.isDebugAndroid() instead.', errors))
4025
4026 return results
4027
4028# TODO: add unit tests
4029def _CheckAndroidToastUsage(input_api, output_api):
4030 """Checks that code uses org.chromium.ui.widget.Toast instead of
4031 android.widget.Toast (Chromium Toast doesn't force hardware
4032 acceleration on low-end devices, saving memory).
4033 """
4034 toast_import_pattern = input_api.re.compile(
4035 r'^import android\.widget\.Toast;$')
4036
4037 errors = []
4038
4039 sources = lambda affected_file: input_api.FilterSourceFile(
4040 affected_file,
4041 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
Bruce Dawson40fece62022-09-16 19:58:314042 DEFAULT_FILES_TO_SKIP + (r'^chromecast/.*',
4043 r'^remoting/.*')),
Sam Maiera6e76d72022-02-11 21:43:504044 files_to_check=[r'.*\.java$'])
4045
4046 for f in input_api.AffectedSourceFiles(sources):
4047 for line_num, line in f.ChangedContents():
4048 if toast_import_pattern.search(line):
4049 errors.append("%s:%d" % (f.LocalPath(), line_num))
4050
4051 results = []
4052
4053 if errors:
4054 results.append(
4055 output_api.PresubmitError(
4056 'android.widget.Toast usage is detected. Android toasts use hardware'
4057 ' acceleration, and can be\ncostly on low-end devices. Please use'
4058 ' org.chromium.ui.widget.Toast instead.\n'
4059 'Contact [email protected] if you have any questions.',
4060 errors))
4061
4062 return results
4063
4064
4065def _CheckAndroidCrLogUsage(input_api, output_api):
4066 """Checks that new logs using org.chromium.base.Log:
4067 - Are using 'TAG' as variable name for the tags (warn)
4068 - Are using a tag that is shorter than 20 characters (error)
4069 """
4070
4071 # Do not check format of logs in the given files
4072 cr_log_check_excluded_paths = [
4073 # //chrome/android/webapk cannot depend on //base
Bruce Dawson40fece62022-09-16 19:58:314074 r"^chrome/android/webapk/.*",
Sam Maiera6e76d72022-02-11 21:43:504075 # WebView license viewer code cannot depend on //base; used in stub APK.
Bruce Dawson40fece62022-09-16 19:58:314076 r"^android_webview/glue/java/src/com/android/"
4077 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504078 # The customtabs_benchmark is a small app that does not depend on Chromium
4079 # java pieces.
Bruce Dawson40fece62022-09-16 19:58:314080 r"tools/android/customtabs_benchmark/.*",
Sam Maiera6e76d72022-02-11 21:43:504081 ]
4082
4083 cr_log_import_pattern = input_api.re.compile(
4084 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
4085 class_in_base_pattern = input_api.re.compile(
4086 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
4087 has_some_log_import_pattern = input_api.re.compile(r'^import .*\.Log;$',
4088 input_api.re.MULTILINE)
4089 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
4090 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
4091 log_decl_pattern = input_api.re.compile(
4092 r'static final String TAG = "(?P<name>(.*))"')
4093 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
4094
4095 REF_MSG = ('See docs/android_logging.md for more info.')
4096 sources = lambda x: input_api.FilterSourceFile(
4097 x,
4098 files_to_check=[r'.*\.java$'],
4099 files_to_skip=cr_log_check_excluded_paths)
4100
4101 tag_decl_errors = []
4102 tag_length_errors = []
4103 tag_errors = []
4104 tag_with_dot_errors = []
4105 util_log_errors = []
4106
4107 for f in input_api.AffectedSourceFiles(sources):
4108 file_content = input_api.ReadFile(f)
4109 has_modified_logs = False
4110 # Per line checks
4111 if (cr_log_import_pattern.search(file_content)
4112 or (class_in_base_pattern.search(file_content)
4113 and not has_some_log_import_pattern.search(file_content))):
4114 # Checks to run for files using cr log
4115 for line_num, line in f.ChangedContents():
4116 if rough_log_decl_pattern.search(line):
4117 has_modified_logs = True
4118
4119 # Check if the new line is doing some logging
4120 match = log_call_pattern.search(line)
4121 if match:
4122 has_modified_logs = True
4123
4124 # Make sure it uses "TAG"
4125 if not match.group('tag') == 'TAG':
4126 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
4127 else:
4128 # Report non cr Log function calls in changed lines
4129 for line_num, line in f.ChangedContents():
4130 if log_call_pattern.search(line):
4131 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
4132
4133 # Per file checks
4134 if has_modified_logs:
4135 # Make sure the tag is using the "cr" prefix and is not too long
4136 match = log_decl_pattern.search(file_content)
4137 tag_name = match.group('name') if match else None
4138 if not tag_name:
4139 tag_decl_errors.append(f.LocalPath())
4140 elif len(tag_name) > 20:
4141 tag_length_errors.append(f.LocalPath())
4142 elif '.' in tag_name:
4143 tag_with_dot_errors.append(f.LocalPath())
4144
4145 results = []
4146 if tag_decl_errors:
4147 results.append(
4148 output_api.PresubmitPromptWarning(
4149 'Please define your tags using the suggested format: .\n'
4150 '"private static final String TAG = "<package tag>".\n'
4151 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
4152 tag_decl_errors))
4153
4154 if tag_length_errors:
4155 results.append(
4156 output_api.PresubmitError(
4157 'The tag length is restricted by the system to be at most '
4158 '20 characters.\n' + REF_MSG, tag_length_errors))
4159
4160 if tag_errors:
4161 results.append(
4162 output_api.PresubmitPromptWarning(
4163 'Please use a variable named "TAG" for your log tags.\n' +
4164 REF_MSG, tag_errors))
4165
4166 if util_log_errors:
4167 results.append(
4168 output_api.PresubmitPromptWarning(
4169 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
4170 util_log_errors))
4171
4172 if tag_with_dot_errors:
4173 results.append(
4174 output_api.PresubmitPromptWarning(
4175 'Dot in log tags cause them to be elided in crash reports.\n' +
4176 REF_MSG, tag_with_dot_errors))
4177
4178 return results
4179
4180
4181def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
4182 """Checks that junit.framework.* is no longer used."""
4183 deprecated_junit_framework_pattern = input_api.re.compile(
4184 r'^import junit\.framework\..*;', input_api.re.MULTILINE)
4185 sources = lambda x: input_api.FilterSourceFile(
4186 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
4187 errors = []
4188 for f in input_api.AffectedFiles(file_filter=sources):
4189 for line_num, line in f.ChangedContents():
4190 if deprecated_junit_framework_pattern.search(line):
4191 errors.append("%s:%d" % (f.LocalPath(), line_num))
4192
4193 results = []
4194 if errors:
4195 results.append(
4196 output_api.PresubmitError(
4197 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
4198 '(org.junit.*) from //third_party/junit. Contact [email protected]'
4199 ' if you have any question.', errors))
4200 return results
4201
4202
4203def _CheckAndroidTestJUnitInheritance(input_api, output_api):
4204 """Checks that if new Java test classes have inheritance.
4205 Either the new test class is JUnit3 test or it is a JUnit4 test class
4206 with a base class, either case is undesirable.
4207 """
4208 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
4209
4210 sources = lambda x: input_api.FilterSourceFile(
4211 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
4212 errors = []
4213 for f in input_api.AffectedFiles(file_filter=sources):
4214 if not f.OldContents():
4215 class_declaration_start_flag = False
4216 for line_num, line in f.ChangedContents():
4217 if class_declaration_pattern.search(line):
4218 class_declaration_start_flag = True
4219 if class_declaration_start_flag and ' extends ' in line:
4220 errors.append('%s:%d' % (f.LocalPath(), line_num))
4221 if '{' in line:
4222 class_declaration_start_flag = False
4223
4224 results = []
4225 if errors:
4226 results.append(
4227 output_api.PresubmitPromptWarning(
4228 'The newly created files include Test classes that inherits from base'
4229 ' class. Please do not use inheritance in JUnit4 tests or add new'
4230 ' JUnit3 tests. Contact [email protected] if you have any'
4231 ' questions.', errors))
4232 return results
4233
4234
4235def _CheckAndroidTestAnnotationUsage(input_api, output_api):
4236 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
4237 deprecated_annotation_import_pattern = input_api.re.compile(
4238 r'^import android\.test\.suitebuilder\.annotation\..*;',
4239 input_api.re.MULTILINE)
4240 sources = lambda x: input_api.FilterSourceFile(
4241 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
4242 errors = []
4243 for f in input_api.AffectedFiles(file_filter=sources):
4244 for line_num, line in f.ChangedContents():
4245 if deprecated_annotation_import_pattern.search(line):
4246 errors.append("%s:%d" % (f.LocalPath(), line_num))
4247
4248 results = []
4249 if errors:
4250 results.append(
4251 output_api.PresubmitError(
4252 'Annotations in android.test.suitebuilder.annotation have been'
Mohamed Heikal3d7a94c2023-03-28 16:55:244253 ' deprecated since API level 24. Please use androidx.test.filters'
4254 ' from //third_party/androidx:androidx_test_runner_java instead.'
Sam Maiera6e76d72022-02-11 21:43:504255 ' Contact [email protected] if you have any questions.',
4256 errors))
4257 return results
4258
4259
4260def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
4261 """Checks if MDPI assets are placed in a correct directory."""
Bruce Dawson6c05e852022-07-21 15:48:514262 file_filter = lambda f: (f.LocalPath().endswith(
4263 '.png') and ('/res/drawable/'.replace('/', input_api.os_path.sep) in f.
4264 LocalPath() or '/res/drawable-ldrtl/'.replace(
4265 '/', input_api.os_path.sep) in f.LocalPath()))
Sam Maiera6e76d72022-02-11 21:43:504266 errors = []
4267 for f in input_api.AffectedFiles(include_deletes=False,
4268 file_filter=file_filter):
4269 errors.append(' %s' % f.LocalPath())
4270
4271 results = []
4272 if errors:
4273 results.append(
4274 output_api.PresubmitError(
4275 'MDPI assets should be placed in /res/drawable-mdpi/ or '
4276 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
4277 '/res/drawable-ldrtl/.\n'
4278 'Contact [email protected] if you have questions.', errors))
4279 return results
4280
4281
4282def _CheckAndroidWebkitImports(input_api, output_api):
4283 """Checks that code uses org.chromium.base.Callback instead of
4284 android.webview.ValueCallback except in the WebView glue layer
4285 and WebLayer.
4286 """
4287 valuecallback_import_pattern = input_api.re.compile(
4288 r'^import android\.webkit\.ValueCallback;$')
4289
4290 errors = []
4291
4292 sources = lambda affected_file: input_api.FilterSourceFile(
4293 affected_file,
4294 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4295 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314296 r'^android_webview/glue/.*',
4297 r'^weblayer/.*',
Sam Maiera6e76d72022-02-11 21:43:504298 )),
4299 files_to_check=[r'.*\.java$'])
4300
4301 for f in input_api.AffectedSourceFiles(sources):
4302 for line_num, line in f.ChangedContents():
4303 if valuecallback_import_pattern.search(line):
4304 errors.append("%s:%d" % (f.LocalPath(), line_num))
4305
4306 results = []
4307
4308 if errors:
4309 results.append(
4310 output_api.PresubmitError(
4311 'android.webkit.ValueCallback usage is detected outside of the glue'
4312 ' layer. To stay compatible with the support library, android.webkit.*'
4313 ' classes should only be used inside the glue layer and'
4314 ' org.chromium.base.Callback should be used instead.', errors))
4315
4316 return results
4317
4318
4319def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
4320 """Checks Android XML styles """
4321
4322 # Return early if no relevant files were modified.
4323 if not any(
4324 _IsXmlOrGrdFile(input_api, f.LocalPath())
4325 for f in input_api.AffectedFiles(include_deletes=False)):
4326 return []
4327
4328 import sys
4329 original_sys_path = sys.path
4330 try:
4331 sys.path = sys.path + [
4332 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4333 'android', 'checkxmlstyle')
4334 ]
4335 import checkxmlstyle
4336 finally:
4337 # Restore sys.path to what it was before.
4338 sys.path = original_sys_path
4339
4340 if is_check_on_upload:
4341 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
4342 else:
4343 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
4344
4345
4346def _CheckAndroidInfoBarDeprecation(input_api, output_api):
4347 """Checks Android Infobar Deprecation """
4348
4349 import sys
4350 original_sys_path = sys.path
4351 try:
4352 sys.path = sys.path + [
4353 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4354 'android', 'infobar_deprecation')
4355 ]
4356 import infobar_deprecation
4357 finally:
4358 # Restore sys.path to what it was before.
4359 sys.path = original_sys_path
4360
4361 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
4362
4363
4364class _PydepsCheckerResult:
4365 def __init__(self, cmd, pydeps_path, process, old_contents):
4366 self._cmd = cmd
4367 self._pydeps_path = pydeps_path
4368 self._process = process
4369 self._old_contents = old_contents
4370
4371 def GetError(self):
4372 """Returns an error message, or None."""
4373 import difflib
4374 if self._process.wait() != 0:
4375 # STDERR should already be printed.
4376 return 'Command failed: ' + self._cmd
4377 new_contents = self._process.stdout.read().splitlines()[2:]
4378 if self._old_contents != new_contents:
4379 diff = '\n'.join(
4380 difflib.context_diff(self._old_contents, new_contents))
4381 return ('File is stale: {}\n'
4382 'Diff (apply to fix):\n'
4383 '{}\n'
4384 'To regenerate, run:\n\n'
4385 ' {}').format(self._pydeps_path, diff, self._cmd)
4386 return None
4387
4388
4389class PydepsChecker:
4390 def __init__(self, input_api, pydeps_files):
4391 self._file_cache = {}
4392 self._input_api = input_api
4393 self._pydeps_files = pydeps_files
4394
4395 def _LoadFile(self, path):
4396 """Returns the list of paths within a .pydeps file relative to //."""
4397 if path not in self._file_cache:
4398 with open(path, encoding='utf-8') as f:
4399 self._file_cache[path] = f.read()
4400 return self._file_cache[path]
4401
4402 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
Gao Shenga79ebd42022-08-08 17:25:594403 """Returns an iterable of paths within the .pydep, relativized to //."""
Sam Maiera6e76d72022-02-11 21:43:504404 pydeps_data = self._LoadFile(pydeps_path)
4405 uses_gn_paths = '--gn-paths' in pydeps_data
4406 entries = (l for l in pydeps_data.splitlines()
4407 if not l.startswith('#'))
4408 if uses_gn_paths:
4409 # Paths look like: //foo/bar/baz
4410 return (e[2:] for e in entries)
4411 else:
4412 # Paths look like: path/relative/to/file.pydeps
4413 os_path = self._input_api.os_path
4414 pydeps_dir = os_path.dirname(pydeps_path)
4415 return (os_path.normpath(os_path.join(pydeps_dir, e))
4416 for e in entries)
4417
4418 def _CreateFilesToPydepsMap(self):
4419 """Returns a map of local_path -> list_of_pydeps."""
4420 ret = {}
4421 for pydep_local_path in self._pydeps_files:
4422 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
4423 ret.setdefault(path, []).append(pydep_local_path)
4424 return ret
4425
4426 def ComputeAffectedPydeps(self):
4427 """Returns an iterable of .pydeps files that might need regenerating."""
4428 affected_pydeps = set()
4429 file_to_pydeps_map = None
4430 for f in self._input_api.AffectedFiles(include_deletes=True):
4431 local_path = f.LocalPath()
4432 # Changes to DEPS can lead to .pydeps changes if any .py files are in
4433 # subrepositories. We can't figure out which files change, so re-check
4434 # all files.
4435 # Changes to print_python_deps.py affect all .pydeps.
4436 if local_path in ('DEPS', 'PRESUBMIT.py'
4437 ) or local_path.endswith('print_python_deps.py'):
4438 return self._pydeps_files
4439 elif local_path.endswith('.pydeps'):
4440 if local_path in self._pydeps_files:
4441 affected_pydeps.add(local_path)
4442 elif local_path.endswith('.py'):
4443 if file_to_pydeps_map is None:
4444 file_to_pydeps_map = self._CreateFilesToPydepsMap()
4445 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
4446 return affected_pydeps
4447
4448 def DetermineIfStaleAsync(self, pydeps_path):
4449 """Runs print_python_deps.py to see if the files is stale."""
4450 import os
4451
4452 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
4453 if old_pydeps_data:
4454 cmd = old_pydeps_data[1][1:].strip()
4455 if '--output' not in cmd:
4456 cmd += ' --output ' + pydeps_path
4457 old_contents = old_pydeps_data[2:]
4458 else:
4459 # A default cmd that should work in most cases (as long as pydeps filename
4460 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
4461 # file is empty/new.
4462 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
4463 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
4464 old_contents = []
4465 env = dict(os.environ)
4466 env['PYTHONDONTWRITEBYTECODE'] = '1'
4467 process = self._input_api.subprocess.Popen(
4468 cmd + ' --output ""',
4469 shell=True,
4470 env=env,
4471 stdout=self._input_api.subprocess.PIPE,
4472 encoding='utf-8')
4473 return _PydepsCheckerResult(cmd, pydeps_path, process, old_contents)
agrievef32bcc72016-04-04 14:57:404474
4475
Tibor Goldschwendt360793f72019-06-25 18:23:494476def _ParseGclientArgs():
Sam Maiera6e76d72022-02-11 21:43:504477 args = {}
4478 with open('build/config/gclient_args.gni', 'r') as f:
4479 for line in f:
4480 line = line.strip()
4481 if not line or line.startswith('#'):
4482 continue
4483 attribute, value = line.split('=')
4484 args[attribute.strip()] = value.strip()
4485 return args
Tibor Goldschwendt360793f72019-06-25 18:23:494486
4487
Saagar Sanghavifceeaae2020-08-12 16:40:364488def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
Sam Maiera6e76d72022-02-11 21:43:504489 """Checks if a .pydeps file needs to be regenerated."""
4490 # This check is for Python dependency lists (.pydeps files), and involves
4491 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
4492 # doesn't work on Windows and Mac, so skip it on other platforms.
4493 if not input_api.platform.startswith('linux'):
4494 return []
Erik Staabc734cd7a2021-11-23 03:11:524495
Sam Maiera6e76d72022-02-11 21:43:504496 results = []
4497 # First, check for new / deleted .pydeps.
4498 for f in input_api.AffectedFiles(include_deletes=True):
4499 # Check whether we are running the presubmit check for a file in src.
4500 # f.LocalPath is relative to repo (src, or internal repo).
4501 # os_path.exists is relative to src repo.
4502 # Therefore if os_path.exists is true, it means f.LocalPath is relative
4503 # to src and we can conclude that the pydeps is in src.
4504 if f.LocalPath().endswith('.pydeps'):
4505 if input_api.os_path.exists(f.LocalPath()):
4506 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
4507 results.append(
4508 output_api.PresubmitError(
4509 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
4510 'remove %s' % f.LocalPath()))
4511 elif f.Action() != 'D' and f.LocalPath(
4512 ) not in _ALL_PYDEPS_FILES:
4513 results.append(
4514 output_api.PresubmitError(
4515 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
4516 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:404517
Sam Maiera6e76d72022-02-11 21:43:504518 if results:
4519 return results
4520
4521 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
4522 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
4523 affected_pydeps = set(checker.ComputeAffectedPydeps())
4524 affected_android_pydeps = affected_pydeps.intersection(
4525 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
4526 if affected_android_pydeps and not is_android:
4527 results.append(
4528 output_api.PresubmitPromptOrNotify(
4529 'You have changed python files that may affect pydeps for android\n'
Gao Shenga79ebd42022-08-08 17:25:594530 'specific scripts. However, the relevant presubmit check cannot be\n'
Sam Maiera6e76d72022-02-11 21:43:504531 'run because you are not using an Android checkout. To validate that\n'
4532 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
4533 'use the android-internal-presubmit optional trybot.\n'
4534 'Possibly stale pydeps files:\n{}'.format(
4535 '\n'.join(affected_android_pydeps))))
4536
4537 all_pydeps = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
4538 pydeps_to_check = affected_pydeps.intersection(all_pydeps)
4539 # Process these concurrently, as each one takes 1-2 seconds.
4540 pydep_results = [checker.DetermineIfStaleAsync(p) for p in pydeps_to_check]
4541 for result in pydep_results:
4542 error_msg = result.GetError()
4543 if error_msg:
4544 results.append(output_api.PresubmitError(error_msg))
4545
agrievef32bcc72016-04-04 14:57:404546 return results
4547
agrievef32bcc72016-04-04 14:57:404548
Saagar Sanghavifceeaae2020-08-12 16:40:364549def CheckSingletonInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504550 """Checks to make sure no header files have |Singleton<|."""
4551
4552 def FileFilter(affected_file):
4553 # It's ok for base/memory/singleton.h to have |Singleton<|.
4554 files_to_skip = (_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
Bruce Dawson40fece62022-09-16 19:58:314555 (r"^base/memory/singleton\.h$",
4556 r"^net/quic/platform/impl/quic_singleton_impl\.h$"))
Sam Maiera6e76d72022-02-11 21:43:504557 return input_api.FilterSourceFile(affected_file,
4558 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:434559
Sam Maiera6e76d72022-02-11 21:43:504560 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
4561 files = []
4562 for f in input_api.AffectedSourceFiles(FileFilter):
4563 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx')
4564 or f.LocalPath().endswith('.hpp')
4565 or f.LocalPath().endswith('.inl')):
4566 contents = input_api.ReadFile(f)
4567 for line in contents.splitlines(False):
4568 if (not line.lstrip().startswith('//')
4569 and # Strip C++ comment.
4570 pattern.search(line)):
4571 files.append(f)
4572 break
glidere61efad2015-02-18 17:39:434573
Sam Maiera6e76d72022-02-11 21:43:504574 if files:
4575 return [
4576 output_api.PresubmitError(
4577 'Found base::Singleton<T> in the following header files.\n' +
4578 'Please move them to an appropriate source file so that the ' +
4579 'template gets instantiated in a single compilation unit.',
4580 files)
4581 ]
4582 return []
glidere61efad2015-02-18 17:39:434583
4584
[email protected]fd20b902014-05-09 02:14:534585_DEPRECATED_CSS = [
4586 # Values
4587 ( "-webkit-box", "flex" ),
4588 ( "-webkit-inline-box", "inline-flex" ),
4589 ( "-webkit-flex", "flex" ),
4590 ( "-webkit-inline-flex", "inline-flex" ),
4591 ( "-webkit-min-content", "min-content" ),
4592 ( "-webkit-max-content", "max-content" ),
4593
4594 # Properties
4595 ( "-webkit-background-clip", "background-clip" ),
4596 ( "-webkit-background-origin", "background-origin" ),
4597 ( "-webkit-background-size", "background-size" ),
4598 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:444599 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:534600
4601 # Functions
4602 ( "-webkit-gradient", "gradient" ),
4603 ( "-webkit-repeating-gradient", "repeating-gradient" ),
4604 ( "-webkit-linear-gradient", "linear-gradient" ),
4605 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
4606 ( "-webkit-radial-gradient", "radial-gradient" ),
4607 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
4608]
4609
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:204610
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:494611# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:364612def CheckNoDeprecatedCss(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504613 """ Make sure that we don't use deprecated CSS
4614 properties, functions or values. Our external
4615 documentation and iOS CSS for dom distiller
4616 (reader mode) are ignored by the hooks as it
4617 needs to be consumed by WebKit. """
4618 results = []
4619 file_inclusion_pattern = [r".+\.css$"]
4620 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
4621 input_api.DEFAULT_FILES_TO_SKIP +
4622 (r"^chrome/common/extensions/docs", r"^chrome/docs",
4623 r"^native_client_sdk"))
4624 file_filter = lambda f: input_api.FilterSourceFile(
4625 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
4626 for fpath in input_api.AffectedFiles(file_filter=file_filter):
4627 for line_num, line in fpath.ChangedContents():
4628 for (deprecated_value, value) in _DEPRECATED_CSS:
4629 if deprecated_value in line:
4630 results.append(
4631 output_api.PresubmitError(
4632 "%s:%d: Use of deprecated CSS %s, use %s instead" %
4633 (fpath.LocalPath(), line_num, deprecated_value,
4634 value)))
4635 return results
[email protected]fd20b902014-05-09 02:14:534636
mohan.reddyf21db962014-10-16 12:26:474637
Saagar Sanghavifceeaae2020-08-12 16:40:364638def CheckForRelativeIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504639 bad_files = {}
4640 for f in input_api.AffectedFiles(include_deletes=False):
4641 if (f.LocalPath().startswith('third_party')
4642 and not f.LocalPath().startswith('third_party/blink')
4643 and not f.LocalPath().startswith('third_party\\blink')):
4644 continue
rlanday6802cf632017-05-30 17:48:364645
Sam Maiera6e76d72022-02-11 21:43:504646 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
4647 continue
rlanday6802cf632017-05-30 17:48:364648
Sam Maiera6e76d72022-02-11 21:43:504649 relative_includes = [
4650 line for _, line in f.ChangedContents()
4651 if "#include" in line and "../" in line
4652 ]
4653 if not relative_includes:
4654 continue
4655 bad_files[f.LocalPath()] = relative_includes
rlanday6802cf632017-05-30 17:48:364656
Sam Maiera6e76d72022-02-11 21:43:504657 if not bad_files:
4658 return []
rlanday6802cf632017-05-30 17:48:364659
Sam Maiera6e76d72022-02-11 21:43:504660 error_descriptions = []
4661 for file_path, bad_lines in bad_files.items():
4662 error_description = file_path
4663 for line in bad_lines:
4664 error_description += '\n ' + line
4665 error_descriptions.append(error_description)
rlanday6802cf632017-05-30 17:48:364666
Sam Maiera6e76d72022-02-11 21:43:504667 results = []
4668 results.append(
4669 output_api.PresubmitError(
4670 'You added one or more relative #include paths (including "../").\n'
4671 'These shouldn\'t be used because they can be used to include headers\n'
4672 'from code that\'s not correctly specified as a dependency in the\n'
4673 'relevant BUILD.gn file(s).', error_descriptions))
rlanday6802cf632017-05-30 17:48:364674
Sam Maiera6e76d72022-02-11 21:43:504675 return results
rlanday6802cf632017-05-30 17:48:364676
Takeshi Yoshinoe387aa32017-08-02 13:16:134677
Saagar Sanghavifceeaae2020-08-12 16:40:364678def CheckForCcIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504679 """Check that nobody tries to include a cc file. It's a relatively
4680 common error which results in duplicate symbols in object
4681 files. This may not always break the build until someone later gets
4682 very confusing linking errors."""
4683 results = []
4684 for f in input_api.AffectedFiles(include_deletes=False):
4685 # We let third_party code do whatever it wants
4686 if (f.LocalPath().startswith('third_party')
4687 and not f.LocalPath().startswith('third_party/blink')
4688 and not f.LocalPath().startswith('third_party\\blink')):
4689 continue
Daniel Bratell65b033262019-04-23 08:17:064690
Sam Maiera6e76d72022-02-11 21:43:504691 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
4692 continue
Daniel Bratell65b033262019-04-23 08:17:064693
Sam Maiera6e76d72022-02-11 21:43:504694 for _, line in f.ChangedContents():
4695 if line.startswith('#include "'):
4696 included_file = line.split('"')[1]
4697 if _IsCPlusPlusFile(input_api, included_file):
4698 # The most common naming for external files with C++ code,
4699 # apart from standard headers, is to call them foo.inc, but
4700 # Chromium sometimes uses foo-inc.cc so allow that as well.
4701 if not included_file.endswith(('.h', '-inc.cc')):
4702 results.append(
4703 output_api.PresubmitError(
4704 'Only header files or .inc files should be included in other\n'
4705 'C++ files. Compiling the contents of a cc file more than once\n'
4706 'will cause duplicate information in the build which may later\n'
4707 'result in strange link_errors.\n' +
4708 f.LocalPath() + ':\n ' + line))
Daniel Bratell65b033262019-04-23 08:17:064709
Sam Maiera6e76d72022-02-11 21:43:504710 return results
Daniel Bratell65b033262019-04-23 08:17:064711
4712
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204713def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
Sam Maiera6e76d72022-02-11 21:43:504714 if not isinstance(key, ast.Str):
4715 return 'Key at line %d must be a string literal' % key.lineno
4716 if not isinstance(value, ast.Dict):
4717 return 'Value at line %d must be a dict' % value.lineno
4718 if len(value.keys) != 1:
4719 return 'Dict at line %d must have single entry' % value.lineno
4720 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
4721 return (
4722 'Entry at line %d must have a string literal \'filepath\' as key' %
4723 value.lineno)
4724 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:134725
Takeshi Yoshinoe387aa32017-08-02 13:16:134726
Sergey Ulanov4af16052018-11-08 02:41:464727def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Sam Maiera6e76d72022-02-11 21:43:504728 if not isinstance(key, ast.Str):
4729 return 'Key at line %d must be a string literal' % key.lineno
4730 if not isinstance(value, ast.List):
4731 return 'Value at line %d must be a list' % value.lineno
4732 for element in value.elts:
4733 if not isinstance(element, ast.Str):
4734 return 'Watchlist elements on line %d is not a string' % key.lineno
4735 if not email_regex.match(element.s):
4736 return ('Watchlist element on line %d doesn\'t look like a valid '
4737 + 'email: %s') % (key.lineno, element.s)
4738 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:134739
Takeshi Yoshinoe387aa32017-08-02 13:16:134740
Sergey Ulanov4af16052018-11-08 02:41:464741def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Sam Maiera6e76d72022-02-11 21:43:504742 mismatch_template = (
4743 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
4744 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:134745
Sam Maiera6e76d72022-02-11 21:43:504746 email_regex = input_api.re.compile(
4747 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
Sergey Ulanov4af16052018-11-08 02:41:464748
Sam Maiera6e76d72022-02-11 21:43:504749 ast = input_api.ast
4750 i = 0
4751 last_key = ''
4752 while True:
4753 if i >= len(wd_dict.keys):
4754 if i >= len(w_dict.keys):
4755 return None
4756 return mismatch_template % ('missing',
4757 'line %d' % w_dict.keys[i].lineno)
4758 elif i >= len(w_dict.keys):
4759 return (mismatch_template %
4760 ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:134761
Sam Maiera6e76d72022-02-11 21:43:504762 wd_key = wd_dict.keys[i]
4763 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:134764
Sam Maiera6e76d72022-02-11 21:43:504765 result = _CheckWatchlistDefinitionsEntrySyntax(wd_key,
4766 wd_dict.values[i], ast)
4767 if result is not None:
4768 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:134769
Sam Maiera6e76d72022-02-11 21:43:504770 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast,
4771 email_regex)
4772 if result is not None:
4773 return 'Bad entry in WATCHLISTS dict: %s' % result
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204774
Sam Maiera6e76d72022-02-11 21:43:504775 if wd_key.s != w_key.s:
4776 return mismatch_template % ('%s at line %d' %
4777 (wd_key.s, wd_key.lineno),
4778 '%s at line %d' %
4779 (w_key.s, w_key.lineno))
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204780
Sam Maiera6e76d72022-02-11 21:43:504781 if wd_key.s < last_key:
4782 return (
4783 'WATCHLISTS dict is not sorted lexicographically at line %d and %d'
4784 % (wd_key.lineno, w_key.lineno))
4785 last_key = wd_key.s
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204786
Sam Maiera6e76d72022-02-11 21:43:504787 i = i + 1
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204788
4789
Sergey Ulanov4af16052018-11-08 02:41:464790def _CheckWATCHLISTSSyntax(expression, input_api):
Sam Maiera6e76d72022-02-11 21:43:504791 ast = input_api.ast
4792 if not isinstance(expression, ast.Expression):
4793 return 'WATCHLISTS file must contain a valid expression'
4794 dictionary = expression.body
4795 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
4796 return 'WATCHLISTS file must have single dict with exactly two entries'
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204797
Sam Maiera6e76d72022-02-11 21:43:504798 first_key = dictionary.keys[0]
4799 first_value = dictionary.values[0]
4800 second_key = dictionary.keys[1]
4801 second_value = dictionary.values[1]
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204802
Sam Maiera6e76d72022-02-11 21:43:504803 if (not isinstance(first_key, ast.Str)
4804 or first_key.s != 'WATCHLIST_DEFINITIONS'
4805 or not isinstance(first_value, ast.Dict)):
4806 return ('The first entry of the dict in WATCHLISTS file must be '
4807 'WATCHLIST_DEFINITIONS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204808
Sam Maiera6e76d72022-02-11 21:43:504809 if (not isinstance(second_key, ast.Str) or second_key.s != 'WATCHLISTS'
4810 or not isinstance(second_value, ast.Dict)):
4811 return ('The second entry of the dict in WATCHLISTS file must be '
4812 'WATCHLISTS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204813
Sam Maiera6e76d72022-02-11 21:43:504814 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:134815
4816
Saagar Sanghavifceeaae2020-08-12 16:40:364817def CheckWATCHLISTS(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504818 for f in input_api.AffectedFiles(include_deletes=False):
4819 if f.LocalPath() == 'WATCHLISTS':
4820 contents = input_api.ReadFile(f, 'r')
Takeshi Yoshinoe387aa32017-08-02 13:16:134821
Sam Maiera6e76d72022-02-11 21:43:504822 try:
4823 # First, make sure that it can be evaluated.
4824 input_api.ast.literal_eval(contents)
4825 # Get an AST tree for it and scan the tree for detailed style checking.
4826 expression = input_api.ast.parse(contents,
4827 filename='WATCHLISTS',
4828 mode='eval')
4829 except ValueError as e:
4830 return [
4831 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4832 long_text=repr(e))
4833 ]
4834 except SyntaxError as e:
4835 return [
4836 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4837 long_text=repr(e))
4838 ]
4839 except TypeError as e:
4840 return [
4841 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4842 long_text=repr(e))
4843 ]
Takeshi Yoshinoe387aa32017-08-02 13:16:134844
Sam Maiera6e76d72022-02-11 21:43:504845 result = _CheckWATCHLISTSSyntax(expression, input_api)
4846 if result is not None:
4847 return [output_api.PresubmitError(result)]
4848 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134849
Sam Maiera6e76d72022-02-11 21:43:504850 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:134851
Sean Kaucb7c9b32022-10-25 21:25:524852def CheckGnRebasePath(input_api, output_api):
4853 """Checks that target_gen_dir is not used wtih "//" in rebase_path().
4854
4855 Developers should use root_build_dir instead of "//" when using target_gen_dir because
4856 Chromium is sometimes built outside of the source tree.
4857 """
4858
4859 def gn_files(f):
4860 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
4861
4862 rebase_path_regex = input_api.re.compile(r'rebase_path\(("\$target_gen_dir"|target_gen_dir), ("/"|"//")\)')
4863 problems = []
4864 for f in input_api.AffectedSourceFiles(gn_files):
4865 for line_num, line in f.ChangedContents():
4866 if rebase_path_regex.search(line):
4867 problems.append(
4868 'Absolute path in rebase_path() in %s:%d' %
4869 (f.LocalPath(), line_num))
4870
4871 if problems:
4872 return [
4873 output_api.PresubmitPromptWarning(
4874 'Using an absolute path in rebase_path()',
4875 items=sorted(problems),
4876 long_text=(
4877 'rebase_path() should use root_build_dir instead of "/" ',
4878 'since builds can be initiated from outside of the source ',
4879 'root.'))
4880 ]
4881 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:134882
Andrew Grieve1b290e4a22020-11-24 20:07:014883def CheckGnGlobForward(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504884 """Checks that forward_variables_from(invoker, "*") follows best practices.
Andrew Grieve1b290e4a22020-11-24 20:07:014885
Sam Maiera6e76d72022-02-11 21:43:504886 As documented at //build/docs/writing_gn_templates.md
4887 """
Andrew Grieve1b290e4a22020-11-24 20:07:014888
Sam Maiera6e76d72022-02-11 21:43:504889 def gn_files(f):
4890 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
Andrew Grieve1b290e4a22020-11-24 20:07:014891
Sam Maiera6e76d72022-02-11 21:43:504892 problems = []
4893 for f in input_api.AffectedSourceFiles(gn_files):
4894 for line_num, line in f.ChangedContents():
4895 if 'forward_variables_from(invoker, "*")' in line:
4896 problems.append(
4897 'Bare forward_variables_from(invoker, "*") in %s:%d' %
4898 (f.LocalPath(), line_num))
4899
4900 if problems:
4901 return [
4902 output_api.PresubmitPromptWarning(
4903 'forward_variables_from("*") without exclusions',
4904 items=sorted(problems),
4905 long_text=(
Gao Shenga79ebd42022-08-08 17:25:594906 'The variables "visibility" and "test_only" should be '
Sam Maiera6e76d72022-02-11 21:43:504907 'explicitly listed in forward_variables_from(). For more '
4908 'details, see:\n'
4909 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
4910 'build/docs/writing_gn_templates.md'
4911 '#Using-forward_variables_from'))
4912 ]
4913 return []
Andrew Grieve1b290e4a22020-11-24 20:07:014914
Saagar Sanghavifceeaae2020-08-12 16:40:364915def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504916 """Checks that newly added header files have corresponding GN changes.
4917 Note that this is only a heuristic. To be precise, run script:
4918 build/check_gn_headers.py.
4919 """
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194920
Sam Maiera6e76d72022-02-11 21:43:504921 def headers(f):
4922 return input_api.FilterSourceFile(
4923 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194924
Sam Maiera6e76d72022-02-11 21:43:504925 new_headers = []
4926 for f in input_api.AffectedSourceFiles(headers):
4927 if f.Action() != 'A':
4928 continue
4929 new_headers.append(f.LocalPath())
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194930
Sam Maiera6e76d72022-02-11 21:43:504931 def gn_files(f):
4932 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194933
Sam Maiera6e76d72022-02-11 21:43:504934 all_gn_changed_contents = ''
4935 for f in input_api.AffectedSourceFiles(gn_files):
4936 for _, line in f.ChangedContents():
4937 all_gn_changed_contents += line
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194938
Sam Maiera6e76d72022-02-11 21:43:504939 problems = []
4940 for header in new_headers:
4941 basename = input_api.os_path.basename(header)
4942 if basename not in all_gn_changed_contents:
4943 problems.append(header)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194944
Sam Maiera6e76d72022-02-11 21:43:504945 if problems:
4946 return [
4947 output_api.PresubmitPromptWarning(
4948 'Missing GN changes for new header files',
4949 items=sorted(problems),
4950 long_text=
4951 'Please double check whether newly added header files need '
4952 'corresponding changes in gn or gni files.\nThis checking is only a '
4953 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4954 'Read https://crbug.com/661774 for more info.')
4955 ]
4956 return []
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194957
4958
Saagar Sanghavifceeaae2020-08-12 16:40:364959def CheckCorrectProductNameInMessages(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504960 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
Michael Giuffridad3bc8672018-10-25 22:48:024961
Sam Maiera6e76d72022-02-11 21:43:504962 This assumes we won't intentionally reference one product from the other
4963 product.
4964 """
4965 all_problems = []
4966 test_cases = [{
4967 "filename_postfix": "google_chrome_strings.grd",
4968 "correct_name": "Chrome",
4969 "incorrect_name": "Chromium",
4970 }, {
4971 "filename_postfix": "chromium_strings.grd",
4972 "correct_name": "Chromium",
4973 "incorrect_name": "Chrome",
4974 }]
Michael Giuffridad3bc8672018-10-25 22:48:024975
Sam Maiera6e76d72022-02-11 21:43:504976 for test_case in test_cases:
4977 problems = []
4978 filename_filter = lambda x: x.LocalPath().endswith(test_case[
4979 "filename_postfix"])
Michael Giuffridad3bc8672018-10-25 22:48:024980
Sam Maiera6e76d72022-02-11 21:43:504981 # Check each new line. Can yield false positives in multiline comments, but
4982 # easier than trying to parse the XML because messages can have nested
4983 # children, and associating message elements with affected lines is hard.
4984 for f in input_api.AffectedSourceFiles(filename_filter):
4985 for line_num, line in f.ChangedContents():
4986 if "<message" in line or "<!--" in line or "-->" in line:
4987 continue
4988 if test_case["incorrect_name"] in line:
4989 problems.append("Incorrect product name in %s:%d" %
4990 (f.LocalPath(), line_num))
Michael Giuffridad3bc8672018-10-25 22:48:024991
Sam Maiera6e76d72022-02-11 21:43:504992 if problems:
4993 message = (
4994 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4995 % (test_case["correct_name"], test_case["correct_name"],
4996 test_case["incorrect_name"]))
4997 all_problems.append(
4998 output_api.PresubmitPromptWarning(message, items=problems))
Michael Giuffridad3bc8672018-10-25 22:48:024999
Sam Maiera6e76d72022-02-11 21:43:505000 return all_problems
Michael Giuffridad3bc8672018-10-25 22:48:025001
5002
Saagar Sanghavifceeaae2020-08-12 16:40:365003def CheckForTooLargeFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505004 """Avoid large files, especially binary files, in the repository since
5005 git doesn't scale well for those. They will be in everyone's repo
5006 clones forever, forever making Chromium slower to clone and work
5007 with."""
Daniel Bratell93eb6c62019-04-29 20:13:365008
Sam Maiera6e76d72022-02-11 21:43:505009 # Uploading files to cloud storage is not trivial so we don't want
5010 # to set the limit too low, but the upper limit for "normal" large
5011 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
5012 # anything over 20 MB is exceptional.
Bruce Dawsonbb414db2022-12-27 20:21:255013 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024
Daniel Bratell93eb6c62019-04-29 20:13:365014
Sam Maiera6e76d72022-02-11 21:43:505015 too_large_files = []
5016 for f in input_api.AffectedFiles():
5017 # Check both added and modified files (but not deleted files).
5018 if f.Action() in ('A', 'M'):
5019 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Joe DeBlasio10a832f2023-04-21 20:20:185020 if size > TOO_LARGE_FILE_SIZE_LIMIT:
Sam Maiera6e76d72022-02-11 21:43:505021 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
Daniel Bratell93eb6c62019-04-29 20:13:365022
Sam Maiera6e76d72022-02-11 21:43:505023 if too_large_files:
5024 message = (
5025 'Do not commit large files to git since git scales badly for those.\n'
5026 +
5027 'Instead put the large files in cloud storage and use DEPS to\n' +
5028 'fetch them.\n' + '\n'.join(too_large_files))
5029 return [
5030 output_api.PresubmitError('Too large files found in commit',
5031 long_text=message + '\n')
5032 ]
5033 else:
5034 return []
Daniel Bratell93eb6c62019-04-29 20:13:365035
Max Morozb47503b2019-08-08 21:03:275036
Saagar Sanghavifceeaae2020-08-12 16:40:365037def CheckFuzzTargetsOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505038 """Checks specific for fuzz target sources."""
5039 EXPORTED_SYMBOLS = [
5040 'LLVMFuzzerInitialize',
5041 'LLVMFuzzerCustomMutator',
5042 'LLVMFuzzerCustomCrossOver',
5043 'LLVMFuzzerMutate',
5044 ]
Max Morozb47503b2019-08-08 21:03:275045
Sam Maiera6e76d72022-02-11 21:43:505046 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
Max Morozb47503b2019-08-08 21:03:275047
Sam Maiera6e76d72022-02-11 21:43:505048 def FilterFile(affected_file):
5049 """Ignore libFuzzer source code."""
5050 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
Bruce Dawson40fece62022-09-16 19:58:315051 files_to_skip = r"^third_party/libFuzzer"
Max Morozb47503b2019-08-08 21:03:275052
Sam Maiera6e76d72022-02-11 21:43:505053 return input_api.FilterSourceFile(affected_file,
5054 files_to_check=[files_to_check],
5055 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:275056
Sam Maiera6e76d72022-02-11 21:43:505057 files_with_missing_header = []
5058 for f in input_api.AffectedSourceFiles(FilterFile):
5059 contents = input_api.ReadFile(f, 'r')
5060 if REQUIRED_HEADER in contents:
5061 continue
Max Morozb47503b2019-08-08 21:03:275062
Sam Maiera6e76d72022-02-11 21:43:505063 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
5064 files_with_missing_header.append(f.LocalPath())
Max Morozb47503b2019-08-08 21:03:275065
Sam Maiera6e76d72022-02-11 21:43:505066 if not files_with_missing_header:
5067 return []
Max Morozb47503b2019-08-08 21:03:275068
Sam Maiera6e76d72022-02-11 21:43:505069 long_text = (
5070 'If you define any of the libFuzzer optional functions (%s), it is '
5071 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
5072 'work incorrectly on Mac (crbug.com/687076).\nNote that '
5073 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
5074 'to access command line arguments passed to the fuzzer. Instead, prefer '
5075 'static initialization and shared resources as documented in '
5076 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
5077 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n'
5078 % (', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER))
Max Morozb47503b2019-08-08 21:03:275079
Sam Maiera6e76d72022-02-11 21:43:505080 return [
5081 output_api.PresubmitPromptWarning(message="Missing '%s' in:" %
5082 REQUIRED_HEADER,
5083 items=files_with_missing_header,
5084 long_text=long_text)
5085 ]
Max Morozb47503b2019-08-08 21:03:275086
5087
Mohamed Heikald048240a2019-11-12 16:57:375088def _CheckNewImagesWarning(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505089 """
5090 Warns authors who add images into the repo to make sure their images are
5091 optimized before committing.
5092 """
5093 images_added = False
5094 image_paths = []
5095 errors = []
5096 filter_lambda = lambda x: input_api.FilterSourceFile(
5097 x,
5098 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
5099 DEFAULT_FILES_TO_SKIP),
5100 files_to_check=[r'.*\/(drawable|mipmap)'])
5101 for f in input_api.AffectedFiles(include_deletes=False,
5102 file_filter=filter_lambda):
5103 local_path = f.LocalPath().lower()
5104 if any(
5105 local_path.endswith(extension)
5106 for extension in _IMAGE_EXTENSIONS):
5107 images_added = True
5108 image_paths.append(f)
5109 if images_added:
5110 errors.append(
5111 output_api.PresubmitPromptWarning(
5112 'It looks like you are trying to commit some images. If these are '
5113 'non-test-only images, please make sure to read and apply the tips in '
5114 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
5115 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
5116 'FYI only and will not block your CL on the CQ.', image_paths))
5117 return errors
Mohamed Heikald048240a2019-11-12 16:57:375118
5119
Saagar Sanghavifceeaae2020-08-12 16:40:365120def ChecksAndroidSpecificOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505121 """Groups upload checks that target android code."""
5122 results = []
5123 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
5124 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
5125 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
5126 results.extend(_CheckAndroidToastUsage(input_api, output_api))
5127 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
5128 results.extend(_CheckAndroidTestJUnitFrameworkImport(
5129 input_api, output_api))
5130 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
5131 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
5132 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
5133 results.extend(_CheckNewImagesWarning(input_api, output_api))
5134 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
5135 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
5136 return results
5137
Becky Zhou7c69b50992018-12-10 19:37:575138
Saagar Sanghavifceeaae2020-08-12 16:40:365139def ChecksAndroidSpecificOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505140 """Groups commit checks that target android code."""
5141 results = []
5142 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
5143 return results
dgnaa68d5e2015-06-10 10:08:225144
Chris Hall59f8d0c72020-05-01 07:31:195145# TODO(chrishall): could we additionally match on any path owned by
5146# ui/accessibility/OWNERS ?
5147_ACCESSIBILITY_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:315148 r"^chrome/browser.*/accessibility/",
5149 r"^chrome/browser/extensions/api/automation.*/",
5150 r"^chrome/renderer/extensions/accessibility_.*",
5151 r"^chrome/tests/data/accessibility/",
Katie Dektar58ef07b2022-09-27 13:19:175152 r"^components/services/screen_ai/",
Bruce Dawson40fece62022-09-16 19:58:315153 r"^content/browser/accessibility/",
5154 r"^content/renderer/accessibility/",
5155 r"^content/tests/data/accessibility/",
5156 r"^extensions/renderer/api/automation/",
Katie Dektar58ef07b2022-09-27 13:19:175157 r"^services/accessibility/",
Bruce Dawson40fece62022-09-16 19:58:315158 r"^ui/accessibility/",
5159 r"^ui/views/accessibility/",
Chris Hall59f8d0c72020-05-01 07:31:195160)
5161
Saagar Sanghavifceeaae2020-08-12 16:40:365162def CheckAccessibilityRelnotesField(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505163 """Checks that commits to accessibility code contain an AX-Relnotes field in
5164 their commit message."""
Chris Hall59f8d0c72020-05-01 07:31:195165
Sam Maiera6e76d72022-02-11 21:43:505166 def FileFilter(affected_file):
5167 paths = _ACCESSIBILITY_PATHS
5168 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:195169
Sam Maiera6e76d72022-02-11 21:43:505170 # Only consider changes affecting accessibility paths.
5171 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
5172 return []
Akihiro Ota08108e542020-05-20 15:30:535173
Sam Maiera6e76d72022-02-11 21:43:505174 # AX-Relnotes can appear in either the description or the footer.
5175 # When searching the description, require 'AX-Relnotes:' to appear at the
5176 # beginning of a line.
5177 ax_regex = input_api.re.compile('ax-relnotes[:=]')
5178 description_has_relnotes = any(
5179 ax_regex.match(line)
5180 for line in input_api.change.DescriptionText().lower().splitlines())
Chris Hall59f8d0c72020-05-01 07:31:195181
Sam Maiera6e76d72022-02-11 21:43:505182 footer_relnotes = input_api.change.GitFootersFromDescription().get(
5183 'AX-Relnotes', [])
5184 if description_has_relnotes or footer_relnotes:
5185 return []
Chris Hall59f8d0c72020-05-01 07:31:195186
Sam Maiera6e76d72022-02-11 21:43:505187 # TODO(chrishall): link to Relnotes documentation in message.
5188 message = (
5189 "Missing 'AX-Relnotes:' field required for accessibility changes"
5190 "\n please add 'AX-Relnotes: [release notes].' to describe any "
5191 "user-facing changes"
5192 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
5193 "user-facing effects"
5194 "\n if this is confusing or annoying then please contact members "
5195 "of ui/accessibility/OWNERS.")
5196
5197 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:225198
Mark Schillacie5a0be22022-01-19 00:38:395199
5200_ACCESSIBILITY_EVENTS_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315201 r"^content/test/data/accessibility/event/.*\.html",
Mark Schillacie5a0be22022-01-19 00:38:395202)
5203
5204_ACCESSIBILITY_TREE_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315205 r"^content/test/data/accessibility/accname/.*\.html",
5206 r"^content/test/data/accessibility/aria/.*\.html",
5207 r"^content/test/data/accessibility/css/.*\.html",
5208 r"^content/test/data/accessibility/html/.*\.html",
Mark Schillacie5a0be22022-01-19 00:38:395209)
5210
5211_ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315212 r"^.*/WebContentsAccessibilityEventsTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:395213)
5214
5215_ACCESSIBILITY_ANDROID_TREE_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315216 r"^.*/WebContentsAccessibilityTreeTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:395217)
5218
5219def CheckAccessibilityEventsTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505220 """Checks that commits that include a newly added, renamed/moved, or deleted
5221 test in the DumpAccessibilityEventsTest suite also includes a corresponding
5222 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:395223
Sam Maiera6e76d72022-02-11 21:43:505224 def FilePathFilter(affected_file):
5225 paths = _ACCESSIBILITY_EVENTS_TEST_PATH
5226 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395227
Sam Maiera6e76d72022-02-11 21:43:505228 def AndroidFilePathFilter(affected_file):
5229 paths = _ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH
5230 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395231
Sam Maiera6e76d72022-02-11 21:43:505232 # Only consider changes in the events test data path with html type.
5233 if not any(
5234 input_api.AffectedFiles(include_deletes=True,
5235 file_filter=FilePathFilter)):
5236 return []
Mark Schillacie5a0be22022-01-19 00:38:395237
Sam Maiera6e76d72022-02-11 21:43:505238 # If the commit contains any change to the Android test file, ignore.
5239 if any(
5240 input_api.AffectedFiles(include_deletes=True,
5241 file_filter=AndroidFilePathFilter)):
5242 return []
Mark Schillacie5a0be22022-01-19 00:38:395243
Sam Maiera6e76d72022-02-11 21:43:505244 # Only consider changes that are adding/renaming or deleting a file
5245 message = []
5246 for f in input_api.AffectedFiles(include_deletes=True,
5247 file_filter=FilePathFilter):
5248 if f.Action() == 'A' or f.Action() == 'D':
5249 message = (
5250 "It appears that you are adding, renaming or deleting"
5251 "\na dump_accessibility_events* test, but have not included"
5252 "\na corresponding change for Android."
5253 "\nPlease include (or remove) the test from:"
5254 "\n content/public/android/javatests/src/org/chromium/"
5255 "content/browser/accessibility/"
5256 "WebContentsAccessibilityEventsTest.java"
5257 "\nIf this message is confusing or annoying, please contact"
5258 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:395259
Sam Maiera6e76d72022-02-11 21:43:505260 # If no message was set, return empty.
5261 if not len(message):
5262 return []
5263
5264 return [output_api.PresubmitPromptWarning(message)]
5265
Mark Schillacie5a0be22022-01-19 00:38:395266
5267def CheckAccessibilityTreeTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505268 """Checks that commits that include a newly added, renamed/moved, or deleted
5269 test in the DumpAccessibilityTreeTest suite also includes a corresponding
5270 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:395271
Sam Maiera6e76d72022-02-11 21:43:505272 def FilePathFilter(affected_file):
5273 paths = _ACCESSIBILITY_TREE_TEST_PATH
5274 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395275
Sam Maiera6e76d72022-02-11 21:43:505276 def AndroidFilePathFilter(affected_file):
5277 paths = _ACCESSIBILITY_ANDROID_TREE_TEST_PATH
5278 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395279
Sam Maiera6e76d72022-02-11 21:43:505280 # Only consider changes in the various tree test data paths with html type.
5281 if not any(
5282 input_api.AffectedFiles(include_deletes=True,
5283 file_filter=FilePathFilter)):
5284 return []
Mark Schillacie5a0be22022-01-19 00:38:395285
Sam Maiera6e76d72022-02-11 21:43:505286 # If the commit contains any change to the Android test file, ignore.
5287 if any(
5288 input_api.AffectedFiles(include_deletes=True,
5289 file_filter=AndroidFilePathFilter)):
5290 return []
Mark Schillacie5a0be22022-01-19 00:38:395291
Sam Maiera6e76d72022-02-11 21:43:505292 # Only consider changes that are adding/renaming or deleting a file
5293 message = []
5294 for f in input_api.AffectedFiles(include_deletes=True,
5295 file_filter=FilePathFilter):
5296 if f.Action() == 'A' or f.Action() == 'D':
5297 message = (
5298 "It appears that you are adding, renaming or deleting"
5299 "\na dump_accessibility_tree* test, but have not included"
5300 "\na corresponding change for Android."
5301 "\nPlease include (or remove) the test from:"
5302 "\n content/public/android/javatests/src/org/chromium/"
5303 "content/browser/accessibility/"
5304 "WebContentsAccessibilityTreeTest.java"
5305 "\nIf this message is confusing or annoying, please contact"
5306 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:395307
Sam Maiera6e76d72022-02-11 21:43:505308 # If no message was set, return empty.
5309 if not len(message):
5310 return []
5311
5312 return [output_api.PresubmitPromptWarning(message)]
Mark Schillacie5a0be22022-01-19 00:38:395313
5314
Bruce Dawson33806592022-11-16 01:44:515315def CheckEsLintConfigChanges(input_api, output_api):
5316 """Suggest using "git cl presubmit --files" when .eslintrc.js files are
5317 modified. This is important because enabling an error in .eslintrc.js can
5318 trigger errors in any .js or .ts files in its directory, leading to hidden
5319 presubmit errors."""
5320 results = []
5321 eslint_filter = lambda f: input_api.FilterSourceFile(
5322 f, files_to_check=[r'.*\.eslintrc\.js$'])
5323 for f in input_api.AffectedFiles(include_deletes=False,
5324 file_filter=eslint_filter):
5325 local_dir = input_api.os_path.dirname(f.LocalPath())
5326 # Use / characters so that the commands printed work on any OS.
5327 local_dir = local_dir.replace(input_api.os_path.sep, '/')
5328 if local_dir:
5329 local_dir += '/'
5330 results.append(
5331 output_api.PresubmitNotifyResult(
5332 '%(file)s modified. Consider running \'git cl presubmit --files '
5333 '"%(dir)s*.js;%(dir)s*.ts"\' in order to check and fix the affected '
5334 'files before landing this change.' %
5335 { 'file' : f.LocalPath(), 'dir' : local_dir}))
5336 return results
5337
5338
seanmccullough4a9356252021-04-08 19:54:095339# string pattern, sequence of strings to show when pattern matches,
5340# error flag. True if match is a presubmit error, otherwise it's a warning.
5341_NON_INCLUSIVE_TERMS = (
5342 (
5343 # Note that \b pattern in python re is pretty particular. In this
5344 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
5345 # ...' will not. This may require some tweaking to catch these cases
5346 # without triggering a lot of false positives. Leaving it naive and
5347 # less matchy for now.
seanmccullough56d1e3cf2021-12-03 18:18:325348 r'/\b(?i)((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:095349 (
5350 'Please don\'t use blacklist, whitelist, ' # nocheck
5351 'or slave in your', # nocheck
5352 'code and make every effort to use other terms. Using "// nocheck"',
5353 '"# nocheck" or "<!-- nocheck -->"',
5354 'at the end of the offending line will bypass this PRESUBMIT error',
5355 'but avoid using this whenever possible. Reach out to',
5356 '[email protected] if you have questions'),
5357 True),)
5358
Saagar Sanghavifceeaae2020-08-12 16:40:365359def ChecksCommon(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505360 """Checks common to both upload and commit."""
5361 results = []
Eric Boren6fd2b932018-01-25 15:05:085362 results.extend(
Sam Maiera6e76d72022-02-11 21:43:505363 input_api.canned_checks.PanProjectChecks(
5364 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:085365
Sam Maiera6e76d72022-02-11 21:43:505366 author = input_api.change.author_email
5367 if author and author not in _KNOWN_ROBOTS:
5368 results.extend(
5369 input_api.canned_checks.CheckAuthorizedAuthor(
5370 input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:245371
Sam Maiera6e76d72022-02-11 21:43:505372 results.extend(
5373 input_api.canned_checks.CheckChangeHasNoTabs(
5374 input_api,
5375 output_api,
5376 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
5377 results.extend(
5378 input_api.RunTests(
5379 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Edward Lesmesce51df52020-08-04 22:10:175380
Bruce Dawsonc8054482022-03-28 15:33:375381 dirmd = 'dirmd.bat' if input_api.is_windows else 'dirmd'
Sam Maiera6e76d72022-02-11 21:43:505382 dirmd_bin = input_api.os_path.join(input_api.PresubmitLocalPath(),
Bruce Dawsonc8054482022-03-28 15:33:375383 'third_party', 'depot_tools', dirmd)
Sam Maiera6e76d72022-02-11 21:43:505384 results.extend(
5385 input_api.RunTests(
5386 input_api.canned_checks.CheckDirMetadataFormat(
5387 input_api, output_api, dirmd_bin)))
5388 results.extend(
5389 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
5390 input_api, output_api))
5391 results.extend(
5392 input_api.canned_checks.CheckNoNewMetadataInOwners(
5393 input_api, output_api))
5394 results.extend(
5395 input_api.canned_checks.CheckInclusiveLanguage(
5396 input_api,
5397 output_api,
5398 excluded_directories_relative_path=[
5399 'infra', 'inclusive_language_presubmit_exempt_dirs.txt'
5400 ],
5401 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Dirk Prankee3c9c62d2021-05-18 18:35:595402
Aleksey Khoroshilov2978c942022-06-13 16:14:125403 presubmit_py_filter = lambda f: input_api.FilterSourceFile(
Bruce Dawson696963f2022-09-13 01:15:475404 f, files_to_check=[r'.*PRESUBMIT\.py$'])
Aleksey Khoroshilov2978c942022-06-13 16:14:125405 for f in input_api.AffectedFiles(include_deletes=False,
5406 file_filter=presubmit_py_filter):
5407 full_path = input_api.os_path.dirname(f.AbsoluteLocalPath())
5408 test_file = input_api.os_path.join(full_path, 'PRESUBMIT_test.py')
5409 # The PRESUBMIT.py file (and the directory containing it) might have
5410 # been affected by being moved or removed, so only try to run the tests
5411 # if they still exist.
5412 if not input_api.os_path.exists(test_file):
5413 continue
Sam Maiera6e76d72022-02-11 21:43:505414
Aleksey Khoroshilov2978c942022-06-13 16:14:125415 use_python3 = False
Bruce Dawson58a45d22023-02-27 11:24:165416 with open(f.LocalPath(), encoding='utf-8') as fp:
Aleksey Khoroshilov2978c942022-06-13 16:14:125417 use_python3 = any(
5418 line.startswith('USE_PYTHON3 = True')
5419 for line in fp.readlines())
5420
5421 results.extend(
5422 input_api.canned_checks.RunUnitTestsInDirectory(
5423 input_api,
5424 output_api,
5425 full_path,
5426 files_to_check=[r'^PRESUBMIT_test\.py$'],
5427 run_on_python2=not use_python3,
5428 run_on_python3=use_python3,
5429 skip_shebang_check=True))
Sam Maiera6e76d72022-02-11 21:43:505430 return results
[email protected]1f7b4172010-01-28 01:17:345431
[email protected]b337cb5b2011-01-23 21:24:055432
Saagar Sanghavifceeaae2020-08-12 16:40:365433def CheckPatchFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505434 problems = [
5435 f.LocalPath() for f in input_api.AffectedFiles()
5436 if f.LocalPath().endswith(('.orig', '.rej'))
5437 ]
5438 # Cargo.toml.orig files are part of third-party crates downloaded from
5439 # crates.io and should be included.
5440 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
5441 if problems:
5442 return [
5443 output_api.PresubmitError("Don't commit .rej and .orig files.",
5444 problems)
5445 ]
5446 else:
5447 return []
[email protected]b8079ae4a2012-12-05 19:56:495448
5449
Saagar Sanghavifceeaae2020-08-12 16:40:365450def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505451 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
5452 macro_re = input_api.re.compile(
5453 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
5454 include_re = input_api.re.compile(r'^#include\s+"build/build_config.h"',
5455 input_api.re.MULTILINE)
5456 extension_re = input_api.re.compile(r'\.[a-z]+$')
5457 errors = []
Bruce Dawsonf7679202022-08-09 20:24:005458 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:505459 for f in input_api.AffectedFiles(include_deletes=False):
Bruce Dawsonf7679202022-08-09 20:24:005460 # The build-config macros are allowed to be used in build_config.h
5461 # without including itself.
5462 if f.LocalPath() == config_h_file:
5463 continue
Sam Maiera6e76d72022-02-11 21:43:505464 if not f.LocalPath().endswith(
5465 ('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
5466 continue
5467 found_line_number = None
5468 found_macro = None
5469 all_lines = input_api.ReadFile(f, 'r').splitlines()
5470 for line_num, line in enumerate(all_lines):
5471 match = macro_re.search(line)
5472 if match:
5473 found_line_number = line_num
5474 found_macro = match.group(2)
5475 break
5476 if not found_line_number:
5477 continue
Kent Tamura5a8755d2017-06-29 23:37:075478
Sam Maiera6e76d72022-02-11 21:43:505479 found_include_line = -1
5480 for line_num, line in enumerate(all_lines):
5481 if include_re.search(line):
5482 found_include_line = line_num
5483 break
5484 if found_include_line >= 0 and found_include_line < found_line_number:
5485 continue
Kent Tamura5a8755d2017-06-29 23:37:075486
Sam Maiera6e76d72022-02-11 21:43:505487 if not f.LocalPath().endswith('.h'):
5488 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
5489 try:
5490 content = input_api.ReadFile(primary_header_path, 'r')
5491 if include_re.search(content):
5492 continue
5493 except IOError:
5494 pass
5495 errors.append('%s:%d %s macro is used without first including build/'
5496 'build_config.h.' %
5497 (f.LocalPath(), found_line_number, found_macro))
5498 if errors:
5499 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
5500 return []
Kent Tamura5a8755d2017-06-29 23:37:075501
5502
Lei Zhang1c12a22f2021-05-12 11:28:455503def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505504 stl_include_re = input_api.re.compile(r'^#include\s+<('
5505 r'algorithm|'
5506 r'array|'
5507 r'limits|'
5508 r'list|'
5509 r'map|'
5510 r'memory|'
5511 r'queue|'
5512 r'set|'
5513 r'string|'
5514 r'unordered_map|'
5515 r'unordered_set|'
5516 r'utility|'
5517 r'vector)>')
5518 std_namespace_re = input_api.re.compile(r'std::')
5519 errors = []
5520 for f in input_api.AffectedFiles():
5521 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
5522 continue
Lei Zhang1c12a22f2021-05-12 11:28:455523
Sam Maiera6e76d72022-02-11 21:43:505524 uses_std_namespace = False
5525 has_stl_include = False
5526 for line in f.NewContents():
5527 if has_stl_include and uses_std_namespace:
5528 break
Lei Zhang1c12a22f2021-05-12 11:28:455529
Sam Maiera6e76d72022-02-11 21:43:505530 if not has_stl_include and stl_include_re.search(line):
5531 has_stl_include = True
5532 continue
Lei Zhang1c12a22f2021-05-12 11:28:455533
Bruce Dawson4a5579a2022-04-08 17:11:365534 if not uses_std_namespace and (std_namespace_re.search(line)
5535 or 'no-std-usage-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:505536 uses_std_namespace = True
5537 continue
Lei Zhang1c12a22f2021-05-12 11:28:455538
Sam Maiera6e76d72022-02-11 21:43:505539 if has_stl_include and not uses_std_namespace:
5540 errors.append(
5541 '%s: Includes STL header(s) but does not reference std::' %
5542 f.LocalPath())
5543 if errors:
5544 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
5545 return []
Lei Zhang1c12a22f2021-05-12 11:28:455546
5547
Xiaohan Wang42d96c22022-01-20 17:23:115548def _CheckForDeprecatedOSMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:505549 """Check for sensible looking, totally invalid OS macros."""
5550 preprocessor_statement = input_api.re.compile(r'^\s*#')
5551 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
5552 results = []
5553 for lnum, line in f.ChangedContents():
5554 if preprocessor_statement.search(line):
5555 for match in os_macro.finditer(line):
5556 results.append(
5557 ' %s:%d: %s' %
5558 (f.LocalPath(), lnum, 'defined(OS_' + match.group(1) +
5559 ') -> BUILDFLAG(IS_' + match.group(1) + ')'))
5560 return results
[email protected]b00342e7f2013-03-26 16:21:545561
5562
Xiaohan Wang42d96c22022-01-20 17:23:115563def CheckForDeprecatedOSMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505564 """Check all affected files for invalid OS macros."""
5565 bad_macros = []
Bruce Dawsonf7679202022-08-09 20:24:005566 # The OS_ macros are allowed to be used in build/build_config.h.
5567 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:505568 for f in input_api.AffectedSourceFiles(None):
Bruce Dawsonf7679202022-08-09 20:24:005569 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')) \
5570 and f.LocalPath() != config_h_file:
Sam Maiera6e76d72022-02-11 21:43:505571 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
[email protected]b00342e7f2013-03-26 16:21:545572
Sam Maiera6e76d72022-02-11 21:43:505573 if not bad_macros:
5574 return []
[email protected]b00342e7f2013-03-26 16:21:545575
Sam Maiera6e76d72022-02-11 21:43:505576 return [
5577 output_api.PresubmitError(
5578 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
5579 'defined in build_config.h):', bad_macros)
5580 ]
[email protected]b00342e7f2013-03-26 16:21:545581
lliabraa35bab3932014-10-01 12:16:445582
5583def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:505584 """Check all affected files for invalid "if defined" macros."""
5585 ALWAYS_DEFINED_MACROS = (
5586 "TARGET_CPU_PPC",
5587 "TARGET_CPU_PPC64",
5588 "TARGET_CPU_68K",
5589 "TARGET_CPU_X86",
5590 "TARGET_CPU_ARM",
5591 "TARGET_CPU_MIPS",
5592 "TARGET_CPU_SPARC",
5593 "TARGET_CPU_ALPHA",
5594 "TARGET_IPHONE_SIMULATOR",
5595 "TARGET_OS_EMBEDDED",
5596 "TARGET_OS_IPHONE",
5597 "TARGET_OS_MAC",
5598 "TARGET_OS_UNIX",
5599 "TARGET_OS_WIN32",
5600 )
5601 ifdef_macro = input_api.re.compile(
5602 r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
5603 results = []
5604 for lnum, line in f.ChangedContents():
5605 for match in ifdef_macro.finditer(line):
5606 if match.group(1) in ALWAYS_DEFINED_MACROS:
5607 always_defined = ' %s is always defined. ' % match.group(1)
5608 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
5609 results.append(
5610 ' %s:%d %s\n\t%s' %
5611 (f.LocalPath(), lnum, always_defined, did_you_mean))
5612 return results
lliabraa35bab3932014-10-01 12:16:445613
5614
Saagar Sanghavifceeaae2020-08-12 16:40:365615def CheckForInvalidIfDefinedMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505616 """Check all affected files for invalid "if defined" macros."""
5617 bad_macros = []
5618 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
5619 for f in input_api.AffectedFiles():
5620 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
5621 continue
5622 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
5623 bad_macros.extend(
5624 _CheckForInvalidIfDefinedMacrosInFile(input_api, f))
lliabraa35bab3932014-10-01 12:16:445625
Sam Maiera6e76d72022-02-11 21:43:505626 if not bad_macros:
5627 return []
lliabraa35bab3932014-10-01 12:16:445628
Sam Maiera6e76d72022-02-11 21:43:505629 return [
5630 output_api.PresubmitError(
5631 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
5632 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
5633 bad_macros)
5634 ]
lliabraa35bab3932014-10-01 12:16:445635
5636
Saagar Sanghavifceeaae2020-08-12 16:40:365637def CheckForIPCRules(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505638 """Check for same IPC rules described in
5639 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
5640 """
5641 base_pattern = r'IPC_ENUM_TRAITS\('
5642 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
5643 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
mlamouria82272622014-09-16 18:45:045644
Sam Maiera6e76d72022-02-11 21:43:505645 problems = []
5646 for f in input_api.AffectedSourceFiles(None):
5647 local_path = f.LocalPath()
5648 if not local_path.endswith('.h'):
5649 continue
5650 for line_number, line in f.ChangedContents():
5651 if inclusion_pattern.search(
5652 line) and not comment_pattern.search(line):
5653 problems.append('%s:%d\n %s' %
5654 (local_path, line_number, line.strip()))
mlamouria82272622014-09-16 18:45:045655
Sam Maiera6e76d72022-02-11 21:43:505656 if problems:
5657 return [
5658 output_api.PresubmitPromptWarning(_IPC_ENUM_TRAITS_DEPRECATED,
5659 problems)
5660 ]
5661 else:
5662 return []
mlamouria82272622014-09-16 18:45:045663
[email protected]b00342e7f2013-03-26 16:21:545664
Saagar Sanghavifceeaae2020-08-12 16:40:365665def CheckForLongPathnames(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505666 """Check to make sure no files being submitted have long paths.
5667 This causes issues on Windows.
5668 """
5669 problems = []
5670 for f in input_api.AffectedTestableFiles():
5671 local_path = f.LocalPath()
5672 # Windows has a path limit of 260 characters. Limit path length to 200 so
5673 # that we have some extra for the prefix on dev machines and the bots.
5674 if len(local_path) > 200:
5675 problems.append(local_path)
Stephen Martinis97a394142018-06-07 23:06:055676
Sam Maiera6e76d72022-02-11 21:43:505677 if problems:
5678 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
5679 else:
5680 return []
Stephen Martinis97a394142018-06-07 23:06:055681
5682
Saagar Sanghavifceeaae2020-08-12 16:40:365683def CheckForIncludeGuards(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505684 """Check that header files have proper guards against multiple inclusion.
5685 If a file should not have such guards (and it probably should) then it
Bruce Dawson4a5579a2022-04-08 17:11:365686 should include the string "no-include-guard-because-multiply-included" or
5687 "no-include-guard-because-pch-file".
Sam Maiera6e76d72022-02-11 21:43:505688 """
Daniel Bratell8ba52722018-03-02 16:06:145689
Sam Maiera6e76d72022-02-11 21:43:505690 def is_chromium_header_file(f):
5691 # We only check header files under the control of the Chromium
5692 # project. That is, those outside third_party apart from
5693 # third_party/blink.
5694 # We also exclude *_message_generator.h headers as they use
5695 # include guards in a special, non-typical way.
5696 file_with_path = input_api.os_path.normpath(f.LocalPath())
5697 return (file_with_path.endswith('.h')
5698 and not file_with_path.endswith('_message_generator.h')
Bruce Dawson4c4c2922022-05-02 18:07:335699 and not file_with_path.endswith('com_imported_mstscax.h')
Sam Maiera6e76d72022-02-11 21:43:505700 and (not file_with_path.startswith('third_party')
5701 or file_with_path.startswith(
5702 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:145703
Sam Maiera6e76d72022-02-11 21:43:505704 def replace_special_with_underscore(string):
5705 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:145706
Sam Maiera6e76d72022-02-11 21:43:505707 errors = []
Daniel Bratell8ba52722018-03-02 16:06:145708
Sam Maiera6e76d72022-02-11 21:43:505709 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
5710 guard_name = None
5711 guard_line_number = None
5712 seen_guard_end = False
Daniel Bratell8ba52722018-03-02 16:06:145713
Sam Maiera6e76d72022-02-11 21:43:505714 file_with_path = input_api.os_path.normpath(f.LocalPath())
5715 base_file_name = input_api.os_path.splitext(
5716 input_api.os_path.basename(file_with_path))[0]
5717 upper_base_file_name = base_file_name.upper()
Daniel Bratell8ba52722018-03-02 16:06:145718
Sam Maiera6e76d72022-02-11 21:43:505719 expected_guard = replace_special_with_underscore(
5720 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:145721
Sam Maiera6e76d72022-02-11 21:43:505722 # For "path/elem/file_name.h" we should really only accept
5723 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
5724 # are too many (1000+) files with slight deviations from the
5725 # coding style. The most important part is that the include guard
5726 # is there, and that it's unique, not the name so this check is
5727 # forgiving for existing files.
5728 #
5729 # As code becomes more uniform, this could be made stricter.
Daniel Bratell8ba52722018-03-02 16:06:145730
Sam Maiera6e76d72022-02-11 21:43:505731 guard_name_pattern_list = [
5732 # Anything with the right suffix (maybe with an extra _).
5733 r'\w+_H__?',
Daniel Bratell8ba52722018-03-02 16:06:145734
Sam Maiera6e76d72022-02-11 21:43:505735 # To cover include guards with old Blink style.
5736 r'\w+_h',
Daniel Bratell8ba52722018-03-02 16:06:145737
Sam Maiera6e76d72022-02-11 21:43:505738 # Anything including the uppercase name of the file.
5739 r'\w*' + input_api.re.escape(
5740 replace_special_with_underscore(upper_base_file_name)) +
5741 r'\w*',
5742 ]
5743 guard_name_pattern = '|'.join(guard_name_pattern_list)
5744 guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
5745 guard_name_pattern + ')')
Daniel Bratell8ba52722018-03-02 16:06:145746
Sam Maiera6e76d72022-02-11 21:43:505747 for line_number, line in enumerate(f.NewContents()):
Bruce Dawson4a5579a2022-04-08 17:11:365748 if ('no-include-guard-because-multiply-included' in line
5749 or 'no-include-guard-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:505750 guard_name = 'DUMMY' # To not trigger check outside the loop.
5751 break
Daniel Bratell8ba52722018-03-02 16:06:145752
Sam Maiera6e76d72022-02-11 21:43:505753 if guard_name is None:
5754 match = guard_pattern.match(line)
5755 if match:
5756 guard_name = match.group(1)
5757 guard_line_number = line_number
Daniel Bratell8ba52722018-03-02 16:06:145758
Sam Maiera6e76d72022-02-11 21:43:505759 # We allow existing files to use include guards whose names
5760 # don't match the chromium style guide, but new files should
5761 # get it right.
Bruce Dawson6cc154e2022-04-12 20:39:495762 if guard_name != expected_guard:
Bruce Dawson95eb7562022-09-14 15:27:165763 if f.Action() == 'A': # If file was just 'A'dded
Sam Maiera6e76d72022-02-11 21:43:505764 errors.append(
5765 output_api.PresubmitPromptWarning(
5766 'Header using the wrong include guard name %s'
5767 % guard_name, [
5768 '%s:%d' %
5769 (f.LocalPath(), line_number + 1)
5770 ], 'Expected: %r\nFound: %r' %
5771 (expected_guard, guard_name)))
5772 else:
5773 # The line after #ifndef should have a #define of the same name.
5774 if line_number == guard_line_number + 1:
5775 expected_line = '#define %s' % guard_name
5776 if line != expected_line:
5777 errors.append(
5778 output_api.PresubmitPromptWarning(
5779 'Missing "%s" for include guard' %
5780 expected_line,
5781 ['%s:%d' % (f.LocalPath(), line_number + 1)],
5782 'Expected: %r\nGot: %r' %
5783 (expected_line, line)))
Daniel Bratell8ba52722018-03-02 16:06:145784
Sam Maiera6e76d72022-02-11 21:43:505785 if not seen_guard_end and line == '#endif // %s' % guard_name:
5786 seen_guard_end = True
5787 elif seen_guard_end:
5788 if line.strip() != '':
5789 errors.append(
5790 output_api.PresubmitPromptWarning(
5791 'Include guard %s not covering the whole file'
5792 % (guard_name), [f.LocalPath()]))
5793 break # Nothing else to check and enough to warn once.
Daniel Bratell8ba52722018-03-02 16:06:145794
Sam Maiera6e76d72022-02-11 21:43:505795 if guard_name is None:
5796 errors.append(
5797 output_api.PresubmitPromptWarning(
Bruce Dawson32114b62022-04-11 16:45:495798 'Missing include guard in %s\n'
Sam Maiera6e76d72022-02-11 21:43:505799 'Recommended name: %s\n'
5800 'This check can be disabled by having the string\n'
Bruce Dawson4a5579a2022-04-08 17:11:365801 '"no-include-guard-because-multiply-included" or\n'
5802 '"no-include-guard-because-pch-file" in the header.'
Sam Maiera6e76d72022-02-11 21:43:505803 % (f.LocalPath(), expected_guard)))
5804
5805 return errors
Daniel Bratell8ba52722018-03-02 16:06:145806
5807
Saagar Sanghavifceeaae2020-08-12 16:40:365808def CheckForWindowsLineEndings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505809 """Check source code and known ascii text files for Windows style line
5810 endings.
5811 """
Bruce Dawson5efbdc652022-04-11 19:29:515812 known_text_files = r'.*\.(txt|html|htm|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:235813
Sam Maiera6e76d72022-02-11 21:43:505814 file_inclusion_pattern = (known_text_files,
5815 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
5816 r'.+%s' % _HEADER_EXTENSIONS)
mostynbb639aca52015-01-07 20:31:235817
Sam Maiera6e76d72022-02-11 21:43:505818 problems = []
5819 source_file_filter = lambda f: input_api.FilterSourceFile(
5820 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
5821 for f in input_api.AffectedSourceFiles(source_file_filter):
Bruce Dawson5efbdc652022-04-11 19:29:515822 # Ignore test files that contain crlf intentionally.
5823 if f.LocalPath().endswith('crlf.txt'):
Daniel Chenga37c03db2022-05-12 17:20:345824 continue
Sam Maiera6e76d72022-02-11 21:43:505825 include_file = False
5826 for line in input_api.ReadFile(f, 'r').splitlines(True):
5827 if line.endswith('\r\n'):
5828 include_file = True
5829 if include_file:
5830 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:235831
Sam Maiera6e76d72022-02-11 21:43:505832 if problems:
5833 return [
5834 output_api.PresubmitPromptWarning(
5835 'Are you sure that you want '
5836 'these files to contain Windows style line endings?\n' +
5837 '\n'.join(problems))
5838 ]
mostynbb639aca52015-01-07 20:31:235839
Sam Maiera6e76d72022-02-11 21:43:505840 return []
5841
mostynbb639aca52015-01-07 20:31:235842
Evan Stade6cfc964c12021-05-18 20:21:165843def CheckIconFilesForLicenseHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505844 """Check that .icon files (which are fragments of C++) have license headers.
5845 """
Evan Stade6cfc964c12021-05-18 20:21:165846
Sam Maiera6e76d72022-02-11 21:43:505847 icon_files = (r'.*\.icon$', )
Evan Stade6cfc964c12021-05-18 20:21:165848
Sam Maiera6e76d72022-02-11 21:43:505849 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
5850 return input_api.canned_checks.CheckLicense(input_api,
5851 output_api,
5852 source_file_filter=icons)
5853
Evan Stade6cfc964c12021-05-18 20:21:165854
Jose Magana2b456f22021-03-09 23:26:405855def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505856 """Check source code for use of Chrome App technologies being
5857 deprecated.
5858 """
Jose Magana2b456f22021-03-09 23:26:405859
Sam Maiera6e76d72022-02-11 21:43:505860 def _CheckForDeprecatedTech(input_api,
5861 output_api,
5862 detection_list,
5863 files_to_check=None,
5864 files_to_skip=None):
Jose Magana2b456f22021-03-09 23:26:405865
Sam Maiera6e76d72022-02-11 21:43:505866 if (files_to_check or files_to_skip):
5867 source_file_filter = lambda f: input_api.FilterSourceFile(
5868 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
5869 else:
5870 source_file_filter = None
5871
5872 problems = []
5873
5874 for f in input_api.AffectedSourceFiles(source_file_filter):
5875 if f.Action() == 'D':
5876 continue
5877 for _, line in f.ChangedContents():
5878 if any(detect in line for detect in detection_list):
5879 problems.append(f.LocalPath())
5880
5881 return problems
5882
5883 # to avoid this presubmit script triggering warnings
5884 files_to_skip = ['PRESUBMIT.py', 'PRESUBMIT_test.py']
Jose Magana2b456f22021-03-09 23:26:405885
5886 problems = []
5887
Sam Maiera6e76d72022-02-11 21:43:505888 # NMF: any files with extensions .nmf or NMF
5889 _NMF_FILES = r'\.(nmf|NMF)$'
5890 problems += _CheckForDeprecatedTech(
5891 input_api,
5892 output_api,
5893 detection_list=[''], # any change to the file will trigger warning
5894 files_to_check=[r'.+%s' % _NMF_FILES])
Jose Magana2b456f22021-03-09 23:26:405895
Sam Maiera6e76d72022-02-11 21:43:505896 # MANIFEST: any manifest.json that in its diff includes "app":
5897 _MANIFEST_FILES = r'(manifest\.json)$'
5898 problems += _CheckForDeprecatedTech(
5899 input_api,
5900 output_api,
5901 detection_list=['"app":'],
5902 files_to_check=[r'.*%s' % _MANIFEST_FILES])
Jose Magana2b456f22021-03-09 23:26:405903
Sam Maiera6e76d72022-02-11 21:43:505904 # NaCl / PNaCl: any file that in its diff contains the strings in the list
5905 problems += _CheckForDeprecatedTech(
5906 input_api,
5907 output_api,
5908 detection_list=['config=nacl', 'enable-nacl', 'cpu=pnacl', 'nacl_io'],
Bruce Dawson40fece62022-09-16 19:58:315909 files_to_skip=files_to_skip + [r"^native_client_sdk/"])
Jose Magana2b456f22021-03-09 23:26:405910
Gao Shenga79ebd42022-08-08 17:25:595911 # PPAPI: any C/C++ file that in its diff includes a ppapi library
Sam Maiera6e76d72022-02-11 21:43:505912 problems += _CheckForDeprecatedTech(
5913 input_api,
5914 output_api,
5915 detection_list=['#include "ppapi', '#include <ppapi'],
5916 files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,
5917 r'.+%s' % _IMPLEMENTATION_EXTENSIONS),
Bruce Dawson40fece62022-09-16 19:58:315918 files_to_skip=[r"^ppapi/"])
Jose Magana2b456f22021-03-09 23:26:405919
Sam Maiera6e76d72022-02-11 21:43:505920 if problems:
5921 return [
5922 output_api.PresubmitPromptWarning(
5923 'You are adding/modifying code'
5924 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
5925 ' PNaCl, PPAPI). See this blog post for more details:\n'
5926 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
5927 'and this documentation for options to replace these technologies:\n'
5928 'https://developer.chrome.com/docs/apps/migration/\n' +
5929 '\n'.join(problems))
5930 ]
Jose Magana2b456f22021-03-09 23:26:405931
Sam Maiera6e76d72022-02-11 21:43:505932 return []
Jose Magana2b456f22021-03-09 23:26:405933
mostynbb639aca52015-01-07 20:31:235934
Saagar Sanghavifceeaae2020-08-12 16:40:365935def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
Sam Maiera6e76d72022-02-11 21:43:505936 """Checks that all source files use SYSLOG properly."""
5937 syslog_files = []
5938 for f in input_api.AffectedSourceFiles(src_file_filter):
5939 for line_number, line in f.ChangedContents():
5940 if 'SYSLOG' in line:
5941 syslog_files.append(f.LocalPath() + ':' + str(line_number))
pastarmovj032ba5bc2017-01-12 10:41:565942
Sam Maiera6e76d72022-02-11 21:43:505943 if syslog_files:
5944 return [
5945 output_api.PresubmitPromptWarning(
5946 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
5947 ' calls.\nFiles to check:\n',
5948 items=syslog_files)
5949 ]
5950 return []
pastarmovj89f7ee12016-09-20 14:58:135951
5952
[email protected]1f7b4172010-01-28 01:17:345953def CheckChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505954 if input_api.version < [2, 0, 0]:
5955 return [
5956 output_api.PresubmitError(
5957 "Your depot_tools is out of date. "
5958 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5959 "but your version is %d.%d.%d" % tuple(input_api.version))
5960 ]
5961 results = []
5962 results.extend(
5963 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
5964 return results
[email protected]ca8d1982009-02-19 16:33:125965
5966
5967def CheckChangeOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505968 if input_api.version < [2, 0, 0]:
5969 return [
5970 output_api.PresubmitError(
5971 "Your depot_tools is out of date. "
5972 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5973 "but your version is %d.%d.%d" % tuple(input_api.version))
5974 ]
Saagar Sanghavifceeaae2020-08-12 16:40:365975
Sam Maiera6e76d72022-02-11 21:43:505976 results = []
5977 # Make sure the tree is 'open'.
5978 results.extend(
5979 input_api.canned_checks.CheckTreeIsOpen(
5980 input_api,
5981 output_api,
5982 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:275983
Sam Maiera6e76d72022-02-11 21:43:505984 results.extend(
5985 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
5986 results.extend(
5987 input_api.canned_checks.CheckChangeHasBugField(input_api, output_api))
5988 results.extend(
5989 input_api.canned_checks.CheckChangeHasNoUnwantedTags(
5990 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505991 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145992
5993
Saagar Sanghavifceeaae2020-08-12 16:40:365994def CheckStrings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505995 """Check string ICU syntax validity and if translation screenshots exist."""
5996 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
5997 # footer is set to true.
5998 git_footers = input_api.change.GitFootersFromDescription()
5999 skip_screenshot_check_footer = [
6000 footer.lower() for footer in git_footers.get(
6001 u'Skip-Translation-Screenshots-Check', [])
6002 ]
6003 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:026004
Sam Maiera6e76d72022-02-11 21:43:506005 import os
6006 import re
6007 import sys
6008 from io import StringIO
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146009
Sam Maiera6e76d72022-02-11 21:43:506010 new_or_added_paths = set(f.LocalPath() for f in input_api.AffectedFiles()
6011 if (f.Action() == 'A' or f.Action() == 'M'))
6012 removed_paths = set(f.LocalPath()
6013 for f in input_api.AffectedFiles(include_deletes=True)
6014 if f.Action() == 'D')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146015
Sam Maiera6e76d72022-02-11 21:43:506016 affected_grds = [
6017 f for f in input_api.AffectedFiles()
6018 if f.LocalPath().endswith(('.grd', '.grdp'))
6019 ]
6020 affected_grds = [
6021 f for f in affected_grds if not 'testdata' in f.LocalPath()
6022 ]
6023 if not affected_grds:
6024 return []
meacer8c0d3832019-12-26 21:46:166025
Sam Maiera6e76d72022-02-11 21:43:506026 affected_png_paths = [
6027 f.AbsoluteLocalPath() for f in input_api.AffectedFiles()
6028 if (f.LocalPath().endswith('.png'))
6029 ]
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146030
Sam Maiera6e76d72022-02-11 21:43:506031 # Check for screenshots. Developers can upload screenshots using
6032 # tools/translation/upload_screenshots.py which finds and uploads
6033 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
6034 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
6035 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
6036 #
6037 # The logic here is as follows:
6038 #
6039 # - If the CL has a .png file under the screenshots directory for a grd
6040 # file, warn the developer. Actual images should never be checked into the
6041 # Chrome repo.
6042 #
6043 # - If the CL contains modified or new messages in grd files and doesn't
6044 # contain the corresponding .sha1 files, warn the developer to add images
6045 # and upload them via tools/translation/upload_screenshots.py.
6046 #
6047 # - If the CL contains modified or new messages in grd files and the
6048 # corresponding .sha1 files, everything looks good.
6049 #
6050 # - If the CL contains removed messages in grd files but the corresponding
6051 # .sha1 files aren't removed, warn the developer to remove them.
6052 unnecessary_screenshots = []
6053 missing_sha1 = []
Bruce Dawson55776c42022-12-09 17:23:476054 missing_sha1_modified = []
Sam Maiera6e76d72022-02-11 21:43:506055 unnecessary_sha1_files = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146056
Sam Maiera6e76d72022-02-11 21:43:506057 # This checks verifies that the ICU syntax of messages this CL touched is
6058 # valid, and reports any found syntax errors.
6059 # Without this presubmit check, ICU syntax errors in Chromium strings can land
6060 # without developers being aware of them. Later on, such ICU syntax errors
6061 # break message extraction for translation, hence would block Chromium
6062 # translations until they are fixed.
6063 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146064
Sam Maiera6e76d72022-02-11 21:43:506065 def _CheckScreenshotAdded(screenshots_dir, message_id):
6066 sha1_path = input_api.os_path.join(screenshots_dir,
6067 message_id + '.png.sha1')
6068 if sha1_path not in new_or_added_paths:
6069 missing_sha1.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146070
Bruce Dawson55776c42022-12-09 17:23:476071 def _CheckScreenshotModified(screenshots_dir, message_id):
6072 sha1_path = input_api.os_path.join(screenshots_dir,
6073 message_id + '.png.sha1')
6074 if sha1_path not in new_or_added_paths:
6075 missing_sha1_modified.append(sha1_path)
6076
Sam Maiera6e76d72022-02-11 21:43:506077 def _CheckScreenshotRemoved(screenshots_dir, message_id):
6078 sha1_path = input_api.os_path.join(screenshots_dir,
6079 message_id + '.png.sha1')
6080 if input_api.os_path.exists(
6081 sha1_path) and sha1_path not in removed_paths:
6082 unnecessary_sha1_files.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146083
Sam Maiera6e76d72022-02-11 21:43:506084 def _ValidateIcuSyntax(text, level, signatures):
6085 """Validates ICU syntax of a text string.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146086
Sam Maiera6e76d72022-02-11 21:43:506087 Check if text looks similar to ICU and checks for ICU syntax correctness
6088 in this case. Reports various issues with ICU syntax and values of
6089 variants. Supports checking of nested messages. Accumulate information of
6090 each ICU messages found in the text for further checking.
Rainhard Findlingfc31844c52020-05-15 09:58:266091
Sam Maiera6e76d72022-02-11 21:43:506092 Args:
6093 text: a string to check.
6094 level: a number of current nesting level.
6095 signatures: an accumulator, a list of tuple of (level, variable,
6096 kind, variants).
Rainhard Findlingfc31844c52020-05-15 09:58:266097
Sam Maiera6e76d72022-02-11 21:43:506098 Returns:
6099 None if a string is not ICU or no issue detected.
6100 A tuple of (message, start index, end index) if an issue detected.
6101 """
6102 valid_types = {
6103 'plural': (frozenset(
6104 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
6105 'other']), frozenset(['=1', 'other'])),
6106 'selectordinal': (frozenset(
6107 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
6108 'other']), frozenset(['one', 'other'])),
6109 'select': (frozenset(), frozenset(['other'])),
6110 }
Rainhard Findlingfc31844c52020-05-15 09:58:266111
Sam Maiera6e76d72022-02-11 21:43:506112 # Check if the message looks like an attempt to use ICU
6113 # plural. If yes - check if its syntax strictly matches ICU format.
6114 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b',
6115 text)
6116 if not like:
6117 signatures.append((level, None, None, None))
6118 return
Rainhard Findlingfc31844c52020-05-15 09:58:266119
Sam Maiera6e76d72022-02-11 21:43:506120 # Check for valid prefix and suffix
6121 m = re.match(
6122 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
6123 r'(plural|selectordinal|select),\s*'
6124 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
6125 if not m:
6126 return (('This message looks like an ICU plural, '
6127 'but does not follow ICU syntax.'), like.start(),
6128 like.end())
6129 starting, variable, kind, variant_pairs = m.groups()
6130 variants, depth, last_pos = _ParseIcuVariants(variant_pairs,
6131 m.start(4))
6132 if depth:
6133 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
6134 len(text))
6135 first = text[0]
6136 ending = text[last_pos:]
6137 if not starting:
6138 return ('Invalid ICU format. No initial opening bracket',
6139 last_pos - 1, last_pos)
6140 if not ending or '}' not in ending:
6141 return ('Invalid ICU format. No final closing bracket',
6142 last_pos - 1, last_pos)
6143 elif first != '{':
6144 return ((
6145 'Invalid ICU format. Extra characters at the start of a complex '
6146 'message (go/icu-message-migration): "%s"') % starting, 0,
6147 len(starting))
6148 elif ending != '}':
6149 return ((
6150 'Invalid ICU format. Extra characters at the end of a complex '
6151 'message (go/icu-message-migration): "%s"') % ending,
6152 last_pos - 1, len(text) - 1)
6153 if kind not in valid_types:
6154 return (('Unknown ICU message type %s. '
6155 'Valid types are: plural, select, selectordinal') % kind,
6156 0, 0)
6157 known, required = valid_types[kind]
6158 defined_variants = set()
6159 for variant, variant_range, value, value_range in variants:
6160 start, end = variant_range
6161 if variant in defined_variants:
6162 return ('Variant "%s" is defined more than once' % variant,
6163 start, end)
6164 elif known and variant not in known:
6165 return ('Variant "%s" is not valid for %s message' %
6166 (variant, kind), start, end)
6167 defined_variants.add(variant)
6168 # Check for nested structure
6169 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
6170 if res:
6171 return (res[0], res[1] + value_range[0] + 1,
6172 res[2] + value_range[0] + 1)
6173 missing = required - defined_variants
6174 if missing:
6175 return ('Required variants missing: %s' % ', '.join(missing), 0,
6176 len(text))
6177 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:266178
Sam Maiera6e76d72022-02-11 21:43:506179 def _ParseIcuVariants(text, offset=0):
6180 """Parse variants part of ICU complex message.
Rainhard Findlingfc31844c52020-05-15 09:58:266181
Sam Maiera6e76d72022-02-11 21:43:506182 Builds a tuple of variant names and values, as well as
6183 their offsets in the input string.
Rainhard Findlingfc31844c52020-05-15 09:58:266184
Sam Maiera6e76d72022-02-11 21:43:506185 Args:
6186 text: a string to parse
6187 offset: additional offset to add to positions in the text to get correct
6188 position in the complete ICU string.
Rainhard Findlingfc31844c52020-05-15 09:58:266189
Sam Maiera6e76d72022-02-11 21:43:506190 Returns:
6191 List of tuples, each tuple consist of four fields: variant name,
6192 variant name span (tuple of two integers), variant value, value
6193 span (tuple of two integers).
6194 """
6195 depth, start, end = 0, -1, -1
6196 variants = []
6197 key = None
6198 for idx, char in enumerate(text):
6199 if char == '{':
6200 if not depth:
6201 start = idx
6202 chunk = text[end + 1:start]
6203 key = chunk.strip()
6204 pos = offset + end + 1 + chunk.find(key)
6205 span = (pos, pos + len(key))
6206 depth += 1
6207 elif char == '}':
6208 if not depth:
6209 return variants, depth, offset + idx
6210 depth -= 1
6211 if not depth:
6212 end = idx
6213 variants.append((key, span, text[start:end + 1],
6214 (offset + start, offset + end + 1)))
6215 return variants, depth, offset + end + 1
Rainhard Findlingfc31844c52020-05-15 09:58:266216
Sam Maiera6e76d72022-02-11 21:43:506217 try:
6218 old_sys_path = sys.path
6219 sys.path = sys.path + [
6220 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
6221 'translation')
6222 ]
6223 from helper import grd_helper
6224 finally:
6225 sys.path = old_sys_path
Rainhard Findlingfc31844c52020-05-15 09:58:266226
Sam Maiera6e76d72022-02-11 21:43:506227 for f in affected_grds:
6228 file_path = f.LocalPath()
6229 old_id_to_msg_map = {}
6230 new_id_to_msg_map = {}
6231 # Note that this code doesn't check if the file has been deleted. This is
6232 # OK because it only uses the old and new file contents and doesn't load
6233 # the file via its path.
6234 # It's also possible that a file's content refers to a renamed or deleted
6235 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
6236 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
6237 # .grdp files.
6238 if file_path.endswith('.grdp'):
6239 if f.OldContents():
6240 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6241 '\n'.join(f.OldContents()))
6242 if f.NewContents():
6243 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6244 '\n'.join(f.NewContents()))
6245 else:
6246 file_dir = input_api.os_path.dirname(file_path) or '.'
6247 if f.OldContents():
6248 old_id_to_msg_map = grd_helper.GetGrdMessages(
6249 StringIO('\n'.join(f.OldContents())), file_dir)
6250 if f.NewContents():
6251 new_id_to_msg_map = grd_helper.GetGrdMessages(
6252 StringIO('\n'.join(f.NewContents())), file_dir)
Rainhard Findlingfc31844c52020-05-15 09:58:266253
Sam Maiera6e76d72022-02-11 21:43:506254 grd_name, ext = input_api.os_path.splitext(
6255 input_api.os_path.basename(file_path))
6256 screenshots_dir = input_api.os_path.join(
6257 input_api.os_path.dirname(file_path),
6258 grd_name + ext.replace('.', '_'))
Rainhard Findlingfc31844c52020-05-15 09:58:266259
Sam Maiera6e76d72022-02-11 21:43:506260 # Compute added, removed and modified message IDs.
6261 old_ids = set(old_id_to_msg_map)
6262 new_ids = set(new_id_to_msg_map)
6263 added_ids = new_ids - old_ids
6264 removed_ids = old_ids - new_ids
6265 modified_ids = set([])
6266 for key in old_ids.intersection(new_ids):
6267 if (old_id_to_msg_map[key].ContentsAsXml('', True) !=
6268 new_id_to_msg_map[key].ContentsAsXml('', True)):
6269 # The message content itself changed. Require an updated screenshot.
6270 modified_ids.add(key)
6271 elif old_id_to_msg_map[key].attrs['meaning'] != \
6272 new_id_to_msg_map[key].attrs['meaning']:
Vincent Boisselle861f11d2023-03-28 21:46:386273 # The message meaning changed. Ensure there is a screenshot for it.
6274 sha1_path = input_api.os_path.join(screenshots_dir,
6275 key + '.png.sha1')
6276 if sha1_path not in new_or_added_paths and not \
6277 input_api.os_path.exists(sha1_path):
6278 # There is neither a previous screenshot nor is a new one added now.
6279 # Require a screenshot.
6280 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146281
Sam Maiera6e76d72022-02-11 21:43:506282 if run_screenshot_check:
6283 # Check the screenshot directory for .png files. Warn if there is any.
6284 for png_path in affected_png_paths:
6285 if png_path.startswith(screenshots_dir):
6286 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146287
Sam Maiera6e76d72022-02-11 21:43:506288 for added_id in added_ids:
6289 _CheckScreenshotAdded(screenshots_dir, added_id)
Rainhard Findlingd8d04372020-08-13 13:30:096290
Sam Maiera6e76d72022-02-11 21:43:506291 for modified_id in modified_ids:
Bruce Dawson55776c42022-12-09 17:23:476292 _CheckScreenshotModified(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146293
Sam Maiera6e76d72022-02-11 21:43:506294 for removed_id in removed_ids:
6295 _CheckScreenshotRemoved(screenshots_dir, removed_id)
6296
6297 # Check new and changed strings for ICU syntax errors.
6298 for key in added_ids.union(modified_ids):
6299 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
6300 err = _ValidateIcuSyntax(msg, 0, [])
6301 if err is not None:
6302 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
6303
6304 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:266305 if run_screenshot_check:
Sam Maiera6e76d72022-02-11 21:43:506306 if unnecessary_screenshots:
6307 results.append(
6308 output_api.PresubmitError(
6309 'Do not include actual screenshots in the changelist. Run '
6310 'tools/translate/upload_screenshots.py to upload them instead:',
6311 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146312
Sam Maiera6e76d72022-02-11 21:43:506313 if missing_sha1:
6314 results.append(
6315 output_api.PresubmitError(
Bruce Dawson55776c42022-12-09 17:23:476316 'You are adding UI strings.\n'
Sam Maiera6e76d72022-02-11 21:43:506317 'To ensure the best translations, take screenshots of the relevant UI '
6318 '(https://g.co/chrome/translation) and add these files to your '
6319 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146320
Bruce Dawson55776c42022-12-09 17:23:476321 if missing_sha1_modified:
6322 results.append(
6323 output_api.PresubmitError(
6324 'You are modifying UI strings or their meanings.\n'
6325 'To ensure the best translations, take screenshots of the relevant UI '
6326 '(https://g.co/chrome/translation) and add these files to your '
6327 'changelist:', sorted(missing_sha1_modified)))
6328
Sam Maiera6e76d72022-02-11 21:43:506329 if unnecessary_sha1_files:
6330 results.append(
6331 output_api.PresubmitError(
6332 'You removed strings associated with these files. Remove:',
6333 sorted(unnecessary_sha1_files)))
6334 else:
6335 results.append(
6336 output_api.PresubmitPromptOrNotify('Skipping translation '
6337 'screenshots check.'))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146338
Sam Maiera6e76d72022-02-11 21:43:506339 if icu_syntax_errors:
6340 results.append(
6341 output_api.PresubmitPromptWarning(
6342 'ICU syntax errors were found in the following strings (problems or '
6343 'feedback? Contact [email protected]):',
6344 items=icu_syntax_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:266345
Sam Maiera6e76d72022-02-11 21:43:506346 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:126347
6348
Saagar Sanghavifceeaae2020-08-12 16:40:366349def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:126350 repo_root=None,
6351 translation_expectations_path=None,
6352 grd_files=None):
Sam Maiera6e76d72022-02-11 21:43:506353 import sys
6354 affected_grds = [
6355 f for f in input_api.AffectedFiles()
6356 if (f.LocalPath().endswith('.grd') or f.LocalPath().endswith('.grdp'))
6357 ]
6358 if not affected_grds:
6359 return []
6360
6361 try:
6362 old_sys_path = sys.path
6363 sys.path = sys.path + [
6364 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
6365 'translation')
6366 ]
6367 from helper import git_helper
6368 from helper import translation_helper
6369 finally:
6370 sys.path = old_sys_path
6371
6372 # Check that translation expectations can be parsed and we can get a list of
6373 # translatable grd files. |repo_root| and |translation_expectations_path| are
6374 # only passed by tests.
6375 if not repo_root:
6376 repo_root = input_api.PresubmitLocalPath()
6377 if not translation_expectations_path:
6378 translation_expectations_path = input_api.os_path.join(
6379 repo_root, 'tools', 'gritsettings', 'translation_expectations.pyl')
6380 if not grd_files:
6381 grd_files = git_helper.list_grds_in_repository(repo_root)
6382
6383 # Ignore bogus grd files used only for testing
Gao Shenga79ebd42022-08-08 17:25:596384 # ui/webui/resources/tools/generate_grd.py.
Sam Maiera6e76d72022-02-11 21:43:506385 ignore_path = input_api.os_path.join('ui', 'webui', 'resources', 'tools',
6386 'tests')
6387 grd_files = [p for p in grd_files if ignore_path not in p]
6388
6389 try:
6390 translation_helper.get_translatable_grds(
6391 repo_root, grd_files, translation_expectations_path)
6392 except Exception as e:
6393 return [
6394 output_api.PresubmitNotifyResult(
6395 'Failed to get a list of translatable grd files. This happens when:\n'
6396 ' - One of the modified grd or grdp files cannot be parsed or\n'
6397 ' - %s is not updated.\n'
6398 'Stack:\n%s' % (translation_expectations_path, str(e)))
6399 ]
Mustafa Emre Acer51f2f742020-03-09 19:41:126400 return []
6401
Ken Rockotc31f4832020-05-29 18:58:516402
Saagar Sanghavifceeaae2020-08-12 16:40:366403def CheckStableMojomChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506404 """Changes to [Stable] mojom types must preserve backward-compatibility."""
6405 changed_mojoms = input_api.AffectedFiles(
6406 include_deletes=True,
6407 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:526408
Bruce Dawson344ab262022-06-04 11:35:106409 if not changed_mojoms or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:506410 return []
6411
6412 delta = []
6413 for mojom in changed_mojoms:
Sam Maiera6e76d72022-02-11 21:43:506414 delta.append({
6415 'filename': mojom.LocalPath(),
6416 'old': '\n'.join(mojom.OldContents()) or None,
6417 'new': '\n'.join(mojom.NewContents()) or None,
6418 })
6419
6420 process = input_api.subprocess.Popen([
Takuto Ikutadca10222022-04-13 02:51:216421 input_api.python3_executable,
Sam Maiera6e76d72022-02-11 21:43:506422 input_api.os_path.join(
6423 input_api.PresubmitLocalPath(), 'mojo', 'public', 'tools', 'mojom',
6424 'check_stable_mojom_compatibility.py'), '--src-root',
6425 input_api.PresubmitLocalPath()
6426 ],
6427 stdin=input_api.subprocess.PIPE,
6428 stdout=input_api.subprocess.PIPE,
6429 stderr=input_api.subprocess.PIPE,
6430 universal_newlines=True)
6431 (x, error) = process.communicate(input=input_api.json.dumps(delta))
6432 if process.returncode:
6433 return [
6434 output_api.PresubmitError(
6435 'One or more [Stable] mojom definitions appears to have been changed '
6436 'in a way that is not backward-compatible.',
6437 long_text=error)
6438 ]
Erik Staabc734cd7a2021-11-23 03:11:526439 return []
6440
Dominic Battre645d42342020-12-04 16:14:106441def CheckDeprecationOfPreferences(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506442 """Removing a preference should come with a deprecation."""
Dominic Battre645d42342020-12-04 16:14:106443
Sam Maiera6e76d72022-02-11 21:43:506444 def FilterFile(affected_file):
6445 """Accept only .cc files and the like."""
6446 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
6447 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
6448 input_api.DEFAULT_FILES_TO_SKIP)
6449 return input_api.FilterSourceFile(
6450 affected_file,
6451 files_to_check=file_inclusion_pattern,
6452 files_to_skip=files_to_skip)
Dominic Battre645d42342020-12-04 16:14:106453
Sam Maiera6e76d72022-02-11 21:43:506454 def ModifiedLines(affected_file):
6455 """Returns a list of tuples (line number, line text) of added and removed
6456 lines.
Dominic Battre645d42342020-12-04 16:14:106457
Sam Maiera6e76d72022-02-11 21:43:506458 Deleted lines share the same line number as the previous line.
Dominic Battre645d42342020-12-04 16:14:106459
Sam Maiera6e76d72022-02-11 21:43:506460 This relies on the scm diff output describing each changed code section
6461 with a line of the form
Dominic Battre645d42342020-12-04 16:14:106462
Sam Maiera6e76d72022-02-11 21:43:506463 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
6464 """
6465 line_num = 0
6466 modified_lines = []
6467 for line in affected_file.GenerateScmDiff().splitlines():
6468 # Extract <new line num> of the patch fragment (see format above).
6469 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@',
6470 line)
6471 if m:
6472 line_num = int(m.groups(1)[0])
6473 continue
6474 if ((line.startswith('+') and not line.startswith('++'))
6475 or (line.startswith('-') and not line.startswith('--'))):
6476 modified_lines.append((line_num, line))
Dominic Battre645d42342020-12-04 16:14:106477
Sam Maiera6e76d72022-02-11 21:43:506478 if not line.startswith('-'):
6479 line_num += 1
6480 return modified_lines
Dominic Battre645d42342020-12-04 16:14:106481
Sam Maiera6e76d72022-02-11 21:43:506482 def FindLineWith(lines, needle):
6483 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
Dominic Battre645d42342020-12-04 16:14:106484
Sam Maiera6e76d72022-02-11 21:43:506485 If 0 or >1 lines contain `needle`, -1 is returned.
6486 """
6487 matching_line_numbers = [
6488 # + 1 for 1-based counting of line numbers.
6489 i + 1 for i, line in enumerate(lines) if needle in line
6490 ]
6491 return matching_line_numbers[0] if len(
6492 matching_line_numbers) == 1 else -1
Dominic Battre645d42342020-12-04 16:14:106493
Sam Maiera6e76d72022-02-11 21:43:506494 def ModifiedPrefMigration(affected_file):
6495 """Returns whether the MigrateObsolete.*Pref functions were modified."""
6496 # Determine first and last lines of MigrateObsolete.*Pref functions.
6497 new_contents = affected_file.NewContents()
6498 range_1 = (FindLineWith(new_contents,
6499 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
6500 FindLineWith(new_contents,
6501 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
6502 range_2 = (FindLineWith(new_contents,
6503 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
6504 FindLineWith(new_contents,
6505 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
6506 if (-1 in range_1 + range_2):
6507 raise Exception(
6508 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.'
6509 )
Dominic Battre645d42342020-12-04 16:14:106510
Sam Maiera6e76d72022-02-11 21:43:506511 # Check whether any of the modified lines are part of the
6512 # MigrateObsolete.*Pref functions.
6513 for line_nr, line in ModifiedLines(affected_file):
6514 if (range_1[0] <= line_nr <= range_1[1]
6515 or range_2[0] <= line_nr <= range_2[1]):
6516 return True
6517 return False
Dominic Battre645d42342020-12-04 16:14:106518
Sam Maiera6e76d72022-02-11 21:43:506519 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
6520 browser_prefs_file_pattern = input_api.re.compile(
6521 r'chrome/browser/prefs/browser_prefs.cc')
Dominic Battre645d42342020-12-04 16:14:106522
Sam Maiera6e76d72022-02-11 21:43:506523 changes = input_api.AffectedFiles(include_deletes=True,
6524 file_filter=FilterFile)
6525 potential_problems = []
6526 for f in changes:
6527 for line in f.GenerateScmDiff().splitlines():
6528 # Check deleted lines for pref registrations.
6529 if (line.startswith('-') and not line.startswith('--')
6530 and register_pref_pattern.search(line)):
6531 potential_problems.append('%s: %s' % (f.LocalPath(), line))
Dominic Battre645d42342020-12-04 16:14:106532
Sam Maiera6e76d72022-02-11 21:43:506533 if browser_prefs_file_pattern.search(f.LocalPath()):
6534 # If the developer modified the MigrateObsolete.*Prefs() functions, we
6535 # assume that they knew that they have to deprecate preferences and don't
6536 # warn.
6537 try:
6538 if ModifiedPrefMigration(f):
6539 return []
6540 except Exception as e:
6541 return [output_api.PresubmitError(str(e))]
Dominic Battre645d42342020-12-04 16:14:106542
Sam Maiera6e76d72022-02-11 21:43:506543 if potential_problems:
6544 return [
6545 output_api.PresubmitPromptWarning(
6546 'Discovered possible removal of preference registrations.\n\n'
6547 'Please make sure to properly deprecate preferences by clearing their\n'
6548 'value for a couple of milestones before finally removing the code.\n'
6549 'Otherwise data may stay in the preferences files forever. See\n'
6550 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
6551 'chrome/browser/prefs/README.md for examples.\n'
6552 'This may be a false positive warning (e.g. if you move preference\n'
6553 'registrations to a different place).\n', potential_problems)
6554 ]
6555 return []
6556
Matt Stark6ef08872021-07-29 01:21:466557
6558def CheckConsistentGrdChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506559 """Changes to GRD files must be consistent for tools to read them."""
6560 changed_grds = input_api.AffectedFiles(
6561 include_deletes=False,
6562 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
6563 errors = []
6564 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
6565 for matcher, msg in _INVALID_GRD_FILE_LINE]
6566 for grd in changed_grds:
6567 for i, line in enumerate(grd.NewContents()):
6568 for matcher, msg in invalid_file_regexes:
6569 if matcher.search(line):
6570 errors.append(
6571 output_api.PresubmitError(
6572 'Problem on {grd}:{i} - {msg}'.format(
6573 grd=grd.LocalPath(), i=i + 1, msg=msg)))
6574 return errors
6575
Kevin McNee967dd2d22021-11-15 16:09:296576
Henrique Ferreiro2a4b55942021-11-29 23:45:366577def CheckAssertAshOnlyCode(input_api, output_api):
6578 """Errors if a BUILD.gn file in an ash/ directory doesn't include
6579 assert(is_chromeos_ash).
6580 """
6581
6582 def FileFilter(affected_file):
6583 """Includes directories known to be Ash only."""
6584 return input_api.FilterSourceFile(
6585 affected_file,
6586 files_to_check=(
6587 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
6588 r'.*/ash/.*BUILD\.gn'), # Any path component.
6589 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
6590
6591 errors = []
6592 pattern = input_api.re.compile(r'assert\(is_chromeos_ash')
Jameson Thies0ce669f2021-12-09 15:56:566593 for f in input_api.AffectedFiles(include_deletes=False,
6594 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:366595 if (not pattern.search(input_api.ReadFile(f))):
6596 errors.append(
6597 output_api.PresubmitError(
6598 'Please add assert(is_chromeos_ash) to %s. If that\'s not '
6599 'possible, please create and issue and add a comment such '
6600 'as:\n # TODO(https://crbug.com/XXX): add '
6601 'assert(is_chromeos_ash) when ...' % f.LocalPath()))
6602 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:276603
6604
6605def _IsRendererOnlyCppFile(input_api, affected_file):
Sam Maiera6e76d72022-02-11 21:43:506606 path = affected_file.LocalPath()
6607 if not _IsCPlusPlusFile(input_api, path):
6608 return False
6609
6610 # Any code under a "renderer" subdirectory is assumed to be Renderer-only.
6611 if "/renderer/" in path:
6612 return True
6613
6614 # Blink's public/web API is only used/included by Renderer-only code. Note
6615 # that public/platform API may be used in non-Renderer processes (e.g. there
6616 # are some includes in code used by Utility, PDF, or Plugin processes).
6617 if "/blink/public/web/" in path:
6618 return True
6619
6620 # We assume that everything else may be used outside of Renderer processes.
Lukasz Anforowicz7016d05e2021-11-30 03:56:276621 return False
6622
Lukasz Anforowicz7016d05e2021-11-30 03:56:276623# TODO(https://crbug.com/1273182): Remove these checks, once they are replaced
6624# by the Chromium Clang Plugin (which will be preferable because it will
6625# 1) report errors earlier - at compile-time and 2) cover more rules).
6626def CheckRawPtrUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506627 """Rough checks that raw_ptr<T> usage guidelines are followed."""
6628 errors = []
6629 # The regex below matches "raw_ptr<" following a word boundary, but not in a
6630 # C++ comment.
6631 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
6632 file_filter = lambda f: _IsRendererOnlyCppFile(input_api, f)
6633 for f, line_num, line in input_api.RightHandSideLines(file_filter):
6634 if raw_ptr_matcher.search(line):
6635 errors.append(
6636 output_api.PresubmitError(
6637 'Problem on {path}:{line} - '\
6638 'raw_ptr<T> should not be used in Renderer-only code '\
6639 '(as documented in the "Pointers to unprotected memory" '\
6640 'section in //base/memory/raw_ptr.md)'.format(
6641 path=f.LocalPath(), line=line_num)))
6642 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:566643
6644
6645def CheckPythonShebang(input_api, output_api):
6646 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
6647 system-wide python.
6648 """
6649 errors = []
6650 sources = lambda affected_file: input_api.FilterSourceFile(
6651 affected_file,
6652 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
6653 r'third_party/blink/web_tests/external/') + input_api.
6654 DEFAULT_FILES_TO_SKIP),
6655 files_to_check=[r'.*\.py$'])
6656 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:276657 for line_num, line in f.ChangedContents():
6658 if line_num == 1 and line.startswith('#!/usr/bin/python'):
6659 errors.append(f.LocalPath())
6660 break
Henrique Ferreirof9819f2e32021-11-30 13:31:566661
6662 result = []
6663 for file in errors:
6664 result.append(
6665 output_api.PresubmitError(
6666 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
6667 file))
6668 return result
James Shen81cc0e22022-06-15 21:10:456669
6670
6671def CheckBatchAnnotation(input_api, output_api):
6672 """Checks that tests have either @Batch or @DoNotBatch annotation. If this
6673 is not an instrumentation test, disregard."""
6674
6675 batch_annotation = input_api.re.compile(r'^\s*@Batch')
6676 do_not_batch_annotation = input_api.re.compile(r'^\s*@DoNotBatch')
6677 robolectric_test = input_api.re.compile(r'[rR]obolectric')
6678 test_class_declaration = input_api.re.compile(r'^\s*public\sclass.*Test')
6679 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
6680
ckitagawae8fd23b2022-06-17 15:29:386681 missing_annotation_errors = []
6682 extra_annotation_errors = []
James Shen81cc0e22022-06-15 21:10:456683
6684 def _FilterFile(affected_file):
6685 return input_api.FilterSourceFile(
6686 affected_file,
6687 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
6688 files_to_check=[r'.*Test\.java$'])
6689
6690 for f in input_api.AffectedSourceFiles(_FilterFile):
6691 batch_matched = None
6692 do_not_batch_matched = None
6693 is_instrumentation_test = True
6694 for line in f.NewContents():
6695 if robolectric_test.search(line) or uiautomator_test.search(line):
6696 # Skip Robolectric and UiAutomator tests.
6697 is_instrumentation_test = False
6698 break
6699 if not batch_matched:
6700 batch_matched = batch_annotation.search(line)
6701 if not do_not_batch_matched:
6702 do_not_batch_matched = do_not_batch_annotation.search(line)
6703 test_class_declaration_matched = test_class_declaration.search(
6704 line)
6705 if test_class_declaration_matched:
6706 break
6707 if (is_instrumentation_test and
6708 not batch_matched and
6709 not do_not_batch_matched):
Sam Maier4cef9242022-10-03 14:21:246710 missing_annotation_errors.append(str(f.LocalPath()))
ckitagawae8fd23b2022-06-17 15:29:386711 if (not is_instrumentation_test and
6712 (batch_matched or
6713 do_not_batch_matched)):
Sam Maier4cef9242022-10-03 14:21:246714 extra_annotation_errors.append(str(f.LocalPath()))
James Shen81cc0e22022-06-15 21:10:456715
6716 results = []
6717
ckitagawae8fd23b2022-06-17 15:29:386718 if missing_annotation_errors:
James Shen81cc0e22022-06-15 21:10:456719 results.append(
6720 output_api.PresubmitPromptWarning(
6721 """
Henrique Nakashimacb4c55a2023-01-30 20:09:096722Instrumentation tests should use either @Batch or @DoNotBatch. Use
6723@Batch(Batch.PER_CLASS) in most cases. Use @Batch(Batch.UNIT_TESTS) when tests
6724have no side-effects. If the tests are not safe to run in batch, please use
6725@DoNotBatch with reasons.
Jens Mueller2085ff82023-02-27 11:54:496726See https://source.chromium.org/chromium/chromium/src/+/main:docs/testing/batching_instrumentation_tests.md
ckitagawae8fd23b2022-06-17 15:29:386727""", missing_annotation_errors))
6728 if extra_annotation_errors:
6729 results.append(
6730 output_api.PresubmitPromptWarning(
6731 """
6732Robolectric tests do not need a @Batch or @DoNotBatch annotations.
6733""", extra_annotation_errors))
James Shen81cc0e22022-06-15 21:10:456734
6735 return results
Sam Maier4cef9242022-10-03 14:21:246736
6737
6738def CheckMockAnnotation(input_api, output_api):
6739 """Checks that we have annotated all Mockito.mock()-ed or Mockito.spy()-ed
6740 classes with @Mock or @Spy. If this is not an instrumentation test,
6741 disregard."""
6742
6743 # This is just trying to be approximately correct. We are not writing a
6744 # Java parser, so special cases like statically importing mock() then
6745 # calling an unrelated non-mockito spy() function will cause a false
6746 # positive.
6747 package_name = input_api.re.compile(r'^package\s+(\w+(?:\.\w+)+);')
6748 mock_static_import = input_api.re.compile(
6749 r'^import\s+static\s+org.mockito.Mockito.(?:mock|spy);')
6750 import_class = input_api.re.compile(r'import\s+((?:\w+\.)+)(\w+);')
6751 mock_annotation = input_api.re.compile(r'^\s*@(?:Mock|Spy)')
6752 field_type = input_api.re.compile(r'(\w+)(?:<\w+>)?\s+\w+\s*(?:;|=)')
6753 mock_or_spy_function_call = r'(?:mock|spy)\(\s*(?:new\s*)?(\w+)(?:\.class|\()'
6754 fully_qualified_mock_function = input_api.re.compile(
6755 r'Mockito\.' + mock_or_spy_function_call)
6756 statically_imported_mock_function = input_api.re.compile(
6757 r'\W' + mock_or_spy_function_call)
6758 robolectric_test = input_api.re.compile(r'[rR]obolectric')
6759 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
6760
6761 def _DoClassLookup(class_name, class_name_map, package):
6762 found = class_name_map.get(class_name)
6763 if found is not None:
6764 return found
6765 else:
6766 return package + '.' + class_name
6767
6768 def _FilterFile(affected_file):
6769 return input_api.FilterSourceFile(
6770 affected_file,
6771 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
6772 files_to_check=[r'.*Test\.java$'])
6773
6774 mocked_by_function_classes = set()
6775 mocked_by_annotation_classes = set()
6776 class_to_filename = {}
6777 for f in input_api.AffectedSourceFiles(_FilterFile):
6778 mock_function_regex = fully_qualified_mock_function
6779 next_line_is_annotated = False
6780 fully_qualified_class_map = {}
6781 package = None
6782
6783 for line in f.NewContents():
6784 if robolectric_test.search(line) or uiautomator_test.search(line):
6785 # Skip Robolectric and UiAutomator tests.
6786 break
6787
6788 m = package_name.search(line)
6789 if m:
6790 package = m.group(1)
6791 continue
6792
6793 if mock_static_import.search(line):
6794 mock_function_regex = statically_imported_mock_function
6795 continue
6796
6797 m = import_class.search(line)
6798 if m:
6799 fully_qualified_class_map[m.group(2)] = m.group(1) + m.group(2)
6800 continue
6801
6802 if next_line_is_annotated:
6803 next_line_is_annotated = False
6804 fully_qualified_class = _DoClassLookup(
6805 field_type.search(line).group(1), fully_qualified_class_map,
6806 package)
6807 mocked_by_annotation_classes.add(fully_qualified_class)
6808 continue
6809
6810 if mock_annotation.search(line):
6811 next_line_is_annotated = True
6812 continue
6813
6814 m = mock_function_regex.search(line)
6815 if m:
6816 fully_qualified_class = _DoClassLookup(m.group(1),
6817 fully_qualified_class_map, package)
6818 # Skipping builtin classes, since they don't get optimized.
6819 if fully_qualified_class.startswith(
6820 'android.') or fully_qualified_class.startswith(
6821 'java.'):
6822 continue
6823 class_to_filename[fully_qualified_class] = str(f.LocalPath())
6824 mocked_by_function_classes.add(fully_qualified_class)
6825
6826 results = []
6827 missed_classes = mocked_by_function_classes - mocked_by_annotation_classes
6828 if missed_classes:
6829 error_locations = []
6830 for c in missed_classes:
6831 error_locations.append(c + ' in ' + class_to_filename[c])
6832 results.append(
6833 output_api.PresubmitPromptWarning(
6834 """
6835Mockito.mock()/spy() cause issues with our Java optimizer. You have 3 options:
68361) If the mocked variable can be a class member, annotate the member with
6837 @Mock/@Spy.
68382) If the mocked variable cannot be a class member, create a dummy member
6839 variable of that type, annotated with @Mock/@Spy. This dummy does not need
6840 to be used or initialized in any way.
68413) If the mocked type is definitely not going to be optimized, whether it's a
6842 builtin type which we don't ship, or a class you know R8 will treat
6843 specially, you can ignore this warning.
6844""", error_locations))
6845
6846 return results
Mike Dougherty1b8be712022-10-20 00:15:136847
6848def CheckNoJsInIos(input_api, output_api):
6849 """Checks to make sure that JavaScript files are not used on iOS."""
6850
6851 def _FilterFile(affected_file):
6852 return input_api.FilterSourceFile(
6853 affected_file,
6854 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP +
Mike Dougherty7bc8a812023-05-02 06:55:216855 (r'^ios/third_party/*', r'^ios/tools/*', r'^third_party/*'),
Mike Dougherty1b8be712022-10-20 00:15:136856 files_to_check=[r'^ios/.*\.js$', r'.*/ios/.*\.js$'])
6857
Mike Dougherty4d1050b2023-03-14 15:59:536858 deleted_files = []
6859
6860 # Collect filenames of all removed JS files.
6861 for f in input_api.AffectedSourceFiles(_FilterFile):
6862 local_path = f.LocalPath()
6863
6864 if input_api.os_path.splitext(local_path)[1] == '.js' and f.Action() == 'D':
6865 deleted_files.append(input_api.os_path.basename(local_path))
6866
Mike Dougherty1b8be712022-10-20 00:15:136867 error_paths = []
Mike Dougherty4d1050b2023-03-14 15:59:536868 moved_paths = []
Mike Dougherty1b8be712022-10-20 00:15:136869 warning_paths = []
6870
6871 for f in input_api.AffectedSourceFiles(_FilterFile):
6872 local_path = f.LocalPath()
6873
6874 if input_api.os_path.splitext(local_path)[1] == '.js':
6875 if f.Action() == 'A':
Mike Dougherty4d1050b2023-03-14 15:59:536876 if input_api.os_path.basename(local_path) in deleted_files:
6877 # This script was probably moved rather than newly created.
6878 # Present a warning instead of an error for these cases.
6879 moved_paths.append(local_path)
6880 else:
6881 error_paths.append(local_path)
Mike Dougherty1b8be712022-10-20 00:15:136882 elif f.Action() != 'D':
6883 warning_paths.append(local_path)
6884
6885 results = []
6886
6887 if warning_paths:
6888 results.append(output_api.PresubmitPromptWarning(
6889 'TypeScript is now fully supported for iOS feature scripts. '
6890 'Consider converting JavaScript files to TypeScript. See '
6891 '//ios/web/public/js_messaging/README.md for more details.',
6892 warning_paths))
6893
Mike Dougherty4d1050b2023-03-14 15:59:536894 if moved_paths:
6895 results.append(output_api.PresubmitPromptWarning(
6896 'Do not use JavaScript on iOS for new files as TypeScript is '
6897 'fully supported. (If this is a moved file, you may leave the '
6898 'script unconverted.) See //ios/web/public/js_messaging/README.md '
6899 'for help using scripts on iOS.', moved_paths))
6900
Mike Dougherty1b8be712022-10-20 00:15:136901 if error_paths:
6902 results.append(output_api.PresubmitError(
6903 'Do not use JavaScript on iOS as TypeScript is fully supported. '
6904 'See //ios/web/public/js_messaging/README.md for help using '
6905 'scripts on iOS.', error_paths))
6906
6907 return results
Hans Wennborg23a81d52023-03-24 16:38:136908
6909def CheckLibcxxRevisionsMatch(input_api, output_api):
6910 """Check to make sure the libc++ version matches across deps files."""
Andrew Grieve21bb6792023-03-27 19:06:486911 # Disable check for changes to sub-repositories.
6912 if input_api.PresubmitLocalPath() != input_api.change.RepositoryRoot():
6913 return []
Hans Wennborg23a81d52023-03-24 16:38:136914
6915 DEPS_FILES = [ 'DEPS', 'buildtools/deps_revisions.gni' ]
6916
6917 file_filter = lambda f: f.LocalPath().replace(
6918 input_api.os_path.sep, '/') in DEPS_FILES
6919 changed_deps_files = input_api.AffectedFiles(file_filter=file_filter)
6920 if not changed_deps_files:
6921 return []
6922
6923 def LibcxxRevision(file):
6924 file = input_api.os_path.join(input_api.PresubmitLocalPath(),
6925 *file.split('/'))
6926 return input_api.re.search(
6927 r'libcxx_revision.*[:=].*[\'"](\w+)[\'"]',
6928 input_api.ReadFile(file)).group(1)
6929
6930 if len(set([LibcxxRevision(f) for f in DEPS_FILES])) == 1:
6931 return []
6932
6933 return [output_api.PresubmitError(
6934 'libcxx_revision not equal across %s' % ', '.join(DEPS_FILES),
6935 changed_deps_files)]