Thanks to visit codestin.com
Credit goes to chromium.googlesource.com

blob: 6f3b72a7add7c9d27bb448fd9447c7a48cbd63b8 [file] [log] [blame]
Avi Drissman24976592022-09-12 15:24:311# Copyright 2012 The Chromium Authors
[email protected]ca8d19842009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
Daniel Chengd88244472022-05-16 09:08:477See https://www.chromium.org/developers/how-tos/depottools/presubmit-scripts/
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d19842009-02-19 16:33:129"""
Daniel Chenga44a1bcd2022-03-15 20:00:1510
Daniel Chenga37c03db2022-05-12 17:20:3411from typing import Callable
Daniel Chenga44a1bcd2022-03-15 20:00:1512from typing import Optional
13from typing import Sequence
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]ca8d19842009-02-19 16:33:1256
John Abd-El-Malek759fea62021-03-13 03:41:1457_EXCLUDED_SET_NO_PARENT_PATHS = (
58 # It's for historical reasons that blink isn't a top level directory, where
59 # it would be allowed to have "set noparent" to avoid top level owners
60 # accidentally +1ing changes.
61 'third_party/blink/OWNERS',
62)
63
wnwenbdc444e2016-05-25 13:44:1564
[email protected]06e6d0ff2012-12-11 01:36:4465# Fragment of a regular expression that matches C++ and Objective-C++
66# implementation files.
67_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
68
wnwenbdc444e2016-05-25 13:44:1569
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1970# Fragment of a regular expression that matches C++ and Objective-C++
71# header files.
72_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
73
74
Aleksey Khoroshilov9b28c032022-06-03 16:35:3275# Paths with sources that don't use //base.
76_NON_BASE_DEPENDENT_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:3177 r"^chrome/browser/browser_switcher/bho/",
78 r"^tools/win/",
Aleksey Khoroshilov9b28c032022-06-03 16:35:3279)
80
81
[email protected]06e6d0ff2012-12-11 01:36:4482# Regular expression that matches code only used for test binaries
83# (best effort).
84_TEST_CODE_EXCLUDED_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:3185 r'.*/(fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[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]ca8d19842009-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 Thiessen0f2547e32020-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.*',
Adithya Srinivasanb2041882022-10-21 19:34:20973 # Needed to use liburlpattern API.
974 r'third_party/blink/renderer/core/url_pattern/.*',
Louise Brettc6d23872023-04-11 02:48:32975 r'third_party/blink/renderer/modules/manifest/manifest_parser\.cc',
David Benjamin3a305f12022-11-19 00:10:03976 # Needed to use QUICHE API.
Victor Vasilieva13f1932022-12-02 15:27:24977 r'net/quic/.*',
978 r'net/spdy/.*',
David Benjamin3a305f12022-11-19 00:10:03979 r'net/test/embedded_test_server/.*',
Victor Vasilieva13f1932022-12-02 15:27:24980 r'net/third_party/quiche/.*',
981 r'services/network/web_transport\.cc',
David Benjaminea985a22023-04-18 22:05:01982 # This code is in the process of being extracted into an external
983 # library, where //base will be unavailable.
984 r'net/cert/pki/.*',
985 r'net/der/.*',
986 # Needed to use APIs from the above.
987 r'net/cert/.*',
Adithya Srinivasanb2041882022-10-21 19:34:20988 # Not an error in third_party folders.
989 _THIRD_PARTY_EXCEPT_BLINK
990 ],
Peter Kasting4f35bfc2022-10-18 18:39:12991 ),
992 BanRule(
993 r'/\babsl::(StrSplit|StrJoin|StrCat|StrAppend|Substitute|StrContains)\b',
994 (
995 'Abseil string utilities are banned. Use base/strings instead.',
996 ),
997 True,
998 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
999 ),
1000 BanRule(
1001 r'/\babsl::(Mutex|CondVar|Notification|Barrier|BlockingCounter)\b',
1002 (
1003 'Abseil synchronization primitives are banned. Use',
1004 'base/synchronization instead.',
1005 ),
1006 True,
1007 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1008 ),
1009 BanRule(
1010 r'/\babsl::(Duration|Time|TimeZone|CivilDay)\b',
1011 (
1012 'Abseil\'s time library is banned. Use base/time instead.',
1013 ),
1014 True,
1015 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1016 ),
1017 BanRule(
Avi Drissman48ee39e2022-02-16 16:31:031018 r'/\bstd::optional\b',
1019 (
Peter Kastinge2c5ee82023-02-15 17:23:081020 'std::optional is not allowed yet (https://crbug.com/1373619). Use ',
1021 'absl::optional instead.',
Avi Drissman48ee39e2022-02-16 16:31:031022 ),
1023 True,
1024 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1025 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151026 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081027 r'/#include <chrono>',
Daniel Bratell609102be2019-03-27 20:53:211028 (
Peter Kastinge2c5ee82023-02-15 17:23:081029 '<chrono> is banned. Use base/time instead.',
Daniel Bratell609102be2019-03-27 20:53:211030 ),
1031 True,
1032 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1033 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151034 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081035 r'/#include <exception>',
Daniel Bratell609102be2019-03-27 20:53:211036 (
1037 'Exceptions are banned and disabled in Chromium.',
1038 ),
1039 True,
1040 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1041 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151042 BanRule(
Daniel Bratell609102be2019-03-27 20:53:211043 r'/\bstd::function\b',
1044 (
Peter Kastinge2c5ee82023-02-15 17:23:081045 'std::function is banned. Use base::{Once,Repeating}Callback instead.',
Daniel Bratell609102be2019-03-27 20:53:211046 ),
Daniel Chenge5583e3c2022-09-22 00:19:411047 True,
Daniel Chengcd23b8b2022-09-16 17:16:241048 [
1049 # Has tests that template trait helpers don't unintentionally match
1050 # std::function.
Daniel Chenge5583e3c2022-09-22 00:19:411051 r'base/functional/callback_helpers_unittest\.cc',
1052 # Required to implement interfaces from the third-party perfetto
1053 # library.
1054 r'base/tracing/perfetto_task_runner\.cc',
1055 r'base/tracing/perfetto_task_runner\.h',
1056 # Needed for interop with the third-party nearby library type
1057 # location::nearby::connections::ResultCallback.
1058 'chrome/services/sharing/nearby/nearby_connections_conversions\.cc'
1059 # Needed for interop with the internal libassistant library.
1060 'chromeos/ash/services/libassistant/callback_utils\.h',
1061 # Needed for interop with Fuchsia fidl APIs.
1062 'fuchsia_web/webengine/browser/context_impl_browsertest\.cc',
1063 'fuchsia_web/webengine/browser/cookie_manager_impl_unittest\.cc',
1064 'fuchsia_web/webengine/browser/media_player_impl_unittest\.cc',
1065 # Required to interop with interfaces from the third-party perfetto
1066 # library.
1067 'services/tracing/public/cpp/perfetto/custom_event_recorder\.cc',
1068 'services/tracing/public/cpp/perfetto/perfetto_traced_process\.cc',
1069 'services/tracing/public/cpp/perfetto/perfetto_traced_process\.h',
1070 'services/tracing/public/cpp/perfetto/perfetto_tracing_backend\.cc',
1071 'services/tracing/public/cpp/perfetto/producer_client\.cc',
1072 'services/tracing/public/cpp/perfetto/producer_client\.h',
1073 'services/tracing/public/cpp/perfetto/producer_test_utils\.cc',
1074 'services/tracing/public/cpp/perfetto/producer_test_utils\.h',
1075 # Required for interop with the third-party webrtc library.
1076 'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.cc',
1077 'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.h',
Bob Beck5fc0be82022-12-12 23:32:521078 # This code is in the process of being extracted into a third-party library.
1079 # See https://crbug.com/1322914
1080 '^net/cert/pki/path_builder_unittest\.cc',
Daniel Chenge5583e3c2022-09-22 00:19:411081 # TODO(https://crbug.com/1364577): Various uses that should be
1082 # migrated to something else.
1083 # Should use base::OnceCallback or base::RepeatingCallback.
1084 'base/allocator/dispatcher/initializer_unittest\.cc',
1085 'chrome/browser/ash/accessibility/speech_monitor\.cc',
1086 'chrome/browser/ash/accessibility/speech_monitor\.h',
1087 'chrome/browser/ash/login/ash_hud_login_browsertest\.cc',
1088 'chromecast/base/observer_unittest\.cc',
1089 'chromecast/browser/cast_web_view\.h',
1090 'chromecast/public/cast_media_shlib\.h',
1091 'device/bluetooth/floss/exported_callback_manager\.h',
1092 'device/bluetooth/floss/floss_dbus_client\.h',
1093 'device/fido/cable/v2_handshake_unittest\.cc',
1094 'device/fido/pin\.cc',
1095 'services/tracing/perfetto/test_utils\.h',
1096 # Should use base::FunctionRef.
1097 'chrome/browser/media/webrtc/test_stats_dictionary\.cc',
1098 'chrome/browser/media/webrtc/test_stats_dictionary\.h',
1099 'chromeos/ash/services/libassistant/device_settings_controller\.cc',
1100 'components/browser_ui/client_certificate/android/ssl_client_certificate_request\.cc',
1101 'components/gwp_asan/client/sampling_malloc_shims_unittest\.cc',
1102 'content/browser/font_unique_name_lookup/font_unique_name_lookup_unittest\.cc',
1103 # Does not need std::function at all.
1104 'components/omnibox/browser/autocomplete_result\.cc',
1105 'device/fido/win/webauthn_api\.cc',
1106 'media/audio/alsa/alsa_util\.cc',
1107 'media/remoting/stream_provider\.h',
1108 'sql/vfs_wrapper\.cc',
1109 # TODO(https://crbug.com/1364585): Remove usage and exception list
1110 # entries.
1111 'extensions/renderer/api/automation/automation_internal_custom_bindings\.cc',
1112 'extensions/renderer/api/automation/automation_internal_custom_bindings\.h',
1113 # TODO(https://crbug.com/1364579): Remove usage and exception list
1114 # entry.
1115 'ui/views/controls/focus_ring\.h',
1116
1117 # Various pre-existing uses in //tools that is low-priority to fix.
1118 'tools/binary_size/libsupersize/viewer/caspian/diff\.cc',
1119 'tools/binary_size/libsupersize/viewer/caspian/model\.cc',
1120 'tools/binary_size/libsupersize/viewer/caspian/model\.h',
1121 'tools/binary_size/libsupersize/viewer/caspian/tree_builder\.h',
1122 'tools/clang/base_bind_rewriters/BaseBindRewriters\.cpp',
1123
Daniel Chengcd23b8b2022-09-16 17:16:241124 # Not an error in third_party folders.
1125 _THIRD_PARTY_EXCEPT_BLINK
1126 ],
Daniel Bratell609102be2019-03-27 20:53:211127 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151128 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081129 r'/#include <X11/',
Tom Andersona95e12042020-09-09 23:08:001130 (
1131 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
1132 ),
1133 True,
1134 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1135 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151136 BanRule(
Daniel Bratell609102be2019-03-27 20:53:211137 r'/\bstd::ratio\b',
1138 (
1139 'std::ratio is banned by the Google Style Guide.',
1140 ),
1141 True,
1142 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:451143 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151144 BanRule(
Peter Kasting6d77e9d2023-02-09 21:58:181145 r'/\bstd::aligned_alloc\b',
1146 (
Peter Kastinge2c5ee82023-02-15 17:23:081147 'std::aligned_alloc() is not yet allowed (crbug.com/1412818). Use ',
1148 'base::AlignedAlloc() instead.',
Peter Kasting6d77e9d2023-02-09 21:58:181149 ),
1150 True,
1151 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1152 ),
1153 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081154 r'/#include <(barrier|latch|semaphore|stop_token)>',
Peter Kasting6d77e9d2023-02-09 21:58:181155 (
Peter Kastinge2c5ee82023-02-15 17:23:081156 'The thread support library is banned. Use base/synchronization '
1157 'instead.',
Peter Kasting6d77e9d2023-02-09 21:58:181158 ),
1159 True,
1160 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1161 ),
1162 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081163 r'/\bstd::(c8rtomb|mbrtoc8)\b',
Peter Kasting6d77e9d2023-02-09 21:58:181164 (
Peter Kastinge2c5ee82023-02-15 17:23:081165 'std::c8rtomb() and std::mbrtoc8() are banned.',
Peter Kasting6d77e9d2023-02-09 21:58:181166 ),
1167 True,
1168 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1169 ),
1170 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081171 r'/\bchar8_t|std::u8string\b',
Peter Kasting6d77e9d2023-02-09 21:58:181172 (
Peter Kastinge2c5ee82023-02-15 17:23:081173 'char8_t and std::u8string are not yet allowed. Can you use [unsigned]',
1174 ' char and std::string instead?',
1175 ),
1176 True,
1177 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1178 ),
1179 BanRule(
1180 r'/(\b(co_await|co_return|co_yield)\b|#include <coroutine>)',
1181 (
1182 'Coroutines are not yet allowed (https://crbug.com/1403840).',
1183 ),
1184 True,
1185 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1186 ),
1187 BanRule(
Peter Kastingcc152522023-03-22 20:17:371188 r'/^\s*(export\s|import\s+["<:\w]|module(;|\s+[:\w]))',
Peter Kasting69357dc2023-03-14 01:34:291189 (
1190 'Modules are disallowed for now due to lack of toolchain support.',
1191 ),
1192 True,
1193 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1194 ),
1195 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081196 r'/\[\[(un)?likely\]\]',
1197 (
1198 '[[likely]] and [[unlikely]] are not yet allowed ',
1199 '(https://crbug.com/1414620). Use [UN]LIKELY instead.',
1200 ),
1201 True,
1202 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1203 ),
1204 BanRule(
1205 r'/#include <format>',
1206 (
1207 '<format> is not yet allowed. Use base::StringPrintf() instead.',
1208 ),
1209 True,
1210 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1211 ),
1212 BanRule(
1213 r'/#include <ranges>',
1214 (
1215 '<ranges> is not yet allowed. Use base/ranges/algorithm.h instead.',
1216 ),
1217 True,
1218 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1219 ),
1220 BanRule(
1221 r'/#include <source_location>',
1222 (
1223 '<source_location> is not yet allowed. Use base/location.h instead.',
1224 ),
1225 True,
1226 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1227 ),
1228 BanRule(
1229 r'/#include <syncstream>',
1230 (
1231 '<syncstream> is banned.',
Peter Kasting6d77e9d2023-02-09 21:58:181232 ),
1233 True,
1234 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1235 ),
1236 BanRule(
Michael Giuffrida7f93d6922019-04-19 14:39:581237 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:191238 (
1239 'RunMessageLoop is deprecated, use RunLoop instead.',
1240 ),
1241 False,
1242 (),
1243 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151244 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441245 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:191246 (
1247 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
1248 "if you're convinced you need this.",
1249 ),
1250 False,
1251 (),
1252 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151253 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441254 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:191255 (
1256 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:041257 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:191258 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
1259 'async events instead of flushing threads.',
1260 ),
1261 False,
1262 (),
1263 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151264 BanRule(
Gabriel Charette147335ea2018-03-22 15:59:191265 r'MessageLoopRunner',
1266 (
1267 'MessageLoopRunner is deprecated, use RunLoop instead.',
1268 ),
1269 False,
1270 (),
1271 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151272 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441273 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:191274 (
1275 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
1276 "gab@ if you found a use case where this is the only solution.",
1277 ),
1278 False,
1279 (),
1280 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151281 BanRule(
Victor Costane48a2e82019-03-15 22:02:341282 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:161283 (
Victor Costane48a2e82019-03-15 22:02:341284 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:161285 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
1286 ),
1287 True,
1288 (
1289 r'^sql/initialization\.(cc|h)$',
1290 r'^third_party/sqlite/.*\.(c|cc|h)$',
1291 ),
1292 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151293 BanRule(
Austin Sullivand661ab52022-11-16 08:55:151294 'CREATE VIEW',
1295 (
1296 'SQL views are disabled in Chromium feature code',
1297 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-views',
1298 ),
1299 True,
1300 (
1301 _THIRD_PARTY_EXCEPT_BLINK,
1302 # sql/ itself uses views when using memory-mapped IO.
1303 r'^sql/.*',
1304 # Various performance tools that do not build as part of Chrome.
1305 r'^infra/.*',
1306 r'^tools/perf.*',
1307 r'.*perfetto.*',
1308 ),
1309 ),
1310 BanRule(
1311 'CREATE VIRTUAL TABLE',
1312 (
1313 'SQL virtual tables are disabled in Chromium feature code',
1314 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-virtual-tables',
1315 ),
1316 True,
1317 (
1318 _THIRD_PARTY_EXCEPT_BLINK,
1319 # sql/ itself uses virtual tables in the recovery module and tests.
1320 r'^sql/.*',
1321 # TODO(https://crbug.com/695592): Remove once WebSQL is deprecated.
1322 r'third_party/blink/web_tests/storage/websql/.*'
1323 # Various performance tools that do not build as part of Chrome.
1324 r'^tools/perf.*',
1325 r'.*perfetto.*',
1326 ),
1327 ),
1328 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441329 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:471330 (
1331 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
1332 'base::RandomShuffle instead.'
1333 ),
1334 True,
1335 (),
1336 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151337 BanRule(
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:241338 'ios/web/public/test/http_server',
1339 (
1340 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
1341 ),
1342 False,
1343 (),
1344 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151345 BanRule(
Robert Liao764c9492019-01-24 18:46:281346 'GetAddressOf',
1347 (
1348 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:531349 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:111350 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:531351 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:281352 ),
1353 True,
1354 (),
1355 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151356 BanRule(
Ben Lewisa9514602019-04-29 17:53:051357 'SHFileOperation',
1358 (
1359 'SHFileOperation was deprecated in Windows Vista, and there are less ',
1360 'complex functions to achieve the same goals. Use IFileOperation for ',
1361 'any esoteric actions instead.'
1362 ),
1363 True,
1364 (),
1365 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151366 BanRule(
Cliff Smolinsky81951642019-04-30 21:39:511367 'StringFromGUID2',
1368 (
1369 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241370 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511371 ),
1372 True,
1373 (
Daniel Chenga44a1bcd2022-03-15 20:00:151374 r'/base/win/win_util_unittest.cc',
Cliff Smolinsky81951642019-04-30 21:39:511375 ),
1376 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151377 BanRule(
Cliff Smolinsky81951642019-04-30 21:39:511378 'StringFromCLSID',
1379 (
1380 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241381 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511382 ),
1383 True,
1384 (
Daniel Chenga44a1bcd2022-03-15 20:00:151385 r'/base/win/win_util_unittest.cc',
Cliff Smolinsky81951642019-04-30 21:39:511386 ),
1387 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151388 BanRule(
Avi Drissman7382afa02019-04-29 23:27:131389 'kCFAllocatorNull',
1390 (
1391 'The use of kCFAllocatorNull with the NoCopy creation of ',
1392 'CoreFoundation types is prohibited.',
1393 ),
1394 True,
1395 (),
1396 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151397 BanRule(
Oksana Zhuravlovafd247772019-05-16 16:57:291398 'mojo::ConvertTo',
1399 (
1400 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1401 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1402 'StringTraits if you would like to convert between custom types and',
1403 'the wire format of mojom types.'
1404 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221405 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291406 (
David Dorwin13dc48b2022-06-03 21:18:421407 r'^fuchsia_web/webengine/browser/url_request_rewrite_rules_manager\.cc$',
1408 r'^fuchsia_web/webengine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291409 r'^third_party/blink/.*\.(cc|h)$',
1410 r'^content/renderer/.*\.(cc|h)$',
1411 ),
1412 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151413 BanRule(
Oksana Zhuravlovac8222d22019-12-19 19:21:161414 'GetInterfaceProvider',
1415 (
1416 'InterfaceProvider is deprecated.',
1417 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1418 'or Platform::GetBrowserInterfaceBroker.'
1419 ),
1420 False,
1421 (),
1422 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151423 BanRule(
Robert Liao1d78df52019-11-11 20:02:011424 'CComPtr',
1425 (
1426 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1427 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1428 'details.'
1429 ),
1430 False,
1431 (),
1432 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151433 BanRule(
Xiaohan Wang72bd2ba2020-02-18 21:38:201434 r'/\b(IFACE|STD)METHOD_?\(',
1435 (
1436 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1437 'Instead, always use IFACEMETHODIMP in the declaration.'
1438 ),
1439 False,
1440 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1441 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151442 BanRule(
Allen Bauer53b43fb12020-03-12 17:21:471443 'set_owned_by_client',
1444 (
1445 'set_owned_by_client is deprecated.',
1446 'views::View already owns the child views by default. This introduces ',
1447 'a competing ownership model which makes the code difficult to reason ',
1448 'about. See http://crbug.com/1044687 for more details.'
1449 ),
1450 False,
1451 (),
1452 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151453 BanRule(
Peter Boström7ff41522021-07-29 03:43:271454 'RemoveAllChildViewsWithoutDeleting',
1455 (
1456 'RemoveAllChildViewsWithoutDeleting is deprecated.',
1457 'This method is deemed dangerous as, unless raw pointers are re-added,',
1458 'calls to this method introduce memory leaks.'
1459 ),
1460 False,
1461 (),
1462 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151463 BanRule(
Eric Secklerbe6f48d2020-05-06 18:09:121464 r'/\bTRACE_EVENT_ASYNC_',
1465 (
1466 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1467 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1468 ),
1469 False,
1470 (
1471 r'^base/trace_event/.*',
1472 r'^base/tracing/.*',
1473 ),
1474 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151475 BanRule(
Aditya Kushwah5a286b72022-02-10 04:54:431476 r'/\bbase::debug::DumpWithoutCrashingUnthrottled[(][)]',
1477 (
1478 'base::debug::DumpWithoutCrashingUnthrottled() does not throttle',
1479 'dumps and may spam crash reports. Consider if the throttled',
1480 'variants suffice instead.',
1481 ),
1482 False,
1483 (),
1484 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151485 BanRule(
Robert Liao22f66a52021-04-10 00:57:521486 'RoInitialize',
1487 (
Robert Liao48018922021-04-16 23:03:021488 'Improper use of [base::win]::RoInitialize() has been implicated in a ',
Robert Liao22f66a52021-04-10 00:57:521489 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
1490 'instead. See http://crbug.com/1197722 for more information.'
1491 ),
1492 True,
Robert Liao48018922021-04-16 23:03:021493 (
Bruce Dawson40fece62022-09-16 19:58:311494 r'^base/win/scoped_winrt_initializer\.cc$',
Robert Liao48018922021-04-16 23:03:021495 ),
Robert Liao22f66a52021-04-10 00:57:521496 ),
Patrick Monettec343bb982022-06-01 17:18:451497 BanRule(
1498 r'base::Watchdog',
1499 (
1500 'base::Watchdog is deprecated because it creates its own thread.',
1501 'Instead, manually start a timer on a SequencedTaskRunner.',
1502 ),
1503 False,
1504 (),
1505 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091506 BanRule(
1507 'base::Passed',
1508 (
1509 'Do not use base::Passed. It is a legacy helper for capturing ',
1510 'move-only types with base::BindRepeating, but invoking the ',
1511 'resulting RepeatingCallback moves the captured value out of ',
1512 'the callback storage, and subsequent invocations may pass the ',
1513 'value in a valid but undefined state. Prefer base::BindOnce().',
1514 'See http://crbug.com/1326449 for context.'
1515 ),
1516 False,
Daniel Cheng91f6fbaf2022-09-16 12:07:481517 (
1518 # False positive, but it is also fine to let bind internals reference
1519 # base::Passed.
Daniel Chengcd23b8b2022-09-16 17:16:241520 r'^base[\\/]functional[\\/]bind\.h',
Daniel Cheng91f6fbaf2022-09-16 12:07:481521 r'^base[\\/]functional[\\/]bind_internal\.h',
1522 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091523 ),
Daniel Cheng2248b332022-07-27 06:16:591524 BanRule(
Daniel Chengba3bc2e2022-10-03 02:45:431525 r'base::Feature k',
1526 (
1527 'Please use BASE_DECLARE_FEATURE() or BASE_FEATURE() instead of ',
1528 'directly declaring/defining features.'
1529 ),
1530 True,
1531 [
1532 _THIRD_PARTY_EXCEPT_BLINK,
1533 ],
1534 ),
Robert Ogden92101dcb2022-10-19 23:49:361535 BanRule(
Arthur Sonzogni1da65fa2023-03-27 16:01:521536 r'/\bchartorune\b',
Robert Ogden92101dcb2022-10-19 23:49:361537 (
1538 'chartorune is not memory-safe, unless you can guarantee the input ',
1539 'string is always null-terminated. Otherwise, please use charntorune ',
1540 'from libphonenumber instead.'
1541 ),
1542 True,
1543 [
1544 _THIRD_PARTY_EXCEPT_BLINK,
1545 # Exceptions to this rule should have a fuzzer.
1546 ],
1547 ),
Arthur Sonzogni1da65fa2023-03-27 16:01:521548 BanRule(
1549 r'/\b#include "base/atomicops\.h"\b',
1550 (
1551 'Do not use base::subtle atomics, but std::atomic, which are simpler '
1552 'to use, have better understood, clearer and richer semantics, and are '
1553 'harder to mis-use. See details in base/atomicops.h.',
1554 ),
1555 False,
1556 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Benoit Lize79cf0592023-01-27 10:01:571557 ),
Arthur Sonzogni60348572e2023-04-07 10:22:521558 BanRule(
1559 r'CrossThreadPersistent<',
1560 (
1561 'Do not use blink::CrossThreadPersistent, but '
1562 'blink::CrossThreadHandle. It is harder to mis-use.',
1563 'More info: '
1564 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1565 'Please contact platform-architecture-dev@ before adding new instances.'
1566 ),
1567 False,
1568 []
1569 ),
1570 BanRule(
1571 r'CrossThreadWeakPersistent<',
1572 (
1573 'Do not use blink::CrossThreadWeakPersistent, but '
1574 'blink::CrossThreadWeakHandle. It is harder to mis-use.',
1575 'More info: '
1576 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1577 'Please contact platform-architecture-dev@ before adding new instances.'
1578 ),
1579 False,
1580 []
1581 ),
Avi Drissman491617c2023-04-13 17:33:151582 BanRule(
1583 r'objc/objc.h',
1584 (
1585 'Do not include <objc/objc.h>. It defines away ARC lifetime '
1586 'annotations, and is thus dangerous.',
1587 'Please use the pimpl pattern; search for `ObjCStorage` for examples.',
1588 'For further reading on how to safely mix C++ and Obj-C, see',
1589 'https://chromium.googlesource.com/chromium/src/+/main/docs/mac/mixing_cpp_and_objc.md'
1590 ),
1591 True,
1592 []
1593 ),
[email protected]127f18ec2012-06-16 05:05:591594)
1595
Daniel Cheng92c15e32022-03-16 17:48:221596_BANNED_MOJOM_PATTERNS : Sequence[BanRule] = (
1597 BanRule(
1598 'handle<shared_buffer>',
1599 (
1600 'Please use one of the more specific shared memory types instead:',
1601 ' mojo_base.mojom.ReadOnlySharedMemoryRegion',
1602 ' mojo_base.mojom.WritableSharedMemoryRegion',
1603 ' mojo_base.mojom.UnsafeSharedMemoryRegion',
1604 ),
1605 True,
1606 ),
1607)
1608
mlamouria82272622014-09-16 18:45:041609_IPC_ENUM_TRAITS_DEPRECATED = (
1610 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501611 'See http://www.chromium.org/Home/chromium-security/education/'
1612 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041613
Stephen Martinis97a394142018-06-07 23:06:051614_LONG_PATH_ERROR = (
1615 'Some files included in this CL have file names that are too long (> 200'
1616 ' characters). If committed, these files will cause issues on Windows. See'
1617 ' https://crbug.com/612667 for more details.'
1618)
1619
Shenghua Zhangbfaa38b82017-11-16 21:58:021620_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Bruce Dawson40fece62022-09-16 19:58:311621 r".*/AppHooksImpl\.java",
1622 r".*/BuildHooksAndroidImpl\.java",
1623 r".*/LicenseContentProvider\.java",
1624 r".*/PlatformServiceBridgeImpl.java",
1625 r".*chrome/android/feed/dummy/.*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021626]
[email protected]127f18ec2012-06-16 05:05:591627
Mohamed Heikald048240a2019-11-12 16:57:371628# List of image extensions that are used as resources in chromium.
1629_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1630
Sean Kau46e29bc2017-08-28 16:31:161631# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401632_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Bruce Dawson40fece62022-09-16 19:58:311633 r'test/data/',
1634 r'testing/buildbot/',
1635 r'^components/policy/resources/policy_templates\.json$',
1636 r'^third_party/protobuf/',
1637 r'^third_party/blink/perf_tests/speedometer/resources/todomvc/learn.json',
1638 r'^third_party/blink/renderer/devtools/protocol\.json$',
1639 r'^third_party/blink/web_tests/external/wpt/',
1640 r'^tools/perf/',
1641 r'^tools/traceline/svgui/startup-release.json',
Daniel Cheng2d4c2d192022-07-01 01:38:311642 # vscode configuration files allow comments
Bruce Dawson40fece62022-09-16 19:58:311643 r'^tools/vscode/',
Sean Kau46e29bc2017-08-28 16:31:161644]
1645
Andrew Grieveb773bad2020-06-05 18:00:381646# These are not checked on the public chromium-presubmit trybot.
1647# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041648# checkouts.
agrievef32bcc72016-04-04 14:57:401649_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381650 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381651]
1652
1653
1654_GENERIC_PYDEPS_FILES = [
Bruce Dawson853b739e62022-05-03 23:03:101655 'android_webview/test/components/run_webview_component_smoketest.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041656 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361657 'base/android/jni_generator/jni_generator.pydeps',
1658 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361659 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041660 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361661 'build/android/gyp/aar.pydeps',
1662 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271663 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361664 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381665 'build/android/gyp/assert_static_initializers.pydeps',
Mohamed Heikal133e1f22023-04-18 20:04:371666 'build/android/gyp/binary_baseline_profile.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361667 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021668 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:221669 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111670 'build/android/gyp/compile_java.pydeps',
Peter Weneaa963f2023-01-20 19:40:301671 'build/android/gyp/compile_kt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361672 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361673 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361674 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111675 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041676 'build/android/gyp/create_app_bundle_apks.pydeps',
1677 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361678 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121679 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091680 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221681 'build/android/gyp/create_size_info_files.pydeps',
Peter Wene6e017e2022-07-27 21:40:401682 'build/android/gyp/create_test_apk_wrapper_script.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001683 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361684 'build/android/gyp/dex.pydeps',
1685 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361686 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:211687 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361688 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361689 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361690 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581691 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361692 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141693 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261694 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:471695 'build/android/gyp/java_google_api_keys.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041696 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361697 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361698 'build/android/gyp/merge_manifest.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:101699 'build/android/gyp/optimize_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361700 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221701 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361702 'build/android/gyp/proguard.pydeps',
Andrew Grievee3a775ab2022-05-16 15:59:221703 'build/android/gyp/system_image_apks.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:101704 'build/android/gyp/trace_event_bytecode_rewriter.pydeps',
Peter Wen578730b2020-03-19 19:55:461705 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:301706 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241707 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361708 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461709 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561710 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361711 'build/android/incremental_install/generate_android_manifest.pydeps',
1712 'build/android/incremental_install/write_installer_json.pydeps',
Stephanie Kim392913b452022-06-15 17:25:321713 'build/android/pylib/results/presentation/test_results_presentation.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041714 'build/android/resource_sizes.pydeps',
1715 'build/android/test_runner.pydeps',
1716 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361717 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361718 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321719 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271720 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1721 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:041722 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001723 'components/cronet/tools/generate_javadoc.pydeps',
1724 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381725 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001726 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381727 'net/tools/testserver/testserver.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181728 'testing/scripts/run_isolated_script_test.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411729 'testing/merge_scripts/standard_isolated_script_merge.pydeps',
1730 'testing/merge_scripts/standard_gtest_merge.pydeps',
1731 'testing/merge_scripts/code_coverage/merge_results.pydeps',
1732 'testing/merge_scripts/code_coverage/merge_steps.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041733 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421734 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
Yuki Shiino38eeaad12022-08-11 06:40:251735 'third_party/blink/renderer/bindings/scripts/check_generated_file_list.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421736 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131737 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:501738 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411739 'third_party/blink/tools/blinkpy/web_tests/merge_results.pydeps',
1740 'third_party/blink/tools/merge_web_test_results.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061741 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221742 'tools/binary_size/supersize.pydeps',
Ben Pastene028104a2022-08-10 19:17:451743 'tools/perf/process_perf_results.pydeps',
agrievef32bcc72016-04-04 14:57:401744]
1745
wnwenbdc444e2016-05-25 13:44:151746
agrievef32bcc72016-04-04 14:57:401747_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1748
1749
Eric Boren6fd2b932018-01-25 15:05:081750# Bypass the AUTHORS check for these accounts.
1751_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591752 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451753 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591754 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521755 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:231756 'wpt-autoroller', 'chrome-weblayer-builder',
Garrett Beaty4d4fcf62021-11-24 17:57:471757 'lacros-version-skew-roller', 'skylab-test-cros-roller',
Sven Zheng722960ba2022-07-18 16:40:461758 'infra-try-recipes-tester', 'lacros-tracking-roller',
Brian Sheedy1c951e62022-10-27 01:16:181759 'lacros-sdk-version-roller', 'chrome-automated-expectation',
Keybo Qianec7dcb12023-01-27 18:38:561760 'chromium-automated-expectation', 'chrome-branch-day')
Eric Boren835d71f2018-09-07 21:09:041761 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271762 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041763 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:161764 for s in ('chromium-internal-autoroll',)
1765 ) | set('%[email protected]' % s
Chong Gub277e342022-10-15 03:30:551766 for s in ('swarming-tasks',)
1767 ) | set('%[email protected]' % s
1768 for s in ('global-integration-try-builder',
1769 'global-integration-ci-builder'))
Eric Boren6fd2b932018-01-25 15:05:081770
Matt Stark6ef08872021-07-29 01:21:461771_INVALID_GRD_FILE_LINE = [
1772 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
1773]
Eric Boren6fd2b932018-01-25 15:05:081774
Daniel Bratell65b033262019-04-23 08:17:061775def _IsCPlusPlusFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501776 """Returns True if this file contains C++-like code (and not Python,
1777 Go, Java, MarkDown, ...)"""
Daniel Bratell65b033262019-04-23 08:17:061778
Sam Maiera6e76d72022-02-11 21:43:501779 ext = input_api.os_path.splitext(file_path)[1]
1780 # This list is compatible with CppChecker.IsCppFile but we should
1781 # consider adding ".c" to it. If we do that we can use this function
1782 # at more places in the code.
1783 return ext in (
1784 '.h',
1785 '.cc',
1786 '.cpp',
1787 '.m',
1788 '.mm',
1789 )
1790
Daniel Bratell65b033262019-04-23 08:17:061791
1792def _IsCPlusPlusHeaderFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501793 return input_api.os_path.splitext(file_path)[1] == ".h"
Daniel Bratell65b033262019-04-23 08:17:061794
1795
1796def _IsJavaFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501797 return input_api.os_path.splitext(file_path)[1] == ".java"
Daniel Bratell65b033262019-04-23 08:17:061798
1799
1800def _IsProtoFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501801 return input_api.os_path.splitext(file_path)[1] == ".proto"
Daniel Bratell65b033262019-04-23 08:17:061802
Mohamed Heikal5e5b7922020-10-29 18:57:591803
Erik Staabc734cd7a2021-11-23 03:11:521804def _IsXmlOrGrdFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501805 ext = input_api.os_path.splitext(file_path)[1]
1806 return ext in ('.grd', '.xml')
Erik Staabc734cd7a2021-11-23 03:11:521807
1808
Sven Zheng76a79ea2022-12-21 21:25:241809def _IsMojomFile(input_api, file_path):
1810 return input_api.os_path.splitext(file_path)[1] == ".mojom"
1811
1812
Mohamed Heikal5e5b7922020-10-29 18:57:591813def CheckNoUpstreamDepsOnClank(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501814 """Prevent additions of dependencies from the upstream repo on //clank."""
1815 # clank can depend on clank
1816 if input_api.change.RepositoryRoot().endswith('clank'):
1817 return []
1818 build_file_patterns = [
1819 r'(.+/)?BUILD\.gn',
1820 r'.+\.gni',
1821 ]
1822 excluded_files = [r'build[/\\]config[/\\]android[/\\]config\.gni']
1823 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
Mohamed Heikal5e5b7922020-10-29 18:57:591824
Sam Maiera6e76d72022-02-11 21:43:501825 error_message = 'Disallowed import on //clank in an upstream build file:'
Mohamed Heikal5e5b7922020-10-29 18:57:591826
Sam Maiera6e76d72022-02-11 21:43:501827 def FilterFile(affected_file):
1828 return input_api.FilterSourceFile(affected_file,
1829 files_to_check=build_file_patterns,
1830 files_to_skip=excluded_files)
Mohamed Heikal5e5b7922020-10-29 18:57:591831
Sam Maiera6e76d72022-02-11 21:43:501832 problems = []
1833 for f in input_api.AffectedSourceFiles(FilterFile):
1834 local_path = f.LocalPath()
1835 for line_number, line in f.ChangedContents():
1836 if (bad_pattern.search(line)):
1837 problems.append('%s:%d\n %s' %
1838 (local_path, line_number, line.strip()))
1839 if problems:
1840 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1841 else:
1842 return []
Mohamed Heikal5e5b7922020-10-29 18:57:591843
1844
Saagar Sanghavifceeaae2020-08-12 16:40:361845def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501846 """Attempts to prevent use of functions intended only for testing in
1847 non-testing code. For now this is just a best-effort implementation
1848 that ignores header files and may have some false positives. A
1849 better implementation would probably need a proper C++ parser.
1850 """
1851 # We only scan .cc files and the like, as the declaration of
1852 # for-testing functions in header files are hard to distinguish from
1853 # calls to such functions without a proper C++ parser.
1854 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191855
Sam Maiera6e76d72022-02-11 21:43:501856 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
1857 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' %
1858 base_function_pattern)
1859 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
1860 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
1861 exclusion_pattern = input_api.re.compile(
1862 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' %
1863 (base_function_pattern, base_function_pattern))
1864 # Avoid a false positive in this case, where the method name, the ::, and
1865 # the closing { are all on different lines due to line wrapping.
1866 # HelperClassForTesting::
1867 # HelperClassForTesting(
1868 # args)
1869 # : member(0) {}
1870 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191871
Sam Maiera6e76d72022-02-11 21:43:501872 def FilterFile(affected_file):
1873 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1874 input_api.DEFAULT_FILES_TO_SKIP)
1875 return input_api.FilterSourceFile(
1876 affected_file,
1877 files_to_check=file_inclusion_pattern,
1878 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191879
Sam Maiera6e76d72022-02-11 21:43:501880 problems = []
1881 for f in input_api.AffectedSourceFiles(FilterFile):
1882 local_path = f.LocalPath()
1883 in_method_defn = False
1884 for line_number, line in f.ChangedContents():
1885 if (inclusion_pattern.search(line)
1886 and not comment_pattern.search(line)
1887 and not exclusion_pattern.search(line)
1888 and not allowlist_pattern.search(line)
1889 and not in_method_defn):
1890 problems.append('%s:%d\n %s' %
1891 (local_path, line_number, line.strip()))
1892 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191893
Sam Maiera6e76d72022-02-11 21:43:501894 if problems:
1895 return [
1896 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
1897 ]
1898 else:
1899 return []
[email protected]55459852011-08-10 15:17:191900
1901
Saagar Sanghavifceeaae2020-08-12 16:40:361902def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501903 """This is a simplified version of
1904 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
1905 """
1906 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1907 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1908 name_pattern = r'ForTest(s|ing)?'
1909 # Describes an occurrence of "ForTest*" inside a // comment.
1910 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
1911 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
1912 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
1913 # Catch calls.
1914 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1915 # Ignore definitions. (Comments are ignored separately.)
1916 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
Vaclav Brozek7dbc28c2018-03-27 08:35:231917
Sam Maiera6e76d72022-02-11 21:43:501918 problems = []
1919 sources = lambda x: input_api.FilterSourceFile(
1920 x,
1921 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
1922 DEFAULT_FILES_TO_SKIP),
1923 files_to_check=[r'.*\.java$'])
1924 for f in input_api.AffectedFiles(include_deletes=False,
1925 file_filter=sources):
1926 local_path = f.LocalPath()
Vaclav Brozek7dbc28c2018-03-27 08:35:231927 is_inside_javadoc = False
Sam Maiera6e76d72022-02-11 21:43:501928 for line_number, line in f.ChangedContents():
1929 if is_inside_javadoc and javadoc_end_re.search(line):
1930 is_inside_javadoc = False
1931 if not is_inside_javadoc and javadoc_start_re.search(line):
1932 is_inside_javadoc = True
1933 if is_inside_javadoc:
1934 continue
1935 if (inclusion_re.search(line) and not comment_re.search(line)
1936 and not annotation_re.search(line)
1937 and not exclusion_re.search(line)):
1938 problems.append('%s:%d\n %s' %
1939 (local_path, line_number, line.strip()))
Vaclav Brozek7dbc28c2018-03-27 08:35:231940
Sam Maiera6e76d72022-02-11 21:43:501941 if problems:
1942 return [
1943 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
1944 ]
1945 else:
1946 return []
Vaclav Brozek7dbc28c2018-03-27 08:35:231947
1948
Saagar Sanghavifceeaae2020-08-12 16:40:361949def CheckNoIOStreamInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501950 """Checks to make sure no .h files include <iostream>."""
1951 files = []
1952 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1953 input_api.re.MULTILINE)
1954 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1955 if not f.LocalPath().endswith('.h'):
1956 continue
1957 contents = input_api.ReadFile(f)
1958 if pattern.search(contents):
1959 files.append(f)
[email protected]10689ca2011-09-02 02:31:541960
Sam Maiera6e76d72022-02-11 21:43:501961 if len(files):
1962 return [
1963 output_api.PresubmitError(
1964 'Do not #include <iostream> in header files, since it inserts static '
1965 'initialization into every file including the header. Instead, '
1966 '#include <ostream>. See http://crbug.com/94794', files)
1967 ]
1968 return []
1969
[email protected]10689ca2011-09-02 02:31:541970
Aleksey Khoroshilov9b28c032022-06-03 16:35:321971def CheckNoStrCatRedefines(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501972 """Checks no windows headers with StrCat redefined are included directly."""
1973 files = []
Aleksey Khoroshilov9b28c032022-06-03 16:35:321974 files_to_check = (r'.+%s' % _HEADER_EXTENSIONS,
1975 r'.+%s' % _IMPLEMENTATION_EXTENSIONS)
1976 files_to_skip = (input_api.DEFAULT_FILES_TO_SKIP +
1977 _NON_BASE_DEPENDENT_PATHS)
1978 sources_filter = lambda f: input_api.FilterSourceFile(
1979 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
1980
Sam Maiera6e76d72022-02-11 21:43:501981 pattern_deny = input_api.re.compile(
1982 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1983 input_api.re.MULTILINE)
1984 pattern_allow = input_api.re.compile(
1985 r'^#include\s"base/win/windows_defines.inc"', input_api.re.MULTILINE)
Aleksey Khoroshilov9b28c032022-06-03 16:35:321986 for f in input_api.AffectedSourceFiles(sources_filter):
Sam Maiera6e76d72022-02-11 21:43:501987 contents = input_api.ReadFile(f)
1988 if pattern_deny.search(
1989 contents) and not pattern_allow.search(contents):
1990 files.append(f.LocalPath())
Danil Chapovalov3518f362018-08-11 16:13:431991
Sam Maiera6e76d72022-02-11 21:43:501992 if len(files):
1993 return [
1994 output_api.PresubmitError(
1995 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1996 'directly since they pollute code with StrCat macro. Instead, '
1997 'include matching header from base/win. See http://crbug.com/856536',
1998 files)
1999 ]
2000 return []
Danil Chapovalov3518f362018-08-11 16:13:432001
[email protected]10689ca2011-09-02 02:31:542002
Saagar Sanghavifceeaae2020-08-12 16:40:362003def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502004 """Checks to make sure no source files use UNIT_TEST."""
2005 problems = []
2006 for f in input_api.AffectedFiles():
2007 if (not f.LocalPath().endswith(('.cc', '.mm'))):
2008 continue
[email protected]72df4e782012-06-21 16:28:182009
Sam Maiera6e76d72022-02-11 21:43:502010 for line_num, line in f.ChangedContents():
2011 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
2012 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]72df4e782012-06-21 16:28:182013
Sam Maiera6e76d72022-02-11 21:43:502014 if not problems:
2015 return []
2016 return [
2017 output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
2018 '\n'.join(problems))
2019 ]
2020
[email protected]72df4e782012-06-21 16:28:182021
Saagar Sanghavifceeaae2020-08-12 16:40:362022def CheckNoDISABLETypoInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502023 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
Dominic Battre033531052018-09-24 15:45:342024
Sam Maiera6e76d72022-02-11 21:43:502025 This test warns if somebody tries to disable a test with the DISABLE_ prefix
2026 instead of DISABLED_. To filter false positives, reports are only generated
2027 if a corresponding MAYBE_ line exists.
2028 """
2029 problems = []
Dominic Battre033531052018-09-24 15:45:342030
Sam Maiera6e76d72022-02-11 21:43:502031 # The following two patterns are looked for in tandem - is a test labeled
2032 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
2033 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
2034 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
Dominic Battre033531052018-09-24 15:45:342035
Sam Maiera6e76d72022-02-11 21:43:502036 # This is for the case that a test is disabled on all platforms.
2037 full_disable_pattern = input_api.re.compile(
2038 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
2039 input_api.re.MULTILINE)
Dominic Battre033531052018-09-24 15:45:342040
Sam Maiera6e76d72022-02-11 21:43:502041 for f in input_api.AffectedFiles(False):
2042 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2043 continue
Dominic Battre033531052018-09-24 15:45:342044
Sam Maiera6e76d72022-02-11 21:43:502045 # Search for MABYE_, DISABLE_ pairs.
2046 disable_lines = {} # Maps of test name to line number.
2047 maybe_lines = {}
2048 for line_num, line in f.ChangedContents():
2049 disable_match = disable_pattern.search(line)
2050 if disable_match:
2051 disable_lines[disable_match.group(1)] = line_num
2052 maybe_match = maybe_pattern.search(line)
2053 if maybe_match:
2054 maybe_lines[maybe_match.group(1)] = line_num
Dominic Battre033531052018-09-24 15:45:342055
Sam Maiera6e76d72022-02-11 21:43:502056 # Search for DISABLE_ occurrences within a TEST() macro.
2057 disable_tests = set(disable_lines.keys())
2058 maybe_tests = set(maybe_lines.keys())
2059 for test in disable_tests.intersection(maybe_tests):
2060 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
Dominic Battre033531052018-09-24 15:45:342061
Sam Maiera6e76d72022-02-11 21:43:502062 contents = input_api.ReadFile(f)
2063 full_disable_match = full_disable_pattern.search(contents)
2064 if full_disable_match:
2065 problems.append(' %s' % f.LocalPath())
Dominic Battre033531052018-09-24 15:45:342066
Sam Maiera6e76d72022-02-11 21:43:502067 if not problems:
2068 return []
2069 return [
2070 output_api.PresubmitPromptWarning(
2071 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
2072 '\n'.join(problems))
2073 ]
2074
Dominic Battre033531052018-09-24 15:45:342075
Nina Satragnof7660532021-09-20 18:03:352076def CheckForgettingMAYBEInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502077 """Checks to make sure tests disabled conditionally are not missing a
2078 corresponding MAYBE_ prefix.
2079 """
2080 # Expect at least a lowercase character in the test name. This helps rule out
2081 # false positives with macros wrapping the actual tests name.
2082 define_maybe_pattern = input_api.re.compile(
2083 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
Bruce Dawsonffc55292022-04-20 04:18:192084 # The test_maybe_pattern needs to handle all of these forms. The standard:
2085 # IN_PROC_TEST_F(SyncTest, MAYBE_Start) {
2086 # With a wrapper macro around the test name:
2087 # IN_PROC_TEST_F(SyncTest, E2E_ENABLED(MAYBE_Start)) {
2088 # And the odd-ball NACL_BROWSER_TEST_f format:
2089 # NACL_BROWSER_TEST_F(NaClBrowserTest, SimpleLoad, {
2090 # The optional E2E_ENABLED-style is handled with (\w*\()?
2091 # The NACL_BROWSER_TEST_F pattern is handled by allowing a trailing comma or
2092 # trailing ')'.
2093 test_maybe_pattern = (
2094 r'^\s*\w*TEST[^(]*\(\s*\w+,\s*(\w*\()?MAYBE_{test_name}[\),]')
Sam Maiera6e76d72022-02-11 21:43:502095 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
2096 warnings = []
Nina Satragnof7660532021-09-20 18:03:352097
Sam Maiera6e76d72022-02-11 21:43:502098 # Read the entire files. We can't just read the affected lines, forgetting to
2099 # add MAYBE_ on a change would not show up otherwise.
2100 for f in input_api.AffectedFiles(False):
2101 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2102 continue
2103 contents = input_api.ReadFile(f)
2104 lines = contents.splitlines(True)
2105 current_position = 0
2106 warning_test_names = set()
2107 for line_num, line in enumerate(lines, start=1):
2108 current_position += len(line)
2109 maybe_match = define_maybe_pattern.search(line)
2110 if maybe_match:
2111 test_name = maybe_match.group('test_name')
2112 # Do not warn twice for the same test.
2113 if (test_name in warning_test_names):
2114 continue
2115 warning_test_names.add(test_name)
Nina Satragnof7660532021-09-20 18:03:352116
Sam Maiera6e76d72022-02-11 21:43:502117 # Attempt to find the corresponding MAYBE_ test or suite, starting from
2118 # the current position.
2119 test_match = input_api.re.compile(
2120 test_maybe_pattern.format(test_name=test_name),
2121 input_api.re.MULTILINE).search(contents, current_position)
2122 suite_match = input_api.re.compile(
2123 suite_maybe_pattern.format(test_name=test_name),
2124 input_api.re.MULTILINE).search(contents, current_position)
2125 if not test_match and not suite_match:
2126 warnings.append(
2127 output_api.PresubmitPromptWarning(
2128 '%s:%d found MAYBE_ defined without corresponding test %s'
2129 % (f.LocalPath(), line_num, test_name)))
2130 return warnings
2131
[email protected]72df4e782012-06-21 16:28:182132
Saagar Sanghavifceeaae2020-08-12 16:40:362133def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502134 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
2135 errors = []
Kalvin Lee4a3b79de2022-05-26 16:00:162136 pattern = input_api.re.compile(r'\bDCHECK_IS_ON\b(?!\(\))',
Sam Maiera6e76d72022-02-11 21:43:502137 input_api.re.MULTILINE)
2138 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2139 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
2140 continue
2141 for lnum, line in f.ChangedContents():
2142 if input_api.re.search(pattern, line):
2143 errors.append(
2144 output_api.PresubmitError((
2145 '%s:%d: Use of DCHECK_IS_ON() must be written as "#if '
2146 + 'DCHECK_IS_ON()", not forgetting the parentheses.') %
2147 (f.LocalPath(), lnum)))
2148 return errors
danakj61c1aa22015-10-26 19:55:522149
2150
Weilun Shia487fad2020-10-28 00:10:342151# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
2152# more reliable way. See
2153# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:192154
wnwenbdc444e2016-05-25 13:44:152155
Saagar Sanghavifceeaae2020-08-12 16:40:362156def CheckFlakyTestUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502157 """Check that FlakyTest annotation is our own instead of the android one"""
2158 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
2159 files = []
2160 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2161 if f.LocalPath().endswith('Test.java'):
2162 if pattern.search(input_api.ReadFile(f)):
2163 files.append(f)
2164 if len(files):
2165 return [
2166 output_api.PresubmitError(
2167 'Use org.chromium.base.test.util.FlakyTest instead of '
2168 'android.test.FlakyTest', files)
2169 ]
2170 return []
mcasasb7440c282015-02-04 14:52:192171
wnwenbdc444e2016-05-25 13:44:152172
Saagar Sanghavifceeaae2020-08-12 16:40:362173def CheckNoDEPSGIT(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502174 """Make sure .DEPS.git is never modified manually."""
2175 if any(f.LocalPath().endswith('.DEPS.git')
2176 for f in input_api.AffectedFiles()):
2177 return [
2178 output_api.PresubmitError(
2179 'Never commit changes to .DEPS.git. This file is maintained by an\n'
2180 'automated system based on what\'s in DEPS and your changes will be\n'
2181 'overwritten.\n'
2182 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
2183 'get-the-code#Rolling_DEPS\n'
2184 'for more information')
2185 ]
2186 return []
[email protected]2a8ac9c2011-10-19 17:20:442187
2188
Sven Zheng76a79ea2022-12-21 21:25:242189def CheckCrosApiNeedBrowserTest(input_api, output_api):
2190 """Check new crosapi should add browser test."""
2191 has_new_crosapi = False
2192 has_browser_test = False
2193 for f in input_api.AffectedFiles():
2194 path = f.LocalPath()
2195 if (path.startswith('chromeos/crosapi/mojom') and
2196 _IsMojomFile(input_api, path) and f.Action() == 'A'):
2197 has_new_crosapi = True
2198 if path.endswith('browsertest.cc') or path.endswith('browser_test.cc'):
2199 has_browser_test = True
2200 if has_new_crosapi and not has_browser_test:
2201 return [
2202 output_api.PresubmitPromptWarning(
2203 'You are adding a new crosapi, but there is no file ends with '
2204 'browsertest.cc file being added or modified. It is important '
2205 'to add crosapi browser test coverage to avoid version '
2206 ' skew issues.\n'
2207 'Check //docs/lacros/test_instructions.md for more information.'
2208 )
2209 ]
2210 return []
2211
2212
Saagar Sanghavifceeaae2020-08-12 16:40:362213def CheckValidHostsInDEPSOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502214 """Checks that DEPS file deps are from allowed_hosts."""
2215 # Run only if DEPS file has been modified to annoy fewer bystanders.
2216 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
2217 return []
2218 # Outsource work to gclient verify
2219 try:
2220 gclient_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
2221 'third_party', 'depot_tools',
2222 'gclient.py')
2223 input_api.subprocess.check_output(
Bruce Dawson8a43cf72022-05-13 17:10:322224 [input_api.python3_executable, gclient_path, 'verify'],
Sam Maiera6e76d72022-02-11 21:43:502225 stderr=input_api.subprocess.STDOUT)
2226 return []
2227 except input_api.subprocess.CalledProcessError as error:
2228 return [
2229 output_api.PresubmitError(
2230 'DEPS file must have only git dependencies.',
2231 long_text=error.output)
2232 ]
tandriief664692014-09-23 14:51:472233
2234
Mario Sanchez Prada2472cab2019-09-18 10:58:312235def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152236 ban_rule):
Allen Bauer84778682022-09-22 16:28:562237 """Helper method for checking for banned constructs.
Mario Sanchez Prada2472cab2019-09-18 10:58:312238
Sam Maiera6e76d72022-02-11 21:43:502239 Returns an string composed of the name of the file, the line number where the
2240 match has been found and the additional text passed as |message| in case the
2241 target type name matches the text inside the line passed as parameter.
2242 """
2243 result = []
Peng Huang9c5949a02020-06-11 19:20:542244
Daniel Chenga44a1bcd2022-03-15 20:00:152245 # Ignore comments about banned types.
2246 if input_api.re.search(r"^ *//", line):
Sam Maiera6e76d72022-02-11 21:43:502247 return result
Daniel Chenga44a1bcd2022-03-15 20:00:152248 # A // nocheck comment will bypass this error.
2249 if line.endswith(" nocheck"):
Sam Maiera6e76d72022-02-11 21:43:502250 return result
2251
2252 matched = False
Daniel Chenga44a1bcd2022-03-15 20:00:152253 if ban_rule.pattern[0:1] == '/':
2254 regex = ban_rule.pattern[1:]
Sam Maiera6e76d72022-02-11 21:43:502255 if input_api.re.search(regex, line):
2256 matched = True
Daniel Chenga44a1bcd2022-03-15 20:00:152257 elif ban_rule.pattern in line:
Sam Maiera6e76d72022-02-11 21:43:502258 matched = True
2259
2260 if matched:
2261 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
Daniel Chenga44a1bcd2022-03-15 20:00:152262 for line in ban_rule.explanation:
2263 result.append(' %s' % line)
Sam Maiera6e76d72022-02-11 21:43:502264
danakjd18e8892020-12-17 17:42:012265 return result
Mario Sanchez Prada2472cab2019-09-18 10:58:312266
2267
Saagar Sanghavifceeaae2020-08-12 16:40:362268def CheckNoBannedFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502269 """Make sure that banned functions are not used."""
2270 warnings = []
2271 errors = []
[email protected]127f18ec2012-06-16 05:05:592272
Sam Maiera6e76d72022-02-11 21:43:502273 def IsExcludedFile(affected_file, excluded_paths):
Daniel Chenga44a1bcd2022-03-15 20:00:152274 if not excluded_paths:
2275 return False
2276
Sam Maiera6e76d72022-02-11 21:43:502277 local_path = affected_file.LocalPath()
Bruce Dawson40fece62022-09-16 19:58:312278 # Consistently use / as path separator to simplify the writing of regex
2279 # expressions.
2280 local_path = local_path.replace(input_api.os_path.sep, '/')
Sam Maiera6e76d72022-02-11 21:43:502281 for item in excluded_paths:
2282 if input_api.re.match(item, local_path):
2283 return True
2284 return False
wnwenbdc444e2016-05-25 13:44:152285
Sam Maiera6e76d72022-02-11 21:43:502286 def IsIosObjcFile(affected_file):
2287 local_path = affected_file.LocalPath()
2288 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m',
2289 '.h'):
2290 return False
2291 basename = input_api.os_path.basename(local_path)
2292 if 'ios' in basename.split('_'):
2293 return True
2294 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
2295 if sep and 'ios' in local_path.split(sep):
2296 return True
2297 return False
Sylvain Defresnea8b73d252018-02-28 15:45:542298
Daniel Chenga44a1bcd2022-03-15 20:00:152299 def CheckForMatch(affected_file, line_num: int, line: str,
2300 ban_rule: BanRule):
2301 if IsExcludedFile(affected_file, ban_rule.excluded_paths):
2302 return
2303
Sam Maiera6e76d72022-02-11 21:43:502304 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152305 ban_rule)
Sam Maiera6e76d72022-02-11 21:43:502306 if problems:
Daniel Chenga44a1bcd2022-03-15 20:00:152307 if ban_rule.treat_as_error is not None and ban_rule.treat_as_error:
Sam Maiera6e76d72022-02-11 21:43:502308 errors.extend(problems)
2309 else:
2310 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:152311
Sam Maiera6e76d72022-02-11 21:43:502312 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2313 for f in input_api.AffectedFiles(file_filter=file_filter):
2314 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152315 for ban_rule in _BANNED_JAVA_FUNCTIONS:
2316 CheckForMatch(f, line_num, line, ban_rule)
Eric Stevensona9a980972017-09-23 00:04:412317
Clement Yan9b330cb2022-11-17 05:25:292318 file_filter = lambda f: f.LocalPath().endswith(('.js', '.ts'))
2319 for f in input_api.AffectedFiles(file_filter=file_filter):
2320 for line_num, line in f.ChangedContents():
2321 for ban_rule in _BANNED_JAVASCRIPT_FUNCTIONS:
2322 CheckForMatch(f, line_num, line, ban_rule)
2323
Sam Maiera6e76d72022-02-11 21:43:502324 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
2325 for f in input_api.AffectedFiles(file_filter=file_filter):
2326 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152327 for ban_rule in _BANNED_OBJC_FUNCTIONS:
2328 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:592329
Sam Maiera6e76d72022-02-11 21:43:502330 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
2331 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152332 for ban_rule in _BANNED_IOS_OBJC_FUNCTIONS:
2333 CheckForMatch(f, line_num, line, ban_rule)
Sylvain Defresnea8b73d252018-02-28 15:45:542334
Sam Maiera6e76d72022-02-11 21:43:502335 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
2336 for f in input_api.AffectedFiles(file_filter=egtest_filter):
2337 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152338 for ban_rule in _BANNED_IOS_EGTEST_FUNCTIONS:
2339 CheckForMatch(f, line_num, line, ban_rule)
Peter K. Lee6c03ccff2019-07-15 14:40:052340
Sam Maiera6e76d72022-02-11 21:43:502341 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
2342 for f in input_api.AffectedFiles(file_filter=file_filter):
2343 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152344 for ban_rule in _BANNED_CPP_FUNCTIONS:
2345 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:592346
Daniel Cheng92c15e32022-03-16 17:48:222347 file_filter = lambda f: f.LocalPath().endswith(('.mojom'))
2348 for f in input_api.AffectedFiles(file_filter=file_filter):
2349 for line_num, line in f.ChangedContents():
2350 for ban_rule in _BANNED_MOJOM_PATTERNS:
2351 CheckForMatch(f, line_num, line, ban_rule)
2352
2353
Sam Maiera6e76d72022-02-11 21:43:502354 result = []
2355 if (warnings):
2356 result.append(
2357 output_api.PresubmitPromptWarning('Banned functions were used.\n' +
2358 '\n'.join(warnings)))
2359 if (errors):
2360 result.append(
2361 output_api.PresubmitError('Banned functions were used.\n' +
2362 '\n'.join(errors)))
2363 return result
[email protected]127f18ec2012-06-16 05:05:592364
Allen Bauer84778682022-09-22 16:28:562365def CheckNoLayoutCallsInTests(input_api, output_api):
2366 """Make sure there are no explicit calls to View::Layout() in tests"""
2367 warnings = []
2368 ban_rule = BanRule(
2369 r'/(\.|->)Layout\(\);',
2370 (
2371 'Direct calls to View::Layout() are not allowed in tests. '
2372 'If the view must be laid out here, use RunScheduledLayout(view). It '
2373 'is found in //ui/views/test/views_test_utils.h. '
2374 'See http://crbug.com/1350521 for more details.',
2375 ),
2376 False,
2377 )
2378 file_filter = lambda f: input_api.re.search(
2379 r'_(unittest|browsertest|ui_test).*\.(cc|mm)$', f.LocalPath())
2380 for f in input_api.AffectedFiles(file_filter = file_filter):
2381 for line_num, line in f.ChangedContents():
2382 problems = _GetMessageForMatchingType(input_api, f,
2383 line_num, line,
2384 ban_rule)
2385 if problems:
2386 warnings.extend(problems)
2387 result = []
2388 if (warnings):
2389 result.append(
2390 output_api.PresubmitPromptWarning(
2391 'Banned call to View::Layout() in tests.\n\n'.join(warnings)))
2392 return result
[email protected]127f18ec2012-06-16 05:05:592393
Michael Thiessen44457642020-02-06 00:24:152394def _CheckAndroidNoBannedImports(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502395 """Make sure that banned java imports are not used."""
2396 errors = []
Michael Thiessen44457642020-02-06 00:24:152397
Sam Maiera6e76d72022-02-11 21:43:502398 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2399 for f in input_api.AffectedFiles(file_filter=file_filter):
2400 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152401 for ban_rule in _BANNED_JAVA_IMPORTS:
2402 # Consider merging this into the above function. There is no
2403 # real difference anymore other than helping with a little
2404 # bit of boilerplate text. Doing so means things like
2405 # `treat_as_error` will also be uniformly handled.
Sam Maiera6e76d72022-02-11 21:43:502406 problems = _GetMessageForMatchingType(input_api, f, line_num,
Daniel Chenga44a1bcd2022-03-15 20:00:152407 line, ban_rule)
Sam Maiera6e76d72022-02-11 21:43:502408 if problems:
2409 errors.extend(problems)
2410 result = []
2411 if (errors):
2412 result.append(
2413 output_api.PresubmitError('Banned imports were used.\n' +
2414 '\n'.join(errors)))
2415 return result
Michael Thiessen44457642020-02-06 00:24:152416
2417
Saagar Sanghavifceeaae2020-08-12 16:40:362418def CheckNoPragmaOnce(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502419 """Make sure that banned functions are not used."""
2420 files = []
2421 pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
2422 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2423 if not f.LocalPath().endswith('.h'):
2424 continue
Bruce Dawson4c4c2922022-05-02 18:07:332425 if f.LocalPath().endswith('com_imported_mstscax.h'):
2426 continue
Sam Maiera6e76d72022-02-11 21:43:502427 contents = input_api.ReadFile(f)
2428 if pattern.search(contents):
2429 files.append(f)
[email protected]6c063c62012-07-11 19:11:062430
Sam Maiera6e76d72022-02-11 21:43:502431 if files:
2432 return [
2433 output_api.PresubmitError(
2434 'Do not use #pragma once in header files.\n'
2435 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
2436 files)
2437 ]
2438 return []
[email protected]6c063c62012-07-11 19:11:062439
[email protected]127f18ec2012-06-16 05:05:592440
Saagar Sanghavifceeaae2020-08-12 16:40:362441def CheckNoTrinaryTrueFalse(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502442 """Checks to make sure we don't introduce use of foo ? true : false."""
2443 problems = []
2444 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
2445 for f in input_api.AffectedFiles():
2446 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2447 continue
[email protected]e7479052012-09-19 00:26:122448
Sam Maiera6e76d72022-02-11 21:43:502449 for line_num, line in f.ChangedContents():
2450 if pattern.match(line):
2451 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]e7479052012-09-19 00:26:122452
Sam Maiera6e76d72022-02-11 21:43:502453 if not problems:
2454 return []
2455 return [
2456 output_api.PresubmitPromptWarning(
2457 'Please consider avoiding the "? true : false" pattern if possible.\n'
2458 + '\n'.join(problems))
2459 ]
[email protected]e7479052012-09-19 00:26:122460
2461
Saagar Sanghavifceeaae2020-08-12 16:40:362462def CheckUnwantedDependencies(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502463 """Runs checkdeps on #include and import statements added in this
2464 change. Breaking - rules is an error, breaking ! rules is a
2465 warning.
2466 """
2467 # Return early if no relevant file types were modified.
2468 for f in input_api.AffectedFiles():
2469 path = f.LocalPath()
2470 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path)
2471 or _IsJavaFile(input_api, path)):
2472 break
[email protected]55f9f382012-07-31 11:02:182473 else:
Sam Maiera6e76d72022-02-11 21:43:502474 return []
rhalavati08acd232017-04-03 07:23:282475
Sam Maiera6e76d72022-02-11 21:43:502476 import sys
2477 # We need to wait until we have an input_api object and use this
2478 # roundabout construct to import checkdeps because this file is
2479 # eval-ed and thus doesn't have __file__.
2480 original_sys_path = sys.path
2481 try:
2482 sys.path = sys.path + [
2483 input_api.os_path.join(input_api.PresubmitLocalPath(),
2484 'buildtools', 'checkdeps')
2485 ]
2486 import checkdeps
2487 from rules import Rule
2488 finally:
2489 # Restore sys.path to what it was before.
2490 sys.path = original_sys_path
[email protected]55f9f382012-07-31 11:02:182491
Sam Maiera6e76d72022-02-11 21:43:502492 added_includes = []
2493 added_imports = []
2494 added_java_imports = []
2495 for f in input_api.AffectedFiles():
2496 if _IsCPlusPlusFile(input_api, f.LocalPath()):
2497 changed_lines = [line for _, line in f.ChangedContents()]
2498 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
2499 elif _IsProtoFile(input_api, f.LocalPath()):
2500 changed_lines = [line for _, line in f.ChangedContents()]
2501 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
2502 elif _IsJavaFile(input_api, f.LocalPath()):
2503 changed_lines = [line for _, line in f.ChangedContents()]
2504 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:242505
Sam Maiera6e76d72022-02-11 21:43:502506 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
2507
2508 error_descriptions = []
2509 warning_descriptions = []
2510 error_subjects = set()
2511 warning_subjects = set()
2512
2513 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2514 added_includes):
2515 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2516 description_with_path = '%s\n %s' % (path, rule_description)
2517 if rule_type == Rule.DISALLOW:
2518 error_descriptions.append(description_with_path)
2519 error_subjects.add("#includes")
2520 else:
2521 warning_descriptions.append(description_with_path)
2522 warning_subjects.add("#includes")
2523
2524 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2525 added_imports):
2526 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2527 description_with_path = '%s\n %s' % (path, rule_description)
2528 if rule_type == Rule.DISALLOW:
2529 error_descriptions.append(description_with_path)
2530 error_subjects.add("imports")
2531 else:
2532 warning_descriptions.append(description_with_path)
2533 warning_subjects.add("imports")
2534
2535 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
2536 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
2537 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2538 description_with_path = '%s\n %s' % (path, rule_description)
2539 if rule_type == Rule.DISALLOW:
2540 error_descriptions.append(description_with_path)
2541 error_subjects.add("imports")
2542 else:
2543 warning_descriptions.append(description_with_path)
2544 warning_subjects.add("imports")
2545
2546 results = []
2547 if error_descriptions:
2548 results.append(
2549 output_api.PresubmitError(
2550 'You added one or more %s that violate checkdeps rules.' %
2551 " and ".join(error_subjects), error_descriptions))
2552 if warning_descriptions:
2553 results.append(
2554 output_api.PresubmitPromptOrNotify(
2555 'You added one or more %s of files that are temporarily\n'
2556 'allowed but being removed. Can you avoid introducing the\n'
2557 '%s? See relevant DEPS file(s) for details and contacts.' %
2558 (" and ".join(warning_subjects), "/".join(warning_subjects)),
2559 warning_descriptions))
2560 return results
[email protected]55f9f382012-07-31 11:02:182561
2562
Saagar Sanghavifceeaae2020-08-12 16:40:362563def CheckFilePermissions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502564 """Check that all files have their permissions properly set."""
2565 if input_api.platform == 'win32':
2566 return []
2567 checkperms_tool = input_api.os_path.join(input_api.PresubmitLocalPath(),
2568 'tools', 'checkperms',
2569 'checkperms.py')
2570 args = [
Bruce Dawson8a43cf72022-05-13 17:10:322571 input_api.python3_executable, checkperms_tool, '--root',
Sam Maiera6e76d72022-02-11 21:43:502572 input_api.change.RepositoryRoot()
2573 ]
2574 with input_api.CreateTemporaryFile() as file_list:
2575 for f in input_api.AffectedFiles():
2576 # checkperms.py file/directory arguments must be relative to the
2577 # repository.
2578 file_list.write((f.LocalPath() + '\n').encode('utf8'))
2579 file_list.close()
2580 args += ['--file-list', file_list.name]
2581 try:
2582 input_api.subprocess.check_output(args)
2583 return []
2584 except input_api.subprocess.CalledProcessError as error:
2585 return [
2586 output_api.PresubmitError('checkperms.py failed:',
2587 long_text=error.output.decode(
2588 'utf-8', 'ignore'))
2589 ]
[email protected]fbcafe5a2012-08-08 15:31:222590
2591
Saagar Sanghavifceeaae2020-08-12 16:40:362592def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502593 """Makes sure we don't include ui/aura/window_property.h
2594 in header files.
2595 """
2596 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2597 errors = []
2598 for f in input_api.AffectedFiles():
2599 if not f.LocalPath().endswith('.h'):
2600 continue
2601 for line_num, line in f.ChangedContents():
2602 if pattern.match(line):
2603 errors.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]c8278b32012-10-30 20:35:492604
Sam Maiera6e76d72022-02-11 21:43:502605 results = []
2606 if errors:
2607 results.append(
2608 output_api.PresubmitError(
2609 'Header files should not include ui/aura/window_property.h',
2610 errors))
2611 return results
[email protected]c8278b32012-10-30 20:35:492612
2613
Omer Katzcc77ea92021-04-26 10:23:282614def CheckNoInternalHeapIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502615 """Makes sure we don't include any headers from
2616 third_party/blink/renderer/platform/heap/impl or
2617 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
2618 third_party/blink/renderer/platform/heap
2619 """
2620 impl_pattern = input_api.re.compile(
2621 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
2622 v8_wrapper_pattern = input_api.re.compile(
2623 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"'
2624 )
Bruce Dawson40fece62022-09-16 19:58:312625 # Consistently use / as path separator to simplify the writing of regex
2626 # expressions.
Sam Maiera6e76d72022-02-11 21:43:502627 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:312628 r"^third_party/blink/renderer/platform/heap/.*",
2629 f.LocalPath().replace(input_api.os_path.sep, '/'))
Sam Maiera6e76d72022-02-11 21:43:502630 errors = []
Omer Katzcc77ea92021-04-26 10:23:282631
Sam Maiera6e76d72022-02-11 21:43:502632 for f in input_api.AffectedFiles(file_filter=file_filter):
2633 for line_num, line in f.ChangedContents():
2634 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
2635 errors.append(' %s:%d' % (f.LocalPath(), line_num))
Omer Katzcc77ea92021-04-26 10:23:282636
Sam Maiera6e76d72022-02-11 21:43:502637 results = []
2638 if errors:
2639 results.append(
2640 output_api.PresubmitError(
2641 'Do not include files from third_party/blink/renderer/platform/heap/impl'
2642 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
2643 'relevant counterparts from third_party/blink/renderer/platform/heap',
2644 errors))
2645 return results
Omer Katzcc77ea92021-04-26 10:23:282646
2647
[email protected]70ca77752012-11-20 03:45:032648def _CheckForVersionControlConflictsInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:502649 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2650 errors = []
2651 for line_num, line in f.ChangedContents():
2652 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
2653 # First-level headers in markdown look a lot like version control
2654 # conflict markers. http://daringfireball.net/projects/markdown/basics
2655 continue
2656 if pattern.match(line):
2657 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2658 return errors
[email protected]70ca77752012-11-20 03:45:032659
2660
Saagar Sanghavifceeaae2020-08-12 16:40:362661def CheckForVersionControlConflicts(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502662 """Usually this is not intentional and will cause a compile failure."""
2663 errors = []
2664 for f in input_api.AffectedFiles():
2665 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
[email protected]70ca77752012-11-20 03:45:032666
Sam Maiera6e76d72022-02-11 21:43:502667 results = []
2668 if errors:
2669 results.append(
2670 output_api.PresubmitError(
2671 'Version control conflict markers found, please resolve.',
2672 errors))
2673 return results
[email protected]70ca77752012-11-20 03:45:032674
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202675
Saagar Sanghavifceeaae2020-08-12 16:40:362676def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502677 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2678 errors = []
2679 for f in input_api.AffectedFiles():
2680 for line_num, line in f.ChangedContents():
2681 if pattern.search(line):
2682 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
estadee17314a02017-01-12 16:22:162683
Sam Maiera6e76d72022-02-11 21:43:502684 results = []
2685 if errors:
2686 results.append(
2687 output_api.PresubmitPromptWarning(
2688 'Found Google support URL addressed by answer number. Please replace '
2689 'with a p= identifier instead. See crbug.com/679462\n',
2690 errors))
2691 return results
estadee17314a02017-01-12 16:22:162692
[email protected]70ca77752012-11-20 03:45:032693
Saagar Sanghavifceeaae2020-08-12 16:40:362694def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502695 def FilterFile(affected_file):
2696 """Filter function for use with input_api.AffectedSourceFiles,
2697 below. This filters out everything except non-test files from
2698 top-level directories that generally speaking should not hard-code
2699 service URLs (e.g. src/android_webview/, src/content/ and others).
2700 """
2701 return input_api.FilterSourceFile(
2702 affected_file,
Bruce Dawson40fece62022-09-16 19:58:312703 files_to_check=[r'^(android_webview|base|content|net)/.*'],
Sam Maiera6e76d72022-02-11 21:43:502704 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2705 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442706
Sam Maiera6e76d72022-02-11 21:43:502707 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2708 '\.(com|net)[^"]*"')
2709 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2710 pattern = input_api.re.compile(base_pattern)
2711 problems = [] # items are (filename, line_number, line)
2712 for f in input_api.AffectedSourceFiles(FilterFile):
2713 for line_num, line in f.ChangedContents():
2714 if not comment_pattern.search(line) and pattern.search(line):
2715 problems.append((f.LocalPath(), line_num, line))
[email protected]06e6d0ff2012-12-11 01:36:442716
Sam Maiera6e76d72022-02-11 21:43:502717 if problems:
2718 return [
2719 output_api.PresubmitPromptOrNotify(
2720 'Most layers below src/chrome/ should not hardcode service URLs.\n'
2721 'Are you sure this is correct?', [
2722 ' %s:%d: %s' % (problem[0], problem[1], problem[2])
2723 for problem in problems
2724 ])
2725 ]
2726 else:
2727 return []
[email protected]06e6d0ff2012-12-11 01:36:442728
2729
Saagar Sanghavifceeaae2020-08-12 16:40:362730def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502731 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
James Cook6b6597c2019-11-06 22:05:292732
Sam Maiera6e76d72022-02-11 21:43:502733 def FileFilter(affected_file):
2734 """Includes directories known to be Chrome OS only."""
2735 return input_api.FilterSourceFile(
2736 affected_file,
2737 files_to_check=(
2738 '^ash/',
2739 '^chromeos/', # Top-level src/chromeos.
2740 '.*/chromeos/', # Any path component.
2741 '^components/arc',
2742 '^components/exo'),
2743 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292744
Sam Maiera6e76d72022-02-11 21:43:502745 prefs = []
2746 priority_prefs = []
2747 for f in input_api.AffectedFiles(file_filter=FileFilter):
2748 for line_num, line in f.ChangedContents():
2749 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF',
2750 line):
2751 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2752 prefs.append(' %s' % line)
2753 if input_api.re.search(
2754 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2755 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2756 priority_prefs.append(' %s' % line)
2757
2758 results = []
2759 if (prefs):
2760 results.append(
2761 output_api.PresubmitPromptWarning(
2762 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2763 'by browser sync settings. If these prefs should be controlled by OS '
2764 'sync settings use SYNCABLE_OS_PREF instead.\n' +
2765 '\n'.join(prefs)))
2766 if (priority_prefs):
2767 results.append(
2768 output_api.PresubmitPromptWarning(
2769 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2770 'controlled by browser sync settings. If these prefs should be '
2771 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2772 'instead.\n' + '\n'.join(prefs)))
2773 return results
James Cook6b6597c2019-11-06 22:05:292774
2775
Saagar Sanghavifceeaae2020-08-12 16:40:362776def CheckNoAbbreviationInPngFileName(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502777 """Makes sure there are no abbreviations in the name of PNG files.
2778 The native_client_sdk directory is excluded because it has auto-generated PNG
2779 files for documentation.
2780 """
2781 errors = []
Yuanqing Zhu9eef02832022-12-04 14:42:172782 files_to_check = [r'.*\.png$']
Bruce Dawson40fece62022-09-16 19:58:312783 files_to_skip = [r'^native_client_sdk/',
2784 r'^services/test/',
2785 r'^third_party/blink/web_tests/',
Bruce Dawson3db456212022-05-02 05:34:182786 ]
Sam Maiera6e76d72022-02-11 21:43:502787 file_filter = lambda f: input_api.FilterSourceFile(
2788 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Yuanqing Zhu9eef02832022-12-04 14:42:172789 abbreviation = input_api.re.compile('.+_[a-z]\.png|.+_[a-z]_.*\.png')
Sam Maiera6e76d72022-02-11 21:43:502790 for f in input_api.AffectedFiles(include_deletes=False,
2791 file_filter=file_filter):
Yuanqing Zhu9eef02832022-12-04 14:42:172792 file_name = input_api.os_path.split(f.LocalPath())[1]
2793 if abbreviation.search(file_name):
2794 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272795
Sam Maiera6e76d72022-02-11 21:43:502796 results = []
2797 if errors:
2798 results.append(
2799 output_api.PresubmitError(
2800 'The name of PNG files should not have abbreviations. \n'
2801 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2802 'Contact [email protected] if you have questions.', errors))
2803 return results
[email protected]d2530012013-01-25 16:39:272804
Evan Stade7cd4a2c2022-08-04 23:37:252805def CheckNoProductIconsAddedToPublicRepo(input_api, output_api):
2806 """Heuristically identifies product icons based on their file name and reminds
2807 contributors not to add them to the Chromium repository.
2808 """
2809 errors = []
2810 files_to_check = [r'.*google.*\.png$|.*google.*\.svg$|.*google.*\.icon$']
2811 file_filter = lambda f: input_api.FilterSourceFile(
2812 f, files_to_check=files_to_check)
2813 for f in input_api.AffectedFiles(include_deletes=False,
2814 file_filter=file_filter):
2815 errors.append(' %s' % f.LocalPath())
2816
2817 results = []
2818 if errors:
Bruce Dawson3bcf0c92022-08-12 00:03:082819 # Give warnings instead of errors on presubmit --all and presubmit
2820 # --files.
2821 message_type = (output_api.PresubmitNotifyResult if input_api.no_diffs
2822 else output_api.PresubmitError)
Evan Stade7cd4a2c2022-08-04 23:37:252823 results.append(
Bruce Dawson3bcf0c92022-08-12 00:03:082824 message_type(
Evan Stade7cd4a2c2022-08-04 23:37:252825 'Trademarked images should not be added to the public repo. '
2826 'See crbug.com/944754', errors))
2827 return results
2828
[email protected]d2530012013-01-25 16:39:272829
Daniel Cheng4dcdb6b2017-04-13 08:30:172830def _ExtractAddRulesFromParsedDeps(parsed_deps):
Sam Maiera6e76d72022-02-11 21:43:502831 """Extract the rules that add dependencies from a parsed DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172832
Sam Maiera6e76d72022-02-11 21:43:502833 Args:
2834 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2835 add_rules = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172836 add_rules.update([
Sam Maiera6e76d72022-02-11 21:43:502837 rule[1:] for rule in parsed_deps.get('include_rules', [])
Daniel Cheng4dcdb6b2017-04-13 08:30:172838 if rule.startswith('+') or rule.startswith('!')
2839 ])
Sam Maiera6e76d72022-02-11 21:43:502840 for _, rules in parsed_deps.get('specific_include_rules', {}).items():
2841 add_rules.update([
2842 rule[1:] for rule in rules
2843 if rule.startswith('+') or rule.startswith('!')
2844 ])
2845 return add_rules
Daniel Cheng4dcdb6b2017-04-13 08:30:172846
2847
2848def _ParseDeps(contents):
Sam Maiera6e76d72022-02-11 21:43:502849 """Simple helper for parsing DEPS files."""
Daniel Cheng4dcdb6b2017-04-13 08:30:172850
Sam Maiera6e76d72022-02-11 21:43:502851 # Stubs for handling special syntax in the root DEPS file.
2852 class _VarImpl:
2853 def __init__(self, local_scope):
2854 self._local_scope = local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172855
Sam Maiera6e76d72022-02-11 21:43:502856 def Lookup(self, var_name):
2857 """Implements the Var syntax."""
2858 try:
2859 return self._local_scope['vars'][var_name]
2860 except KeyError:
2861 raise Exception('Var is not defined: %s' % var_name)
Daniel Cheng4dcdb6b2017-04-13 08:30:172862
Sam Maiera6e76d72022-02-11 21:43:502863 local_scope = {}
2864 global_scope = {
2865 'Var': _VarImpl(local_scope).Lookup,
2866 'Str': str,
2867 }
Dirk Pranke1b9e06382021-05-14 01:16:222868
Sam Maiera6e76d72022-02-11 21:43:502869 exec(contents, global_scope, local_scope)
2870 return local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172871
2872
2873def _CalculateAddedDeps(os_path, old_contents, new_contents):
Sam Maiera6e76d72022-02-11 21:43:502874 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
2875 a set of DEPS entries that we should look up.
[email protected]14a6131c2014-01-08 01:15:412876
Sam Maiera6e76d72022-02-11 21:43:502877 For a directory (rather than a specific filename) we fake a path to
2878 a specific filename by adding /DEPS. This is chosen as a file that
2879 will seldom or never be subject to per-file include_rules.
2880 """
2881 # We ignore deps entries on auto-generated directories.
2882 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082883
Sam Maiera6e76d72022-02-11 21:43:502884 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2885 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
Daniel Cheng4dcdb6b2017-04-13 08:30:172886
Sam Maiera6e76d72022-02-11 21:43:502887 added_deps = new_deps.difference(old_deps)
Daniel Cheng4dcdb6b2017-04-13 08:30:172888
Sam Maiera6e76d72022-02-11 21:43:502889 results = set()
2890 for added_dep in added_deps:
2891 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2892 continue
2893 # Assume that a rule that ends in .h is a rule for a specific file.
2894 if added_dep.endswith('.h'):
2895 results.add(added_dep)
2896 else:
2897 results.add(os_path.join(added_dep, 'DEPS'))
2898 return results
[email protected]f32e2d1e2013-07-26 21:39:082899
2900
Saagar Sanghavifceeaae2020-08-12 16:40:362901def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502902 """When a dependency prefixed with + is added to a DEPS file, we
2903 want to make sure that the change is reviewed by an OWNER of the
2904 target file or directory, to avoid layering violations from being
2905 introduced. This check verifies that this happens.
2906 """
2907 # We rely on Gerrit's code-owners to check approvals.
2908 # input_api.gerrit is always set for Chromium, but other projects
2909 # might not use Gerrit.
Bruce Dawson344ab262022-06-04 11:35:102910 if not input_api.gerrit or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:502911 return []
Bruce Dawsonb357aeb2022-08-09 15:38:302912 if 'PRESUBMIT_SKIP_NETWORK' in input_api.environ:
Sam Maiera6e76d72022-02-11 21:43:502913 return []
Bruce Dawsonb357aeb2022-08-09 15:38:302914 try:
2915 if (input_api.change.issue and
2916 input_api.gerrit.IsOwnersOverrideApproved(
2917 input_api.change.issue)):
2918 # Skip OWNERS check when Owners-Override label is approved. This is
2919 # intended for global owners, trusted bots, and on-call sheriffs.
2920 # Review is still required for these changes.
2921 return []
2922 except Exception as e:
Sam Maier4cef9242022-10-03 14:21:242923 return [output_api.PresubmitPromptWarning(
2924 'Failed to retrieve owner override status - %s' % str(e))]
Edward Lesmes6fba51082021-01-20 04:20:232925
Sam Maiera6e76d72022-02-11 21:43:502926 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242927
Bruce Dawson40fece62022-09-16 19:58:312928 # Consistently use / as path separator to simplify the writing of regex
2929 # expressions.
Sam Maiera6e76d72022-02-11 21:43:502930 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:312931 r"^third_party/blink/.*",
2932 f.LocalPath().replace(input_api.os_path.sep, '/'))
Sam Maiera6e76d72022-02-11 21:43:502933 for f in input_api.AffectedFiles(include_deletes=False,
2934 file_filter=file_filter):
2935 filename = input_api.os_path.basename(f.LocalPath())
2936 if filename == 'DEPS':
2937 virtual_depended_on_files.update(
2938 _CalculateAddedDeps(input_api.os_path,
2939 '\n'.join(f.OldContents()),
2940 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552941
Sam Maiera6e76d72022-02-11 21:43:502942 if not virtual_depended_on_files:
2943 return []
[email protected]e871964c2013-05-13 14:14:552944
Sam Maiera6e76d72022-02-11 21:43:502945 if input_api.is_committing:
2946 if input_api.tbr:
2947 return [
2948 output_api.PresubmitNotifyResult(
2949 '--tbr was specified, skipping OWNERS check for DEPS additions'
2950 )
2951 ]
Daniel Cheng3008dc12022-05-13 04:02:112952 # TODO(dcheng): Make this generate an error on dry runs if the reviewer
2953 # is not added, to prevent review serialization.
Sam Maiera6e76d72022-02-11 21:43:502954 if input_api.dry_run:
2955 return [
2956 output_api.PresubmitNotifyResult(
2957 'This is a dry run, skipping OWNERS check for DEPS additions'
2958 )
2959 ]
2960 if not input_api.change.issue:
2961 return [
2962 output_api.PresubmitError(
2963 "DEPS approval by OWNERS check failed: this change has "
2964 "no change number, so we can't check it for approvals.")
2965 ]
2966 output = output_api.PresubmitError
[email protected]14a6131c2014-01-08 01:15:412967 else:
Sam Maiera6e76d72022-02-11 21:43:502968 output = output_api.PresubmitNotifyResult
[email protected]e871964c2013-05-13 14:14:552969
Sam Maiera6e76d72022-02-11 21:43:502970 owner_email, reviewers = (
2971 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2972 input_api, None, approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552973
Sam Maiera6e76d72022-02-11 21:43:502974 owner_email = owner_email or input_api.change.author_email
2975
2976 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2977 virtual_depended_on_files, reviewers.union([owner_email]), [])
2978 missing_files = [
2979 f for f in virtual_depended_on_files
2980 if approval_status[f] != input_api.owners_client.APPROVED
2981 ]
2982
2983 # We strip the /DEPS part that was added by
2984 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2985 # directory.
2986 def StripDeps(path):
2987 start_deps = path.rfind('/DEPS')
2988 if start_deps != -1:
2989 return path[:start_deps]
2990 else:
2991 return path
2992
2993 unapproved_dependencies = [
2994 "'+%s'," % StripDeps(path) for path in missing_files
2995 ]
2996
2997 if unapproved_dependencies:
2998 output_list = [
2999 output(
3000 'You need LGTM from owners of depends-on paths in DEPS that were '
3001 'modified in this CL:\n %s' %
3002 '\n '.join(sorted(unapproved_dependencies)))
3003 ]
3004 suggested_owners = input_api.owners_client.SuggestOwners(
3005 missing_files, exclude=[owner_email])
3006 output_list.append(
3007 output('Suggested missing target path OWNERS:\n %s' %
3008 '\n '.join(suggested_owners or [])))
3009 return output_list
3010
3011 return []
[email protected]e871964c2013-05-13 14:14:553012
3013
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493014# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:363015def CheckSpamLogging(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503016 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3017 files_to_skip = (
3018 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3019 input_api.DEFAULT_FILES_TO_SKIP + (
Jaewon Jung2f323bb2022-12-07 23:55:013020 r"^base/fuchsia/scoped_fx_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313021 r"^base/logging\.h$",
3022 r"^base/logging\.cc$",
3023 r"^base/task/thread_pool/task_tracker\.cc$",
3024 r"^chrome/app/chrome_main_delegate\.cc$",
Yao Li359937b2023-02-15 23:43:033025 r"^chrome/browser/ash/arc/enterprise/cert_store/arc_cert_installer\.cc$",
3026 r"^chrome/browser/ash/policy/remote_commands/user_command_arc_job\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313027 r"^chrome/browser/chrome_browser_main\.cc$",
3028 r"^chrome/browser/ui/startup/startup_browser_creator\.cc$",
3029 r"^chrome/browser/browser_switcher/bho/.*",
3030 r"^chrome/browser/diagnostics/diagnostics_writer\.cc$",
3031 r"^chrome/chrome_cleaner/.*",
3032 r"^chrome/chrome_elf/dll_hash/dll_hash_main\.cc$",
3033 r"^chrome/installer/setup/.*",
3034 r"^chromecast/",
Bruce Dawson40fece62022-09-16 19:58:313035 r"^components/media_control/renderer/media_playback_options\.cc$",
Salma Elmahallawy52976452023-01-27 17:04:493036 r"^components/policy/core/common/policy_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313037 r"^components/viz/service/display/"
Sam Maiera6e76d72022-02-11 21:43:503038 r"overlay_strategy_underlay_cast\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313039 r"^components/zucchini/.*",
Sam Maiera6e76d72022-02-11 21:43:503040 # TODO(peter): Remove exception. https://crbug.com/534537
Bruce Dawson40fece62022-09-16 19:58:313041 r"^content/browser/notifications/"
Sam Maiera6e76d72022-02-11 21:43:503042 r"notification_event_dispatcher_impl\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313043 r"^content/common/gpu/client/gl_helper_benchmark\.cc$",
3044 r"^courgette/courgette_minimal_tool\.cc$",
3045 r"^courgette/courgette_tool\.cc$",
3046 r"^extensions/renderer/logging_native_handler\.cc$",
3047 r"^fuchsia_web/common/init_logging\.cc$",
3048 r"^fuchsia_web/runners/common/web_component\.cc$",
Caroline Liua7050132023-02-13 22:23:153049 r"^fuchsia_web/shell/.*\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313050 r"^headless/app/headless_shell\.cc$",
3051 r"^ipc/ipc_logging\.cc$",
3052 r"^native_client_sdk/",
3053 r"^remoting/base/logging\.h$",
3054 r"^remoting/host/.*",
3055 r"^sandbox/linux/.*",
3056 r"^storage/browser/file_system/dump_file_system\.cc$",
3057 r"^tools/",
3058 r"^ui/base/resource/data_pack\.cc$",
3059 r"^ui/aura/bench/bench_main\.cc$",
3060 r"^ui/ozone/platform/cast/",
3061 r"^ui/base/x/xwmstartupcheck/"
Sam Maiera6e76d72022-02-11 21:43:503062 r"xwmstartupcheck\.cc$"))
3063 source_file_filter = lambda x: input_api.FilterSourceFile(
3064 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:403065
Sam Maiera6e76d72022-02-11 21:43:503066 log_info = set([])
3067 printf = set([])
[email protected]85218562013-11-22 07:41:403068
Sam Maiera6e76d72022-02-11 21:43:503069 for f in input_api.AffectedSourceFiles(source_file_filter):
3070 for _, line in f.ChangedContents():
3071 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
3072 log_info.add(f.LocalPath())
3073 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
3074 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:373075
Sam Maiera6e76d72022-02-11 21:43:503076 if input_api.re.search(r"\bprintf\(", line):
3077 printf.add(f.LocalPath())
3078 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
3079 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:403080
Sam Maiera6e76d72022-02-11 21:43:503081 if log_info:
3082 return [
3083 output_api.PresubmitError(
3084 'These files spam the console log with LOG(INFO):',
3085 items=log_info)
3086 ]
3087 if printf:
3088 return [
3089 output_api.PresubmitError(
3090 'These files spam the console log with printf/fprintf:',
3091 items=printf)
3092 ]
3093 return []
[email protected]85218562013-11-22 07:41:403094
3095
Saagar Sanghavifceeaae2020-08-12 16:40:363096def CheckForAnonymousVariables(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503097 """These types are all expected to hold locks while in scope and
3098 so should never be anonymous (which causes them to be immediately
3099 destroyed)."""
3100 they_who_must_be_named = [
3101 'base::AutoLock',
3102 'base::AutoReset',
3103 'base::AutoUnlock',
3104 'SkAutoAlphaRestore',
3105 'SkAutoBitmapShaderInstall',
3106 'SkAutoBlitterChoose',
3107 'SkAutoBounderCommit',
3108 'SkAutoCallProc',
3109 'SkAutoCanvasRestore',
3110 'SkAutoCommentBlock',
3111 'SkAutoDescriptor',
3112 'SkAutoDisableDirectionCheck',
3113 'SkAutoDisableOvalCheck',
3114 'SkAutoFree',
3115 'SkAutoGlyphCache',
3116 'SkAutoHDC',
3117 'SkAutoLockColors',
3118 'SkAutoLockPixels',
3119 'SkAutoMalloc',
3120 'SkAutoMaskFreeImage',
3121 'SkAutoMutexAcquire',
3122 'SkAutoPathBoundsUpdate',
3123 'SkAutoPDFRelease',
3124 'SkAutoRasterClipValidate',
3125 'SkAutoRef',
3126 'SkAutoTime',
3127 'SkAutoTrace',
3128 'SkAutoUnref',
3129 ]
3130 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
3131 # bad: base::AutoLock(lock.get());
3132 # not bad: base::AutoLock lock(lock.get());
3133 bad_pattern = input_api.re.compile(anonymous)
3134 # good: new base::AutoLock(lock.get())
3135 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
3136 errors = []
[email protected]49aa76a2013-12-04 06:59:163137
Sam Maiera6e76d72022-02-11 21:43:503138 for f in input_api.AffectedFiles():
3139 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
3140 continue
3141 for linenum, line in f.ChangedContents():
3142 if bad_pattern.search(line) and not good_pattern.search(line):
3143 errors.append('%s:%d' % (f.LocalPath(), linenum))
[email protected]49aa76a2013-12-04 06:59:163144
Sam Maiera6e76d72022-02-11 21:43:503145 if errors:
3146 return [
3147 output_api.PresubmitError(
3148 'These lines create anonymous variables that need to be named:',
3149 items=errors)
3150 ]
3151 return []
[email protected]49aa76a2013-12-04 06:59:163152
3153
Saagar Sanghavifceeaae2020-08-12 16:40:363154def CheckUniquePtrOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503155 # Returns whether |template_str| is of the form <T, U...> for some types T
3156 # and U. Assumes that |template_str| is already in the form <...>.
3157 def HasMoreThanOneArg(template_str):
3158 # Level of <...> nesting.
3159 nesting = 0
3160 for c in template_str:
3161 if c == '<':
3162 nesting += 1
3163 elif c == '>':
3164 nesting -= 1
3165 elif c == ',' and nesting == 1:
3166 return True
3167 return False
Vaclav Brozekb7fadb692018-08-30 06:39:533168
Sam Maiera6e76d72022-02-11 21:43:503169 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3170 sources = lambda affected_file: input_api.FilterSourceFile(
3171 affected_file,
3172 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3173 DEFAULT_FILES_TO_SKIP),
3174 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:553175
Sam Maiera6e76d72022-02-11 21:43:503176 # Pattern to capture a single "<...>" block of template arguments. It can
3177 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
3178 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
3179 # latter would likely require counting that < and > match, which is not
3180 # expressible in regular languages. Should the need arise, one can introduce
3181 # limited counting (matching up to a total number of nesting depth), which
3182 # should cover all practical cases for already a low nesting limit.
3183 template_arg_pattern = (
3184 r'<[^>]*' # Opening block of <.
3185 r'>([^<]*>)?') # Closing block of >.
3186 # Prefix expressing that whatever follows is not already inside a <...>
3187 # block.
3188 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
3189 null_construct_pattern = input_api.re.compile(
3190 not_inside_template_arg_pattern + r'\bstd::unique_ptr' +
3191 template_arg_pattern + r'\(\)')
Vaclav Brozeka54c528b2018-04-06 19:23:553192
Sam Maiera6e76d72022-02-11 21:43:503193 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
3194 template_arg_no_array_pattern = (
3195 r'<[^>]*[^]]' # Opening block of <.
3196 r'>([^(<]*[^]]>)?') # Closing block of >.
3197 # Prefix saying that what follows is the start of an expression.
3198 start_of_expr_pattern = r'(=|\breturn|^)\s*'
3199 # Suffix saying that what follows are call parentheses with a non-empty list
3200 # of arguments.
3201 nonempty_arg_list_pattern = r'\(([^)]|$)'
3202 # Put the template argument into a capture group for deeper examination later.
3203 return_construct_pattern = input_api.re.compile(
3204 start_of_expr_pattern + r'std::unique_ptr' + '(?P<template_arg>' +
3205 template_arg_no_array_pattern + ')' + nonempty_arg_list_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:553206
Sam Maiera6e76d72022-02-11 21:43:503207 problems_constructor = []
3208 problems_nullptr = []
3209 for f in input_api.AffectedSourceFiles(sources):
3210 for line_number, line in f.ChangedContents():
3211 # Disallow:
3212 # return std::unique_ptr<T>(foo);
3213 # bar = std::unique_ptr<T>(foo);
3214 # But allow:
3215 # return std::unique_ptr<T[]>(foo);
3216 # bar = std::unique_ptr<T[]>(foo);
3217 # And also allow cases when the second template argument is present. Those
3218 # cases cannot be handled by std::make_unique:
3219 # return std::unique_ptr<T, U>(foo);
3220 # bar = std::unique_ptr<T, U>(foo);
3221 local_path = f.LocalPath()
3222 return_construct_result = return_construct_pattern.search(line)
3223 if return_construct_result and not HasMoreThanOneArg(
3224 return_construct_result.group('template_arg')):
3225 problems_constructor.append(
3226 '%s:%d\n %s' % (local_path, line_number, line.strip()))
3227 # Disallow:
3228 # std::unique_ptr<T>()
3229 if null_construct_pattern.search(line):
3230 problems_nullptr.append(
3231 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Vaclav Brozek851d9602018-04-04 16:13:053232
Sam Maiera6e76d72022-02-11 21:43:503233 errors = []
3234 if problems_nullptr:
3235 errors.append(
3236 output_api.PresubmitPromptWarning(
3237 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
3238 problems_nullptr))
3239 if problems_constructor:
3240 errors.append(
3241 output_api.PresubmitError(
3242 'The following files use explicit std::unique_ptr constructor. '
3243 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
3244 'std::make_unique is not an option.', problems_constructor))
3245 return errors
Peter Kasting4844e46e2018-02-23 07:27:103246
3247
Saagar Sanghavifceeaae2020-08-12 16:40:363248def CheckUserActionUpdate(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503249 """Checks if any new user action has been added."""
3250 if any('actions.xml' == input_api.os_path.basename(f)
3251 for f in input_api.LocalPaths()):
3252 # If actions.xml is already included in the changelist, the PRESUBMIT
3253 # for actions.xml will do a more complete presubmit check.
3254 return []
3255
3256 file_inclusion_pattern = [r'.*\.(cc|mm)$']
3257 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3258 input_api.DEFAULT_FILES_TO_SKIP)
3259 file_filter = lambda f: input_api.FilterSourceFile(
3260 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
3261
3262 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
3263 current_actions = None
3264 for f in input_api.AffectedFiles(file_filter=file_filter):
3265 for line_num, line in f.ChangedContents():
3266 match = input_api.re.search(action_re, line)
3267 if match:
3268 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
3269 # loaded only once.
3270 if not current_actions:
Bruce Dawson6cb2d4d2023-03-01 21:35:093271 with open('tools/metrics/actions/actions.xml',
3272 encoding='utf-8') as actions_f:
Sam Maiera6e76d72022-02-11 21:43:503273 current_actions = actions_f.read()
3274 # Search for the matched user action name in |current_actions|.
3275 for action_name in match.groups():
3276 action = 'name="{0}"'.format(action_name)
3277 if action not in current_actions:
3278 return [
3279 output_api.PresubmitPromptWarning(
3280 'File %s line %d: %s is missing in '
3281 'tools/metrics/actions/actions.xml. Please run '
3282 'tools/metrics/actions/extract_actions.py to update.'
3283 % (f.LocalPath(), line_num, action_name))
3284 ]
[email protected]999261d2014-03-03 20:08:083285 return []
3286
[email protected]999261d2014-03-03 20:08:083287
Daniel Cheng13ca61a882017-08-25 15:11:253288def _ImportJSONCommentEater(input_api):
Sam Maiera6e76d72022-02-11 21:43:503289 import sys
3290 sys.path = sys.path + [
3291 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3292 'json_comment_eater')
3293 ]
3294 import json_comment_eater
3295 return json_comment_eater
Daniel Cheng13ca61a882017-08-25 15:11:253296
3297
[email protected]99171a92014-06-03 08:44:473298def _GetJSONParseError(input_api, filename, eat_comments=True):
dchenge07de812016-06-20 19:27:173299 try:
Sam Maiera6e76d72022-02-11 21:43:503300 contents = input_api.ReadFile(filename)
3301 if eat_comments:
3302 json_comment_eater = _ImportJSONCommentEater(input_api)
3303 contents = json_comment_eater.Nom(contents)
dchenge07de812016-06-20 19:27:173304
Sam Maiera6e76d72022-02-11 21:43:503305 input_api.json.loads(contents)
3306 except ValueError as e:
3307 return e
Andrew Grieve4deedb12022-02-03 21:34:503308 return None
3309
3310
Sam Maiera6e76d72022-02-11 21:43:503311def _GetIDLParseError(input_api, filename):
3312 try:
3313 contents = input_api.ReadFile(filename)
Devlin Croninf7582a12022-04-21 21:14:283314 for i, char in enumerate(contents):
Daniel Chenga37c03db2022-05-12 17:20:343315 if not char.isascii():
3316 return (
3317 'Non-ascii character "%s" (ord %d) found at offset %d.' %
3318 (char, ord(char), i))
Sam Maiera6e76d72022-02-11 21:43:503319 idl_schema = input_api.os_path.join(input_api.PresubmitLocalPath(),
3320 'tools', 'json_schema_compiler',
3321 'idl_schema.py')
3322 process = input_api.subprocess.Popen(
Bruce Dawson679fb082022-04-14 00:47:283323 [input_api.python3_executable, idl_schema],
Sam Maiera6e76d72022-02-11 21:43:503324 stdin=input_api.subprocess.PIPE,
3325 stdout=input_api.subprocess.PIPE,
3326 stderr=input_api.subprocess.PIPE,
3327 universal_newlines=True)
3328 (_, error) = process.communicate(input=contents)
3329 return error or None
3330 except ValueError as e:
3331 return e
agrievef32bcc72016-04-04 14:57:403332
agrievef32bcc72016-04-04 14:57:403333
Sam Maiera6e76d72022-02-11 21:43:503334def CheckParseErrors(input_api, output_api):
3335 """Check that IDL and JSON files do not contain syntax errors."""
3336 actions = {
3337 '.idl': _GetIDLParseError,
3338 '.json': _GetJSONParseError,
3339 }
3340 # Most JSON files are preprocessed and support comments, but these do not.
3341 json_no_comments_patterns = [
Bruce Dawson40fece62022-09-16 19:58:313342 r'^testing/',
Sam Maiera6e76d72022-02-11 21:43:503343 ]
3344 # Only run IDL checker on files in these directories.
3345 idl_included_patterns = [
Bruce Dawson40fece62022-09-16 19:58:313346 r'^chrome/common/extensions/api/',
3347 r'^extensions/common/api/',
Sam Maiera6e76d72022-02-11 21:43:503348 ]
agrievef32bcc72016-04-04 14:57:403349
Sam Maiera6e76d72022-02-11 21:43:503350 def get_action(affected_file):
3351 filename = affected_file.LocalPath()
3352 return actions.get(input_api.os_path.splitext(filename)[1])
agrievef32bcc72016-04-04 14:57:403353
Sam Maiera6e76d72022-02-11 21:43:503354 def FilterFile(affected_file):
3355 action = get_action(affected_file)
3356 if not action:
3357 return False
3358 path = affected_file.LocalPath()
agrievef32bcc72016-04-04 14:57:403359
Sam Maiera6e76d72022-02-11 21:43:503360 if _MatchesFile(input_api,
3361 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS, path):
3362 return False
3363
3364 if (action == _GetIDLParseError
3365 and not _MatchesFile(input_api, idl_included_patterns, path)):
3366 return False
3367 return True
3368
3369 results = []
3370 for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
3371 include_deletes=False):
3372 action = get_action(affected_file)
3373 kwargs = {}
3374 if (action == _GetJSONParseError
3375 and _MatchesFile(input_api, json_no_comments_patterns,
3376 affected_file.LocalPath())):
3377 kwargs['eat_comments'] = False
3378 parse_error = action(input_api, affected_file.AbsoluteLocalPath(),
3379 **kwargs)
3380 if parse_error:
3381 results.append(
3382 output_api.PresubmitError(
3383 '%s could not be parsed: %s' %
3384 (affected_file.LocalPath(), parse_error)))
3385 return results
3386
3387
3388def CheckJavaStyle(input_api, output_api):
3389 """Runs checkstyle on changed java files and returns errors if any exist."""
3390
3391 # Return early if no java files were modified.
3392 if not any(
3393 _IsJavaFile(input_api, f.LocalPath())
3394 for f in input_api.AffectedFiles()):
3395 return []
3396
3397 import sys
3398 original_sys_path = sys.path
3399 try:
3400 sys.path = sys.path + [
3401 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3402 'android', 'checkstyle')
3403 ]
3404 import checkstyle
3405 finally:
3406 # Restore sys.path to what it was before.
3407 sys.path = original_sys_path
3408
Andrew Grieve4f88e3ca2022-11-22 19:09:203409 return checkstyle.run_presubmit(
Sam Maiera6e76d72022-02-11 21:43:503410 input_api,
3411 output_api,
Sam Maiera6e76d72022-02-11 21:43:503412 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
3413
3414
3415def CheckPythonDevilInit(input_api, output_api):
3416 """Checks to make sure devil is initialized correctly in python scripts."""
3417 script_common_initialize_pattern = input_api.re.compile(
3418 r'script_common\.InitializeEnvironment\(')
3419 devil_env_config_initialize = input_api.re.compile(
3420 r'devil_env\.config\.Initialize\(')
3421
3422 errors = []
3423
3424 sources = lambda affected_file: input_api.FilterSourceFile(
3425 affected_file,
3426 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:313427 r'^build/android/devil_chromium\.py',
3428 r'^third_party/.*',
Sam Maiera6e76d72022-02-11 21:43:503429 )),
3430 files_to_check=[r'.*\.py$'])
3431
3432 for f in input_api.AffectedSourceFiles(sources):
3433 for line_num, line in f.ChangedContents():
3434 if (script_common_initialize_pattern.search(line)
3435 or devil_env_config_initialize.search(line)):
3436 errors.append("%s:%d" % (f.LocalPath(), line_num))
3437
3438 results = []
3439
3440 if errors:
3441 results.append(
3442 output_api.PresubmitError(
3443 'Devil initialization should always be done using '
3444 'devil_chromium.Initialize() in the chromium project, to use better '
3445 'defaults for dependencies (ex. up-to-date version of adb).',
3446 errors))
3447
3448 return results
3449
3450
3451def _MatchesFile(input_api, patterns, path):
Bruce Dawson40fece62022-09-16 19:58:313452 # Consistently use / as path separator to simplify the writing of regex
3453 # expressions.
3454 path = path.replace(input_api.os_path.sep, '/')
Sam Maiera6e76d72022-02-11 21:43:503455 for pattern in patterns:
3456 if input_api.re.search(pattern, path):
3457 return True
3458 return False
3459
3460
Daniel Chenga37c03db2022-05-12 17:20:343461def _ChangeHasSecurityReviewer(input_api, owners_file):
3462 """Returns True iff the CL has a reviewer from SECURITY_OWNERS.
Sam Maiera6e76d72022-02-11 21:43:503463
Daniel Chenga37c03db2022-05-12 17:20:343464 Args:
3465 input_api: The presubmit input API.
3466 owners_file: OWNERS file with required reviewers. Typically, this is
3467 something like ipc/SECURITY_OWNERS.
3468
3469 Note: if the presubmit is running for commit rather than for upload, this
3470 only returns True if a security reviewer has also approved the CL.
Sam Maiera6e76d72022-02-11 21:43:503471 """
Daniel Chengd88244472022-05-16 09:08:473472 # Owners-Override should bypass all additional OWNERS enforcement checks.
3473 # A CR+1 vote will still be required to land this change.
3474 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
3475 input_api.change.issue)):
3476 return True
3477
Daniel Chenga37c03db2022-05-12 17:20:343478 owner_email, reviewers = (
3479 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
Daniel Cheng3008dc12022-05-13 04:02:113480 input_api,
3481 None,
3482 approval_needed=input_api.is_committing and not input_api.dry_run))
Sam Maiera6e76d72022-02-11 21:43:503483
Daniel Chenga37c03db2022-05-12 17:20:343484 security_owners = input_api.owners_client.ListOwners(owners_file)
3485 return any(owner in reviewers for owner in security_owners)
Sam Maiera6e76d72022-02-11 21:43:503486
Daniel Chenga37c03db2022-05-12 17:20:343487
3488@dataclass
Daniel Cheng171dad8d2022-05-21 00:40:253489class _SecurityProblemWithItems:
3490 problem: str
3491 items: Sequence[str]
3492
3493
3494@dataclass
Daniel Chenga37c03db2022-05-12 17:20:343495class _MissingSecurityOwnersResult:
Daniel Cheng171dad8d2022-05-21 00:40:253496 owners_file_problems: Sequence[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:343497 has_security_sensitive_files: bool
Daniel Cheng171dad8d2022-05-21 00:40:253498 missing_reviewer_problem: Optional[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:343499
3500
3501def _FindMissingSecurityOwners(input_api,
3502 output_api,
3503 file_patterns: Sequence[str],
3504 excluded_patterns: Sequence[str],
3505 required_owners_file: str,
3506 custom_rule_function: Optional[Callable] = None
3507 ) -> _MissingSecurityOwnersResult:
3508 """Find OWNERS files missing per-file rules for security-sensitive files.
3509
3510 Args:
3511 input_api: the PRESUBMIT input API object.
3512 output_api: the PRESUBMIT output API object.
3513 file_patterns: basename patterns that require a corresponding per-file
3514 security restriction.
3515 excluded_patterns: path patterns that should be exempted from
3516 requiring a security restriction.
3517 required_owners_file: path to the required OWNERS file, e.g.
3518 ipc/SECURITY_OWNERS
3519 cc_alias: If not None, email that will be CCed automatically if the
3520 change contains security-sensitive files, as determined by
3521 `file_patterns` and `excluded_patterns`.
3522 custom_rule_function: If not None, will be called with `input_api` and
3523 the current file under consideration. Returning True will add an
3524 exact match per-file rule check for the current file.
3525 """
3526
3527 # `to_check` is a mapping of an OWNERS file path to Patterns.
3528 #
3529 # Patterns is a dictionary mapping glob patterns (suitable for use in
3530 # per-file rules) to a PatternEntry.
3531 #
Sam Maiera6e76d72022-02-11 21:43:503532 # PatternEntry is a dictionary with two keys:
3533 # - 'files': the files that are matched by this pattern
3534 # - 'rules': the per-file rules needed for this pattern
Daniel Chenga37c03db2022-05-12 17:20:343535 #
Sam Maiera6e76d72022-02-11 21:43:503536 # For example, if we expect OWNERS file to contain rules for *.mojom and
3537 # *_struct_traits*.*, Patterns might look like this:
3538 # {
3539 # '*.mojom': {
3540 # 'files': ...,
3541 # 'rules': [
3542 # 'per-file *.mojom=set noparent',
3543 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
3544 # ],
3545 # },
3546 # '*_struct_traits*.*': {
3547 # 'files': ...,
3548 # 'rules': [
3549 # 'per-file *_struct_traits*.*=set noparent',
3550 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
3551 # ],
3552 # },
3553 # }
3554 to_check = {}
Daniel Chenga37c03db2022-05-12 17:20:343555 files_to_review = []
Sam Maiera6e76d72022-02-11 21:43:503556
Daniel Chenga37c03db2022-05-12 17:20:343557 def AddPatternToCheck(file, pattern):
Sam Maiera6e76d72022-02-11 21:43:503558 owners_file = input_api.os_path.join(
Daniel Chengd88244472022-05-16 09:08:473559 input_api.os_path.dirname(file.LocalPath()), 'OWNERS')
Sam Maiera6e76d72022-02-11 21:43:503560 if owners_file not in to_check:
3561 to_check[owners_file] = {}
3562 if pattern not in to_check[owners_file]:
3563 to_check[owners_file][pattern] = {
3564 'files': [],
3565 'rules': [
Daniel Chenga37c03db2022-05-12 17:20:343566 f'per-file {pattern}=set noparent',
3567 f'per-file {pattern}=file://{required_owners_file}',
Sam Maiera6e76d72022-02-11 21:43:503568 ]
3569 }
Daniel Chenged57a162022-05-25 02:56:343570 to_check[owners_file][pattern]['files'].append(file.LocalPath())
Daniel Chenga37c03db2022-05-12 17:20:343571 files_to_review.append(file.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:503572
Daniel Chenga37c03db2022-05-12 17:20:343573 # Only enforce security OWNERS rules for a directory if that directory has a
3574 # file that matches `file_patterns`. For example, if a directory only
3575 # contains *.mojom files and no *_messages*.h files, the check should only
3576 # ensure that rules for *.mojom files are present.
3577 for file in input_api.AffectedFiles(include_deletes=False):
3578 file_basename = input_api.os_path.basename(file.LocalPath())
3579 if custom_rule_function is not None and custom_rule_function(
3580 input_api, file):
3581 AddPatternToCheck(file, file_basename)
3582 continue
Sam Maiera6e76d72022-02-11 21:43:503583
Daniel Chenga37c03db2022-05-12 17:20:343584 if any(
3585 input_api.fnmatch.fnmatch(file.LocalPath(), pattern)
3586 for pattern in excluded_patterns):
Sam Maiera6e76d72022-02-11 21:43:503587 continue
3588
3589 for pattern in file_patterns:
Daniel Chenga37c03db2022-05-12 17:20:343590 # Unlike `excluded_patterns`, `file_patterns` is checked only against the
3591 # file's basename.
3592 if input_api.fnmatch.fnmatch(file_basename, pattern):
3593 AddPatternToCheck(file, pattern)
Sam Maiera6e76d72022-02-11 21:43:503594 break
3595
Daniel Chenga37c03db2022-05-12 17:20:343596 has_security_sensitive_files = bool(to_check)
Daniel Cheng171dad8d2022-05-21 00:40:253597
3598 # Check if any newly added lines in OWNERS files intersect with required
3599 # per-file OWNERS lines. If so, ensure that a security reviewer is included.
3600 # This is a hack, but is needed because the OWNERS check (by design) ignores
3601 # new OWNERS entries; otherwise, a non-owner could add someone as a new
3602 # OWNER and have that newly-added OWNER self-approve their own addition.
3603 newly_covered_files = []
3604 for file in input_api.AffectedFiles(include_deletes=False):
3605 if not file.LocalPath() in to_check:
3606 continue
3607 for _, line in file.ChangedContents():
3608 for _, entry in to_check[file.LocalPath()].items():
3609 if line in entry['rules']:
3610 newly_covered_files.extend(entry['files'])
3611
3612 missing_reviewer_problems = None
3613 if newly_covered_files and not _ChangeHasSecurityReviewer(
Daniel Chenga37c03db2022-05-12 17:20:343614 input_api, required_owners_file):
Daniel Cheng171dad8d2022-05-21 00:40:253615 missing_reviewer_problems = _SecurityProblemWithItems(
3616 f'Review from an owner in {required_owners_file} is required for '
3617 'the following newly-added files:',
3618 [f'{file}' for file in sorted(set(newly_covered_files))])
Sam Maiera6e76d72022-02-11 21:43:503619
3620 # Go through the OWNERS files to check, filtering out rules that are already
3621 # present in that OWNERS file.
3622 for owners_file, patterns in to_check.items():
3623 try:
Daniel Cheng171dad8d2022-05-21 00:40:253624 lines = set(
3625 input_api.ReadFile(
3626 input_api.os_path.join(input_api.change.RepositoryRoot(),
3627 owners_file)).splitlines())
3628 for entry in patterns.values():
3629 entry['rules'] = [
3630 rule for rule in entry['rules'] if rule not in lines
3631 ]
Sam Maiera6e76d72022-02-11 21:43:503632 except IOError:
3633 # No OWNERS file, so all the rules are definitely missing.
3634 continue
3635
3636 # All the remaining lines weren't found in OWNERS files, so emit an error.
Daniel Cheng171dad8d2022-05-21 00:40:253637 owners_file_problems = []
Daniel Chenga37c03db2022-05-12 17:20:343638
Sam Maiera6e76d72022-02-11 21:43:503639 for owners_file, patterns in to_check.items():
3640 missing_lines = []
3641 files = []
3642 for _, entry in patterns.items():
Daniel Chenged57a162022-05-25 02:56:343643 files.extend(entry['files'])
Sam Maiera6e76d72022-02-11 21:43:503644 missing_lines.extend(entry['rules'])
Sam Maiera6e76d72022-02-11 21:43:503645 if missing_lines:
Daniel Cheng171dad8d2022-05-21 00:40:253646 joined_missing_lines = '\n'.join(line for line in missing_lines)
3647 owners_file_problems.append(
3648 _SecurityProblemWithItems(
3649 'Found missing OWNERS lines for security-sensitive files. '
3650 f'Please add the following lines to {owners_file}:\n'
3651 f'{joined_missing_lines}\n\nTo ensure security review for:',
3652 files))
Daniel Chenga37c03db2022-05-12 17:20:343653
Daniel Cheng171dad8d2022-05-21 00:40:253654 return _MissingSecurityOwnersResult(owners_file_problems,
Daniel Chenga37c03db2022-05-12 17:20:343655 has_security_sensitive_files,
Daniel Cheng171dad8d2022-05-21 00:40:253656 missing_reviewer_problems)
Daniel Chenga37c03db2022-05-12 17:20:343657
3658
3659def _CheckChangeForIpcSecurityOwners(input_api, output_api):
3660 # Whether or not a file affects IPC is (mostly) determined by a simple list
3661 # of filename patterns.
3662 file_patterns = [
3663 # Legacy IPC:
3664 '*_messages.cc',
3665 '*_messages*.h',
3666 '*_param_traits*.*',
3667 # Mojo IPC:
3668 '*.mojom',
3669 '*_mojom_traits*.*',
3670 '*_type_converter*.*',
3671 # Android native IPC:
3672 '*.aidl',
3673 ]
3674
Daniel Chenga37c03db2022-05-12 17:20:343675 excluded_patterns = [
Daniel Cheng518943f2022-05-12 22:15:463676 # These third_party directories do not contain IPCs, but contain files
3677 # matching the above patterns, which trigger false positives.
Daniel Chenga37c03db2022-05-12 17:20:343678 'third_party/crashpad/*',
3679 'third_party/blink/renderer/platform/bindings/*',
3680 'third_party/protobuf/benchmarks/python/*',
3681 'third_party/win_build_output/*',
Daniel Chengd88244472022-05-16 09:08:473682 # Enum-only mojoms used for web metrics, so no security review needed.
3683 'third_party/blink/public/mojom/use_counter/metrics/*',
Daniel Chenga37c03db2022-05-12 17:20:343684 # These files are just used to communicate between class loaders running
3685 # in the same process.
3686 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
3687 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
3688 ]
3689
3690 def IsMojoServiceManifestFile(input_api, file):
3691 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
3692 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
3693 if not manifest_pattern.search(file.LocalPath()):
3694 return False
3695
3696 if test_manifest_pattern.search(file.LocalPath()):
3697 return False
3698
3699 # All actual service manifest files should contain at least one
3700 # qualified reference to service_manager::Manifest.
3701 return any('service_manager::Manifest' in line
3702 for line in file.NewContents())
3703
3704 return _FindMissingSecurityOwners(
3705 input_api,
3706 output_api,
3707 file_patterns,
3708 excluded_patterns,
3709 'ipc/SECURITY_OWNERS',
3710 custom_rule_function=IsMojoServiceManifestFile)
3711
3712
3713def _CheckChangeForFuchsiaSecurityOwners(input_api, output_api):
3714 file_patterns = [
3715 # Component specifications.
3716 '*.cml', # Component Framework v2.
3717 '*.cmx', # Component Framework v1.
3718
3719 # Fuchsia IDL protocol specifications.
3720 '*.fidl',
3721 ]
3722
3723 # Don't check for owners files for changes in these directories.
3724 excluded_patterns = [
3725 'third_party/crashpad/*',
3726 ]
3727
3728 return _FindMissingSecurityOwners(input_api, output_api, file_patterns,
3729 excluded_patterns,
3730 'build/fuchsia/SECURITY_OWNERS')
3731
3732
3733def CheckSecurityOwners(input_api, output_api):
3734 """Checks that various security-sensitive files have an IPC OWNERS rule."""
3735 ipc_results = _CheckChangeForIpcSecurityOwners(input_api, output_api)
3736 fuchsia_results = _CheckChangeForFuchsiaSecurityOwners(
3737 input_api, output_api)
3738
3739 if ipc_results.has_security_sensitive_files:
3740 output_api.AppendCC('[email protected]')
Sam Maiera6e76d72022-02-11 21:43:503741
3742 results = []
Daniel Chenga37c03db2022-05-12 17:20:343743
Daniel Cheng171dad8d2022-05-21 00:40:253744 missing_reviewer_problems = []
3745 if ipc_results.missing_reviewer_problem:
3746 missing_reviewer_problems.append(ipc_results.missing_reviewer_problem)
3747 if fuchsia_results.missing_reviewer_problem:
3748 missing_reviewer_problems.append(
3749 fuchsia_results.missing_reviewer_problem)
Daniel Chenga37c03db2022-05-12 17:20:343750
Daniel Cheng171dad8d2022-05-21 00:40:253751 # Missing reviewers are an error unless there's no issue number
3752 # associated with this branch; in that case, the presubmit is being run
3753 # with --all or --files.
3754 #
3755 # Note that upload should never be an error; otherwise, it would be
3756 # impossible to upload changes at all.
3757 if input_api.is_committing and input_api.change.issue:
3758 make_presubmit_message = output_api.PresubmitError
3759 else:
3760 make_presubmit_message = output_api.PresubmitNotifyResult
3761 for problem in missing_reviewer_problems:
Sam Maiera6e76d72022-02-11 21:43:503762 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:253763 make_presubmit_message(problem.problem, items=problem.items))
Daniel Chenga37c03db2022-05-12 17:20:343764
Daniel Cheng171dad8d2022-05-21 00:40:253765 owners_file_problems = []
3766 owners_file_problems.extend(ipc_results.owners_file_problems)
3767 owners_file_problems.extend(fuchsia_results.owners_file_problems)
Daniel Chenga37c03db2022-05-12 17:20:343768
Daniel Cheng171dad8d2022-05-21 00:40:253769 for problem in owners_file_problems:
Daniel Cheng3008dc12022-05-13 04:02:113770 # Missing per-file rules are always an error. While swarming and caching
3771 # means that uploading a patchset with updated OWNERS files and sending
3772 # it to the CQ again should not have a large incremental cost, it is
3773 # still frustrating to discover the error only after the change has
3774 # already been uploaded.
Daniel Chenga37c03db2022-05-12 17:20:343775 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:253776 output_api.PresubmitError(problem.problem, items=problem.items))
Sam Maiera6e76d72022-02-11 21:43:503777
3778 return results
3779
3780
3781def _GetFilesUsingSecurityCriticalFunctions(input_api):
3782 """Checks affected files for changes to security-critical calls. This
3783 function checks the full change diff, to catch both additions/changes
3784 and removals.
3785
3786 Returns a dict keyed by file name, and the value is a set of detected
3787 functions.
3788 """
3789 # Map of function pretty name (displayed in an error) to the pattern to
3790 # match it with.
3791 _PATTERNS_TO_CHECK = {
3792 'content::GetServiceSandboxType<>()': 'GetServiceSandboxType\\<'
3793 }
3794 _PATTERNS_TO_CHECK = {
3795 k: input_api.re.compile(v)
3796 for k, v in _PATTERNS_TO_CHECK.items()
3797 }
3798
Sam Maiera6e76d72022-02-11 21:43:503799 # We don't want to trigger on strings within this file.
3800 def presubmit_file_filter(f):
Daniel Chenga37c03db2022-05-12 17:20:343801 return 'PRESUBMIT.py' != input_api.os_path.split(f.LocalPath())[1]
Sam Maiera6e76d72022-02-11 21:43:503802
3803 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3804 files_to_functions = {}
3805 for f in input_api.AffectedFiles(file_filter=presubmit_file_filter):
3806 diff = f.GenerateScmDiff()
3807 for line in diff.split('\n'):
3808 # Not using just RightHandSideLines() because removing a
3809 # call to a security-critical function can be just as important
3810 # as adding or changing the arguments.
3811 if line.startswith('-') or (line.startswith('+')
3812 and not line.startswith('++')):
3813 for name, pattern in _PATTERNS_TO_CHECK.items():
3814 if pattern.search(line):
3815 path = f.LocalPath()
3816 if not path in files_to_functions:
3817 files_to_functions[path] = set()
3818 files_to_functions[path].add(name)
3819 return files_to_functions
3820
3821
3822def CheckSecurityChanges(input_api, output_api):
3823 """Checks that changes involving security-critical functions are reviewed
3824 by the security team.
3825 """
3826 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3827 if not len(files_to_functions):
3828 return []
3829
Sam Maiera6e76d72022-02-11 21:43:503830 owners_file = 'ipc/SECURITY_OWNERS'
Daniel Chenga37c03db2022-05-12 17:20:343831 if _ChangeHasSecurityReviewer(input_api, owners_file):
Sam Maiera6e76d72022-02-11 21:43:503832 return []
3833
Daniel Chenga37c03db2022-05-12 17:20:343834 msg = 'The following files change calls to security-sensitive functions\n' \
Sam Maiera6e76d72022-02-11 21:43:503835 'that need to be reviewed by {}.\n'.format(owners_file)
3836 for path, names in files_to_functions.items():
3837 msg += ' {}\n'.format(path)
3838 for name in names:
3839 msg += ' {}\n'.format(name)
3840 msg += '\n'
3841
3842 if input_api.is_committing:
3843 output = output_api.PresubmitError
Mohamed Heikale217fc852020-07-06 19:44:033844 else:
Sam Maiera6e76d72022-02-11 21:43:503845 output = output_api.PresubmitNotifyResult
3846 return [output(msg)]
3847
3848
3849def CheckSetNoParent(input_api, output_api):
3850 """Checks that set noparent is only used together with an OWNERS file in
3851 //build/OWNERS.setnoparent (see also
3852 //docs/code_reviews.md#owners-files-details)
3853 """
3854 # Return early if no OWNERS files were modified.
3855 if not any(f.LocalPath().endswith('OWNERS')
3856 for f in input_api.AffectedFiles(include_deletes=False)):
3857 return []
3858
3859 errors = []
3860
3861 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3862 allowed_owners_files = set()
Bruce Dawson58a45d22023-02-27 11:24:163863 with open(allowed_owners_files_file, 'r', encoding='utf-8') as f:
Sam Maiera6e76d72022-02-11 21:43:503864 for line in f:
3865 line = line.strip()
3866 if not line or line.startswith('#'):
3867 continue
3868 allowed_owners_files.add(line)
3869
3870 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3871
3872 for f in input_api.AffectedFiles(include_deletes=False):
3873 if not f.LocalPath().endswith('OWNERS'):
3874 continue
3875
3876 found_owners_files = set()
3877 found_set_noparent_lines = dict()
3878
3879 # Parse the OWNERS file.
3880 for lineno, line in enumerate(f.NewContents(), 1):
3881 line = line.strip()
3882 if line.startswith('set noparent'):
3883 found_set_noparent_lines[''] = lineno
3884 if line.startswith('file://'):
3885 if line in allowed_owners_files:
3886 found_owners_files.add('')
3887 if line.startswith('per-file'):
3888 match = per_file_pattern.match(line)
3889 if match:
3890 glob = match.group(1).strip()
3891 directive = match.group(2).strip()
3892 if directive == 'set noparent':
3893 found_set_noparent_lines[glob] = lineno
3894 if directive.startswith('file://'):
3895 if directive in allowed_owners_files:
3896 found_owners_files.add(glob)
3897
3898 # Check that every set noparent line has a corresponding file:// line
3899 # listed in build/OWNERS.setnoparent. An exception is made for top level
3900 # directories since src/OWNERS shouldn't review them.
Bruce Dawson6bb0d672022-04-06 15:13:493901 linux_path = f.LocalPath().replace(input_api.os_path.sep, '/')
3902 if (linux_path.count('/') != 1
3903 and (not linux_path in _EXCLUDED_SET_NO_PARENT_PATHS)):
Sam Maiera6e76d72022-02-11 21:43:503904 for set_noparent_line in found_set_noparent_lines:
3905 if set_noparent_line in found_owners_files:
3906 continue
3907 errors.append(' %s:%d' %
Bruce Dawson6bb0d672022-04-06 15:13:493908 (linux_path,
Sam Maiera6e76d72022-02-11 21:43:503909 found_set_noparent_lines[set_noparent_line]))
3910
3911 results = []
3912 if errors:
3913 if input_api.is_committing:
3914 output = output_api.PresubmitError
3915 else:
3916 output = output_api.PresubmitPromptWarning
3917 results.append(
3918 output(
3919 'Found the following "set noparent" restrictions in OWNERS files that '
3920 'do not include owners from build/OWNERS.setnoparent:',
3921 long_text='\n\n'.join(errors)))
3922 return results
3923
3924
3925def CheckUselessForwardDeclarations(input_api, output_api):
3926 """Checks that added or removed lines in non third party affected
3927 header files do not lead to new useless class or struct forward
3928 declaration.
3929 """
3930 results = []
3931 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3932 input_api.re.MULTILINE)
3933 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3934 input_api.re.MULTILINE)
3935 for f in input_api.AffectedFiles(include_deletes=False):
3936 if (f.LocalPath().startswith('third_party')
3937 and not f.LocalPath().startswith('third_party/blink')
3938 and not f.LocalPath().startswith('third_party\\blink')):
3939 continue
3940
3941 if not f.LocalPath().endswith('.h'):
3942 continue
3943
3944 contents = input_api.ReadFile(f)
3945 fwd_decls = input_api.re.findall(class_pattern, contents)
3946 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3947
3948 useless_fwd_decls = []
3949 for decl in fwd_decls:
3950 count = sum(1 for _ in input_api.re.finditer(
3951 r'\b%s\b' % input_api.re.escape(decl), contents))
3952 if count == 1:
3953 useless_fwd_decls.append(decl)
3954
3955 if not useless_fwd_decls:
3956 continue
3957
3958 for line in f.GenerateScmDiff().splitlines():
3959 if (line.startswith('-') and not line.startswith('--')
3960 or line.startswith('+') and not line.startswith('++')):
3961 for decl in useless_fwd_decls:
3962 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3963 results.append(
3964 output_api.PresubmitPromptWarning(
3965 '%s: %s forward declaration is no longer needed'
3966 % (f.LocalPath(), decl)))
3967 useless_fwd_decls.remove(decl)
3968
3969 return results
3970
3971
3972def _CheckAndroidDebuggableBuild(input_api, output_api):
3973 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3974 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3975 this is a debuggable build of Android.
3976 """
3977 build_type_check_pattern = input_api.re.compile(
3978 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3979
3980 errors = []
3981
3982 sources = lambda affected_file: input_api.FilterSourceFile(
3983 affected_file,
3984 files_to_skip=(
3985 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3986 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:313987 r"^android_webview/support_library/boundary_interfaces/",
3988 r"^chrome/android/webapk/.*",
3989 r'^third_party/.*',
3990 r"tools/android/customtabs_benchmark/.*",
3991 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:503992 )),
3993 files_to_check=[r'.*\.java$'])
3994
3995 for f in input_api.AffectedSourceFiles(sources):
3996 for line_num, line in f.ChangedContents():
3997 if build_type_check_pattern.search(line):
3998 errors.append("%s:%d" % (f.LocalPath(), line_num))
3999
4000 results = []
4001
4002 if errors:
4003 results.append(
4004 output_api.PresubmitPromptWarning(
4005 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
4006 ' Please use BuildInfo.isDebugAndroid() instead.', errors))
4007
4008 return results
4009
4010# TODO: add unit tests
4011def _CheckAndroidToastUsage(input_api, output_api):
4012 """Checks that code uses org.chromium.ui.widget.Toast instead of
4013 android.widget.Toast (Chromium Toast doesn't force hardware
4014 acceleration on low-end devices, saving memory).
4015 """
4016 toast_import_pattern = input_api.re.compile(
4017 r'^import android\.widget\.Toast;$')
4018
4019 errors = []
4020
4021 sources = lambda affected_file: input_api.FilterSourceFile(
4022 affected_file,
4023 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
Bruce Dawson40fece62022-09-16 19:58:314024 DEFAULT_FILES_TO_SKIP + (r'^chromecast/.*',
4025 r'^remoting/.*')),
Sam Maiera6e76d72022-02-11 21:43:504026 files_to_check=[r'.*\.java$'])
4027
4028 for f in input_api.AffectedSourceFiles(sources):
4029 for line_num, line in f.ChangedContents():
4030 if toast_import_pattern.search(line):
4031 errors.append("%s:%d" % (f.LocalPath(), line_num))
4032
4033 results = []
4034
4035 if errors:
4036 results.append(
4037 output_api.PresubmitError(
4038 'android.widget.Toast usage is detected. Android toasts use hardware'
4039 ' acceleration, and can be\ncostly on low-end devices. Please use'
4040 ' org.chromium.ui.widget.Toast instead.\n'
4041 'Contact [email protected] if you have any questions.',
4042 errors))
4043
4044 return results
4045
4046
4047def _CheckAndroidCrLogUsage(input_api, output_api):
4048 """Checks that new logs using org.chromium.base.Log:
4049 - Are using 'TAG' as variable name for the tags (warn)
4050 - Are using a tag that is shorter than 20 characters (error)
4051 """
4052
4053 # Do not check format of logs in the given files
4054 cr_log_check_excluded_paths = [
4055 # //chrome/android/webapk cannot depend on //base
Bruce Dawson40fece62022-09-16 19:58:314056 r"^chrome/android/webapk/.*",
Sam Maiera6e76d72022-02-11 21:43:504057 # WebView license viewer code cannot depend on //base; used in stub APK.
Bruce Dawson40fece62022-09-16 19:58:314058 r"^android_webview/glue/java/src/com/android/"
4059 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504060 # The customtabs_benchmark is a small app that does not depend on Chromium
4061 # java pieces.
Bruce Dawson40fece62022-09-16 19:58:314062 r"tools/android/customtabs_benchmark/.*",
Sam Maiera6e76d72022-02-11 21:43:504063 ]
4064
4065 cr_log_import_pattern = input_api.re.compile(
4066 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
4067 class_in_base_pattern = input_api.re.compile(
4068 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
4069 has_some_log_import_pattern = input_api.re.compile(r'^import .*\.Log;$',
4070 input_api.re.MULTILINE)
4071 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
4072 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
4073 log_decl_pattern = input_api.re.compile(
4074 r'static final String TAG = "(?P<name>(.*))"')
4075 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
4076
4077 REF_MSG = ('See docs/android_logging.md for more info.')
4078 sources = lambda x: input_api.FilterSourceFile(
4079 x,
4080 files_to_check=[r'.*\.java$'],
4081 files_to_skip=cr_log_check_excluded_paths)
4082
4083 tag_decl_errors = []
4084 tag_length_errors = []
4085 tag_errors = []
4086 tag_with_dot_errors = []
4087 util_log_errors = []
4088
4089 for f in input_api.AffectedSourceFiles(sources):
4090 file_content = input_api.ReadFile(f)
4091 has_modified_logs = False
4092 # Per line checks
4093 if (cr_log_import_pattern.search(file_content)
4094 or (class_in_base_pattern.search(file_content)
4095 and not has_some_log_import_pattern.search(file_content))):
4096 # Checks to run for files using cr log
4097 for line_num, line in f.ChangedContents():
4098 if rough_log_decl_pattern.search(line):
4099 has_modified_logs = True
4100
4101 # Check if the new line is doing some logging
4102 match = log_call_pattern.search(line)
4103 if match:
4104 has_modified_logs = True
4105
4106 # Make sure it uses "TAG"
4107 if not match.group('tag') == 'TAG':
4108 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
4109 else:
4110 # Report non cr Log function calls in changed lines
4111 for line_num, line in f.ChangedContents():
4112 if log_call_pattern.search(line):
4113 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
4114
4115 # Per file checks
4116 if has_modified_logs:
4117 # Make sure the tag is using the "cr" prefix and is not too long
4118 match = log_decl_pattern.search(file_content)
4119 tag_name = match.group('name') if match else None
4120 if not tag_name:
4121 tag_decl_errors.append(f.LocalPath())
4122 elif len(tag_name) > 20:
4123 tag_length_errors.append(f.LocalPath())
4124 elif '.' in tag_name:
4125 tag_with_dot_errors.append(f.LocalPath())
4126
4127 results = []
4128 if tag_decl_errors:
4129 results.append(
4130 output_api.PresubmitPromptWarning(
4131 'Please define your tags using the suggested format: .\n'
4132 '"private static final String TAG = "<package tag>".\n'
4133 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
4134 tag_decl_errors))
4135
4136 if tag_length_errors:
4137 results.append(
4138 output_api.PresubmitError(
4139 'The tag length is restricted by the system to be at most '
4140 '20 characters.\n' + REF_MSG, tag_length_errors))
4141
4142 if tag_errors:
4143 results.append(
4144 output_api.PresubmitPromptWarning(
4145 'Please use a variable named "TAG" for your log tags.\n' +
4146 REF_MSG, tag_errors))
4147
4148 if util_log_errors:
4149 results.append(
4150 output_api.PresubmitPromptWarning(
4151 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
4152 util_log_errors))
4153
4154 if tag_with_dot_errors:
4155 results.append(
4156 output_api.PresubmitPromptWarning(
4157 'Dot in log tags cause them to be elided in crash reports.\n' +
4158 REF_MSG, tag_with_dot_errors))
4159
4160 return results
4161
4162
4163def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
4164 """Checks that junit.framework.* is no longer used."""
4165 deprecated_junit_framework_pattern = input_api.re.compile(
4166 r'^import junit\.framework\..*;', input_api.re.MULTILINE)
4167 sources = lambda x: input_api.FilterSourceFile(
4168 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
4169 errors = []
4170 for f in input_api.AffectedFiles(file_filter=sources):
4171 for line_num, line in f.ChangedContents():
4172 if deprecated_junit_framework_pattern.search(line):
4173 errors.append("%s:%d" % (f.LocalPath(), line_num))
4174
4175 results = []
4176 if errors:
4177 results.append(
4178 output_api.PresubmitError(
4179 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
4180 '(org.junit.*) from //third_party/junit. Contact [email protected]'
4181 ' if you have any question.', errors))
4182 return results
4183
4184
4185def _CheckAndroidTestJUnitInheritance(input_api, output_api):
4186 """Checks that if new Java test classes have inheritance.
4187 Either the new test class is JUnit3 test or it is a JUnit4 test class
4188 with a base class, either case is undesirable.
4189 """
4190 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
4191
4192 sources = lambda x: input_api.FilterSourceFile(
4193 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
4194 errors = []
4195 for f in input_api.AffectedFiles(file_filter=sources):
4196 if not f.OldContents():
4197 class_declaration_start_flag = False
4198 for line_num, line in f.ChangedContents():
4199 if class_declaration_pattern.search(line):
4200 class_declaration_start_flag = True
4201 if class_declaration_start_flag and ' extends ' in line:
4202 errors.append('%s:%d' % (f.LocalPath(), line_num))
4203 if '{' in line:
4204 class_declaration_start_flag = False
4205
4206 results = []
4207 if errors:
4208 results.append(
4209 output_api.PresubmitPromptWarning(
4210 'The newly created files include Test classes that inherits from base'
4211 ' class. Please do not use inheritance in JUnit4 tests or add new'
4212 ' JUnit3 tests. Contact [email protected] if you have any'
4213 ' questions.', errors))
4214 return results
4215
4216
4217def _CheckAndroidTestAnnotationUsage(input_api, output_api):
4218 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
4219 deprecated_annotation_import_pattern = input_api.re.compile(
4220 r'^import android\.test\.suitebuilder\.annotation\..*;',
4221 input_api.re.MULTILINE)
4222 sources = lambda x: input_api.FilterSourceFile(
4223 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
4224 errors = []
4225 for f in input_api.AffectedFiles(file_filter=sources):
4226 for line_num, line in f.ChangedContents():
4227 if deprecated_annotation_import_pattern.search(line):
4228 errors.append("%s:%d" % (f.LocalPath(), line_num))
4229
4230 results = []
4231 if errors:
4232 results.append(
4233 output_api.PresubmitError(
4234 'Annotations in android.test.suitebuilder.annotation have been'
Mohamed Heikal3d7a94c2023-03-28 16:55:244235 ' deprecated since API level 24. Please use androidx.test.filters'
4236 ' from //third_party/androidx:androidx_test_runner_java instead.'
Sam Maiera6e76d72022-02-11 21:43:504237 ' Contact [email protected] if you have any questions.',
4238 errors))
4239 return results
4240
4241
4242def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
4243 """Checks if MDPI assets are placed in a correct directory."""
Bruce Dawson6c05e852022-07-21 15:48:514244 file_filter = lambda f: (f.LocalPath().endswith(
4245 '.png') and ('/res/drawable/'.replace('/', input_api.os_path.sep) in f.
4246 LocalPath() or '/res/drawable-ldrtl/'.replace(
4247 '/', input_api.os_path.sep) in f.LocalPath()))
Sam Maiera6e76d72022-02-11 21:43:504248 errors = []
4249 for f in input_api.AffectedFiles(include_deletes=False,
4250 file_filter=file_filter):
4251 errors.append(' %s' % f.LocalPath())
4252
4253 results = []
4254 if errors:
4255 results.append(
4256 output_api.PresubmitError(
4257 'MDPI assets should be placed in /res/drawable-mdpi/ or '
4258 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
4259 '/res/drawable-ldrtl/.\n'
4260 'Contact [email protected] if you have questions.', errors))
4261 return results
4262
4263
4264def _CheckAndroidWebkitImports(input_api, output_api):
4265 """Checks that code uses org.chromium.base.Callback instead of
4266 android.webview.ValueCallback except in the WebView glue layer
4267 and WebLayer.
4268 """
4269 valuecallback_import_pattern = input_api.re.compile(
4270 r'^import android\.webkit\.ValueCallback;$')
4271
4272 errors = []
4273
4274 sources = lambda affected_file: input_api.FilterSourceFile(
4275 affected_file,
4276 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4277 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314278 r'^android_webview/glue/.*',
4279 r'^weblayer/.*',
Sam Maiera6e76d72022-02-11 21:43:504280 )),
4281 files_to_check=[r'.*\.java$'])
4282
4283 for f in input_api.AffectedSourceFiles(sources):
4284 for line_num, line in f.ChangedContents():
4285 if valuecallback_import_pattern.search(line):
4286 errors.append("%s:%d" % (f.LocalPath(), line_num))
4287
4288 results = []
4289
4290 if errors:
4291 results.append(
4292 output_api.PresubmitError(
4293 'android.webkit.ValueCallback usage is detected outside of the glue'
4294 ' layer. To stay compatible with the support library, android.webkit.*'
4295 ' classes should only be used inside the glue layer and'
4296 ' org.chromium.base.Callback should be used instead.', errors))
4297
4298 return results
4299
4300
4301def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
4302 """Checks Android XML styles """
4303
4304 # Return early if no relevant files were modified.
4305 if not any(
4306 _IsXmlOrGrdFile(input_api, f.LocalPath())
4307 for f in input_api.AffectedFiles(include_deletes=False)):
4308 return []
4309
4310 import sys
4311 original_sys_path = sys.path
4312 try:
4313 sys.path = sys.path + [
4314 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4315 'android', 'checkxmlstyle')
4316 ]
4317 import checkxmlstyle
4318 finally:
4319 # Restore sys.path to what it was before.
4320 sys.path = original_sys_path
4321
4322 if is_check_on_upload:
4323 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
4324 else:
4325 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
4326
4327
4328def _CheckAndroidInfoBarDeprecation(input_api, output_api):
4329 """Checks Android Infobar Deprecation """
4330
4331 import sys
4332 original_sys_path = sys.path
4333 try:
4334 sys.path = sys.path + [
4335 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4336 'android', 'infobar_deprecation')
4337 ]
4338 import infobar_deprecation
4339 finally:
4340 # Restore sys.path to what it was before.
4341 sys.path = original_sys_path
4342
4343 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
4344
4345
4346class _PydepsCheckerResult:
4347 def __init__(self, cmd, pydeps_path, process, old_contents):
4348 self._cmd = cmd
4349 self._pydeps_path = pydeps_path
4350 self._process = process
4351 self._old_contents = old_contents
4352
4353 def GetError(self):
4354 """Returns an error message, or None."""
4355 import difflib
4356 if self._process.wait() != 0:
4357 # STDERR should already be printed.
4358 return 'Command failed: ' + self._cmd
4359 new_contents = self._process.stdout.read().splitlines()[2:]
4360 if self._old_contents != new_contents:
4361 diff = '\n'.join(
4362 difflib.context_diff(self._old_contents, new_contents))
4363 return ('File is stale: {}\n'
4364 'Diff (apply to fix):\n'
4365 '{}\n'
4366 'To regenerate, run:\n\n'
4367 ' {}').format(self._pydeps_path, diff, self._cmd)
4368 return None
4369
4370
4371class PydepsChecker:
4372 def __init__(self, input_api, pydeps_files):
4373 self._file_cache = {}
4374 self._input_api = input_api
4375 self._pydeps_files = pydeps_files
4376
4377 def _LoadFile(self, path):
4378 """Returns the list of paths within a .pydeps file relative to //."""
4379 if path not in self._file_cache:
4380 with open(path, encoding='utf-8') as f:
4381 self._file_cache[path] = f.read()
4382 return self._file_cache[path]
4383
4384 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
Gao Shenga79ebd42022-08-08 17:25:594385 """Returns an iterable of paths within the .pydep, relativized to //."""
Sam Maiera6e76d72022-02-11 21:43:504386 pydeps_data = self._LoadFile(pydeps_path)
4387 uses_gn_paths = '--gn-paths' in pydeps_data
4388 entries = (l for l in pydeps_data.splitlines()
4389 if not l.startswith('#'))
4390 if uses_gn_paths:
4391 # Paths look like: //foo/bar/baz
4392 return (e[2:] for e in entries)
4393 else:
4394 # Paths look like: path/relative/to/file.pydeps
4395 os_path = self._input_api.os_path
4396 pydeps_dir = os_path.dirname(pydeps_path)
4397 return (os_path.normpath(os_path.join(pydeps_dir, e))
4398 for e in entries)
4399
4400 def _CreateFilesToPydepsMap(self):
4401 """Returns a map of local_path -> list_of_pydeps."""
4402 ret = {}
4403 for pydep_local_path in self._pydeps_files:
4404 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
4405 ret.setdefault(path, []).append(pydep_local_path)
4406 return ret
4407
4408 def ComputeAffectedPydeps(self):
4409 """Returns an iterable of .pydeps files that might need regenerating."""
4410 affected_pydeps = set()
4411 file_to_pydeps_map = None
4412 for f in self._input_api.AffectedFiles(include_deletes=True):
4413 local_path = f.LocalPath()
4414 # Changes to DEPS can lead to .pydeps changes if any .py files are in
4415 # subrepositories. We can't figure out which files change, so re-check
4416 # all files.
4417 # Changes to print_python_deps.py affect all .pydeps.
4418 if local_path in ('DEPS', 'PRESUBMIT.py'
4419 ) or local_path.endswith('print_python_deps.py'):
4420 return self._pydeps_files
4421 elif local_path.endswith('.pydeps'):
4422 if local_path in self._pydeps_files:
4423 affected_pydeps.add(local_path)
4424 elif local_path.endswith('.py'):
4425 if file_to_pydeps_map is None:
4426 file_to_pydeps_map = self._CreateFilesToPydepsMap()
4427 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
4428 return affected_pydeps
4429
4430 def DetermineIfStaleAsync(self, pydeps_path):
4431 """Runs print_python_deps.py to see if the files is stale."""
4432 import os
4433
4434 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
4435 if old_pydeps_data:
4436 cmd = old_pydeps_data[1][1:].strip()
4437 if '--output' not in cmd:
4438 cmd += ' --output ' + pydeps_path
4439 old_contents = old_pydeps_data[2:]
4440 else:
4441 # A default cmd that should work in most cases (as long as pydeps filename
4442 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
4443 # file is empty/new.
4444 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
4445 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
4446 old_contents = []
4447 env = dict(os.environ)
4448 env['PYTHONDONTWRITEBYTECODE'] = '1'
4449 process = self._input_api.subprocess.Popen(
4450 cmd + ' --output ""',
4451 shell=True,
4452 env=env,
4453 stdout=self._input_api.subprocess.PIPE,
4454 encoding='utf-8')
4455 return _PydepsCheckerResult(cmd, pydeps_path, process, old_contents)
agrievef32bcc72016-04-04 14:57:404456
4457
Tibor Goldschwendt360793f72019-06-25 18:23:494458def _ParseGclientArgs():
Sam Maiera6e76d72022-02-11 21:43:504459 args = {}
4460 with open('build/config/gclient_args.gni', 'r') as f:
4461 for line in f:
4462 line = line.strip()
4463 if not line or line.startswith('#'):
4464 continue
4465 attribute, value = line.split('=')
4466 args[attribute.strip()] = value.strip()
4467 return args
Tibor Goldschwendt360793f72019-06-25 18:23:494468
4469
Saagar Sanghavifceeaae2020-08-12 16:40:364470def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
Sam Maiera6e76d72022-02-11 21:43:504471 """Checks if a .pydeps file needs to be regenerated."""
4472 # This check is for Python dependency lists (.pydeps files), and involves
4473 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
4474 # doesn't work on Windows and Mac, so skip it on other platforms.
4475 if not input_api.platform.startswith('linux'):
4476 return []
Erik Staabc734cd7a2021-11-23 03:11:524477
Sam Maiera6e76d72022-02-11 21:43:504478 results = []
4479 # First, check for new / deleted .pydeps.
4480 for f in input_api.AffectedFiles(include_deletes=True):
4481 # Check whether we are running the presubmit check for a file in src.
4482 # f.LocalPath is relative to repo (src, or internal repo).
4483 # os_path.exists is relative to src repo.
4484 # Therefore if os_path.exists is true, it means f.LocalPath is relative
4485 # to src and we can conclude that the pydeps is in src.
4486 if f.LocalPath().endswith('.pydeps'):
4487 if input_api.os_path.exists(f.LocalPath()):
4488 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
4489 results.append(
4490 output_api.PresubmitError(
4491 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
4492 'remove %s' % f.LocalPath()))
4493 elif f.Action() != 'D' and f.LocalPath(
4494 ) not in _ALL_PYDEPS_FILES:
4495 results.append(
4496 output_api.PresubmitError(
4497 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
4498 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:404499
Sam Maiera6e76d72022-02-11 21:43:504500 if results:
4501 return results
4502
4503 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
4504 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
4505 affected_pydeps = set(checker.ComputeAffectedPydeps())
4506 affected_android_pydeps = affected_pydeps.intersection(
4507 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
4508 if affected_android_pydeps and not is_android:
4509 results.append(
4510 output_api.PresubmitPromptOrNotify(
4511 'You have changed python files that may affect pydeps for android\n'
Gao Shenga79ebd42022-08-08 17:25:594512 'specific scripts. However, the relevant presubmit check cannot be\n'
Sam Maiera6e76d72022-02-11 21:43:504513 'run because you are not using an Android checkout. To validate that\n'
4514 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
4515 'use the android-internal-presubmit optional trybot.\n'
4516 'Possibly stale pydeps files:\n{}'.format(
4517 '\n'.join(affected_android_pydeps))))
4518
4519 all_pydeps = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
4520 pydeps_to_check = affected_pydeps.intersection(all_pydeps)
4521 # Process these concurrently, as each one takes 1-2 seconds.
4522 pydep_results = [checker.DetermineIfStaleAsync(p) for p in pydeps_to_check]
4523 for result in pydep_results:
4524 error_msg = result.GetError()
4525 if error_msg:
4526 results.append(output_api.PresubmitError(error_msg))
4527
agrievef32bcc72016-04-04 14:57:404528 return results
4529
agrievef32bcc72016-04-04 14:57:404530
Saagar Sanghavifceeaae2020-08-12 16:40:364531def CheckSingletonInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504532 """Checks to make sure no header files have |Singleton<|."""
4533
4534 def FileFilter(affected_file):
4535 # It's ok for base/memory/singleton.h to have |Singleton<|.
4536 files_to_skip = (_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
Bruce Dawson40fece62022-09-16 19:58:314537 (r"^base/memory/singleton\.h$",
4538 r"^net/quic/platform/impl/quic_singleton_impl\.h$"))
Sam Maiera6e76d72022-02-11 21:43:504539 return input_api.FilterSourceFile(affected_file,
4540 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:434541
Sam Maiera6e76d72022-02-11 21:43:504542 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
4543 files = []
4544 for f in input_api.AffectedSourceFiles(FileFilter):
4545 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx')
4546 or f.LocalPath().endswith('.hpp')
4547 or f.LocalPath().endswith('.inl')):
4548 contents = input_api.ReadFile(f)
4549 for line in contents.splitlines(False):
4550 if (not line.lstrip().startswith('//')
4551 and # Strip C++ comment.
4552 pattern.search(line)):
4553 files.append(f)
4554 break
glidere61efad2015-02-18 17:39:434555
Sam Maiera6e76d72022-02-11 21:43:504556 if files:
4557 return [
4558 output_api.PresubmitError(
4559 'Found base::Singleton<T> in the following header files.\n' +
4560 'Please move them to an appropriate source file so that the ' +
4561 'template gets instantiated in a single compilation unit.',
4562 files)
4563 ]
4564 return []
glidere61efad2015-02-18 17:39:434565
4566
[email protected]fd20b902014-05-09 02:14:534567_DEPRECATED_CSS = [
4568 # Values
4569 ( "-webkit-box", "flex" ),
4570 ( "-webkit-inline-box", "inline-flex" ),
4571 ( "-webkit-flex", "flex" ),
4572 ( "-webkit-inline-flex", "inline-flex" ),
4573 ( "-webkit-min-content", "min-content" ),
4574 ( "-webkit-max-content", "max-content" ),
4575
4576 # Properties
4577 ( "-webkit-background-clip", "background-clip" ),
4578 ( "-webkit-background-origin", "background-origin" ),
4579 ( "-webkit-background-size", "background-size" ),
4580 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:444581 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:534582
4583 # Functions
4584 ( "-webkit-gradient", "gradient" ),
4585 ( "-webkit-repeating-gradient", "repeating-gradient" ),
4586 ( "-webkit-linear-gradient", "linear-gradient" ),
4587 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
4588 ( "-webkit-radial-gradient", "radial-gradient" ),
4589 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
4590]
4591
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:204592
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:494593# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:364594def CheckNoDeprecatedCss(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504595 """ Make sure that we don't use deprecated CSS
4596 properties, functions or values. Our external
4597 documentation and iOS CSS for dom distiller
4598 (reader mode) are ignored by the hooks as it
4599 needs to be consumed by WebKit. """
4600 results = []
4601 file_inclusion_pattern = [r".+\.css$"]
4602 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
4603 input_api.DEFAULT_FILES_TO_SKIP +
4604 (r"^chrome/common/extensions/docs", r"^chrome/docs",
4605 r"^native_client_sdk"))
4606 file_filter = lambda f: input_api.FilterSourceFile(
4607 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
4608 for fpath in input_api.AffectedFiles(file_filter=file_filter):
4609 for line_num, line in fpath.ChangedContents():
4610 for (deprecated_value, value) in _DEPRECATED_CSS:
4611 if deprecated_value in line:
4612 results.append(
4613 output_api.PresubmitError(
4614 "%s:%d: Use of deprecated CSS %s, use %s instead" %
4615 (fpath.LocalPath(), line_num, deprecated_value,
4616 value)))
4617 return results
[email protected]fd20b902014-05-09 02:14:534618
mohan.reddyf21db962014-10-16 12:26:474619
Saagar Sanghavifceeaae2020-08-12 16:40:364620def CheckForRelativeIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504621 bad_files = {}
4622 for f in input_api.AffectedFiles(include_deletes=False):
4623 if (f.LocalPath().startswith('third_party')
4624 and not f.LocalPath().startswith('third_party/blink')
4625 and not f.LocalPath().startswith('third_party\\blink')):
4626 continue
rlanday6802cf632017-05-30 17:48:364627
Sam Maiera6e76d72022-02-11 21:43:504628 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
4629 continue
rlanday6802cf632017-05-30 17:48:364630
Sam Maiera6e76d72022-02-11 21:43:504631 relative_includes = [
4632 line for _, line in f.ChangedContents()
4633 if "#include" in line and "../" in line
4634 ]
4635 if not relative_includes:
4636 continue
4637 bad_files[f.LocalPath()] = relative_includes
rlanday6802cf632017-05-30 17:48:364638
Sam Maiera6e76d72022-02-11 21:43:504639 if not bad_files:
4640 return []
rlanday6802cf632017-05-30 17:48:364641
Sam Maiera6e76d72022-02-11 21:43:504642 error_descriptions = []
4643 for file_path, bad_lines in bad_files.items():
4644 error_description = file_path
4645 for line in bad_lines:
4646 error_description += '\n ' + line
4647 error_descriptions.append(error_description)
rlanday6802cf632017-05-30 17:48:364648
Sam Maiera6e76d72022-02-11 21:43:504649 results = []
4650 results.append(
4651 output_api.PresubmitError(
4652 'You added one or more relative #include paths (including "../").\n'
4653 'These shouldn\'t be used because they can be used to include headers\n'
4654 'from code that\'s not correctly specified as a dependency in the\n'
4655 'relevant BUILD.gn file(s).', error_descriptions))
rlanday6802cf632017-05-30 17:48:364656
Sam Maiera6e76d72022-02-11 21:43:504657 return results
rlanday6802cf632017-05-30 17:48:364658
Takeshi Yoshinoe387aa32017-08-02 13:16:134659
Saagar Sanghavifceeaae2020-08-12 16:40:364660def CheckForCcIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504661 """Check that nobody tries to include a cc file. It's a relatively
4662 common error which results in duplicate symbols in object
4663 files. This may not always break the build until someone later gets
4664 very confusing linking errors."""
4665 results = []
4666 for f in input_api.AffectedFiles(include_deletes=False):
4667 # We let third_party code do whatever it wants
4668 if (f.LocalPath().startswith('third_party')
4669 and not f.LocalPath().startswith('third_party/blink')
4670 and not f.LocalPath().startswith('third_party\\blink')):
4671 continue
Daniel Bratell65b033262019-04-23 08:17:064672
Sam Maiera6e76d72022-02-11 21:43:504673 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
4674 continue
Daniel Bratell65b033262019-04-23 08:17:064675
Sam Maiera6e76d72022-02-11 21:43:504676 for _, line in f.ChangedContents():
4677 if line.startswith('#include "'):
4678 included_file = line.split('"')[1]
4679 if _IsCPlusPlusFile(input_api, included_file):
4680 # The most common naming for external files with C++ code,
4681 # apart from standard headers, is to call them foo.inc, but
4682 # Chromium sometimes uses foo-inc.cc so allow that as well.
4683 if not included_file.endswith(('.h', '-inc.cc')):
4684 results.append(
4685 output_api.PresubmitError(
4686 'Only header files or .inc files should be included in other\n'
4687 'C++ files. Compiling the contents of a cc file more than once\n'
4688 'will cause duplicate information in the build which may later\n'
4689 'result in strange link_errors.\n' +
4690 f.LocalPath() + ':\n ' + line))
Daniel Bratell65b033262019-04-23 08:17:064691
Sam Maiera6e76d72022-02-11 21:43:504692 return results
Daniel Bratell65b033262019-04-23 08:17:064693
4694
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204695def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
Sam Maiera6e76d72022-02-11 21:43:504696 if not isinstance(key, ast.Str):
4697 return 'Key at line %d must be a string literal' % key.lineno
4698 if not isinstance(value, ast.Dict):
4699 return 'Value at line %d must be a dict' % value.lineno
4700 if len(value.keys) != 1:
4701 return 'Dict at line %d must have single entry' % value.lineno
4702 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
4703 return (
4704 'Entry at line %d must have a string literal \'filepath\' as key' %
4705 value.lineno)
4706 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:134707
Takeshi Yoshinoe387aa32017-08-02 13:16:134708
Sergey Ulanov4af16052018-11-08 02:41:464709def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Sam Maiera6e76d72022-02-11 21:43:504710 if not isinstance(key, ast.Str):
4711 return 'Key at line %d must be a string literal' % key.lineno
4712 if not isinstance(value, ast.List):
4713 return 'Value at line %d must be a list' % value.lineno
4714 for element in value.elts:
4715 if not isinstance(element, ast.Str):
4716 return 'Watchlist elements on line %d is not a string' % key.lineno
4717 if not email_regex.match(element.s):
4718 return ('Watchlist element on line %d doesn\'t look like a valid '
4719 + 'email: %s') % (key.lineno, element.s)
4720 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:134721
Takeshi Yoshinoe387aa32017-08-02 13:16:134722
Sergey Ulanov4af16052018-11-08 02:41:464723def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Sam Maiera6e76d72022-02-11 21:43:504724 mismatch_template = (
4725 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
4726 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:134727
Sam Maiera6e76d72022-02-11 21:43:504728 email_regex = input_api.re.compile(
4729 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
Sergey Ulanov4af16052018-11-08 02:41:464730
Sam Maiera6e76d72022-02-11 21:43:504731 ast = input_api.ast
4732 i = 0
4733 last_key = ''
4734 while True:
4735 if i >= len(wd_dict.keys):
4736 if i >= len(w_dict.keys):
4737 return None
4738 return mismatch_template % ('missing',
4739 'line %d' % w_dict.keys[i].lineno)
4740 elif i >= len(w_dict.keys):
4741 return (mismatch_template %
4742 ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:134743
Sam Maiera6e76d72022-02-11 21:43:504744 wd_key = wd_dict.keys[i]
4745 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:134746
Sam Maiera6e76d72022-02-11 21:43:504747 result = _CheckWatchlistDefinitionsEntrySyntax(wd_key,
4748 wd_dict.values[i], ast)
4749 if result is not None:
4750 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:134751
Sam Maiera6e76d72022-02-11 21:43:504752 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast,
4753 email_regex)
4754 if result is not None:
4755 return 'Bad entry in WATCHLISTS dict: %s' % result
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204756
Sam Maiera6e76d72022-02-11 21:43:504757 if wd_key.s != w_key.s:
4758 return mismatch_template % ('%s at line %d' %
4759 (wd_key.s, wd_key.lineno),
4760 '%s at line %d' %
4761 (w_key.s, w_key.lineno))
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204762
Sam Maiera6e76d72022-02-11 21:43:504763 if wd_key.s < last_key:
4764 return (
4765 'WATCHLISTS dict is not sorted lexicographically at line %d and %d'
4766 % (wd_key.lineno, w_key.lineno))
4767 last_key = wd_key.s
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204768
Sam Maiera6e76d72022-02-11 21:43:504769 i = i + 1
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204770
4771
Sergey Ulanov4af16052018-11-08 02:41:464772def _CheckWATCHLISTSSyntax(expression, input_api):
Sam Maiera6e76d72022-02-11 21:43:504773 ast = input_api.ast
4774 if not isinstance(expression, ast.Expression):
4775 return 'WATCHLISTS file must contain a valid expression'
4776 dictionary = expression.body
4777 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
4778 return 'WATCHLISTS file must have single dict with exactly two entries'
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204779
Sam Maiera6e76d72022-02-11 21:43:504780 first_key = dictionary.keys[0]
4781 first_value = dictionary.values[0]
4782 second_key = dictionary.keys[1]
4783 second_value = dictionary.values[1]
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204784
Sam Maiera6e76d72022-02-11 21:43:504785 if (not isinstance(first_key, ast.Str)
4786 or first_key.s != 'WATCHLIST_DEFINITIONS'
4787 or not isinstance(first_value, ast.Dict)):
4788 return ('The first entry of the dict in WATCHLISTS file must be '
4789 'WATCHLIST_DEFINITIONS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204790
Sam Maiera6e76d72022-02-11 21:43:504791 if (not isinstance(second_key, ast.Str) or second_key.s != 'WATCHLISTS'
4792 or not isinstance(second_value, ast.Dict)):
4793 return ('The second entry of the dict in WATCHLISTS file must be '
4794 'WATCHLISTS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204795
Sam Maiera6e76d72022-02-11 21:43:504796 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:134797
4798
Saagar Sanghavifceeaae2020-08-12 16:40:364799def CheckWATCHLISTS(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504800 for f in input_api.AffectedFiles(include_deletes=False):
4801 if f.LocalPath() == 'WATCHLISTS':
4802 contents = input_api.ReadFile(f, 'r')
Takeshi Yoshinoe387aa32017-08-02 13:16:134803
Sam Maiera6e76d72022-02-11 21:43:504804 try:
4805 # First, make sure that it can be evaluated.
4806 input_api.ast.literal_eval(contents)
4807 # Get an AST tree for it and scan the tree for detailed style checking.
4808 expression = input_api.ast.parse(contents,
4809 filename='WATCHLISTS',
4810 mode='eval')
4811 except ValueError as e:
4812 return [
4813 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4814 long_text=repr(e))
4815 ]
4816 except SyntaxError as e:
4817 return [
4818 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4819 long_text=repr(e))
4820 ]
4821 except TypeError as e:
4822 return [
4823 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4824 long_text=repr(e))
4825 ]
Takeshi Yoshinoe387aa32017-08-02 13:16:134826
Sam Maiera6e76d72022-02-11 21:43:504827 result = _CheckWATCHLISTSSyntax(expression, input_api)
4828 if result is not None:
4829 return [output_api.PresubmitError(result)]
4830 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134831
Sam Maiera6e76d72022-02-11 21:43:504832 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:134833
Sean Kaucb7c9b32022-10-25 21:25:524834def CheckGnRebasePath(input_api, output_api):
4835 """Checks that target_gen_dir is not used wtih "//" in rebase_path().
4836
4837 Developers should use root_build_dir instead of "//" when using target_gen_dir because
4838 Chromium is sometimes built outside of the source tree.
4839 """
4840
4841 def gn_files(f):
4842 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
4843
4844 rebase_path_regex = input_api.re.compile(r'rebase_path\(("\$target_gen_dir"|target_gen_dir), ("/"|"//")\)')
4845 problems = []
4846 for f in input_api.AffectedSourceFiles(gn_files):
4847 for line_num, line in f.ChangedContents():
4848 if rebase_path_regex.search(line):
4849 problems.append(
4850 'Absolute path in rebase_path() in %s:%d' %
4851 (f.LocalPath(), line_num))
4852
4853 if problems:
4854 return [
4855 output_api.PresubmitPromptWarning(
4856 'Using an absolute path in rebase_path()',
4857 items=sorted(problems),
4858 long_text=(
4859 'rebase_path() should use root_build_dir instead of "/" ',
4860 'since builds can be initiated from outside of the source ',
4861 'root.'))
4862 ]
4863 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:134864
Andrew Grieve1b290e4a22020-11-24 20:07:014865def CheckGnGlobForward(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504866 """Checks that forward_variables_from(invoker, "*") follows best practices.
Andrew Grieve1b290e4a22020-11-24 20:07:014867
Sam Maiera6e76d72022-02-11 21:43:504868 As documented at //build/docs/writing_gn_templates.md
4869 """
Andrew Grieve1b290e4a22020-11-24 20:07:014870
Sam Maiera6e76d72022-02-11 21:43:504871 def gn_files(f):
4872 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
Andrew Grieve1b290e4a22020-11-24 20:07:014873
Sam Maiera6e76d72022-02-11 21:43:504874 problems = []
4875 for f in input_api.AffectedSourceFiles(gn_files):
4876 for line_num, line in f.ChangedContents():
4877 if 'forward_variables_from(invoker, "*")' in line:
4878 problems.append(
4879 'Bare forward_variables_from(invoker, "*") in %s:%d' %
4880 (f.LocalPath(), line_num))
4881
4882 if problems:
4883 return [
4884 output_api.PresubmitPromptWarning(
4885 'forward_variables_from("*") without exclusions',
4886 items=sorted(problems),
4887 long_text=(
Gao Shenga79ebd42022-08-08 17:25:594888 'The variables "visibility" and "test_only" should be '
Sam Maiera6e76d72022-02-11 21:43:504889 'explicitly listed in forward_variables_from(). For more '
4890 'details, see:\n'
4891 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
4892 'build/docs/writing_gn_templates.md'
4893 '#Using-forward_variables_from'))
4894 ]
4895 return []
Andrew Grieve1b290e4a22020-11-24 20:07:014896
Saagar Sanghavifceeaae2020-08-12 16:40:364897def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504898 """Checks that newly added header files have corresponding GN changes.
4899 Note that this is only a heuristic. To be precise, run script:
4900 build/check_gn_headers.py.
4901 """
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194902
Sam Maiera6e76d72022-02-11 21:43:504903 def headers(f):
4904 return input_api.FilterSourceFile(
4905 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194906
Sam Maiera6e76d72022-02-11 21:43:504907 new_headers = []
4908 for f in input_api.AffectedSourceFiles(headers):
4909 if f.Action() != 'A':
4910 continue
4911 new_headers.append(f.LocalPath())
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194912
Sam Maiera6e76d72022-02-11 21:43:504913 def gn_files(f):
4914 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194915
Sam Maiera6e76d72022-02-11 21:43:504916 all_gn_changed_contents = ''
4917 for f in input_api.AffectedSourceFiles(gn_files):
4918 for _, line in f.ChangedContents():
4919 all_gn_changed_contents += line
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194920
Sam Maiera6e76d72022-02-11 21:43:504921 problems = []
4922 for header in new_headers:
4923 basename = input_api.os_path.basename(header)
4924 if basename not in all_gn_changed_contents:
4925 problems.append(header)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194926
Sam Maiera6e76d72022-02-11 21:43:504927 if problems:
4928 return [
4929 output_api.PresubmitPromptWarning(
4930 'Missing GN changes for new header files',
4931 items=sorted(problems),
4932 long_text=
4933 'Please double check whether newly added header files need '
4934 'corresponding changes in gn or gni files.\nThis checking is only a '
4935 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4936 'Read https://crbug.com/661774 for more info.')
4937 ]
4938 return []
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194939
4940
Saagar Sanghavifceeaae2020-08-12 16:40:364941def CheckCorrectProductNameInMessages(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504942 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
Michael Giuffridad3bc8672018-10-25 22:48:024943
Sam Maiera6e76d72022-02-11 21:43:504944 This assumes we won't intentionally reference one product from the other
4945 product.
4946 """
4947 all_problems = []
4948 test_cases = [{
4949 "filename_postfix": "google_chrome_strings.grd",
4950 "correct_name": "Chrome",
4951 "incorrect_name": "Chromium",
4952 }, {
4953 "filename_postfix": "chromium_strings.grd",
4954 "correct_name": "Chromium",
4955 "incorrect_name": "Chrome",
4956 }]
Michael Giuffridad3bc8672018-10-25 22:48:024957
Sam Maiera6e76d72022-02-11 21:43:504958 for test_case in test_cases:
4959 problems = []
4960 filename_filter = lambda x: x.LocalPath().endswith(test_case[
4961 "filename_postfix"])
Michael Giuffridad3bc8672018-10-25 22:48:024962
Sam Maiera6e76d72022-02-11 21:43:504963 # Check each new line. Can yield false positives in multiline comments, but
4964 # easier than trying to parse the XML because messages can have nested
4965 # children, and associating message elements with affected lines is hard.
4966 for f in input_api.AffectedSourceFiles(filename_filter):
4967 for line_num, line in f.ChangedContents():
4968 if "<message" in line or "<!--" in line or "-->" in line:
4969 continue
4970 if test_case["incorrect_name"] in line:
4971 problems.append("Incorrect product name in %s:%d" %
4972 (f.LocalPath(), line_num))
Michael Giuffridad3bc8672018-10-25 22:48:024973
Sam Maiera6e76d72022-02-11 21:43:504974 if problems:
4975 message = (
4976 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4977 % (test_case["correct_name"], test_case["correct_name"],
4978 test_case["incorrect_name"]))
4979 all_problems.append(
4980 output_api.PresubmitPromptWarning(message, items=problems))
Michael Giuffridad3bc8672018-10-25 22:48:024981
Sam Maiera6e76d72022-02-11 21:43:504982 return all_problems
Michael Giuffridad3bc8672018-10-25 22:48:024983
4984
Saagar Sanghavifceeaae2020-08-12 16:40:364985def CheckForTooLargeFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504986 """Avoid large files, especially binary files, in the repository since
4987 git doesn't scale well for those. They will be in everyone's repo
4988 clones forever, forever making Chromium slower to clone and work
4989 with."""
Daniel Bratell93eb6c62019-04-29 20:13:364990
Sam Maiera6e76d72022-02-11 21:43:504991 # Uploading files to cloud storage is not trivial so we don't want
4992 # to set the limit too low, but the upper limit for "normal" large
4993 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4994 # anything over 20 MB is exceptional.
Bruce Dawsonbb414db2022-12-27 20:21:254995 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024
4996 # Special exemption for a file that is slightly over the limit.
4997 SPECIAL_FILE_SIZE_LIMIT = 25 * 1024 * 1024
4998 SPECIAL_FILE_NAME = 'transport_security_state_static.json'
Daniel Bratell93eb6c62019-04-29 20:13:364999
Sam Maiera6e76d72022-02-11 21:43:505000 too_large_files = []
5001 for f in input_api.AffectedFiles():
5002 # Check both added and modified files (but not deleted files).
5003 if f.Action() in ('A', 'M'):
5004 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Bruce Dawsonbb414db2022-12-27 20:21:255005 limit = (SPECIAL_FILE_SIZE_LIMIT if
5006 f.AbsoluteLocalPath().endswith(SPECIAL_FILE_NAME) else
5007 TOO_LARGE_FILE_SIZE_LIMIT)
5008 if size > limit:
Sam Maiera6e76d72022-02-11 21:43:505009 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
Daniel Bratell93eb6c62019-04-29 20:13:365010
Sam Maiera6e76d72022-02-11 21:43:505011 if too_large_files:
5012 message = (
5013 'Do not commit large files to git since git scales badly for those.\n'
5014 +
5015 'Instead put the large files in cloud storage and use DEPS to\n' +
5016 'fetch them.\n' + '\n'.join(too_large_files))
5017 return [
5018 output_api.PresubmitError('Too large files found in commit',
5019 long_text=message + '\n')
5020 ]
5021 else:
5022 return []
Daniel Bratell93eb6c62019-04-29 20:13:365023
Max Morozb47503b2019-08-08 21:03:275024
Saagar Sanghavifceeaae2020-08-12 16:40:365025def CheckFuzzTargetsOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505026 """Checks specific for fuzz target sources."""
5027 EXPORTED_SYMBOLS = [
5028 'LLVMFuzzerInitialize',
5029 'LLVMFuzzerCustomMutator',
5030 'LLVMFuzzerCustomCrossOver',
5031 'LLVMFuzzerMutate',
5032 ]
Max Morozb47503b2019-08-08 21:03:275033
Sam Maiera6e76d72022-02-11 21:43:505034 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
Max Morozb47503b2019-08-08 21:03:275035
Sam Maiera6e76d72022-02-11 21:43:505036 def FilterFile(affected_file):
5037 """Ignore libFuzzer source code."""
5038 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
Bruce Dawson40fece62022-09-16 19:58:315039 files_to_skip = r"^third_party/libFuzzer"
Max Morozb47503b2019-08-08 21:03:275040
Sam Maiera6e76d72022-02-11 21:43:505041 return input_api.FilterSourceFile(affected_file,
5042 files_to_check=[files_to_check],
5043 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:275044
Sam Maiera6e76d72022-02-11 21:43:505045 files_with_missing_header = []
5046 for f in input_api.AffectedSourceFiles(FilterFile):
5047 contents = input_api.ReadFile(f, 'r')
5048 if REQUIRED_HEADER in contents:
5049 continue
Max Morozb47503b2019-08-08 21:03:275050
Sam Maiera6e76d72022-02-11 21:43:505051 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
5052 files_with_missing_header.append(f.LocalPath())
Max Morozb47503b2019-08-08 21:03:275053
Sam Maiera6e76d72022-02-11 21:43:505054 if not files_with_missing_header:
5055 return []
Max Morozb47503b2019-08-08 21:03:275056
Sam Maiera6e76d72022-02-11 21:43:505057 long_text = (
5058 'If you define any of the libFuzzer optional functions (%s), it is '
5059 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
5060 'work incorrectly on Mac (crbug.com/687076).\nNote that '
5061 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
5062 'to access command line arguments passed to the fuzzer. Instead, prefer '
5063 'static initialization and shared resources as documented in '
5064 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
5065 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n'
5066 % (', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER))
Max Morozb47503b2019-08-08 21:03:275067
Sam Maiera6e76d72022-02-11 21:43:505068 return [
5069 output_api.PresubmitPromptWarning(message="Missing '%s' in:" %
5070 REQUIRED_HEADER,
5071 items=files_with_missing_header,
5072 long_text=long_text)
5073 ]
Max Morozb47503b2019-08-08 21:03:275074
5075
Mohamed Heikald048240a2019-11-12 16:57:375076def _CheckNewImagesWarning(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505077 """
5078 Warns authors who add images into the repo to make sure their images are
5079 optimized before committing.
5080 """
5081 images_added = False
5082 image_paths = []
5083 errors = []
5084 filter_lambda = lambda x: input_api.FilterSourceFile(
5085 x,
5086 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
5087 DEFAULT_FILES_TO_SKIP),
5088 files_to_check=[r'.*\/(drawable|mipmap)'])
5089 for f in input_api.AffectedFiles(include_deletes=False,
5090 file_filter=filter_lambda):
5091 local_path = f.LocalPath().lower()
5092 if any(
5093 local_path.endswith(extension)
5094 for extension in _IMAGE_EXTENSIONS):
5095 images_added = True
5096 image_paths.append(f)
5097 if images_added:
5098 errors.append(
5099 output_api.PresubmitPromptWarning(
5100 'It looks like you are trying to commit some images. If these are '
5101 'non-test-only images, please make sure to read and apply the tips in '
5102 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
5103 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
5104 'FYI only and will not block your CL on the CQ.', image_paths))
5105 return errors
Mohamed Heikald048240a2019-11-12 16:57:375106
5107
Saagar Sanghavifceeaae2020-08-12 16:40:365108def ChecksAndroidSpecificOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505109 """Groups upload checks that target android code."""
5110 results = []
5111 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
5112 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
5113 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
5114 results.extend(_CheckAndroidToastUsage(input_api, output_api))
5115 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
5116 results.extend(_CheckAndroidTestJUnitFrameworkImport(
5117 input_api, output_api))
5118 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
5119 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
5120 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
5121 results.extend(_CheckNewImagesWarning(input_api, output_api))
5122 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
5123 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
5124 return results
5125
Becky Zhou7c69b50992018-12-10 19:37:575126
Saagar Sanghavifceeaae2020-08-12 16:40:365127def ChecksAndroidSpecificOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505128 """Groups commit checks that target android code."""
5129 results = []
5130 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
5131 return results
dgnaa68d5e2015-06-10 10:08:225132
Chris Hall59f8d0c72020-05-01 07:31:195133# TODO(chrishall): could we additionally match on any path owned by
5134# ui/accessibility/OWNERS ?
5135_ACCESSIBILITY_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:315136 r"^chrome/browser.*/accessibility/",
5137 r"^chrome/browser/extensions/api/automation.*/",
5138 r"^chrome/renderer/extensions/accessibility_.*",
5139 r"^chrome/tests/data/accessibility/",
Katie Dektar58ef07b2022-09-27 13:19:175140 r"^components/services/screen_ai/",
Bruce Dawson40fece62022-09-16 19:58:315141 r"^content/browser/accessibility/",
5142 r"^content/renderer/accessibility/",
5143 r"^content/tests/data/accessibility/",
5144 r"^extensions/renderer/api/automation/",
Katie Dektar58ef07b2022-09-27 13:19:175145 r"^services/accessibility/",
Bruce Dawson40fece62022-09-16 19:58:315146 r"^ui/accessibility/",
5147 r"^ui/views/accessibility/",
Chris Hall59f8d0c72020-05-01 07:31:195148)
5149
Saagar Sanghavifceeaae2020-08-12 16:40:365150def CheckAccessibilityRelnotesField(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505151 """Checks that commits to accessibility code contain an AX-Relnotes field in
5152 their commit message."""
Chris Hall59f8d0c72020-05-01 07:31:195153
Sam Maiera6e76d72022-02-11 21:43:505154 def FileFilter(affected_file):
5155 paths = _ACCESSIBILITY_PATHS
5156 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:195157
Sam Maiera6e76d72022-02-11 21:43:505158 # Only consider changes affecting accessibility paths.
5159 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
5160 return []
Akihiro Ota08108e542020-05-20 15:30:535161
Sam Maiera6e76d72022-02-11 21:43:505162 # AX-Relnotes can appear in either the description or the footer.
5163 # When searching the description, require 'AX-Relnotes:' to appear at the
5164 # beginning of a line.
5165 ax_regex = input_api.re.compile('ax-relnotes[:=]')
5166 description_has_relnotes = any(
5167 ax_regex.match(line)
5168 for line in input_api.change.DescriptionText().lower().splitlines())
Chris Hall59f8d0c72020-05-01 07:31:195169
Sam Maiera6e76d72022-02-11 21:43:505170 footer_relnotes = input_api.change.GitFootersFromDescription().get(
5171 'AX-Relnotes', [])
5172 if description_has_relnotes or footer_relnotes:
5173 return []
Chris Hall59f8d0c72020-05-01 07:31:195174
Sam Maiera6e76d72022-02-11 21:43:505175 # TODO(chrishall): link to Relnotes documentation in message.
5176 message = (
5177 "Missing 'AX-Relnotes:' field required for accessibility changes"
5178 "\n please add 'AX-Relnotes: [release notes].' to describe any "
5179 "user-facing changes"
5180 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
5181 "user-facing effects"
5182 "\n if this is confusing or annoying then please contact members "
5183 "of ui/accessibility/OWNERS.")
5184
5185 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:225186
Mark Schillacie5a0be22022-01-19 00:38:395187
5188_ACCESSIBILITY_EVENTS_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315189 r"^content/test/data/accessibility/event/.*\.html",
Mark Schillacie5a0be22022-01-19 00:38:395190)
5191
5192_ACCESSIBILITY_TREE_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315193 r"^content/test/data/accessibility/accname/.*\.html",
5194 r"^content/test/data/accessibility/aria/.*\.html",
5195 r"^content/test/data/accessibility/css/.*\.html",
5196 r"^content/test/data/accessibility/html/.*\.html",
Mark Schillacie5a0be22022-01-19 00:38:395197)
5198
5199_ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315200 r"^.*/WebContentsAccessibilityEventsTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:395201)
5202
5203_ACCESSIBILITY_ANDROID_TREE_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315204 r"^.*/WebContentsAccessibilityTreeTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:395205)
5206
5207def CheckAccessibilityEventsTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505208 """Checks that commits that include a newly added, renamed/moved, or deleted
5209 test in the DumpAccessibilityEventsTest suite also includes a corresponding
5210 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:395211
Sam Maiera6e76d72022-02-11 21:43:505212 def FilePathFilter(affected_file):
5213 paths = _ACCESSIBILITY_EVENTS_TEST_PATH
5214 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395215
Sam Maiera6e76d72022-02-11 21:43:505216 def AndroidFilePathFilter(affected_file):
5217 paths = _ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH
5218 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395219
Sam Maiera6e76d72022-02-11 21:43:505220 # Only consider changes in the events test data path with html type.
5221 if not any(
5222 input_api.AffectedFiles(include_deletes=True,
5223 file_filter=FilePathFilter)):
5224 return []
Mark Schillacie5a0be22022-01-19 00:38:395225
Sam Maiera6e76d72022-02-11 21:43:505226 # If the commit contains any change to the Android test file, ignore.
5227 if any(
5228 input_api.AffectedFiles(include_deletes=True,
5229 file_filter=AndroidFilePathFilter)):
5230 return []
Mark Schillacie5a0be22022-01-19 00:38:395231
Sam Maiera6e76d72022-02-11 21:43:505232 # Only consider changes that are adding/renaming or deleting a file
5233 message = []
5234 for f in input_api.AffectedFiles(include_deletes=True,
5235 file_filter=FilePathFilter):
5236 if f.Action() == 'A' or f.Action() == 'D':
5237 message = (
5238 "It appears that you are adding, renaming or deleting"
5239 "\na dump_accessibility_events* test, but have not included"
5240 "\na corresponding change for Android."
5241 "\nPlease include (or remove) the test from:"
5242 "\n content/public/android/javatests/src/org/chromium/"
5243 "content/browser/accessibility/"
5244 "WebContentsAccessibilityEventsTest.java"
5245 "\nIf this message is confusing or annoying, please contact"
5246 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:395247
Sam Maiera6e76d72022-02-11 21:43:505248 # If no message was set, return empty.
5249 if not len(message):
5250 return []
5251
5252 return [output_api.PresubmitPromptWarning(message)]
5253
Mark Schillacie5a0be22022-01-19 00:38:395254
5255def CheckAccessibilityTreeTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505256 """Checks that commits that include a newly added, renamed/moved, or deleted
5257 test in the DumpAccessibilityTreeTest suite also includes a corresponding
5258 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:395259
Sam Maiera6e76d72022-02-11 21:43:505260 def FilePathFilter(affected_file):
5261 paths = _ACCESSIBILITY_TREE_TEST_PATH
5262 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395263
Sam Maiera6e76d72022-02-11 21:43:505264 def AndroidFilePathFilter(affected_file):
5265 paths = _ACCESSIBILITY_ANDROID_TREE_TEST_PATH
5266 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395267
Sam Maiera6e76d72022-02-11 21:43:505268 # Only consider changes in the various tree test data paths with html type.
5269 if not any(
5270 input_api.AffectedFiles(include_deletes=True,
5271 file_filter=FilePathFilter)):
5272 return []
Mark Schillacie5a0be22022-01-19 00:38:395273
Sam Maiera6e76d72022-02-11 21:43:505274 # If the commit contains any change to the Android test file, ignore.
5275 if any(
5276 input_api.AffectedFiles(include_deletes=True,
5277 file_filter=AndroidFilePathFilter)):
5278 return []
Mark Schillacie5a0be22022-01-19 00:38:395279
Sam Maiera6e76d72022-02-11 21:43:505280 # Only consider changes that are adding/renaming or deleting a file
5281 message = []
5282 for f in input_api.AffectedFiles(include_deletes=True,
5283 file_filter=FilePathFilter):
5284 if f.Action() == 'A' or f.Action() == 'D':
5285 message = (
5286 "It appears that you are adding, renaming or deleting"
5287 "\na dump_accessibility_tree* test, but have not included"
5288 "\na corresponding change for Android."
5289 "\nPlease include (or remove) the test from:"
5290 "\n content/public/android/javatests/src/org/chromium/"
5291 "content/browser/accessibility/"
5292 "WebContentsAccessibilityTreeTest.java"
5293 "\nIf this message is confusing or annoying, please contact"
5294 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:395295
Sam Maiera6e76d72022-02-11 21:43:505296 # If no message was set, return empty.
5297 if not len(message):
5298 return []
5299
5300 return [output_api.PresubmitPromptWarning(message)]
Mark Schillacie5a0be22022-01-19 00:38:395301
5302
Bruce Dawson33806592022-11-16 01:44:515303def CheckEsLintConfigChanges(input_api, output_api):
5304 """Suggest using "git cl presubmit --files" when .eslintrc.js files are
5305 modified. This is important because enabling an error in .eslintrc.js can
5306 trigger errors in any .js or .ts files in its directory, leading to hidden
5307 presubmit errors."""
5308 results = []
5309 eslint_filter = lambda f: input_api.FilterSourceFile(
5310 f, files_to_check=[r'.*\.eslintrc\.js$'])
5311 for f in input_api.AffectedFiles(include_deletes=False,
5312 file_filter=eslint_filter):
5313 local_dir = input_api.os_path.dirname(f.LocalPath())
5314 # Use / characters so that the commands printed work on any OS.
5315 local_dir = local_dir.replace(input_api.os_path.sep, '/')
5316 if local_dir:
5317 local_dir += '/'
5318 results.append(
5319 output_api.PresubmitNotifyResult(
5320 '%(file)s modified. Consider running \'git cl presubmit --files '
5321 '"%(dir)s*.js;%(dir)s*.ts"\' in order to check and fix the affected '
5322 'files before landing this change.' %
5323 { 'file' : f.LocalPath(), 'dir' : local_dir}))
5324 return results
5325
5326
seanmccullough4a9356252021-04-08 19:54:095327# string pattern, sequence of strings to show when pattern matches,
5328# error flag. True if match is a presubmit error, otherwise it's a warning.
5329_NON_INCLUSIVE_TERMS = (
5330 (
5331 # Note that \b pattern in python re is pretty particular. In this
5332 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
5333 # ...' will not. This may require some tweaking to catch these cases
5334 # without triggering a lot of false positives. Leaving it naive and
5335 # less matchy for now.
seanmccullough56d1e3cf2021-12-03 18:18:325336 r'/\b(?i)((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:095337 (
5338 'Please don\'t use blacklist, whitelist, ' # nocheck
5339 'or slave in your', # nocheck
5340 'code and make every effort to use other terms. Using "// nocheck"',
5341 '"# nocheck" or "<!-- nocheck -->"',
5342 'at the end of the offending line will bypass this PRESUBMIT error',
5343 'but avoid using this whenever possible. Reach out to',
5344 '[email protected] if you have questions'),
5345 True),)
5346
Saagar Sanghavifceeaae2020-08-12 16:40:365347def ChecksCommon(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505348 """Checks common to both upload and commit."""
5349 results = []
Eric Boren6fd2b932018-01-25 15:05:085350 results.extend(
Sam Maiera6e76d72022-02-11 21:43:505351 input_api.canned_checks.PanProjectChecks(
5352 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:085353
Sam Maiera6e76d72022-02-11 21:43:505354 author = input_api.change.author_email
5355 if author and author not in _KNOWN_ROBOTS:
5356 results.extend(
5357 input_api.canned_checks.CheckAuthorizedAuthor(
5358 input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:245359
Sam Maiera6e76d72022-02-11 21:43:505360 results.extend(
5361 input_api.canned_checks.CheckChangeHasNoTabs(
5362 input_api,
5363 output_api,
5364 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
5365 results.extend(
5366 input_api.RunTests(
5367 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Edward Lesmesce51df52020-08-04 22:10:175368
Bruce Dawsonc8054482022-03-28 15:33:375369 dirmd = 'dirmd.bat' if input_api.is_windows else 'dirmd'
Sam Maiera6e76d72022-02-11 21:43:505370 dirmd_bin = input_api.os_path.join(input_api.PresubmitLocalPath(),
Bruce Dawsonc8054482022-03-28 15:33:375371 'third_party', 'depot_tools', dirmd)
Sam Maiera6e76d72022-02-11 21:43:505372 results.extend(
5373 input_api.RunTests(
5374 input_api.canned_checks.CheckDirMetadataFormat(
5375 input_api, output_api, dirmd_bin)))
5376 results.extend(
5377 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
5378 input_api, output_api))
5379 results.extend(
5380 input_api.canned_checks.CheckNoNewMetadataInOwners(
5381 input_api, output_api))
5382 results.extend(
5383 input_api.canned_checks.CheckInclusiveLanguage(
5384 input_api,
5385 output_api,
5386 excluded_directories_relative_path=[
5387 'infra', 'inclusive_language_presubmit_exempt_dirs.txt'
5388 ],
5389 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Dirk Prankee3c9c62d2021-05-18 18:35:595390
Aleksey Khoroshilov2978c942022-06-13 16:14:125391 presubmit_py_filter = lambda f: input_api.FilterSourceFile(
Bruce Dawson696963f2022-09-13 01:15:475392 f, files_to_check=[r'.*PRESUBMIT\.py$'])
Aleksey Khoroshilov2978c942022-06-13 16:14:125393 for f in input_api.AffectedFiles(include_deletes=False,
5394 file_filter=presubmit_py_filter):
5395 full_path = input_api.os_path.dirname(f.AbsoluteLocalPath())
5396 test_file = input_api.os_path.join(full_path, 'PRESUBMIT_test.py')
5397 # The PRESUBMIT.py file (and the directory containing it) might have
5398 # been affected by being moved or removed, so only try to run the tests
5399 # if they still exist.
5400 if not input_api.os_path.exists(test_file):
5401 continue
Sam Maiera6e76d72022-02-11 21:43:505402
Aleksey Khoroshilov2978c942022-06-13 16:14:125403 use_python3 = False
Bruce Dawson58a45d22023-02-27 11:24:165404 with open(f.LocalPath(), encoding='utf-8') as fp:
Aleksey Khoroshilov2978c942022-06-13 16:14:125405 use_python3 = any(
5406 line.startswith('USE_PYTHON3 = True')
5407 for line in fp.readlines())
5408
5409 results.extend(
5410 input_api.canned_checks.RunUnitTestsInDirectory(
5411 input_api,
5412 output_api,
5413 full_path,
5414 files_to_check=[r'^PRESUBMIT_test\.py$'],
5415 run_on_python2=not use_python3,
5416 run_on_python3=use_python3,
5417 skip_shebang_check=True))
Sam Maiera6e76d72022-02-11 21:43:505418 return results
[email protected]1f7b4172010-01-28 01:17:345419
[email protected]b337cb5b2011-01-23 21:24:055420
Saagar Sanghavifceeaae2020-08-12 16:40:365421def CheckPatchFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505422 problems = [
5423 f.LocalPath() for f in input_api.AffectedFiles()
5424 if f.LocalPath().endswith(('.orig', '.rej'))
5425 ]
5426 # Cargo.toml.orig files are part of third-party crates downloaded from
5427 # crates.io and should be included.
5428 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
5429 if problems:
5430 return [
5431 output_api.PresubmitError("Don't commit .rej and .orig files.",
5432 problems)
5433 ]
5434 else:
5435 return []
[email protected]b8079ae4a2012-12-05 19:56:495436
5437
Saagar Sanghavifceeaae2020-08-12 16:40:365438def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505439 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
5440 macro_re = input_api.re.compile(
5441 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
5442 include_re = input_api.re.compile(r'^#include\s+"build/build_config.h"',
5443 input_api.re.MULTILINE)
5444 extension_re = input_api.re.compile(r'\.[a-z]+$')
5445 errors = []
Bruce Dawsonf7679202022-08-09 20:24:005446 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:505447 for f in input_api.AffectedFiles(include_deletes=False):
Bruce Dawsonf7679202022-08-09 20:24:005448 # The build-config macros are allowed to be used in build_config.h
5449 # without including itself.
5450 if f.LocalPath() == config_h_file:
5451 continue
Sam Maiera6e76d72022-02-11 21:43:505452 if not f.LocalPath().endswith(
5453 ('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
5454 continue
5455 found_line_number = None
5456 found_macro = None
5457 all_lines = input_api.ReadFile(f, 'r').splitlines()
5458 for line_num, line in enumerate(all_lines):
5459 match = macro_re.search(line)
5460 if match:
5461 found_line_number = line_num
5462 found_macro = match.group(2)
5463 break
5464 if not found_line_number:
5465 continue
Kent Tamura5a8755d2017-06-29 23:37:075466
Sam Maiera6e76d72022-02-11 21:43:505467 found_include_line = -1
5468 for line_num, line in enumerate(all_lines):
5469 if include_re.search(line):
5470 found_include_line = line_num
5471 break
5472 if found_include_line >= 0 and found_include_line < found_line_number:
5473 continue
Kent Tamura5a8755d2017-06-29 23:37:075474
Sam Maiera6e76d72022-02-11 21:43:505475 if not f.LocalPath().endswith('.h'):
5476 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
5477 try:
5478 content = input_api.ReadFile(primary_header_path, 'r')
5479 if include_re.search(content):
5480 continue
5481 except IOError:
5482 pass
5483 errors.append('%s:%d %s macro is used without first including build/'
5484 'build_config.h.' %
5485 (f.LocalPath(), found_line_number, found_macro))
5486 if errors:
5487 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
5488 return []
Kent Tamura5a8755d2017-06-29 23:37:075489
5490
Lei Zhang1c12a22f2021-05-12 11:28:455491def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505492 stl_include_re = input_api.re.compile(r'^#include\s+<('
5493 r'algorithm|'
5494 r'array|'
5495 r'limits|'
5496 r'list|'
5497 r'map|'
5498 r'memory|'
5499 r'queue|'
5500 r'set|'
5501 r'string|'
5502 r'unordered_map|'
5503 r'unordered_set|'
5504 r'utility|'
5505 r'vector)>')
5506 std_namespace_re = input_api.re.compile(r'std::')
5507 errors = []
5508 for f in input_api.AffectedFiles():
5509 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
5510 continue
Lei Zhang1c12a22f2021-05-12 11:28:455511
Sam Maiera6e76d72022-02-11 21:43:505512 uses_std_namespace = False
5513 has_stl_include = False
5514 for line in f.NewContents():
5515 if has_stl_include and uses_std_namespace:
5516 break
Lei Zhang1c12a22f2021-05-12 11:28:455517
Sam Maiera6e76d72022-02-11 21:43:505518 if not has_stl_include and stl_include_re.search(line):
5519 has_stl_include = True
5520 continue
Lei Zhang1c12a22f2021-05-12 11:28:455521
Bruce Dawson4a5579a2022-04-08 17:11:365522 if not uses_std_namespace and (std_namespace_re.search(line)
5523 or 'no-std-usage-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:505524 uses_std_namespace = True
5525 continue
Lei Zhang1c12a22f2021-05-12 11:28:455526
Sam Maiera6e76d72022-02-11 21:43:505527 if has_stl_include and not uses_std_namespace:
5528 errors.append(
5529 '%s: Includes STL header(s) but does not reference std::' %
5530 f.LocalPath())
5531 if errors:
5532 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
5533 return []
Lei Zhang1c12a22f2021-05-12 11:28:455534
5535
Xiaohan Wang42d96c22022-01-20 17:23:115536def _CheckForDeprecatedOSMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:505537 """Check for sensible looking, totally invalid OS macros."""
5538 preprocessor_statement = input_api.re.compile(r'^\s*#')
5539 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
5540 results = []
5541 for lnum, line in f.ChangedContents():
5542 if preprocessor_statement.search(line):
5543 for match in os_macro.finditer(line):
5544 results.append(
5545 ' %s:%d: %s' %
5546 (f.LocalPath(), lnum, 'defined(OS_' + match.group(1) +
5547 ') -> BUILDFLAG(IS_' + match.group(1) + ')'))
5548 return results
[email protected]b00342e7f2013-03-26 16:21:545549
5550
Xiaohan Wang42d96c22022-01-20 17:23:115551def CheckForDeprecatedOSMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505552 """Check all affected files for invalid OS macros."""
5553 bad_macros = []
Bruce Dawsonf7679202022-08-09 20:24:005554 # The OS_ macros are allowed to be used in build/build_config.h.
5555 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:505556 for f in input_api.AffectedSourceFiles(None):
Bruce Dawsonf7679202022-08-09 20:24:005557 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')) \
5558 and f.LocalPath() != config_h_file:
Sam Maiera6e76d72022-02-11 21:43:505559 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
[email protected]b00342e7f2013-03-26 16:21:545560
Sam Maiera6e76d72022-02-11 21:43:505561 if not bad_macros:
5562 return []
[email protected]b00342e7f2013-03-26 16:21:545563
Sam Maiera6e76d72022-02-11 21:43:505564 return [
5565 output_api.PresubmitError(
5566 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
5567 'defined in build_config.h):', bad_macros)
5568 ]
[email protected]b00342e7f2013-03-26 16:21:545569
lliabraa35bab3932014-10-01 12:16:445570
5571def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:505572 """Check all affected files for invalid "if defined" macros."""
5573 ALWAYS_DEFINED_MACROS = (
5574 "TARGET_CPU_PPC",
5575 "TARGET_CPU_PPC64",
5576 "TARGET_CPU_68K",
5577 "TARGET_CPU_X86",
5578 "TARGET_CPU_ARM",
5579 "TARGET_CPU_MIPS",
5580 "TARGET_CPU_SPARC",
5581 "TARGET_CPU_ALPHA",
5582 "TARGET_IPHONE_SIMULATOR",
5583 "TARGET_OS_EMBEDDED",
5584 "TARGET_OS_IPHONE",
5585 "TARGET_OS_MAC",
5586 "TARGET_OS_UNIX",
5587 "TARGET_OS_WIN32",
5588 )
5589 ifdef_macro = input_api.re.compile(
5590 r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
5591 results = []
5592 for lnum, line in f.ChangedContents():
5593 for match in ifdef_macro.finditer(line):
5594 if match.group(1) in ALWAYS_DEFINED_MACROS:
5595 always_defined = ' %s is always defined. ' % match.group(1)
5596 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
5597 results.append(
5598 ' %s:%d %s\n\t%s' %
5599 (f.LocalPath(), lnum, always_defined, did_you_mean))
5600 return results
lliabraa35bab3932014-10-01 12:16:445601
5602
Saagar Sanghavifceeaae2020-08-12 16:40:365603def CheckForInvalidIfDefinedMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505604 """Check all affected files for invalid "if defined" macros."""
5605 bad_macros = []
5606 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
5607 for f in input_api.AffectedFiles():
5608 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
5609 continue
5610 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
5611 bad_macros.extend(
5612 _CheckForInvalidIfDefinedMacrosInFile(input_api, f))
lliabraa35bab3932014-10-01 12:16:445613
Sam Maiera6e76d72022-02-11 21:43:505614 if not bad_macros:
5615 return []
lliabraa35bab3932014-10-01 12:16:445616
Sam Maiera6e76d72022-02-11 21:43:505617 return [
5618 output_api.PresubmitError(
5619 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
5620 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
5621 bad_macros)
5622 ]
lliabraa35bab3932014-10-01 12:16:445623
5624
Saagar Sanghavifceeaae2020-08-12 16:40:365625def CheckForIPCRules(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505626 """Check for same IPC rules described in
5627 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
5628 """
5629 base_pattern = r'IPC_ENUM_TRAITS\('
5630 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
5631 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
mlamouria82272622014-09-16 18:45:045632
Sam Maiera6e76d72022-02-11 21:43:505633 problems = []
5634 for f in input_api.AffectedSourceFiles(None):
5635 local_path = f.LocalPath()
5636 if not local_path.endswith('.h'):
5637 continue
5638 for line_number, line in f.ChangedContents():
5639 if inclusion_pattern.search(
5640 line) and not comment_pattern.search(line):
5641 problems.append('%s:%d\n %s' %
5642 (local_path, line_number, line.strip()))
mlamouria82272622014-09-16 18:45:045643
Sam Maiera6e76d72022-02-11 21:43:505644 if problems:
5645 return [
5646 output_api.PresubmitPromptWarning(_IPC_ENUM_TRAITS_DEPRECATED,
5647 problems)
5648 ]
5649 else:
5650 return []
mlamouria82272622014-09-16 18:45:045651
[email protected]b00342e7f2013-03-26 16:21:545652
Saagar Sanghavifceeaae2020-08-12 16:40:365653def CheckForLongPathnames(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505654 """Check to make sure no files being submitted have long paths.
5655 This causes issues on Windows.
5656 """
5657 problems = []
5658 for f in input_api.AffectedTestableFiles():
5659 local_path = f.LocalPath()
5660 # Windows has a path limit of 260 characters. Limit path length to 200 so
5661 # that we have some extra for the prefix on dev machines and the bots.
5662 if len(local_path) > 200:
5663 problems.append(local_path)
Stephen Martinis97a394142018-06-07 23:06:055664
Sam Maiera6e76d72022-02-11 21:43:505665 if problems:
5666 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
5667 else:
5668 return []
Stephen Martinis97a394142018-06-07 23:06:055669
5670
Saagar Sanghavifceeaae2020-08-12 16:40:365671def CheckForIncludeGuards(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505672 """Check that header files have proper guards against multiple inclusion.
5673 If a file should not have such guards (and it probably should) then it
Bruce Dawson4a5579a2022-04-08 17:11:365674 should include the string "no-include-guard-because-multiply-included" or
5675 "no-include-guard-because-pch-file".
Sam Maiera6e76d72022-02-11 21:43:505676 """
Daniel Bratell8ba52722018-03-02 16:06:145677
Sam Maiera6e76d72022-02-11 21:43:505678 def is_chromium_header_file(f):
5679 # We only check header files under the control of the Chromium
5680 # project. That is, those outside third_party apart from
5681 # third_party/blink.
5682 # We also exclude *_message_generator.h headers as they use
5683 # include guards in a special, non-typical way.
5684 file_with_path = input_api.os_path.normpath(f.LocalPath())
5685 return (file_with_path.endswith('.h')
5686 and not file_with_path.endswith('_message_generator.h')
Bruce Dawson4c4c2922022-05-02 18:07:335687 and not file_with_path.endswith('com_imported_mstscax.h')
Sam Maiera6e76d72022-02-11 21:43:505688 and (not file_with_path.startswith('third_party')
5689 or file_with_path.startswith(
5690 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:145691
Sam Maiera6e76d72022-02-11 21:43:505692 def replace_special_with_underscore(string):
5693 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:145694
Sam Maiera6e76d72022-02-11 21:43:505695 errors = []
Daniel Bratell8ba52722018-03-02 16:06:145696
Sam Maiera6e76d72022-02-11 21:43:505697 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
5698 guard_name = None
5699 guard_line_number = None
5700 seen_guard_end = False
Daniel Bratell8ba52722018-03-02 16:06:145701
Sam Maiera6e76d72022-02-11 21:43:505702 file_with_path = input_api.os_path.normpath(f.LocalPath())
5703 base_file_name = input_api.os_path.splitext(
5704 input_api.os_path.basename(file_with_path))[0]
5705 upper_base_file_name = base_file_name.upper()
Daniel Bratell8ba52722018-03-02 16:06:145706
Sam Maiera6e76d72022-02-11 21:43:505707 expected_guard = replace_special_with_underscore(
5708 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:145709
Sam Maiera6e76d72022-02-11 21:43:505710 # For "path/elem/file_name.h" we should really only accept
5711 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
5712 # are too many (1000+) files with slight deviations from the
5713 # coding style. The most important part is that the include guard
5714 # is there, and that it's unique, not the name so this check is
5715 # forgiving for existing files.
5716 #
5717 # As code becomes more uniform, this could be made stricter.
Daniel Bratell8ba52722018-03-02 16:06:145718
Sam Maiera6e76d72022-02-11 21:43:505719 guard_name_pattern_list = [
5720 # Anything with the right suffix (maybe with an extra _).
5721 r'\w+_H__?',
Daniel Bratell8ba52722018-03-02 16:06:145722
Sam Maiera6e76d72022-02-11 21:43:505723 # To cover include guards with old Blink style.
5724 r'\w+_h',
Daniel Bratell8ba52722018-03-02 16:06:145725
Sam Maiera6e76d72022-02-11 21:43:505726 # Anything including the uppercase name of the file.
5727 r'\w*' + input_api.re.escape(
5728 replace_special_with_underscore(upper_base_file_name)) +
5729 r'\w*',
5730 ]
5731 guard_name_pattern = '|'.join(guard_name_pattern_list)
5732 guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
5733 guard_name_pattern + ')')
Daniel Bratell8ba52722018-03-02 16:06:145734
Sam Maiera6e76d72022-02-11 21:43:505735 for line_number, line in enumerate(f.NewContents()):
Bruce Dawson4a5579a2022-04-08 17:11:365736 if ('no-include-guard-because-multiply-included' in line
5737 or 'no-include-guard-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:505738 guard_name = 'DUMMY' # To not trigger check outside the loop.
5739 break
Daniel Bratell8ba52722018-03-02 16:06:145740
Sam Maiera6e76d72022-02-11 21:43:505741 if guard_name is None:
5742 match = guard_pattern.match(line)
5743 if match:
5744 guard_name = match.group(1)
5745 guard_line_number = line_number
Daniel Bratell8ba52722018-03-02 16:06:145746
Sam Maiera6e76d72022-02-11 21:43:505747 # We allow existing files to use include guards whose names
5748 # don't match the chromium style guide, but new files should
5749 # get it right.
Bruce Dawson6cc154e2022-04-12 20:39:495750 if guard_name != expected_guard:
Bruce Dawson95eb7562022-09-14 15:27:165751 if f.Action() == 'A': # If file was just 'A'dded
Sam Maiera6e76d72022-02-11 21:43:505752 errors.append(
5753 output_api.PresubmitPromptWarning(
5754 'Header using the wrong include guard name %s'
5755 % guard_name, [
5756 '%s:%d' %
5757 (f.LocalPath(), line_number + 1)
5758 ], 'Expected: %r\nFound: %r' %
5759 (expected_guard, guard_name)))
5760 else:
5761 # The line after #ifndef should have a #define of the same name.
5762 if line_number == guard_line_number + 1:
5763 expected_line = '#define %s' % guard_name
5764 if line != expected_line:
5765 errors.append(
5766 output_api.PresubmitPromptWarning(
5767 'Missing "%s" for include guard' %
5768 expected_line,
5769 ['%s:%d' % (f.LocalPath(), line_number + 1)],
5770 'Expected: %r\nGot: %r' %
5771 (expected_line, line)))
Daniel Bratell8ba52722018-03-02 16:06:145772
Sam Maiera6e76d72022-02-11 21:43:505773 if not seen_guard_end and line == '#endif // %s' % guard_name:
5774 seen_guard_end = True
5775 elif seen_guard_end:
5776 if line.strip() != '':
5777 errors.append(
5778 output_api.PresubmitPromptWarning(
5779 'Include guard %s not covering the whole file'
5780 % (guard_name), [f.LocalPath()]))
5781 break # Nothing else to check and enough to warn once.
Daniel Bratell8ba52722018-03-02 16:06:145782
Sam Maiera6e76d72022-02-11 21:43:505783 if guard_name is None:
5784 errors.append(
5785 output_api.PresubmitPromptWarning(
Bruce Dawson32114b62022-04-11 16:45:495786 'Missing include guard in %s\n'
Sam Maiera6e76d72022-02-11 21:43:505787 'Recommended name: %s\n'
5788 'This check can be disabled by having the string\n'
Bruce Dawson4a5579a2022-04-08 17:11:365789 '"no-include-guard-because-multiply-included" or\n'
5790 '"no-include-guard-because-pch-file" in the header.'
Sam Maiera6e76d72022-02-11 21:43:505791 % (f.LocalPath(), expected_guard)))
5792
5793 return errors
Daniel Bratell8ba52722018-03-02 16:06:145794
5795
Saagar Sanghavifceeaae2020-08-12 16:40:365796def CheckForWindowsLineEndings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505797 """Check source code and known ascii text files for Windows style line
5798 endings.
5799 """
Bruce Dawson5efbdc652022-04-11 19:29:515800 known_text_files = r'.*\.(txt|html|htm|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:235801
Sam Maiera6e76d72022-02-11 21:43:505802 file_inclusion_pattern = (known_text_files,
5803 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
5804 r'.+%s' % _HEADER_EXTENSIONS)
mostynbb639aca52015-01-07 20:31:235805
Sam Maiera6e76d72022-02-11 21:43:505806 problems = []
5807 source_file_filter = lambda f: input_api.FilterSourceFile(
5808 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
5809 for f in input_api.AffectedSourceFiles(source_file_filter):
Bruce Dawson5efbdc652022-04-11 19:29:515810 # Ignore test files that contain crlf intentionally.
5811 if f.LocalPath().endswith('crlf.txt'):
Daniel Chenga37c03db2022-05-12 17:20:345812 continue
Sam Maiera6e76d72022-02-11 21:43:505813 include_file = False
5814 for line in input_api.ReadFile(f, 'r').splitlines(True):
5815 if line.endswith('\r\n'):
5816 include_file = True
5817 if include_file:
5818 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:235819
Sam Maiera6e76d72022-02-11 21:43:505820 if problems:
5821 return [
5822 output_api.PresubmitPromptWarning(
5823 'Are you sure that you want '
5824 'these files to contain Windows style line endings?\n' +
5825 '\n'.join(problems))
5826 ]
mostynbb639aca52015-01-07 20:31:235827
Sam Maiera6e76d72022-02-11 21:43:505828 return []
5829
mostynbb639aca52015-01-07 20:31:235830
Evan Stade6cfc964c12021-05-18 20:21:165831def CheckIconFilesForLicenseHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505832 """Check that .icon files (which are fragments of C++) have license headers.
5833 """
Evan Stade6cfc964c12021-05-18 20:21:165834
Sam Maiera6e76d72022-02-11 21:43:505835 icon_files = (r'.*\.icon$', )
Evan Stade6cfc964c12021-05-18 20:21:165836
Sam Maiera6e76d72022-02-11 21:43:505837 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
5838 return input_api.canned_checks.CheckLicense(input_api,
5839 output_api,
5840 source_file_filter=icons)
5841
Evan Stade6cfc964c12021-05-18 20:21:165842
Jose Magana2b456f22021-03-09 23:26:405843def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505844 """Check source code for use of Chrome App technologies being
5845 deprecated.
5846 """
Jose Magana2b456f22021-03-09 23:26:405847
Sam Maiera6e76d72022-02-11 21:43:505848 def _CheckForDeprecatedTech(input_api,
5849 output_api,
5850 detection_list,
5851 files_to_check=None,
5852 files_to_skip=None):
Jose Magana2b456f22021-03-09 23:26:405853
Sam Maiera6e76d72022-02-11 21:43:505854 if (files_to_check or files_to_skip):
5855 source_file_filter = lambda f: input_api.FilterSourceFile(
5856 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
5857 else:
5858 source_file_filter = None
5859
5860 problems = []
5861
5862 for f in input_api.AffectedSourceFiles(source_file_filter):
5863 if f.Action() == 'D':
5864 continue
5865 for _, line in f.ChangedContents():
5866 if any(detect in line for detect in detection_list):
5867 problems.append(f.LocalPath())
5868
5869 return problems
5870
5871 # to avoid this presubmit script triggering warnings
5872 files_to_skip = ['PRESUBMIT.py', 'PRESUBMIT_test.py']
Jose Magana2b456f22021-03-09 23:26:405873
5874 problems = []
5875
Sam Maiera6e76d72022-02-11 21:43:505876 # NMF: any files with extensions .nmf or NMF
5877 _NMF_FILES = r'\.(nmf|NMF)$'
5878 problems += _CheckForDeprecatedTech(
5879 input_api,
5880 output_api,
5881 detection_list=[''], # any change to the file will trigger warning
5882 files_to_check=[r'.+%s' % _NMF_FILES])
Jose Magana2b456f22021-03-09 23:26:405883
Sam Maiera6e76d72022-02-11 21:43:505884 # MANIFEST: any manifest.json that in its diff includes "app":
5885 _MANIFEST_FILES = r'(manifest\.json)$'
5886 problems += _CheckForDeprecatedTech(
5887 input_api,
5888 output_api,
5889 detection_list=['"app":'],
5890 files_to_check=[r'.*%s' % _MANIFEST_FILES])
Jose Magana2b456f22021-03-09 23:26:405891
Sam Maiera6e76d72022-02-11 21:43:505892 # NaCl / PNaCl: any file that in its diff contains the strings in the list
5893 problems += _CheckForDeprecatedTech(
5894 input_api,
5895 output_api,
5896 detection_list=['config=nacl', 'enable-nacl', 'cpu=pnacl', 'nacl_io'],
Bruce Dawson40fece62022-09-16 19:58:315897 files_to_skip=files_to_skip + [r"^native_client_sdk/"])
Jose Magana2b456f22021-03-09 23:26:405898
Gao Shenga79ebd42022-08-08 17:25:595899 # PPAPI: any C/C++ file that in its diff includes a ppapi library
Sam Maiera6e76d72022-02-11 21:43:505900 problems += _CheckForDeprecatedTech(
5901 input_api,
5902 output_api,
5903 detection_list=['#include "ppapi', '#include <ppapi'],
5904 files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,
5905 r'.+%s' % _IMPLEMENTATION_EXTENSIONS),
Bruce Dawson40fece62022-09-16 19:58:315906 files_to_skip=[r"^ppapi/"])
Jose Magana2b456f22021-03-09 23:26:405907
Sam Maiera6e76d72022-02-11 21:43:505908 if problems:
5909 return [
5910 output_api.PresubmitPromptWarning(
5911 'You are adding/modifying code'
5912 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
5913 ' PNaCl, PPAPI). See this blog post for more details:\n'
5914 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
5915 'and this documentation for options to replace these technologies:\n'
5916 'https://developer.chrome.com/docs/apps/migration/\n' +
5917 '\n'.join(problems))
5918 ]
Jose Magana2b456f22021-03-09 23:26:405919
Sam Maiera6e76d72022-02-11 21:43:505920 return []
Jose Magana2b456f22021-03-09 23:26:405921
mostynbb639aca52015-01-07 20:31:235922
Saagar Sanghavifceeaae2020-08-12 16:40:365923def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
Sam Maiera6e76d72022-02-11 21:43:505924 """Checks that all source files use SYSLOG properly."""
5925 syslog_files = []
5926 for f in input_api.AffectedSourceFiles(src_file_filter):
5927 for line_number, line in f.ChangedContents():
5928 if 'SYSLOG' in line:
5929 syslog_files.append(f.LocalPath() + ':' + str(line_number))
pastarmovj032ba5bc2017-01-12 10:41:565930
Sam Maiera6e76d72022-02-11 21:43:505931 if syslog_files:
5932 return [
5933 output_api.PresubmitPromptWarning(
5934 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
5935 ' calls.\nFiles to check:\n',
5936 items=syslog_files)
5937 ]
5938 return []
pastarmovj89f7ee12016-09-20 14:58:135939
5940
[email protected]1f7b4172010-01-28 01:17:345941def CheckChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505942 if input_api.version < [2, 0, 0]:
5943 return [
5944 output_api.PresubmitError(
5945 "Your depot_tools is out of date. "
5946 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5947 "but your version is %d.%d.%d" % tuple(input_api.version))
5948 ]
5949 results = []
5950 results.extend(
5951 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
5952 return results
[email protected]ca8d19842009-02-19 16:33:125953
5954
5955def CheckChangeOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505956 if input_api.version < [2, 0, 0]:
5957 return [
5958 output_api.PresubmitError(
5959 "Your depot_tools is out of date. "
5960 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5961 "but your version is %d.%d.%d" % tuple(input_api.version))
5962 ]
Saagar Sanghavifceeaae2020-08-12 16:40:365963
Sam Maiera6e76d72022-02-11 21:43:505964 results = []
5965 # Make sure the tree is 'open'.
5966 results.extend(
5967 input_api.canned_checks.CheckTreeIsOpen(
5968 input_api,
5969 output_api,
5970 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:275971
Sam Maiera6e76d72022-02-11 21:43:505972 results.extend(
5973 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
5974 results.extend(
5975 input_api.canned_checks.CheckChangeHasBugField(input_api, output_api))
5976 results.extend(
5977 input_api.canned_checks.CheckChangeHasNoUnwantedTags(
5978 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505979 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145980
5981
Saagar Sanghavifceeaae2020-08-12 16:40:365982def CheckStrings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505983 """Check string ICU syntax validity and if translation screenshots exist."""
5984 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
5985 # footer is set to true.
5986 git_footers = input_api.change.GitFootersFromDescription()
5987 skip_screenshot_check_footer = [
5988 footer.lower() for footer in git_footers.get(
5989 u'Skip-Translation-Screenshots-Check', [])
5990 ]
5991 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:025992
Sam Maiera6e76d72022-02-11 21:43:505993 import os
5994 import re
5995 import sys
5996 from io import StringIO
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145997
Sam Maiera6e76d72022-02-11 21:43:505998 new_or_added_paths = set(f.LocalPath() for f in input_api.AffectedFiles()
5999 if (f.Action() == 'A' or f.Action() == 'M'))
6000 removed_paths = set(f.LocalPath()
6001 for f in input_api.AffectedFiles(include_deletes=True)
6002 if f.Action() == 'D')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146003
Sam Maiera6e76d72022-02-11 21:43:506004 affected_grds = [
6005 f for f in input_api.AffectedFiles()
6006 if f.LocalPath().endswith(('.grd', '.grdp'))
6007 ]
6008 affected_grds = [
6009 f for f in affected_grds if not 'testdata' in f.LocalPath()
6010 ]
6011 if not affected_grds:
6012 return []
meacer8c0d3832019-12-26 21:46:166013
Sam Maiera6e76d72022-02-11 21:43:506014 affected_png_paths = [
6015 f.AbsoluteLocalPath() for f in input_api.AffectedFiles()
6016 if (f.LocalPath().endswith('.png'))
6017 ]
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146018
Sam Maiera6e76d72022-02-11 21:43:506019 # Check for screenshots. Developers can upload screenshots using
6020 # tools/translation/upload_screenshots.py which finds and uploads
6021 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
6022 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
6023 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
6024 #
6025 # The logic here is as follows:
6026 #
6027 # - If the CL has a .png file under the screenshots directory for a grd
6028 # file, warn the developer. Actual images should never be checked into the
6029 # Chrome repo.
6030 #
6031 # - If the CL contains modified or new messages in grd files and doesn't
6032 # contain the corresponding .sha1 files, warn the developer to add images
6033 # and upload them via tools/translation/upload_screenshots.py.
6034 #
6035 # - If the CL contains modified or new messages in grd files and the
6036 # corresponding .sha1 files, everything looks good.
6037 #
6038 # - If the CL contains removed messages in grd files but the corresponding
6039 # .sha1 files aren't removed, warn the developer to remove them.
6040 unnecessary_screenshots = []
6041 missing_sha1 = []
Bruce Dawson55776c42022-12-09 17:23:476042 missing_sha1_modified = []
Sam Maiera6e76d72022-02-11 21:43:506043 unnecessary_sha1_files = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146044
Sam Maiera6e76d72022-02-11 21:43:506045 # This checks verifies that the ICU syntax of messages this CL touched is
6046 # valid, and reports any found syntax errors.
6047 # Without this presubmit check, ICU syntax errors in Chromium strings can land
6048 # without developers being aware of them. Later on, such ICU syntax errors
6049 # break message extraction for translation, hence would block Chromium
6050 # translations until they are fixed.
6051 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146052
Sam Maiera6e76d72022-02-11 21:43:506053 def _CheckScreenshotAdded(screenshots_dir, message_id):
6054 sha1_path = input_api.os_path.join(screenshots_dir,
6055 message_id + '.png.sha1')
6056 if sha1_path not in new_or_added_paths:
6057 missing_sha1.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146058
Bruce Dawson55776c42022-12-09 17:23:476059 def _CheckScreenshotModified(screenshots_dir, message_id):
6060 sha1_path = input_api.os_path.join(screenshots_dir,
6061 message_id + '.png.sha1')
6062 if sha1_path not in new_or_added_paths:
6063 missing_sha1_modified.append(sha1_path)
6064
Sam Maiera6e76d72022-02-11 21:43:506065 def _CheckScreenshotRemoved(screenshots_dir, message_id):
6066 sha1_path = input_api.os_path.join(screenshots_dir,
6067 message_id + '.png.sha1')
6068 if input_api.os_path.exists(
6069 sha1_path) and sha1_path not in removed_paths:
6070 unnecessary_sha1_files.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146071
Sam Maiera6e76d72022-02-11 21:43:506072 def _ValidateIcuSyntax(text, level, signatures):
6073 """Validates ICU syntax of a text string.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146074
Sam Maiera6e76d72022-02-11 21:43:506075 Check if text looks similar to ICU and checks for ICU syntax correctness
6076 in this case. Reports various issues with ICU syntax and values of
6077 variants. Supports checking of nested messages. Accumulate information of
6078 each ICU messages found in the text for further checking.
Rainhard Findlingfc31844c52020-05-15 09:58:266079
Sam Maiera6e76d72022-02-11 21:43:506080 Args:
6081 text: a string to check.
6082 level: a number of current nesting level.
6083 signatures: an accumulator, a list of tuple of (level, variable,
6084 kind, variants).
Rainhard Findlingfc31844c52020-05-15 09:58:266085
Sam Maiera6e76d72022-02-11 21:43:506086 Returns:
6087 None if a string is not ICU or no issue detected.
6088 A tuple of (message, start index, end index) if an issue detected.
6089 """
6090 valid_types = {
6091 'plural': (frozenset(
6092 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
6093 'other']), frozenset(['=1', 'other'])),
6094 'selectordinal': (frozenset(
6095 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
6096 'other']), frozenset(['one', 'other'])),
6097 'select': (frozenset(), frozenset(['other'])),
6098 }
Rainhard Findlingfc31844c52020-05-15 09:58:266099
Sam Maiera6e76d72022-02-11 21:43:506100 # Check if the message looks like an attempt to use ICU
6101 # plural. If yes - check if its syntax strictly matches ICU format.
6102 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b',
6103 text)
6104 if not like:
6105 signatures.append((level, None, None, None))
6106 return
Rainhard Findlingfc31844c52020-05-15 09:58:266107
Sam Maiera6e76d72022-02-11 21:43:506108 # Check for valid prefix and suffix
6109 m = re.match(
6110 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
6111 r'(plural|selectordinal|select),\s*'
6112 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
6113 if not m:
6114 return (('This message looks like an ICU plural, '
6115 'but does not follow ICU syntax.'), like.start(),
6116 like.end())
6117 starting, variable, kind, variant_pairs = m.groups()
6118 variants, depth, last_pos = _ParseIcuVariants(variant_pairs,
6119 m.start(4))
6120 if depth:
6121 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
6122 len(text))
6123 first = text[0]
6124 ending = text[last_pos:]
6125 if not starting:
6126 return ('Invalid ICU format. No initial opening bracket',
6127 last_pos - 1, last_pos)
6128 if not ending or '}' not in ending:
6129 return ('Invalid ICU format. No final closing bracket',
6130 last_pos - 1, last_pos)
6131 elif first != '{':
6132 return ((
6133 'Invalid ICU format. Extra characters at the start of a complex '
6134 'message (go/icu-message-migration): "%s"') % starting, 0,
6135 len(starting))
6136 elif ending != '}':
6137 return ((
6138 'Invalid ICU format. Extra characters at the end of a complex '
6139 'message (go/icu-message-migration): "%s"') % ending,
6140 last_pos - 1, len(text) - 1)
6141 if kind not in valid_types:
6142 return (('Unknown ICU message type %s. '
6143 'Valid types are: plural, select, selectordinal') % kind,
6144 0, 0)
6145 known, required = valid_types[kind]
6146 defined_variants = set()
6147 for variant, variant_range, value, value_range in variants:
6148 start, end = variant_range
6149 if variant in defined_variants:
6150 return ('Variant "%s" is defined more than once' % variant,
6151 start, end)
6152 elif known and variant not in known:
6153 return ('Variant "%s" is not valid for %s message' %
6154 (variant, kind), start, end)
6155 defined_variants.add(variant)
6156 # Check for nested structure
6157 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
6158 if res:
6159 return (res[0], res[1] + value_range[0] + 1,
6160 res[2] + value_range[0] + 1)
6161 missing = required - defined_variants
6162 if missing:
6163 return ('Required variants missing: %s' % ', '.join(missing), 0,
6164 len(text))
6165 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:266166
Sam Maiera6e76d72022-02-11 21:43:506167 def _ParseIcuVariants(text, offset=0):
6168 """Parse variants part of ICU complex message.
Rainhard Findlingfc31844c52020-05-15 09:58:266169
Sam Maiera6e76d72022-02-11 21:43:506170 Builds a tuple of variant names and values, as well as
6171 their offsets in the input string.
Rainhard Findlingfc31844c52020-05-15 09:58:266172
Sam Maiera6e76d72022-02-11 21:43:506173 Args:
6174 text: a string to parse
6175 offset: additional offset to add to positions in the text to get correct
6176 position in the complete ICU string.
Rainhard Findlingfc31844c52020-05-15 09:58:266177
Sam Maiera6e76d72022-02-11 21:43:506178 Returns:
6179 List of tuples, each tuple consist of four fields: variant name,
6180 variant name span (tuple of two integers), variant value, value
6181 span (tuple of two integers).
6182 """
6183 depth, start, end = 0, -1, -1
6184 variants = []
6185 key = None
6186 for idx, char in enumerate(text):
6187 if char == '{':
6188 if not depth:
6189 start = idx
6190 chunk = text[end + 1:start]
6191 key = chunk.strip()
6192 pos = offset + end + 1 + chunk.find(key)
6193 span = (pos, pos + len(key))
6194 depth += 1
6195 elif char == '}':
6196 if not depth:
6197 return variants, depth, offset + idx
6198 depth -= 1
6199 if not depth:
6200 end = idx
6201 variants.append((key, span, text[start:end + 1],
6202 (offset + start, offset + end + 1)))
6203 return variants, depth, offset + end + 1
Rainhard Findlingfc31844c52020-05-15 09:58:266204
Sam Maiera6e76d72022-02-11 21:43:506205 try:
6206 old_sys_path = sys.path
6207 sys.path = sys.path + [
6208 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
6209 'translation')
6210 ]
6211 from helper import grd_helper
6212 finally:
6213 sys.path = old_sys_path
Rainhard Findlingfc31844c52020-05-15 09:58:266214
Sam Maiera6e76d72022-02-11 21:43:506215 for f in affected_grds:
6216 file_path = f.LocalPath()
6217 old_id_to_msg_map = {}
6218 new_id_to_msg_map = {}
6219 # Note that this code doesn't check if the file has been deleted. This is
6220 # OK because it only uses the old and new file contents and doesn't load
6221 # the file via its path.
6222 # It's also possible that a file's content refers to a renamed or deleted
6223 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
6224 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
6225 # .grdp files.
6226 if file_path.endswith('.grdp'):
6227 if f.OldContents():
6228 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6229 '\n'.join(f.OldContents()))
6230 if f.NewContents():
6231 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6232 '\n'.join(f.NewContents()))
6233 else:
6234 file_dir = input_api.os_path.dirname(file_path) or '.'
6235 if f.OldContents():
6236 old_id_to_msg_map = grd_helper.GetGrdMessages(
6237 StringIO('\n'.join(f.OldContents())), file_dir)
6238 if f.NewContents():
6239 new_id_to_msg_map = grd_helper.GetGrdMessages(
6240 StringIO('\n'.join(f.NewContents())), file_dir)
Rainhard Findlingfc31844c52020-05-15 09:58:266241
Sam Maiera6e76d72022-02-11 21:43:506242 grd_name, ext = input_api.os_path.splitext(
6243 input_api.os_path.basename(file_path))
6244 screenshots_dir = input_api.os_path.join(
6245 input_api.os_path.dirname(file_path),
6246 grd_name + ext.replace('.', '_'))
Rainhard Findlingfc31844c52020-05-15 09:58:266247
Sam Maiera6e76d72022-02-11 21:43:506248 # Compute added, removed and modified message IDs.
6249 old_ids = set(old_id_to_msg_map)
6250 new_ids = set(new_id_to_msg_map)
6251 added_ids = new_ids - old_ids
6252 removed_ids = old_ids - new_ids
6253 modified_ids = set([])
6254 for key in old_ids.intersection(new_ids):
6255 if (old_id_to_msg_map[key].ContentsAsXml('', True) !=
6256 new_id_to_msg_map[key].ContentsAsXml('', True)):
6257 # The message content itself changed. Require an updated screenshot.
6258 modified_ids.add(key)
6259 elif old_id_to_msg_map[key].attrs['meaning'] != \
6260 new_id_to_msg_map[key].attrs['meaning']:
Vincent Boisselle861f11db2023-03-28 21:46:386261 # The message meaning changed. Ensure there is a screenshot for it.
6262 sha1_path = input_api.os_path.join(screenshots_dir,
6263 key + '.png.sha1')
6264 if sha1_path not in new_or_added_paths and not \
6265 input_api.os_path.exists(sha1_path):
6266 # There is neither a previous screenshot nor is a new one added now.
6267 # Require a screenshot.
6268 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146269
Sam Maiera6e76d72022-02-11 21:43:506270 if run_screenshot_check:
6271 # Check the screenshot directory for .png files. Warn if there is any.
6272 for png_path in affected_png_paths:
6273 if png_path.startswith(screenshots_dir):
6274 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146275
Sam Maiera6e76d72022-02-11 21:43:506276 for added_id in added_ids:
6277 _CheckScreenshotAdded(screenshots_dir, added_id)
Rainhard Findlingd8d04372020-08-13 13:30:096278
Sam Maiera6e76d72022-02-11 21:43:506279 for modified_id in modified_ids:
Bruce Dawson55776c42022-12-09 17:23:476280 _CheckScreenshotModified(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146281
Sam Maiera6e76d72022-02-11 21:43:506282 for removed_id in removed_ids:
6283 _CheckScreenshotRemoved(screenshots_dir, removed_id)
6284
6285 # Check new and changed strings for ICU syntax errors.
6286 for key in added_ids.union(modified_ids):
6287 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
6288 err = _ValidateIcuSyntax(msg, 0, [])
6289 if err is not None:
6290 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
6291
6292 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:266293 if run_screenshot_check:
Sam Maiera6e76d72022-02-11 21:43:506294 if unnecessary_screenshots:
6295 results.append(
6296 output_api.PresubmitError(
6297 'Do not include actual screenshots in the changelist. Run '
6298 'tools/translate/upload_screenshots.py to upload them instead:',
6299 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146300
Sam Maiera6e76d72022-02-11 21:43:506301 if missing_sha1:
6302 results.append(
6303 output_api.PresubmitError(
Bruce Dawson55776c42022-12-09 17:23:476304 'You are adding UI strings.\n'
Sam Maiera6e76d72022-02-11 21:43:506305 'To ensure the best translations, take screenshots of the relevant UI '
6306 '(https://g.co/chrome/translation) and add these files to your '
6307 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146308
Bruce Dawson55776c42022-12-09 17:23:476309 if missing_sha1_modified:
6310 results.append(
6311 output_api.PresubmitError(
6312 'You are modifying UI strings or their meanings.\n'
6313 'To ensure the best translations, take screenshots of the relevant UI '
6314 '(https://g.co/chrome/translation) and add these files to your '
6315 'changelist:', sorted(missing_sha1_modified)))
6316
Sam Maiera6e76d72022-02-11 21:43:506317 if unnecessary_sha1_files:
6318 results.append(
6319 output_api.PresubmitError(
6320 'You removed strings associated with these files. Remove:',
6321 sorted(unnecessary_sha1_files)))
6322 else:
6323 results.append(
6324 output_api.PresubmitPromptOrNotify('Skipping translation '
6325 'screenshots check.'))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146326
Sam Maiera6e76d72022-02-11 21:43:506327 if icu_syntax_errors:
6328 results.append(
6329 output_api.PresubmitPromptWarning(
6330 'ICU syntax errors were found in the following strings (problems or '
6331 'feedback? Contact [email protected]):',
6332 items=icu_syntax_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:266333
Sam Maiera6e76d72022-02-11 21:43:506334 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:126335
6336
Saagar Sanghavifceeaae2020-08-12 16:40:366337def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:126338 repo_root=None,
6339 translation_expectations_path=None,
6340 grd_files=None):
Sam Maiera6e76d72022-02-11 21:43:506341 import sys
6342 affected_grds = [
6343 f for f in input_api.AffectedFiles()
6344 if (f.LocalPath().endswith('.grd') or f.LocalPath().endswith('.grdp'))
6345 ]
6346 if not affected_grds:
6347 return []
6348
6349 try:
6350 old_sys_path = sys.path
6351 sys.path = sys.path + [
6352 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
6353 'translation')
6354 ]
6355 from helper import git_helper
6356 from helper import translation_helper
6357 finally:
6358 sys.path = old_sys_path
6359
6360 # Check that translation expectations can be parsed and we can get a list of
6361 # translatable grd files. |repo_root| and |translation_expectations_path| are
6362 # only passed by tests.
6363 if not repo_root:
6364 repo_root = input_api.PresubmitLocalPath()
6365 if not translation_expectations_path:
6366 translation_expectations_path = input_api.os_path.join(
6367 repo_root, 'tools', 'gritsettings', 'translation_expectations.pyl')
6368 if not grd_files:
6369 grd_files = git_helper.list_grds_in_repository(repo_root)
6370
6371 # Ignore bogus grd files used only for testing
Gao Shenga79ebd42022-08-08 17:25:596372 # ui/webui/resources/tools/generate_grd.py.
Sam Maiera6e76d72022-02-11 21:43:506373 ignore_path = input_api.os_path.join('ui', 'webui', 'resources', 'tools',
6374 'tests')
6375 grd_files = [p for p in grd_files if ignore_path not in p]
6376
6377 try:
6378 translation_helper.get_translatable_grds(
6379 repo_root, grd_files, translation_expectations_path)
6380 except Exception as e:
6381 return [
6382 output_api.PresubmitNotifyResult(
6383 'Failed to get a list of translatable grd files. This happens when:\n'
6384 ' - One of the modified grd or grdp files cannot be parsed or\n'
6385 ' - %s is not updated.\n'
6386 'Stack:\n%s' % (translation_expectations_path, str(e)))
6387 ]
Mustafa Emre Acer51f2f742020-03-09 19:41:126388 return []
6389
Ken Rockotc31f4832020-05-29 18:58:516390
Saagar Sanghavifceeaae2020-08-12 16:40:366391def CheckStableMojomChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506392 """Changes to [Stable] mojom types must preserve backward-compatibility."""
6393 changed_mojoms = input_api.AffectedFiles(
6394 include_deletes=True,
6395 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:526396
Bruce Dawson344ab262022-06-04 11:35:106397 if not changed_mojoms or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:506398 return []
6399
6400 delta = []
6401 for mojom in changed_mojoms:
Sam Maiera6e76d72022-02-11 21:43:506402 delta.append({
6403 'filename': mojom.LocalPath(),
6404 'old': '\n'.join(mojom.OldContents()) or None,
6405 'new': '\n'.join(mojom.NewContents()) or None,
6406 })
6407
6408 process = input_api.subprocess.Popen([
Takuto Ikutadca10222022-04-13 02:51:216409 input_api.python3_executable,
Sam Maiera6e76d72022-02-11 21:43:506410 input_api.os_path.join(
6411 input_api.PresubmitLocalPath(), 'mojo', 'public', 'tools', 'mojom',
6412 'check_stable_mojom_compatibility.py'), '--src-root',
6413 input_api.PresubmitLocalPath()
6414 ],
6415 stdin=input_api.subprocess.PIPE,
6416 stdout=input_api.subprocess.PIPE,
6417 stderr=input_api.subprocess.PIPE,
6418 universal_newlines=True)
6419 (x, error) = process.communicate(input=input_api.json.dumps(delta))
6420 if process.returncode:
6421 return [
6422 output_api.PresubmitError(
6423 'One or more [Stable] mojom definitions appears to have been changed '
6424 'in a way that is not backward-compatible.',
6425 long_text=error)
6426 ]
Erik Staabc734cd7a2021-11-23 03:11:526427 return []
6428
Dominic Battre645d42342020-12-04 16:14:106429def CheckDeprecationOfPreferences(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506430 """Removing a preference should come with a deprecation."""
Dominic Battre645d42342020-12-04 16:14:106431
Sam Maiera6e76d72022-02-11 21:43:506432 def FilterFile(affected_file):
6433 """Accept only .cc files and the like."""
6434 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
6435 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
6436 input_api.DEFAULT_FILES_TO_SKIP)
6437 return input_api.FilterSourceFile(
6438 affected_file,
6439 files_to_check=file_inclusion_pattern,
6440 files_to_skip=files_to_skip)
Dominic Battre645d42342020-12-04 16:14:106441
Sam Maiera6e76d72022-02-11 21:43:506442 def ModifiedLines(affected_file):
6443 """Returns a list of tuples (line number, line text) of added and removed
6444 lines.
Dominic Battre645d42342020-12-04 16:14:106445
Sam Maiera6e76d72022-02-11 21:43:506446 Deleted lines share the same line number as the previous line.
Dominic Battre645d42342020-12-04 16:14:106447
Sam Maiera6e76d72022-02-11 21:43:506448 This relies on the scm diff output describing each changed code section
6449 with a line of the form
Dominic Battre645d42342020-12-04 16:14:106450
Sam Maiera6e76d72022-02-11 21:43:506451 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
6452 """
6453 line_num = 0
6454 modified_lines = []
6455 for line in affected_file.GenerateScmDiff().splitlines():
6456 # Extract <new line num> of the patch fragment (see format above).
6457 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@',
6458 line)
6459 if m:
6460 line_num = int(m.groups(1)[0])
6461 continue
6462 if ((line.startswith('+') and not line.startswith('++'))
6463 or (line.startswith('-') and not line.startswith('--'))):
6464 modified_lines.append((line_num, line))
Dominic Battre645d42342020-12-04 16:14:106465
Sam Maiera6e76d72022-02-11 21:43:506466 if not line.startswith('-'):
6467 line_num += 1
6468 return modified_lines
Dominic Battre645d42342020-12-04 16:14:106469
Sam Maiera6e76d72022-02-11 21:43:506470 def FindLineWith(lines, needle):
6471 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
Dominic Battre645d42342020-12-04 16:14:106472
Sam Maiera6e76d72022-02-11 21:43:506473 If 0 or >1 lines contain `needle`, -1 is returned.
6474 """
6475 matching_line_numbers = [
6476 # + 1 for 1-based counting of line numbers.
6477 i + 1 for i, line in enumerate(lines) if needle in line
6478 ]
6479 return matching_line_numbers[0] if len(
6480 matching_line_numbers) == 1 else -1
Dominic Battre645d42342020-12-04 16:14:106481
Sam Maiera6e76d72022-02-11 21:43:506482 def ModifiedPrefMigration(affected_file):
6483 """Returns whether the MigrateObsolete.*Pref functions were modified."""
6484 # Determine first and last lines of MigrateObsolete.*Pref functions.
6485 new_contents = affected_file.NewContents()
6486 range_1 = (FindLineWith(new_contents,
6487 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
6488 FindLineWith(new_contents,
6489 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
6490 range_2 = (FindLineWith(new_contents,
6491 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
6492 FindLineWith(new_contents,
6493 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
6494 if (-1 in range_1 + range_2):
6495 raise Exception(
6496 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.'
6497 )
Dominic Battre645d42342020-12-04 16:14:106498
Sam Maiera6e76d72022-02-11 21:43:506499 # Check whether any of the modified lines are part of the
6500 # MigrateObsolete.*Pref functions.
6501 for line_nr, line in ModifiedLines(affected_file):
6502 if (range_1[0] <= line_nr <= range_1[1]
6503 or range_2[0] <= line_nr <= range_2[1]):
6504 return True
6505 return False
Dominic Battre645d42342020-12-04 16:14:106506
Sam Maiera6e76d72022-02-11 21:43:506507 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
6508 browser_prefs_file_pattern = input_api.re.compile(
6509 r'chrome/browser/prefs/browser_prefs.cc')
Dominic Battre645d42342020-12-04 16:14:106510
Sam Maiera6e76d72022-02-11 21:43:506511 changes = input_api.AffectedFiles(include_deletes=True,
6512 file_filter=FilterFile)
6513 potential_problems = []
6514 for f in changes:
6515 for line in f.GenerateScmDiff().splitlines():
6516 # Check deleted lines for pref registrations.
6517 if (line.startswith('-') and not line.startswith('--')
6518 and register_pref_pattern.search(line)):
6519 potential_problems.append('%s: %s' % (f.LocalPath(), line))
Dominic Battre645d42342020-12-04 16:14:106520
Sam Maiera6e76d72022-02-11 21:43:506521 if browser_prefs_file_pattern.search(f.LocalPath()):
6522 # If the developer modified the MigrateObsolete.*Prefs() functions, we
6523 # assume that they knew that they have to deprecate preferences and don't
6524 # warn.
6525 try:
6526 if ModifiedPrefMigration(f):
6527 return []
6528 except Exception as e:
6529 return [output_api.PresubmitError(str(e))]
Dominic Battre645d42342020-12-04 16:14:106530
Sam Maiera6e76d72022-02-11 21:43:506531 if potential_problems:
6532 return [
6533 output_api.PresubmitPromptWarning(
6534 'Discovered possible removal of preference registrations.\n\n'
6535 'Please make sure to properly deprecate preferences by clearing their\n'
6536 'value for a couple of milestones before finally removing the code.\n'
6537 'Otherwise data may stay in the preferences files forever. See\n'
6538 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
6539 'chrome/browser/prefs/README.md for examples.\n'
6540 'This may be a false positive warning (e.g. if you move preference\n'
6541 'registrations to a different place).\n', potential_problems)
6542 ]
6543 return []
6544
Matt Stark6ef08872021-07-29 01:21:466545
6546def CheckConsistentGrdChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506547 """Changes to GRD files must be consistent for tools to read them."""
6548 changed_grds = input_api.AffectedFiles(
6549 include_deletes=False,
6550 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
6551 errors = []
6552 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
6553 for matcher, msg in _INVALID_GRD_FILE_LINE]
6554 for grd in changed_grds:
6555 for i, line in enumerate(grd.NewContents()):
6556 for matcher, msg in invalid_file_regexes:
6557 if matcher.search(line):
6558 errors.append(
6559 output_api.PresubmitError(
6560 'Problem on {grd}:{i} - {msg}'.format(
6561 grd=grd.LocalPath(), i=i + 1, msg=msg)))
6562 return errors
6563
Kevin McNee967dd2d22021-11-15 16:09:296564
Henrique Ferreiro2a4b55942021-11-29 23:45:366565def CheckAssertAshOnlyCode(input_api, output_api):
6566 """Errors if a BUILD.gn file in an ash/ directory doesn't include
6567 assert(is_chromeos_ash).
6568 """
6569
6570 def FileFilter(affected_file):
6571 """Includes directories known to be Ash only."""
6572 return input_api.FilterSourceFile(
6573 affected_file,
6574 files_to_check=(
6575 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
6576 r'.*/ash/.*BUILD\.gn'), # Any path component.
6577 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
6578
6579 errors = []
6580 pattern = input_api.re.compile(r'assert\(is_chromeos_ash')
Jameson Thies0ce669f2021-12-09 15:56:566581 for f in input_api.AffectedFiles(include_deletes=False,
6582 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:366583 if (not pattern.search(input_api.ReadFile(f))):
6584 errors.append(
6585 output_api.PresubmitError(
6586 'Please add assert(is_chromeos_ash) to %s. If that\'s not '
6587 'possible, please create and issue and add a comment such '
6588 'as:\n # TODO(https://crbug.com/XXX): add '
6589 'assert(is_chromeos_ash) when ...' % f.LocalPath()))
6590 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:276591
6592
6593def _IsRendererOnlyCppFile(input_api, affected_file):
Sam Maiera6e76d72022-02-11 21:43:506594 path = affected_file.LocalPath()
6595 if not _IsCPlusPlusFile(input_api, path):
6596 return False
6597
6598 # Any code under a "renderer" subdirectory is assumed to be Renderer-only.
6599 if "/renderer/" in path:
6600 return True
6601
6602 # Blink's public/web API is only used/included by Renderer-only code. Note
6603 # that public/platform API may be used in non-Renderer processes (e.g. there
6604 # are some includes in code used by Utility, PDF, or Plugin processes).
6605 if "/blink/public/web/" in path:
6606 return True
6607
6608 # We assume that everything else may be used outside of Renderer processes.
Lukasz Anforowicz7016d05e2021-11-30 03:56:276609 return False
6610
Lukasz Anforowicz7016d05e2021-11-30 03:56:276611# TODO(https://crbug.com/1273182): Remove these checks, once they are replaced
6612# by the Chromium Clang Plugin (which will be preferable because it will
6613# 1) report errors earlier - at compile-time and 2) cover more rules).
6614def CheckRawPtrUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506615 """Rough checks that raw_ptr<T> usage guidelines are followed."""
6616 errors = []
6617 # The regex below matches "raw_ptr<" following a word boundary, but not in a
6618 # C++ comment.
6619 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
6620 file_filter = lambda f: _IsRendererOnlyCppFile(input_api, f)
6621 for f, line_num, line in input_api.RightHandSideLines(file_filter):
6622 if raw_ptr_matcher.search(line):
6623 errors.append(
6624 output_api.PresubmitError(
6625 'Problem on {path}:{line} - '\
6626 'raw_ptr<T> should not be used in Renderer-only code '\
6627 '(as documented in the "Pointers to unprotected memory" '\
6628 'section in //base/memory/raw_ptr.md)'.format(
6629 path=f.LocalPath(), line=line_num)))
6630 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:566631
6632
6633def CheckPythonShebang(input_api, output_api):
6634 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
6635 system-wide python.
6636 """
6637 errors = []
6638 sources = lambda affected_file: input_api.FilterSourceFile(
6639 affected_file,
6640 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
6641 r'third_party/blink/web_tests/external/') + input_api.
6642 DEFAULT_FILES_TO_SKIP),
6643 files_to_check=[r'.*\.py$'])
6644 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:276645 for line_num, line in f.ChangedContents():
6646 if line_num == 1 and line.startswith('#!/usr/bin/python'):
6647 errors.append(f.LocalPath())
6648 break
Henrique Ferreirof9819f2e32021-11-30 13:31:566649
6650 result = []
6651 for file in errors:
6652 result.append(
6653 output_api.PresubmitError(
6654 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
6655 file))
6656 return result
James Shen81cc0e22022-06-15 21:10:456657
6658
6659def CheckBatchAnnotation(input_api, output_api):
6660 """Checks that tests have either @Batch or @DoNotBatch annotation. If this
6661 is not an instrumentation test, disregard."""
6662
6663 batch_annotation = input_api.re.compile(r'^\s*@Batch')
6664 do_not_batch_annotation = input_api.re.compile(r'^\s*@DoNotBatch')
6665 robolectric_test = input_api.re.compile(r'[rR]obolectric')
6666 test_class_declaration = input_api.re.compile(r'^\s*public\sclass.*Test')
6667 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
6668
ckitagawae8fd23b2022-06-17 15:29:386669 missing_annotation_errors = []
6670 extra_annotation_errors = []
James Shen81cc0e22022-06-15 21:10:456671
6672 def _FilterFile(affected_file):
6673 return input_api.FilterSourceFile(
6674 affected_file,
6675 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
6676 files_to_check=[r'.*Test\.java$'])
6677
6678 for f in input_api.AffectedSourceFiles(_FilterFile):
6679 batch_matched = None
6680 do_not_batch_matched = None
6681 is_instrumentation_test = True
6682 for line in f.NewContents():
6683 if robolectric_test.search(line) or uiautomator_test.search(line):
6684 # Skip Robolectric and UiAutomator tests.
6685 is_instrumentation_test = False
6686 break
6687 if not batch_matched:
6688 batch_matched = batch_annotation.search(line)
6689 if not do_not_batch_matched:
6690 do_not_batch_matched = do_not_batch_annotation.search(line)
6691 test_class_declaration_matched = test_class_declaration.search(
6692 line)
6693 if test_class_declaration_matched:
6694 break
6695 if (is_instrumentation_test and
6696 not batch_matched and
6697 not do_not_batch_matched):
Sam Maier4cef9242022-10-03 14:21:246698 missing_annotation_errors.append(str(f.LocalPath()))
ckitagawae8fd23b2022-06-17 15:29:386699 if (not is_instrumentation_test and
6700 (batch_matched or
6701 do_not_batch_matched)):
Sam Maier4cef9242022-10-03 14:21:246702 extra_annotation_errors.append(str(f.LocalPath()))
James Shen81cc0e22022-06-15 21:10:456703
6704 results = []
6705
ckitagawae8fd23b2022-06-17 15:29:386706 if missing_annotation_errors:
James Shen81cc0e22022-06-15 21:10:456707 results.append(
6708 output_api.PresubmitPromptWarning(
6709 """
Henrique Nakashimacb4c55a2023-01-30 20:09:096710Instrumentation tests should use either @Batch or @DoNotBatch. Use
6711@Batch(Batch.PER_CLASS) in most cases. Use @Batch(Batch.UNIT_TESTS) when tests
6712have no side-effects. If the tests are not safe to run in batch, please use
6713@DoNotBatch with reasons.
Jens Mueller2085ff82023-02-27 11:54:496714See https://source.chromium.org/chromium/chromium/src/+/main:docs/testing/batching_instrumentation_tests.md
ckitagawae8fd23b2022-06-17 15:29:386715""", missing_annotation_errors))
6716 if extra_annotation_errors:
6717 results.append(
6718 output_api.PresubmitPromptWarning(
6719 """
6720Robolectric tests do not need a @Batch or @DoNotBatch annotations.
6721""", extra_annotation_errors))
James Shen81cc0e22022-06-15 21:10:456722
6723 return results
Sam Maier4cef9242022-10-03 14:21:246724
6725
6726def CheckMockAnnotation(input_api, output_api):
6727 """Checks that we have annotated all Mockito.mock()-ed or Mockito.spy()-ed
6728 classes with @Mock or @Spy. If this is not an instrumentation test,
6729 disregard."""
6730
6731 # This is just trying to be approximately correct. We are not writing a
6732 # Java parser, so special cases like statically importing mock() then
6733 # calling an unrelated non-mockito spy() function will cause a false
6734 # positive.
6735 package_name = input_api.re.compile(r'^package\s+(\w+(?:\.\w+)+);')
6736 mock_static_import = input_api.re.compile(
6737 r'^import\s+static\s+org.mockito.Mockito.(?:mock|spy);')
6738 import_class = input_api.re.compile(r'import\s+((?:\w+\.)+)(\w+);')
6739 mock_annotation = input_api.re.compile(r'^\s*@(?:Mock|Spy)')
6740 field_type = input_api.re.compile(r'(\w+)(?:<\w+>)?\s+\w+\s*(?:;|=)')
6741 mock_or_spy_function_call = r'(?:mock|spy)\(\s*(?:new\s*)?(\w+)(?:\.class|\()'
6742 fully_qualified_mock_function = input_api.re.compile(
6743 r'Mockito\.' + mock_or_spy_function_call)
6744 statically_imported_mock_function = input_api.re.compile(
6745 r'\W' + mock_or_spy_function_call)
6746 robolectric_test = input_api.re.compile(r'[rR]obolectric')
6747 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
6748
6749 def _DoClassLookup(class_name, class_name_map, package):
6750 found = class_name_map.get(class_name)
6751 if found is not None:
6752 return found
6753 else:
6754 return package + '.' + class_name
6755
6756 def _FilterFile(affected_file):
6757 return input_api.FilterSourceFile(
6758 affected_file,
6759 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
6760 files_to_check=[r'.*Test\.java$'])
6761
6762 mocked_by_function_classes = set()
6763 mocked_by_annotation_classes = set()
6764 class_to_filename = {}
6765 for f in input_api.AffectedSourceFiles(_FilterFile):
6766 mock_function_regex = fully_qualified_mock_function
6767 next_line_is_annotated = False
6768 fully_qualified_class_map = {}
6769 package = None
6770
6771 for line in f.NewContents():
6772 if robolectric_test.search(line) or uiautomator_test.search(line):
6773 # Skip Robolectric and UiAutomator tests.
6774 break
6775
6776 m = package_name.search(line)
6777 if m:
6778 package = m.group(1)
6779 continue
6780
6781 if mock_static_import.search(line):
6782 mock_function_regex = statically_imported_mock_function
6783 continue
6784
6785 m = import_class.search(line)
6786 if m:
6787 fully_qualified_class_map[m.group(2)] = m.group(1) + m.group(2)
6788 continue
6789
6790 if next_line_is_annotated:
6791 next_line_is_annotated = False
6792 fully_qualified_class = _DoClassLookup(
6793 field_type.search(line).group(1), fully_qualified_class_map,
6794 package)
6795 mocked_by_annotation_classes.add(fully_qualified_class)
6796 continue
6797
6798 if mock_annotation.search(line):
6799 next_line_is_annotated = True
6800 continue
6801
6802 m = mock_function_regex.search(line)
6803 if m:
6804 fully_qualified_class = _DoClassLookup(m.group(1),
6805 fully_qualified_class_map, package)
6806 # Skipping builtin classes, since they don't get optimized.
6807 if fully_qualified_class.startswith(
6808 'android.') or fully_qualified_class.startswith(
6809 'java.'):
6810 continue
6811 class_to_filename[fully_qualified_class] = str(f.LocalPath())
6812 mocked_by_function_classes.add(fully_qualified_class)
6813
6814 results = []
6815 missed_classes = mocked_by_function_classes - mocked_by_annotation_classes
6816 if missed_classes:
6817 error_locations = []
6818 for c in missed_classes:
6819 error_locations.append(c + ' in ' + class_to_filename[c])
6820 results.append(
6821 output_api.PresubmitPromptWarning(
6822 """
6823Mockito.mock()/spy() cause issues with our Java optimizer. You have 3 options:
68241) If the mocked variable can be a class member, annotate the member with
6825 @Mock/@Spy.
68262) If the mocked variable cannot be a class member, create a dummy member
6827 variable of that type, annotated with @Mock/@Spy. This dummy does not need
6828 to be used or initialized in any way.
68293) If the mocked type is definitely not going to be optimized, whether it's a
6830 builtin type which we don't ship, or a class you know R8 will treat
6831 specially, you can ignore this warning.
6832""", error_locations))
6833
6834 return results
Mike Dougherty1b8be712022-10-20 00:15:136835
6836def CheckNoJsInIos(input_api, output_api):
6837 """Checks to make sure that JavaScript files are not used on iOS."""
6838
6839 def _FilterFile(affected_file):
6840 return input_api.FilterSourceFile(
6841 affected_file,
6842 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP +
6843 (r'^ios/third_party/*', r'^third_party/*'),
6844 files_to_check=[r'^ios/.*\.js$', r'.*/ios/.*\.js$'])
6845
Mike Dougherty4d1050b2023-03-14 15:59:536846 deleted_files = []
6847
6848 # Collect filenames of all removed JS files.
6849 for f in input_api.AffectedSourceFiles(_FilterFile):
6850 local_path = f.LocalPath()
6851
6852 if input_api.os_path.splitext(local_path)[1] == '.js' and f.Action() == 'D':
6853 deleted_files.append(input_api.os_path.basename(local_path))
6854
Mike Dougherty1b8be712022-10-20 00:15:136855 error_paths = []
Mike Dougherty4d1050b2023-03-14 15:59:536856 moved_paths = []
Mike Dougherty1b8be712022-10-20 00:15:136857 warning_paths = []
6858
6859 for f in input_api.AffectedSourceFiles(_FilterFile):
6860 local_path = f.LocalPath()
6861
6862 if input_api.os_path.splitext(local_path)[1] == '.js':
6863 if f.Action() == 'A':
Mike Dougherty4d1050b2023-03-14 15:59:536864 if input_api.os_path.basename(local_path) in deleted_files:
6865 # This script was probably moved rather than newly created.
6866 # Present a warning instead of an error for these cases.
6867 moved_paths.append(local_path)
6868 else:
6869 error_paths.append(local_path)
Mike Dougherty1b8be712022-10-20 00:15:136870 elif f.Action() != 'D':
6871 warning_paths.append(local_path)
6872
6873 results = []
6874
6875 if warning_paths:
6876 results.append(output_api.PresubmitPromptWarning(
6877 'TypeScript is now fully supported for iOS feature scripts. '
6878 'Consider converting JavaScript files to TypeScript. See '
6879 '//ios/web/public/js_messaging/README.md for more details.',
6880 warning_paths))
6881
Mike Dougherty4d1050b2023-03-14 15:59:536882 if moved_paths:
6883 results.append(output_api.PresubmitPromptWarning(
6884 'Do not use JavaScript on iOS for new files as TypeScript is '
6885 'fully supported. (If this is a moved file, you may leave the '
6886 'script unconverted.) See //ios/web/public/js_messaging/README.md '
6887 'for help using scripts on iOS.', moved_paths))
6888
Mike Dougherty1b8be712022-10-20 00:15:136889 if error_paths:
6890 results.append(output_api.PresubmitError(
6891 'Do not use JavaScript on iOS as TypeScript is fully supported. '
6892 'See //ios/web/public/js_messaging/README.md for help using '
6893 'scripts on iOS.', error_paths))
6894
6895 return results
Hans Wennborg23a81d52023-03-24 16:38:136896
6897def CheckLibcxxRevisionsMatch(input_api, output_api):
6898 """Check to make sure the libc++ version matches across deps files."""
Andrew Grieve21bb6792023-03-27 19:06:486899 # Disable check for changes to sub-repositories.
6900 if input_api.PresubmitLocalPath() != input_api.change.RepositoryRoot():
6901 return []
Hans Wennborg23a81d52023-03-24 16:38:136902
6903 DEPS_FILES = [ 'DEPS', 'buildtools/deps_revisions.gni' ]
6904
6905 file_filter = lambda f: f.LocalPath().replace(
6906 input_api.os_path.sep, '/') in DEPS_FILES
6907 changed_deps_files = input_api.AffectedFiles(file_filter=file_filter)
6908 if not changed_deps_files:
6909 return []
6910
6911 def LibcxxRevision(file):
6912 file = input_api.os_path.join(input_api.PresubmitLocalPath(),
6913 *file.split('/'))
6914 return input_api.re.search(
6915 r'libcxx_revision.*[:=].*[\'"](\w+)[\'"]',
6916 input_api.ReadFile(file)).group(1)
6917
6918 if len(set([LibcxxRevision(f) for f in DEPS_FILES])) == 1:
6919 return []
6920
6921 return [output_api.PresubmitError(
6922 'libcxx_revision not equal across %s' % ', '.join(DEPS_FILES),
6923 changed_deps_files)]