blob: 16cf53f8e52c719d1f668f7351ff5acd0df26004 [file] [log] [blame]
Avi Drissman24976592022-09-12 15:24:311# Copyright 2012 The Chromium Authors
maruel@chromium.orgca8d19842009-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.
maruel@chromium.orgca8d19842009-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'
joi@chromium.orgeea609a2011-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
maruel@chromium.org379e7dd2010-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/.*",
maruel@chromium.org3e4eb112011-01-18 03:29:5443 r".*MakeFile$",
gman@chromium.org1084ccc2012-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$",
maruel@chromium.org4306417642009-06-11 00:33:4055)
maruel@chromium.orgca8d19842009-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
joi@chromium.org06e6d0ff2012-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
joi@chromium.org06e6d0ff2012-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,
joi@chromium.org06e6d0ff2012-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' %
danakj@chromium.orge2d7e6f2013-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/.*',
darin@chromium.org7b054982013-11-27 00:44:47100 # Non-production example code.
Bruce Dawson40fece62022-09-16 19:58:31101 r'mojo/examples/.*',
lliabraa@chromium.org8176de12014-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/*'
joi@chromium.org06e6d0ff2012-12-11 01:36:44110)
maruel@chromium.orgca8d19842009-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
joi@chromium.orgeea609a2011-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.')
joi@chromium.orgeea609a2011-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
marja@chromium.orgcf9b78f2012-11-14 11:40:28142
Daniel Chenga44a1bcd2022-03-15 20:00:15143
Daniel Cheng917ce542022-03-15 20:46:57144_BANNED_JAVA_IMPORTS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15145 BanRule(
146 'import java.net.URI;',
147 (
148 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
149 ),
150 excluded_paths=(
151 (r'net/android/javatests/src/org/chromium/net/'
152 'AndroidProxySelectorTest\.java'),
153 r'components/cronet/',
154 r'third_party/robolectric/local/',
155 ),
Michael Thiessen44457642020-02-06 00:24:15156 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15157 BanRule(
158 'import android.annotation.TargetApi;',
159 (
160 'Do not use TargetApi, use @androidx.annotation.RequiresApi instead. '
161 'RequiresApi ensures that any calls are guarded by the appropriate '
162 'SDK_INT check. See https://crbug.com/1116486.',
163 ),
164 ),
165 BanRule(
Mohamed Heikal3d7a94c2023-03-28 16:55:24166 'import androidx.test.rule.UiThreadTestRule;',
Daniel Chenga44a1bcd2022-03-15 20:00:15167 (
168 'Do not use UiThreadTestRule, just use '
169 '@org.chromium.base.test.UiThreadTest on test methods that should run '
170 'on the UI thread. See https://crbug.com/1111893.',
171 ),
172 ),
173 BanRule(
Mohamed Heikal3d7a94c2023-03-28 16:55:24174 'import androidx.test.annotation.UiThreadTest;',
175 ('Do not use androidx.test.annotation.UiThreadTest, use '
Daniel Chenga44a1bcd2022-03-15 20:00:15176 'org.chromium.base.test.UiThreadTest instead. See '
177 'https://crbug.com/1111893.',
178 ),
179 ),
180 BanRule(
Mohamed Heikal3d7a94c2023-03-28 16:55:24181 'import androidx.test.rule.ActivityTestRule;',
Daniel Chenga44a1bcd2022-03-15 20:00:15182 (
183 'Do not use ActivityTestRule, use '
184 'org.chromium.base.test.BaseActivityTestRule instead.',
185 ),
186 excluded_paths=(
187 'components/cronet/',
188 ),
189 ),
Min Qinbc44383c2023-02-22 17:25:26190 BanRule(
191 'import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;',
192 (
193 'Do not use VectorDrawableCompat, use getResources().getDrawable() to '
194 'avoid extra indirections. Please also add trace event as the call '
195 'might take more than 20 ms to complete.',
196 ),
197 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15198)
wnwenbdc444e2016-05-25 13:44:15199
Daniel Cheng917ce542022-03-15 20:46:57200_BANNED_JAVA_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15201 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41202 'StrictMode.allowThreadDiskReads()',
203 (
204 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
205 'directly.',
206 ),
207 False,
208 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15209 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41210 'StrictMode.allowThreadDiskWrites()',
211 (
212 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
213 'directly.',
214 ),
215 False,
216 ),
Daniel Cheng917ce542022-03-15 20:46:57217 BanRule(
Michael Thiessen0f2547e2020-07-27 21:55:36218 '.waitForIdleSync()',
219 (
220 'Do not use waitForIdleSync as it masks underlying issues. There is '
221 'almost always something else you should wait on instead.',
222 ),
223 False,
224 ),
Ashley Newson09cbd602022-10-26 11:40:14225 BanRule(
Ashley Newsoneb6f5ced2022-10-26 14:45:42226 r'/(?<!\bsuper\.)(?<!\bIntent )\bregisterReceiver\(',
Ashley Newson09cbd602022-10-26 11:40:14227 (
228 'Do not call android.content.Context.registerReceiver (or an override) '
229 'directly. Use one of the wrapper methods defined in '
230 'org.chromium.base.ContextUtils, such as '
231 'registerProtectedBroadcastReceiver, '
232 'registerExportedBroadcastReceiver, or '
233 'registerNonExportedBroadcastReceiver. See their documentation for '
234 'which one to use.',
235 ),
236 True,
237 excluded_paths=(
Ashley Newson22bc26d2022-11-01 20:30:57238 r'.*Test[^a-z]',
239 r'third_party/',
Ashley Newson09cbd602022-10-26 11:40:14240 'base/android/java/src/org/chromium/base/ContextUtils.java',
Brandon Mousseau7e76a9c2022-12-08 22:08:38241 'chromecast/browser/android/apk/src/org/chromium/chromecast/shell/BroadcastReceiverScope.java',
Ashley Newson09cbd602022-10-26 11:40:14242 ),
243 ),
Ted Chocd5b327b12022-11-05 02:13:22244 BanRule(
245 r'/(?:extends|new)\s*(?:android.util.)?Property<[A-Za-z.]+,\s*(?:Integer|Float)>',
246 (
247 'Do not use Property<..., Integer|Float>, but use FloatProperty or '
248 'IntProperty because it will avoid unnecessary autoboxing of '
249 'primitives.',
250 ),
251 ),
Peilin Wangbba4a8652022-11-10 16:33:57252 BanRule(
253 'requestLayout()',
254 (
255 'Layouts can be expensive. Prefer using ViewUtils.requestLayout(), '
256 'which emits a trace event with additional information to help with '
257 'scroll jank investigations. See http://crbug.com/1354176.',
258 ),
259 False,
260 excluded_paths=(
261 'ui/android/java/src/org/chromium/ui/base/ViewUtils.java',
262 ),
263 ),
Ted Chocf40ea9152023-02-14 19:02:39264 BanRule(
265 'Profile.getLastUsedRegularProfile()',
266 (
267 'Prefer passing in the Profile reference instead of relying on the '
268 'static getLastUsedRegularProfile() call. Only top level entry points '
269 '(e.g. Activities) should call this method. Otherwise, the Profile '
270 'should either be passed in explicitly or retreived from an existing '
271 'entity with a reference to the Profile (e.g. WebContents).',
272 ),
273 False,
274 excluded_paths=(
275 r'.*Test[A-Z]?.*\.java',
276 ),
277 ),
Min Qinbc44383c2023-02-22 17:25:26278 BanRule(
279 r'/(ResourcesCompat|getResources\(\))\.getDrawable\(\)',
280 (
281 'getDrawable() can be expensive. If you have a lot of calls to '
282 'GetDrawable() or your code may introduce janks, please put your calls '
283 'inside a trace().',
284 ),
285 False,
286 excluded_paths=(
287 r'.*Test[A-Z]?.*\.java',
288 ),
289 ),
Henrique Nakashimabbf2b262023-03-10 17:21:39290 BanRule(
291 r'/RecordHistogram\.getHistogram(ValueCount|TotalCount|Samples)ForTesting\(',
292 (
293 'Raw histogram counts are easy to misuse; for example they don\'t reset '
294 'between batched tests. Use HistogramWatcher to check histogram records instead.',
295 ),
296 False,
297 excluded_paths=(
298 'base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java',
299 'base/test/android/javatests/src/org/chromium/base/test/util/HistogramWatcher.java',
300 ),
301 ),
Eric Stevensona9a980972017-09-23 00:04:41302)
303
Clement Yan9b330cb2022-11-17 05:25:29304_BANNED_JAVASCRIPT_FUNCTIONS : Sequence [BanRule] = (
305 BanRule(
306 r'/\bchrome\.send\b',
307 (
308 'The use of chrome.send is disallowed in Chrome (context: https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/security/handling-messages-from-web-content.md).',
309 'Please use mojo instead for new webuis. https://docs.google.com/document/d/1RF-GSUoveYa37eoyZ9EhwMtaIwoW7Z88pIgNZ9YzQi4/edit#heading=h.gkk22wgk6wff',
310 ),
311 True,
312 (
313 r'^(?!ash\/webui).+',
314 # TODO(crbug.com/1385601): pre-existing violations still need to be
315 # cleaned up.
Rebekah Potter57aa94df2022-12-13 20:30:58316 'ash/webui/common/resources/cr.m.js',
Clement Yan9b330cb2022-11-17 05:25:29317 'ash/webui/common/resources/multidevice_setup/multidevice_setup_browser_proxy.js',
318 'ash/webui/common/resources/quick_unlock/lock_screen_constants.js',
319 'ash/webui/common/resources/smb_shares/smb_browser_proxy.js',
320 'ash/webui/connectivity_diagnostics/resources/connectivity_diagnostics.js',
321 'ash/webui/diagnostics_ui/resources/diagnostics_browser_proxy.ts',
322 'ash/webui/multidevice_debug/resources/logs.js',
323 'ash/webui/multidevice_debug/resources/webui.js',
324 'ash/webui/projector_app/resources/annotator/trusted/annotator_browser_proxy.js',
325 'ash/webui/projector_app/resources/app/trusted/projector_browser_proxy.js',
326 'ash/webui/scanning/resources/scanning_browser_proxy.js',
327 ),
328 ),
329)
330
Daniel Cheng917ce542022-03-15 20:46:57331_BANNED_OBJC_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15332 BanRule(
avi@chromium.org127f18ec2012-06-16 05:05:59333 'addTrackingRect:',
avi@chromium.org23e6cbc2012-06-16 18:51:20334 (
335 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
avi@chromium.org127f18ec2012-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(
leng@chromium.orgeaae1972014-04-16 04:17:26342 r'/NSTrackingArea\W',
avi@chromium.org23e6cbc2012-06-16 18:51:20343 (
344 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
avi@chromium.org127f18ec2012-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(
avi@chromium.org127f18ec2012-06-16 05:05:59351 'convertPointFromBase:',
avi@chromium.org23e6cbc2012-06-16 18:51:20352 (
353 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
avi@chromium.org127f18ec2012-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(
avi@chromium.org127f18ec2012-06-16 05:05:59360 'convertPointToBase:',
avi@chromium.org23e6cbc2012-06-16 18:51:20361 (
362 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
avi@chromium.org127f18ec2012-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(
avi@chromium.org127f18ec2012-06-16 05:05:59369 'convertRectFromBase:',
avi@chromium.org23e6cbc2012-06-16 18:51:20370 (
371 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
avi@chromium.org127f18ec2012-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(
avi@chromium.org127f18ec2012-06-16 05:05:59378 'convertRectToBase:',
avi@chromium.org23e6cbc2012-06-16 18:51:20379 (
380 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
avi@chromium.org127f18ec2012-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(
avi@chromium.org127f18ec2012-06-16 05:05:59387 'convertSizeFromBase:',
avi@chromium.org23e6cbc2012-06-16 18:51:20388 (
389 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
avi@chromium.org127f18ec2012-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(
avi@chromium.org127f18ec2012-06-16 05:05:59396 'convertSizeToBase:',
avi@chromium.org23e6cbc2012-06-16 18:51:20397 (
398 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
avi@chromium.org127f18ec2012-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 ),
avi@chromium.org127f18ec2012-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(
avi@chromium.org23e6cbc2012-06-16 18:51:20493 'FRIEND_TEST(',
494 (
jam@chromium.orge3c945502012-06-26 20:01:49495 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
avi@chromium.org23e6cbc2012-06-16 18:51:20496 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
497 ),
498 False,
jochen@chromium.org7345da02012-11-27 14:31:49499 (),
avi@chromium.org23e6cbc2012-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(
enne@chromium.org52657f62013-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.'
enne@chromium.org52657f62013-05-20 05:30:31515 ),
516 True,
517 (),
518 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15519 BanRule(
enne@chromium.org52657f62013-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.'
enne@chromium.org52657f62013-05-20 05:30:31524 ),
525 True,
526 (),
527 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15528 BanRule(
enne@chromium.org52657f62013-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.'
enne@chromium.org52657f62013-05-20 05:30:31533 ),
534 True,
535 (),
536 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15537 BanRule(
enne@chromium.org52657f62013-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.'
enne@chromium.org52657f62013-05-20 05:30:31543 ),
544 True,
545 (),
546 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15547 BanRule(
mark@chromium.orgd89eec82013-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(
mark@chromium.orgd89eec82013-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$',
mark@chromium.orgd89eec82013-12-03 14:10:59569 ),
570 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15571 BanRule(
jochen@chromium.orgec5b3f02014-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,
rockot@chromium.orgf55c90ee62014-04-12 00:50:03578 (
Bruce Dawson40fece62022-09-16 19:58:31579 r'extensions/renderer/safe_builtins\.*',
rockot@chromium.orgf55c90ee62014-04-12 00:50:03580 ),
jochen@chromium.orgec5b3f02014-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)',
miktb599ed12023-05-26 07:03:56765 # Clang plugins have different build config.
766 '^tools/clang/plugins/',
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',
Brianna Goldstein846d8002023-05-16 19:24:30924 r'chrome/browser/ip_protection/.*',
Victor Vasiliev23b9ea6a2023-01-05 19:42:29925 # Not an error in third_party folders.
926 _THIRD_PARTY_EXCEPT_BLINK
927 ],
Peter Kasting4f35bfc2022-10-18 18:39:12928 ),
929 BanRule(
930 r'/\babsl::StatusOr\b',
931 (
932 'absl::StatusOr is banned. Use base::expected instead.',
933 ),
934 True,
Adithya Srinivasanb2041882022-10-21 19:34:20935 [
936 # Needed to use liburlpattern API.
937 r'third_party/blink/renderer/core/url_pattern/.*',
Louise Brettc6d23872023-04-11 02:48:32938 r'third_party/blink/renderer/modules/manifest/manifest_parser\.cc',
Brianna Goldstein846d8002023-05-16 19:24:30939 # Needed to use QUICHE API.
940 r'chrome/browser/ip_protection/.*',
Adithya Srinivasanb2041882022-10-21 19:34:20941 # Not an error in third_party folders.
942 _THIRD_PARTY_EXCEPT_BLINK
943 ],
Peter Kasting4f35bfc2022-10-18 18:39:12944 ),
945 BanRule(
946 r'/\babsl::StrFormat\b',
947 (
Peter Kastinge2c5ee82023-02-15 17:23:08948 'absl::StrFormat() is not allowed yet (https://crbug.com/1371963). ',
949 'Use base::StringPrintf() instead.',
Peter Kasting4f35bfc2022-10-18 18:39:12950 ),
951 True,
952 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
953 ),
954 BanRule(
David Benjaminea985a22023-04-18 22:05:01955 r'/\babsl::string_view\b',
Peter Kasting4f35bfc2022-10-18 18:39:12956 (
David Benjaminea985a22023-04-18 22:05:01957 'absl::string_view is a legacy spelling of std::string_view, which is ',
958 'not allowed yet (https://crbug.com/691162). Use base::StringPiece ',
959 'instead, unless std::string_view is needed to use with an external ',
960 'API.',
961 ),
962 True,
963 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
964 ),
965 BanRule(
966 r'/\bstd::(u16)?string_view\b',
967 (
968 'std::[u16]string_view is not yet allowed (crbug.com/691162). Use ',
969 'base::StringPiece[16] instead, unless std::[u16]string_view is ',
970 'needed to use an external API.',
Peter Kasting4f35bfc2022-10-18 18:39:12971 ),
972 True,
Adithya Srinivasanb2041882022-10-21 19:34:20973 [
David Benjaminea985a22023-04-18 22:05:01974 # Needed to implement and test std::string_view interoperability.
975 r'base/strings/string_piece.*',
Xiaochen Zhouf19c97f2023-04-28 13:04:32976 # Needed to use re2::RE2 regular expression library.
977 r'third_party/blink/common/interest_group/ad_display_size_utils.cc',
Adithya Srinivasanb2041882022-10-21 19:34:20978 # Needed to use liburlpattern API.
979 r'third_party/blink/renderer/core/url_pattern/.*',
Louise Brettc6d23872023-04-11 02:48:32980 r'third_party/blink/renderer/modules/manifest/manifest_parser\.cc',
David Benjamin3a305f12022-11-19 00:10:03981 # Needed to use QUICHE API.
Victor Vasilieva13f1932022-12-02 15:27:24982 r'net/quic/.*',
983 r'net/spdy/.*',
David Benjamin3a305f12022-11-19 00:10:03984 r'net/test/embedded_test_server/.*',
Victor Vasilieva13f1932022-12-02 15:27:24985 r'net/third_party/quiche/.*',
986 r'services/network/web_transport\.cc',
David Benjaminea985a22023-04-18 22:05:01987 # This code is in the process of being extracted into an external
988 # library, where //base will be unavailable.
989 r'net/cert/pki/.*',
990 r'net/der/.*',
991 # Needed to use APIs from the above.
992 r'net/cert/.*',
Adithya Srinivasanb2041882022-10-21 19:34:20993 # Not an error in third_party folders.
994 _THIRD_PARTY_EXCEPT_BLINK
995 ],
Peter Kasting4f35bfc2022-10-18 18:39:12996 ),
997 BanRule(
998 r'/\babsl::(StrSplit|StrJoin|StrCat|StrAppend|Substitute|StrContains)\b',
999 (
1000 'Abseil string utilities are banned. Use base/strings instead.',
1001 ),
1002 True,
1003 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1004 ),
1005 BanRule(
1006 r'/\babsl::(Mutex|CondVar|Notification|Barrier|BlockingCounter)\b',
1007 (
1008 'Abseil synchronization primitives are banned. Use',
1009 'base/synchronization instead.',
1010 ),
1011 True,
1012 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1013 ),
1014 BanRule(
1015 r'/\babsl::(Duration|Time|TimeZone|CivilDay)\b',
1016 (
1017 'Abseil\'s time library is banned. Use base/time instead.',
1018 ),
1019 True,
1020 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1021 ),
1022 BanRule(
Avi Drissman48ee39e2022-02-16 16:31:031023 r'/\bstd::optional\b',
1024 (
Peter Kastinge2c5ee82023-02-15 17:23:081025 'std::optional is not allowed yet (https://crbug.com/1373619). Use ',
1026 'absl::optional instead.',
Avi Drissman48ee39e2022-02-16 16:31:031027 ),
1028 True,
miktb599ed12023-05-26 07:03:561029 [
1030 # Clang plugins have different build config.
1031 '^tools/clang/plugins/',
1032 # Not an error in third_party folders.
1033 _THIRD_PARTY_EXCEPT_BLINK,
1034 ],
Avi Drissman48ee39e2022-02-16 16:31:031035 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151036 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081037 r'/#include <chrono>',
Daniel Bratell609102be2019-03-27 20:53:211038 (
Peter Kastinge2c5ee82023-02-15 17:23:081039 '<chrono> is banned. Use base/time instead.',
Daniel Bratell609102be2019-03-27 20:53:211040 ),
1041 True,
1042 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1043 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151044 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081045 r'/#include <exception>',
Daniel Bratell609102be2019-03-27 20:53:211046 (
1047 'Exceptions are banned and disabled in Chromium.',
1048 ),
1049 True,
1050 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1051 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151052 BanRule(
Daniel Bratell609102be2019-03-27 20:53:211053 r'/\bstd::function\b',
1054 (
Peter Kastinge2c5ee82023-02-15 17:23:081055 'std::function is banned. Use base::{Once,Repeating}Callback instead.',
Daniel Bratell609102be2019-03-27 20:53:211056 ),
Daniel Chenge5583e3c2022-09-22 00:19:411057 True,
Daniel Chengcd23b8b2022-09-16 17:16:241058 [
1059 # Has tests that template trait helpers don't unintentionally match
1060 # std::function.
Daniel Chenge5583e3c2022-09-22 00:19:411061 r'base/functional/callback_helpers_unittest\.cc',
1062 # Required to implement interfaces from the third-party perfetto
1063 # library.
1064 r'base/tracing/perfetto_task_runner\.cc',
1065 r'base/tracing/perfetto_task_runner\.h',
1066 # Needed for interop with the third-party nearby library type
1067 # location::nearby::connections::ResultCallback.
1068 'chrome/services/sharing/nearby/nearby_connections_conversions\.cc'
1069 # Needed for interop with the internal libassistant library.
1070 'chromeos/ash/services/libassistant/callback_utils\.h',
1071 # Needed for interop with Fuchsia fidl APIs.
1072 'fuchsia_web/webengine/browser/context_impl_browsertest\.cc',
1073 'fuchsia_web/webengine/browser/cookie_manager_impl_unittest\.cc',
1074 'fuchsia_web/webengine/browser/media_player_impl_unittest\.cc',
1075 # Required to interop with interfaces from the third-party perfetto
1076 # library.
1077 'services/tracing/public/cpp/perfetto/custom_event_recorder\.cc',
1078 'services/tracing/public/cpp/perfetto/perfetto_traced_process\.cc',
1079 'services/tracing/public/cpp/perfetto/perfetto_traced_process\.h',
1080 'services/tracing/public/cpp/perfetto/perfetto_tracing_backend\.cc',
1081 'services/tracing/public/cpp/perfetto/producer_client\.cc',
1082 'services/tracing/public/cpp/perfetto/producer_client\.h',
1083 'services/tracing/public/cpp/perfetto/producer_test_utils\.cc',
1084 'services/tracing/public/cpp/perfetto/producer_test_utils\.h',
1085 # Required for interop with the third-party webrtc library.
1086 'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.cc',
1087 'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.h',
Bob Beck5fc0be82022-12-12 23:32:521088 # This code is in the process of being extracted into a third-party library.
1089 # See https://crbug.com/1322914
1090 '^net/cert/pki/path_builder_unittest\.cc',
Brianna Goldstein846d8002023-05-16 19:24:301091 # Needed to use QUICHE API
1092 r'chrome/browser/ip_protection/.*',
Daniel Chenge5583e3c2022-09-22 00:19:411093 # TODO(https://crbug.com/1364577): Various uses that should be
1094 # migrated to something else.
1095 # Should use base::OnceCallback or base::RepeatingCallback.
1096 'base/allocator/dispatcher/initializer_unittest\.cc',
1097 'chrome/browser/ash/accessibility/speech_monitor\.cc',
1098 'chrome/browser/ash/accessibility/speech_monitor\.h',
1099 'chrome/browser/ash/login/ash_hud_login_browsertest\.cc',
1100 'chromecast/base/observer_unittest\.cc',
1101 'chromecast/browser/cast_web_view\.h',
1102 'chromecast/public/cast_media_shlib\.h',
1103 'device/bluetooth/floss/exported_callback_manager\.h',
1104 'device/bluetooth/floss/floss_dbus_client\.h',
1105 'device/fido/cable/v2_handshake_unittest\.cc',
1106 'device/fido/pin\.cc',
1107 'services/tracing/perfetto/test_utils\.h',
1108 # Should use base::FunctionRef.
1109 'chrome/browser/media/webrtc/test_stats_dictionary\.cc',
1110 'chrome/browser/media/webrtc/test_stats_dictionary\.h',
1111 'chromeos/ash/services/libassistant/device_settings_controller\.cc',
1112 'components/browser_ui/client_certificate/android/ssl_client_certificate_request\.cc',
1113 'components/gwp_asan/client/sampling_malloc_shims_unittest\.cc',
1114 'content/browser/font_unique_name_lookup/font_unique_name_lookup_unittest\.cc',
1115 # Does not need std::function at all.
1116 'components/omnibox/browser/autocomplete_result\.cc',
1117 'device/fido/win/webauthn_api\.cc',
1118 'media/audio/alsa/alsa_util\.cc',
1119 'media/remoting/stream_provider\.h',
1120 'sql/vfs_wrapper\.cc',
1121 # TODO(https://crbug.com/1364585): Remove usage and exception list
1122 # entries.
1123 'extensions/renderer/api/automation/automation_internal_custom_bindings\.cc',
1124 'extensions/renderer/api/automation/automation_internal_custom_bindings\.h',
1125 # TODO(https://crbug.com/1364579): Remove usage and exception list
1126 # entry.
1127 'ui/views/controls/focus_ring\.h',
1128
1129 # Various pre-existing uses in //tools that is low-priority to fix.
1130 'tools/binary_size/libsupersize/viewer/caspian/diff\.cc',
1131 'tools/binary_size/libsupersize/viewer/caspian/model\.cc',
1132 'tools/binary_size/libsupersize/viewer/caspian/model\.h',
1133 'tools/binary_size/libsupersize/viewer/caspian/tree_builder\.h',
1134 'tools/clang/base_bind_rewriters/BaseBindRewriters\.cpp',
1135
Daniel Chengcd23b8b2022-09-16 17:16:241136 # Not an error in third_party folders.
1137 _THIRD_PARTY_EXCEPT_BLINK
1138 ],
Daniel Bratell609102be2019-03-27 20:53:211139 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151140 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081141 r'/#include <X11/',
Tom Andersona95e12042020-09-09 23:08:001142 (
1143 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
1144 ),
1145 True,
1146 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1147 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151148 BanRule(
Daniel Bratell609102be2019-03-27 20:53:211149 r'/\bstd::ratio\b',
1150 (
1151 'std::ratio is banned by the Google Style Guide.',
1152 ),
1153 True,
1154 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:451155 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151156 BanRule(
Peter Kasting6d77e9d2023-02-09 21:58:181157 r'/\bstd::aligned_alloc\b',
1158 (
Peter Kastinge2c5ee82023-02-15 17:23:081159 'std::aligned_alloc() is not yet allowed (crbug.com/1412818). Use ',
1160 'base::AlignedAlloc() instead.',
Peter Kasting6d77e9d2023-02-09 21:58:181161 ),
1162 True,
1163 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1164 ),
1165 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081166 r'/#include <(barrier|latch|semaphore|stop_token)>',
Peter Kasting6d77e9d2023-02-09 21:58:181167 (
Peter Kastinge2c5ee82023-02-15 17:23:081168 'The thread support library is banned. Use base/synchronization '
1169 'instead.',
Peter Kasting6d77e9d2023-02-09 21:58:181170 ),
1171 True,
1172 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1173 ),
1174 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081175 r'/\bstd::(c8rtomb|mbrtoc8)\b',
Peter Kasting6d77e9d2023-02-09 21:58:181176 (
Peter Kastinge2c5ee82023-02-15 17:23:081177 'std::c8rtomb() and std::mbrtoc8() are banned.',
Peter Kasting6d77e9d2023-02-09 21:58:181178 ),
1179 True,
1180 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1181 ),
1182 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081183 r'/\bchar8_t|std::u8string\b',
Peter Kasting6d77e9d2023-02-09 21:58:181184 (
Peter Kastinge2c5ee82023-02-15 17:23:081185 'char8_t and std::u8string are not yet allowed. Can you use [unsigned]',
1186 ' char and std::string instead?',
1187 ),
1188 True,
Daniel Cheng893c563f2023-04-21 09:54:521189 [
1190 # The demangler does not use this type but needs to know about it.
1191 'base/third_party/symbolize/demangle\.cc',
1192 # Don't warn in third_party folders.
1193 _THIRD_PARTY_EXCEPT_BLINK
1194 ],
Peter Kastinge2c5ee82023-02-15 17:23:081195 ),
1196 BanRule(
1197 r'/(\b(co_await|co_return|co_yield)\b|#include <coroutine>)',
1198 (
1199 'Coroutines are not yet allowed (https://crbug.com/1403840).',
1200 ),
1201 True,
1202 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1203 ),
1204 BanRule(
Peter Kastingcc152522023-03-22 20:17:371205 r'/^\s*(export\s|import\s+["<:\w]|module(;|\s+[:\w]))',
Peter Kasting69357dc2023-03-14 01:34:291206 (
1207 'Modules are disallowed for now due to lack of toolchain support.',
1208 ),
1209 True,
1210 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1211 ),
1212 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081213 r'/\[\[(un)?likely\]\]',
1214 (
1215 '[[likely]] and [[unlikely]] are not yet allowed ',
1216 '(https://crbug.com/1414620). Use [UN]LIKELY instead.',
1217 ),
1218 True,
1219 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1220 ),
1221 BanRule(
1222 r'/#include <format>',
1223 (
1224 '<format> is not yet allowed. Use base::StringPrintf() instead.',
1225 ),
1226 True,
1227 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1228 ),
1229 BanRule(
1230 r'/#include <ranges>',
1231 (
1232 '<ranges> is not yet allowed. Use base/ranges/algorithm.h instead.',
1233 ),
1234 True,
1235 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1236 ),
1237 BanRule(
1238 r'/#include <source_location>',
1239 (
1240 '<source_location> is not yet allowed. Use base/location.h instead.',
1241 ),
1242 True,
1243 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1244 ),
1245 BanRule(
1246 r'/#include <syncstream>',
1247 (
1248 '<syncstream> is banned.',
Peter Kasting6d77e9d2023-02-09 21:58:181249 ),
1250 True,
1251 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1252 ),
1253 BanRule(
Michael Giuffrida7f93d6922019-04-19 14:39:581254 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:191255 (
1256 'RunMessageLoop is deprecated, use RunLoop instead.',
1257 ),
1258 False,
1259 (),
1260 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151261 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441262 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:191263 (
1264 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
1265 "if you're convinced you need this.",
1266 ),
1267 False,
1268 (),
1269 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151270 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441271 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:191272 (
1273 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:041274 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:191275 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
1276 'async events instead of flushing threads.',
1277 ),
1278 False,
1279 (),
1280 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151281 BanRule(
Gabriel Charette147335ea2018-03-22 15:59:191282 r'MessageLoopRunner',
1283 (
1284 'MessageLoopRunner is deprecated, use RunLoop instead.',
1285 ),
1286 False,
1287 (),
1288 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151289 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441290 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:191291 (
1292 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
1293 "gab@ if you found a use case where this is the only solution.",
1294 ),
1295 False,
1296 (),
1297 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151298 BanRule(
Victor Costane48a2e82019-03-15 22:02:341299 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:161300 (
Victor Costane48a2e82019-03-15 22:02:341301 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:161302 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
1303 ),
1304 True,
1305 (
1306 r'^sql/initialization\.(cc|h)$',
1307 r'^third_party/sqlite/.*\.(c|cc|h)$',
1308 ),
1309 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151310 BanRule(
Austin Sullivand661ab52022-11-16 08:55:151311 'CREATE VIEW',
1312 (
1313 'SQL views are disabled in Chromium feature code',
1314 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-views',
1315 ),
1316 True,
1317 (
1318 _THIRD_PARTY_EXCEPT_BLINK,
1319 # sql/ itself uses views when using memory-mapped IO.
1320 r'^sql/.*',
1321 # Various performance tools that do not build as part of Chrome.
1322 r'^infra/.*',
1323 r'^tools/perf.*',
1324 r'.*perfetto.*',
1325 ),
1326 ),
1327 BanRule(
1328 'CREATE VIRTUAL TABLE',
1329 (
1330 'SQL virtual tables are disabled in Chromium feature code',
1331 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-virtual-tables',
1332 ),
1333 True,
1334 (
1335 _THIRD_PARTY_EXCEPT_BLINK,
1336 # sql/ itself uses virtual tables in the recovery module and tests.
1337 r'^sql/.*',
1338 # TODO(https://crbug.com/695592): Remove once WebSQL is deprecated.
1339 r'third_party/blink/web_tests/storage/websql/.*'
1340 # Various performance tools that do not build as part of Chrome.
1341 r'^tools/perf.*',
1342 r'.*perfetto.*',
1343 ),
1344 ),
1345 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441346 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:471347 (
1348 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
1349 'base::RandomShuffle instead.'
1350 ),
1351 True,
1352 (),
1353 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151354 BanRule(
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:241355 'ios/web/public/test/http_server',
1356 (
1357 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
1358 ),
1359 False,
1360 (),
1361 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151362 BanRule(
Robert Liao764c9492019-01-24 18:46:281363 'GetAddressOf',
1364 (
1365 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:531366 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:111367 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:531368 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:281369 ),
1370 True,
1371 (),
1372 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151373 BanRule(
Ben Lewisa9514602019-04-29 17:53:051374 'SHFileOperation',
1375 (
1376 'SHFileOperation was deprecated in Windows Vista, and there are less ',
1377 'complex functions to achieve the same goals. Use IFileOperation for ',
1378 'any esoteric actions instead.'
1379 ),
1380 True,
1381 (),
1382 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151383 BanRule(
Cliff Smolinsky81951642019-04-30 21:39:511384 'StringFromGUID2',
1385 (
1386 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241387 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511388 ),
1389 True,
1390 (
Daniel Chenga44a1bcd2022-03-15 20:00:151391 r'/base/win/win_util_unittest.cc',
Cliff Smolinsky81951642019-04-30 21:39:511392 ),
1393 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151394 BanRule(
Cliff Smolinsky81951642019-04-30 21:39:511395 'StringFromCLSID',
1396 (
1397 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241398 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511399 ),
1400 True,
1401 (
Daniel Chenga44a1bcd2022-03-15 20:00:151402 r'/base/win/win_util_unittest.cc',
Cliff Smolinsky81951642019-04-30 21:39:511403 ),
1404 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151405 BanRule(
Avi Drissman7382afa02019-04-29 23:27:131406 'kCFAllocatorNull',
1407 (
1408 'The use of kCFAllocatorNull with the NoCopy creation of ',
1409 'CoreFoundation types is prohibited.',
1410 ),
1411 True,
1412 (),
1413 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151414 BanRule(
Oksana Zhuravlovafd247772019-05-16 16:57:291415 'mojo::ConvertTo',
1416 (
1417 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1418 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1419 'StringTraits if you would like to convert between custom types and',
1420 'the wire format of mojom types.'
1421 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221422 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291423 (
David Dorwin13dc48b2022-06-03 21:18:421424 r'^fuchsia_web/webengine/browser/url_request_rewrite_rules_manager\.cc$',
1425 r'^fuchsia_web/webengine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291426 r'^third_party/blink/.*\.(cc|h)$',
1427 r'^content/renderer/.*\.(cc|h)$',
1428 ),
1429 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151430 BanRule(
Oksana Zhuravlovac8222d22019-12-19 19:21:161431 'GetInterfaceProvider',
1432 (
1433 'InterfaceProvider is deprecated.',
1434 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1435 'or Platform::GetBrowserInterfaceBroker.'
1436 ),
1437 False,
1438 (),
1439 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151440 BanRule(
Robert Liao1d78df52019-11-11 20:02:011441 'CComPtr',
1442 (
1443 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1444 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1445 'details.'
1446 ),
1447 False,
1448 (),
1449 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151450 BanRule(
Xiaohan Wang72bd2ba2020-02-18 21:38:201451 r'/\b(IFACE|STD)METHOD_?\(',
1452 (
1453 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1454 'Instead, always use IFACEMETHODIMP in the declaration.'
1455 ),
1456 False,
1457 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1458 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151459 BanRule(
Allen Bauer53b43fb12020-03-12 17:21:471460 'set_owned_by_client',
1461 (
1462 'set_owned_by_client is deprecated.',
1463 'views::View already owns the child views by default. This introduces ',
1464 'a competing ownership model which makes the code difficult to reason ',
1465 'about. See http://crbug.com/1044687 for more details.'
1466 ),
1467 False,
1468 (),
1469 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151470 BanRule(
Peter Boström7ff41522021-07-29 03:43:271471 'RemoveAllChildViewsWithoutDeleting',
1472 (
1473 'RemoveAllChildViewsWithoutDeleting is deprecated.',
1474 'This method is deemed dangerous as, unless raw pointers are re-added,',
1475 'calls to this method introduce memory leaks.'
1476 ),
1477 False,
1478 (),
1479 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151480 BanRule(
Eric Secklerbe6f48d2020-05-06 18:09:121481 r'/\bTRACE_EVENT_ASYNC_',
1482 (
1483 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1484 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1485 ),
1486 False,
1487 (
1488 r'^base/trace_event/.*',
1489 r'^base/tracing/.*',
1490 ),
1491 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151492 BanRule(
Aditya Kushwah5a286b72022-02-10 04:54:431493 r'/\bbase::debug::DumpWithoutCrashingUnthrottled[(][)]',
1494 (
1495 'base::debug::DumpWithoutCrashingUnthrottled() does not throttle',
1496 'dumps and may spam crash reports. Consider if the throttled',
1497 'variants suffice instead.',
1498 ),
1499 False,
1500 (),
1501 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151502 BanRule(
Robert Liao22f66a52021-04-10 00:57:521503 'RoInitialize',
1504 (
Robert Liao48018922021-04-16 23:03:021505 'Improper use of [base::win]::RoInitialize() has been implicated in a ',
Robert Liao22f66a52021-04-10 00:57:521506 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
1507 'instead. See http://crbug.com/1197722 for more information.'
1508 ),
1509 True,
Robert Liao48018922021-04-16 23:03:021510 (
Bruce Dawson40fece62022-09-16 19:58:311511 r'^base/win/scoped_winrt_initializer\.cc$',
Danil Chapovalov07694382023-05-24 17:55:211512 r'^third_party/abseil-cpp/absl/.*',
Robert Liao48018922021-04-16 23:03:021513 ),
Robert Liao22f66a52021-04-10 00:57:521514 ),
Patrick Monettec343bb982022-06-01 17:18:451515 BanRule(
1516 r'base::Watchdog',
1517 (
1518 'base::Watchdog is deprecated because it creates its own thread.',
1519 'Instead, manually start a timer on a SequencedTaskRunner.',
1520 ),
1521 False,
1522 (),
1523 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091524 BanRule(
1525 'base::Passed',
1526 (
1527 'Do not use base::Passed. It is a legacy helper for capturing ',
1528 'move-only types with base::BindRepeating, but invoking the ',
1529 'resulting RepeatingCallback moves the captured value out of ',
1530 'the callback storage, and subsequent invocations may pass the ',
1531 'value in a valid but undefined state. Prefer base::BindOnce().',
1532 'See http://crbug.com/1326449 for context.'
1533 ),
1534 False,
Daniel Cheng91f6fbaf2022-09-16 12:07:481535 (
1536 # False positive, but it is also fine to let bind internals reference
1537 # base::Passed.
Daniel Chengcd23b8b2022-09-16 17:16:241538 r'^base[\\/]functional[\\/]bind\.h',
Daniel Cheng91f6fbaf2022-09-16 12:07:481539 r'^base[\\/]functional[\\/]bind_internal\.h',
1540 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091541 ),
Daniel Cheng2248b332022-07-27 06:16:591542 BanRule(
Daniel Chengba3bc2e2022-10-03 02:45:431543 r'base::Feature k',
1544 (
1545 'Please use BASE_DECLARE_FEATURE() or BASE_FEATURE() instead of ',
1546 'directly declaring/defining features.'
1547 ),
1548 True,
1549 [
1550 _THIRD_PARTY_EXCEPT_BLINK,
1551 ],
1552 ),
Robert Ogden92101dcb2022-10-19 23:49:361553 BanRule(
Arthur Sonzogni1da65fa2023-03-27 16:01:521554 r'/\bchartorune\b',
Robert Ogden92101dcb2022-10-19 23:49:361555 (
1556 'chartorune is not memory-safe, unless you can guarantee the input ',
1557 'string is always null-terminated. Otherwise, please use charntorune ',
1558 'from libphonenumber instead.'
1559 ),
1560 True,
1561 [
1562 _THIRD_PARTY_EXCEPT_BLINK,
1563 # Exceptions to this rule should have a fuzzer.
1564 ],
1565 ),
Arthur Sonzogni1da65fa2023-03-27 16:01:521566 BanRule(
1567 r'/\b#include "base/atomicops\.h"\b',
1568 (
1569 'Do not use base::subtle atomics, but std::atomic, which are simpler '
1570 'to use, have better understood, clearer and richer semantics, and are '
1571 'harder to mis-use. See details in base/atomicops.h.',
1572 ),
1573 False,
1574 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Benoit Lize79cf0592023-01-27 10:01:571575 ),
Arthur Sonzogni60348572e2023-04-07 10:22:521576 BanRule(
1577 r'CrossThreadPersistent<',
1578 (
1579 'Do not use blink::CrossThreadPersistent, but '
1580 'blink::CrossThreadHandle. It is harder to mis-use.',
1581 'More info: '
1582 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1583 'Please contact platform-architecture-dev@ before adding new instances.'
1584 ),
1585 False,
1586 []
1587 ),
1588 BanRule(
1589 r'CrossThreadWeakPersistent<',
1590 (
1591 'Do not use blink::CrossThreadWeakPersistent, but '
1592 'blink::CrossThreadWeakHandle. It is harder to mis-use.',
1593 'More info: '
1594 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1595 'Please contact platform-architecture-dev@ before adding new instances.'
1596 ),
1597 False,
1598 []
1599 ),
Avi Drissman491617c2023-04-13 17:33:151600 BanRule(
1601 r'objc/objc.h',
1602 (
1603 'Do not include <objc/objc.h>. It defines away ARC lifetime '
1604 'annotations, and is thus dangerous.',
1605 'Please use the pimpl pattern; search for `ObjCStorage` for examples.',
1606 'For further reading on how to safely mix C++ and Obj-C, see',
1607 'https://chromium.googlesource.com/chromium/src/+/main/docs/mac/mixing_cpp_and_objc.md'
1608 ),
1609 True,
1610 []
1611 ),
Grace Park8d59b54b2023-04-26 17:53:351612 BanRule(
1613 r'/#include <filesystem>',
1614 (
1615 'libc++ <filesystem> is banned per the Google C++ styleguide.',
1616 ),
1617 True,
1618 # This fuzzing framework is a standalone open source project and
1619 # cannot rely on Chromium base.
1620 (r'third_party/centipede'),
1621 ),
Daniel Cheng72153e02023-05-18 21:18:141622 BanRule(
1623 r'TopDocument()',
1624 (
1625 'TopDocument() does not work correctly with out-of-process iframes. '
1626 'Please do not introduce new uses.',
1627 ),
1628 True,
1629 (
1630 # TODO(crbug.com/617677): Remove all remaining uses.
1631 r'^third_party/blink/renderer/core/dom/document\.cc',
1632 r'^third_party/blink/renderer/core/dom/document\.h',
1633 r'^third_party/blink/renderer/core/dom/element\.cc',
1634 r'^third_party/blink/renderer/core/exported/web_disallow_transition_scope_test\.cc',
1635 r'^third_party/blink/renderer/core/exported/web_document_test\.cc',
Daniel Cheng72153e02023-05-18 21:18:141636 r'^third_party/blink/renderer/core/html/html_anchor_element\.cc',
1637 r'^third_party/blink/renderer/core/html/html_dialog_element\.cc',
1638 r'^third_party/blink/renderer/core/html/html_element\.cc',
1639 r'^third_party/blink/renderer/core/html/html_frame_owner_element\.cc',
1640 r'^third_party/blink/renderer/core/html/media/video_wake_lock\.cc',
1641 r'^third_party/blink/renderer/core/loader/anchor_element_interaction_tracker\.cc',
1642 r'^third_party/blink/renderer/core/page/scrolling/root_scroller_controller\.cc',
1643 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.cc',
1644 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.h',
1645 r'^third_party/blink/renderer/core/script/classic_pending_script\.cc',
1646 r'^third_party/blink/renderer/core/script/script_loader\.cc',
1647 ),
1648 ),
avi@chromium.org127f18ec2012-06-16 05:05:591649)
1650
Daniel Cheng92c15e32022-03-16 17:48:221651_BANNED_MOJOM_PATTERNS : Sequence[BanRule] = (
1652 BanRule(
1653 'handle<shared_buffer>',
1654 (
1655 'Please use one of the more specific shared memory types instead:',
1656 ' mojo_base.mojom.ReadOnlySharedMemoryRegion',
1657 ' mojo_base.mojom.WritableSharedMemoryRegion',
1658 ' mojo_base.mojom.UnsafeSharedMemoryRegion',
1659 ),
1660 True,
1661 ),
1662)
1663
mlamouria82272622014-09-16 18:45:041664_IPC_ENUM_TRAITS_DEPRECATED = (
1665 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501666 'See http://www.chromium.org/Home/chromium-security/education/'
1667 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041668
Stephen Martinis97a394142018-06-07 23:06:051669_LONG_PATH_ERROR = (
1670 'Some files included in this CL have file names that are too long (> 200'
1671 ' characters). If committed, these files will cause issues on Windows. See'
1672 ' https://crbug.com/612667 for more details.'
1673)
1674
Shenghua Zhangbfaa38b82017-11-16 21:58:021675_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Bruce Dawson40fece62022-09-16 19:58:311676 r".*/AppHooksImpl\.java",
1677 r".*/BuildHooksAndroidImpl\.java",
1678 r".*/LicenseContentProvider\.java",
1679 r".*/PlatformServiceBridgeImpl.java",
1680 r".*chrome/android/feed/dummy/.*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021681]
avi@chromium.org127f18ec2012-06-16 05:05:591682
Mohamed Heikald048240a2019-11-12 16:57:371683# List of image extensions that are used as resources in chromium.
1684_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1685
Sean Kau46e29bc2017-08-28 16:31:161686# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401687_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Bruce Dawson40fece62022-09-16 19:58:311688 r'test/data/',
1689 r'testing/buildbot/',
1690 r'^components/policy/resources/policy_templates\.json$',
1691 r'^third_party/protobuf/',
Camillo Bruni1411a352023-05-24 12:39:031692 r'^third_party/blink/perf_tests/speedometer.*/resources/todomvc/learn\.json',
Bruce Dawson40fece62022-09-16 19:58:311693 r'^third_party/blink/renderer/devtools/protocol\.json$',
1694 r'^third_party/blink/web_tests/external/wpt/',
1695 r'^tools/perf/',
1696 r'^tools/traceline/svgui/startup-release.json',
Daniel Cheng2d4c2d192022-07-01 01:38:311697 # vscode configuration files allow comments
Bruce Dawson40fece62022-09-16 19:58:311698 r'^tools/vscode/',
Sean Kau46e29bc2017-08-28 16:31:161699]
1700
Andrew Grieveb773bad2020-06-05 18:00:381701# These are not checked on the public chromium-presubmit trybot.
1702# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041703# checkouts.
agrievef32bcc72016-04-04 14:57:401704_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381705 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381706]
1707
1708
1709_GENERIC_PYDEPS_FILES = [
Bruce Dawson853b739e62022-05-03 23:03:101710 'android_webview/test/components/run_webview_component_smoketest.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041711 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361712 'base/android/jni_generator/jni_generator.pydeps',
1713 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361714 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041715 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361716 'build/android/gyp/aar.pydeps',
1717 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271718 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361719 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381720 'build/android/gyp/assert_static_initializers.pydeps',
Mohamed Heikal133e1f22023-04-18 20:04:371721 'build/android/gyp/binary_baseline_profile.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361722 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021723 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:221724 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111725 'build/android/gyp/compile_java.pydeps',
Peter Weneaa963f2023-01-20 19:40:301726 'build/android/gyp/compile_kt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361727 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361728 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361729 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111730 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041731 'build/android/gyp/create_app_bundle_apks.pydeps',
1732 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361733 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121734 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091735 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221736 'build/android/gyp/create_size_info_files.pydeps',
Peter Wene6e017e2022-07-27 21:40:401737 'build/android/gyp/create_test_apk_wrapper_script.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001738 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361739 'build/android/gyp/dex.pydeps',
1740 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361741 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:211742 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361743 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361744 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361745 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581746 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361747 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141748 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261749 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:471750 'build/android/gyp/java_google_api_keys.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041751 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361752 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361753 'build/android/gyp/merge_manifest.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:101754 'build/android/gyp/optimize_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361755 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221756 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361757 'build/android/gyp/proguard.pydeps',
Andrew Grievee3a775ab2022-05-16 15:59:221758 'build/android/gyp/system_image_apks.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:101759 'build/android/gyp/trace_event_bytecode_rewriter.pydeps',
Peter Wen578730b2020-03-19 19:55:461760 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:301761 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241762 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361763 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461764 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561765 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361766 'build/android/incremental_install/generate_android_manifest.pydeps',
1767 'build/android/incremental_install/write_installer_json.pydeps',
Stephanie Kim392913b452022-06-15 17:25:321768 'build/android/pylib/results/presentation/test_results_presentation.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041769 'build/android/resource_sizes.pydeps',
1770 'build/android/test_runner.pydeps',
1771 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361772 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361773 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321774 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271775 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1776 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:041777 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001778 'components/cronet/tools/generate_javadoc.pydeps',
1779 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381780 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001781 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381782 'net/tools/testserver/testserver.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181783 'testing/scripts/run_isolated_script_test.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411784 'testing/merge_scripts/standard_isolated_script_merge.pydeps',
1785 'testing/merge_scripts/standard_gtest_merge.pydeps',
1786 'testing/merge_scripts/code_coverage/merge_results.pydeps',
1787 'testing/merge_scripts/code_coverage/merge_steps.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041788 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421789 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
Yuki Shiino38eeaad12022-08-11 06:40:251790 'third_party/blink/renderer/bindings/scripts/check_generated_file_list.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421791 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131792 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:501793 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411794 'third_party/blink/tools/blinkpy/web_tests/merge_results.pydeps',
1795 'third_party/blink/tools/merge_web_test_results.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061796 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221797 'tools/binary_size/supersize.pydeps',
Ben Pastene028104a2022-08-10 19:17:451798 'tools/perf/process_perf_results.pydeps',
agrievef32bcc72016-04-04 14:57:401799]
1800
wnwenbdc444e2016-05-25 13:44:151801
agrievef32bcc72016-04-04 14:57:401802_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1803
1804
Eric Boren6fd2b932018-01-25 15:05:081805# Bypass the AUTHORS check for these accounts.
1806_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591807 ) | set('%s@appspot.gserviceaccount.com' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451808 ) | set('%s@developer.gserviceaccount.com' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591809 ) | set('%s@chops-service-accounts.iam.gserviceaccount.com' % s
smutde797052019-12-04 02:03:521810 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:231811 'wpt-autoroller', 'chrome-weblayer-builder',
Garrett Beaty4d4fcf62021-11-24 17:57:471812 'lacros-version-skew-roller', 'skylab-test-cros-roller',
Sven Zheng722960ba2022-07-18 16:40:461813 'infra-try-recipes-tester', 'lacros-tracking-roller',
Brian Sheedy1c951e62022-10-27 01:16:181814 'lacros-sdk-version-roller', 'chrome-automated-expectation',
Stephanie Kimb49bdd242023-04-28 16:46:041815 'chromium-automated-expectation', 'chrome-branch-day',
1816 'chromium-autosharder')
Eric Boren835d71f2018-09-07 21:09:041817 ) | set('%s@skia-public.iam.gserviceaccount.com' % s
Eric Boren66150e52020-01-08 11:20:271818 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041819 ) | set('%s@skia-corp.google.com.iam.gserviceaccount.com' % s
Yulan Lineb0cfba2021-04-09 18:43:161820 for s in ('chromium-internal-autoroll',)
1821 ) | set('%s@owners-cleanup-prod.google.com.iam.gserviceaccount.com' % s
Chong Gub277e342022-10-15 03:30:551822 for s in ('swarming-tasks',)
1823 ) | set('%s@fuchsia-infra.iam.gserviceaccount.com' % s
1824 for s in ('global-integration-try-builder',
1825 'global-integration-ci-builder'))
Eric Boren6fd2b932018-01-25 15:05:081826
Matt Stark6ef08872021-07-29 01:21:461827_INVALID_GRD_FILE_LINE = [
1828 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
1829]
Eric Boren6fd2b932018-01-25 15:05:081830
Daniel Bratell65b033262019-04-23 08:17:061831def _IsCPlusPlusFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501832 """Returns True if this file contains C++-like code (and not Python,
1833 Go, Java, MarkDown, ...)"""
Daniel Bratell65b033262019-04-23 08:17:061834
Sam Maiera6e76d72022-02-11 21:43:501835 ext = input_api.os_path.splitext(file_path)[1]
1836 # This list is compatible with CppChecker.IsCppFile but we should
1837 # consider adding ".c" to it. If we do that we can use this function
1838 # at more places in the code.
1839 return ext in (
1840 '.h',
1841 '.cc',
1842 '.cpp',
1843 '.m',
1844 '.mm',
1845 )
1846
Daniel Bratell65b033262019-04-23 08:17:061847
1848def _IsCPlusPlusHeaderFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501849 return input_api.os_path.splitext(file_path)[1] == ".h"
Daniel Bratell65b033262019-04-23 08:17:061850
1851
1852def _IsJavaFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501853 return input_api.os_path.splitext(file_path)[1] == ".java"
Daniel Bratell65b033262019-04-23 08:17:061854
1855
1856def _IsProtoFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501857 return input_api.os_path.splitext(file_path)[1] == ".proto"
Daniel Bratell65b033262019-04-23 08:17:061858
Mohamed Heikal5e5b7922020-10-29 18:57:591859
Erik Staabc734cd7a2021-11-23 03:11:521860def _IsXmlOrGrdFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501861 ext = input_api.os_path.splitext(file_path)[1]
1862 return ext in ('.grd', '.xml')
Erik Staabc734cd7a2021-11-23 03:11:521863
1864
Sven Zheng76a79ea2022-12-21 21:25:241865def _IsMojomFile(input_api, file_path):
1866 return input_api.os_path.splitext(file_path)[1] == ".mojom"
1867
1868
Mohamed Heikal5e5b7922020-10-29 18:57:591869def CheckNoUpstreamDepsOnClank(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501870 """Prevent additions of dependencies from the upstream repo on //clank."""
1871 # clank can depend on clank
1872 if input_api.change.RepositoryRoot().endswith('clank'):
1873 return []
1874 build_file_patterns = [
1875 r'(.+/)?BUILD\.gn',
1876 r'.+\.gni',
1877 ]
1878 excluded_files = [r'build[/\\]config[/\\]android[/\\]config\.gni']
1879 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
Mohamed Heikal5e5b7922020-10-29 18:57:591880
Sam Maiera6e76d72022-02-11 21:43:501881 error_message = 'Disallowed import on //clank in an upstream build file:'
Mohamed Heikal5e5b7922020-10-29 18:57:591882
Sam Maiera6e76d72022-02-11 21:43:501883 def FilterFile(affected_file):
1884 return input_api.FilterSourceFile(affected_file,
1885 files_to_check=build_file_patterns,
1886 files_to_skip=excluded_files)
Mohamed Heikal5e5b7922020-10-29 18:57:591887
Sam Maiera6e76d72022-02-11 21:43:501888 problems = []
1889 for f in input_api.AffectedSourceFiles(FilterFile):
1890 local_path = f.LocalPath()
1891 for line_number, line in f.ChangedContents():
1892 if (bad_pattern.search(line)):
1893 problems.append('%s:%d\n %s' %
1894 (local_path, line_number, line.strip()))
1895 if problems:
1896 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1897 else:
1898 return []
Mohamed Heikal5e5b7922020-10-29 18:57:591899
1900
Saagar Sanghavifceeaae2020-08-12 16:40:361901def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501902 """Attempts to prevent use of functions intended only for testing in
1903 non-testing code. For now this is just a best-effort implementation
1904 that ignores header files and may have some false positives. A
1905 better implementation would probably need a proper C++ parser.
1906 """
1907 # We only scan .cc files and the like, as the declaration of
1908 # for-testing functions in header files are hard to distinguish from
1909 # calls to such functions without a proper C++ parser.
1910 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
joi@chromium.org55459852011-08-10 15:17:191911
Sam Maiera6e76d72022-02-11 21:43:501912 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
1913 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' %
1914 base_function_pattern)
1915 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
1916 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
1917 exclusion_pattern = input_api.re.compile(
1918 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' %
1919 (base_function_pattern, base_function_pattern))
1920 # Avoid a false positive in this case, where the method name, the ::, and
1921 # the closing { are all on different lines due to line wrapping.
1922 # HelperClassForTesting::
1923 # HelperClassForTesting(
1924 # args)
1925 # : member(0) {}
1926 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
joi@chromium.org55459852011-08-10 15:17:191927
Sam Maiera6e76d72022-02-11 21:43:501928 def FilterFile(affected_file):
1929 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1930 input_api.DEFAULT_FILES_TO_SKIP)
1931 return input_api.FilterSourceFile(
1932 affected_file,
1933 files_to_check=file_inclusion_pattern,
1934 files_to_skip=files_to_skip)
joi@chromium.org55459852011-08-10 15:17:191935
Sam Maiera6e76d72022-02-11 21:43:501936 problems = []
1937 for f in input_api.AffectedSourceFiles(FilterFile):
1938 local_path = f.LocalPath()
1939 in_method_defn = False
1940 for line_number, line in f.ChangedContents():
1941 if (inclusion_pattern.search(line)
1942 and not comment_pattern.search(line)
1943 and not exclusion_pattern.search(line)
1944 and not allowlist_pattern.search(line)
1945 and not in_method_defn):
1946 problems.append('%s:%d\n %s' %
1947 (local_path, line_number, line.strip()))
1948 in_method_defn = method_defn_pattern.search(line)
joi@chromium.org55459852011-08-10 15:17:191949
Sam Maiera6e76d72022-02-11 21:43:501950 if problems:
1951 return [
1952 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
1953 ]
1954 else:
1955 return []
joi@chromium.org55459852011-08-10 15:17:191956
1957
Saagar Sanghavifceeaae2020-08-12 16:40:361958def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501959 """This is a simplified version of
1960 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
1961 """
1962 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1963 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1964 name_pattern = r'ForTest(s|ing)?'
1965 # Describes an occurrence of "ForTest*" inside a // comment.
1966 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
1967 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
1968 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
1969 # Catch calls.
1970 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1971 # Ignore definitions. (Comments are ignored separately.)
1972 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
Vaclav Brozek7dbc28c2018-03-27 08:35:231973
Sam Maiera6e76d72022-02-11 21:43:501974 problems = []
1975 sources = lambda x: input_api.FilterSourceFile(
1976 x,
1977 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
1978 DEFAULT_FILES_TO_SKIP),
1979 files_to_check=[r'.*\.java$'])
1980 for f in input_api.AffectedFiles(include_deletes=False,
1981 file_filter=sources):
1982 local_path = f.LocalPath()
Vaclav Brozek7dbc28c2018-03-27 08:35:231983 is_inside_javadoc = False
Sam Maiera6e76d72022-02-11 21:43:501984 for line_number, line in f.ChangedContents():
1985 if is_inside_javadoc and javadoc_end_re.search(line):
1986 is_inside_javadoc = False
1987 if not is_inside_javadoc and javadoc_start_re.search(line):
1988 is_inside_javadoc = True
1989 if is_inside_javadoc:
1990 continue
1991 if (inclusion_re.search(line) and not comment_re.search(line)
1992 and not annotation_re.search(line)
1993 and not exclusion_re.search(line)):
1994 problems.append('%s:%d\n %s' %
1995 (local_path, line_number, line.strip()))
Vaclav Brozek7dbc28c2018-03-27 08:35:231996
Sam Maiera6e76d72022-02-11 21:43:501997 if problems:
1998 return [
1999 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
2000 ]
2001 else:
2002 return []
Vaclav Brozek7dbc28c2018-03-27 08:35:232003
2004
Saagar Sanghavifceeaae2020-08-12 16:40:362005def CheckNoIOStreamInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502006 """Checks to make sure no .h files include <iostream>."""
2007 files = []
2008 pattern = input_api.re.compile(r'^#include\s*<iostream>',
2009 input_api.re.MULTILINE)
2010 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2011 if not f.LocalPath().endswith('.h'):
2012 continue
2013 contents = input_api.ReadFile(f)
2014 if pattern.search(contents):
2015 files.append(f)
thakis@chromium.org10689ca2011-09-02 02:31:542016
Sam Maiera6e76d72022-02-11 21:43:502017 if len(files):
2018 return [
2019 output_api.PresubmitError(
2020 'Do not #include <iostream> in header files, since it inserts static '
2021 'initialization into every file including the header. Instead, '
2022 '#include <ostream>. See http://crbug.com/94794', files)
2023 ]
2024 return []
2025
thakis@chromium.org10689ca2011-09-02 02:31:542026
Aleksey Khoroshilov9b28c032022-06-03 16:35:322027def CheckNoStrCatRedefines(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502028 """Checks no windows headers with StrCat redefined are included directly."""
2029 files = []
Aleksey Khoroshilov9b28c032022-06-03 16:35:322030 files_to_check = (r'.+%s' % _HEADER_EXTENSIONS,
2031 r'.+%s' % _IMPLEMENTATION_EXTENSIONS)
2032 files_to_skip = (input_api.DEFAULT_FILES_TO_SKIP +
2033 _NON_BASE_DEPENDENT_PATHS)
2034 sources_filter = lambda f: input_api.FilterSourceFile(
2035 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
2036
Sam Maiera6e76d72022-02-11 21:43:502037 pattern_deny = input_api.re.compile(
2038 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
2039 input_api.re.MULTILINE)
2040 pattern_allow = input_api.re.compile(
2041 r'^#include\s"base/win/windows_defines.inc"', input_api.re.MULTILINE)
Aleksey Khoroshilov9b28c032022-06-03 16:35:322042 for f in input_api.AffectedSourceFiles(sources_filter):
Sam Maiera6e76d72022-02-11 21:43:502043 contents = input_api.ReadFile(f)
2044 if pattern_deny.search(
2045 contents) and not pattern_allow.search(contents):
2046 files.append(f.LocalPath())
Danil Chapovalov3518f362018-08-11 16:13:432047
Sam Maiera6e76d72022-02-11 21:43:502048 if len(files):
2049 return [
2050 output_api.PresubmitError(
2051 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
2052 'directly since they pollute code with StrCat macro. Instead, '
2053 'include matching header from base/win. See http://crbug.com/856536',
2054 files)
2055 ]
2056 return []
Danil Chapovalov3518f362018-08-11 16:13:432057
thakis@chromium.org10689ca2011-09-02 02:31:542058
Saagar Sanghavifceeaae2020-08-12 16:40:362059def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502060 """Checks to make sure no source files use UNIT_TEST."""
2061 problems = []
2062 for f in input_api.AffectedFiles():
2063 if (not f.LocalPath().endswith(('.cc', '.mm'))):
2064 continue
jam@chromium.org72df4e782012-06-21 16:28:182065
Sam Maiera6e76d72022-02-11 21:43:502066 for line_num, line in f.ChangedContents():
2067 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
2068 problems.append(' %s:%d' % (f.LocalPath(), line_num))
jam@chromium.org72df4e782012-06-21 16:28:182069
Sam Maiera6e76d72022-02-11 21:43:502070 if not problems:
2071 return []
2072 return [
2073 output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
2074 '\n'.join(problems))
2075 ]
2076
jam@chromium.org72df4e782012-06-21 16:28:182077
Saagar Sanghavifceeaae2020-08-12 16:40:362078def CheckNoDISABLETypoInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502079 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
Dominic Battre033531052018-09-24 15:45:342080
Sam Maiera6e76d72022-02-11 21:43:502081 This test warns if somebody tries to disable a test with the DISABLE_ prefix
2082 instead of DISABLED_. To filter false positives, reports are only generated
2083 if a corresponding MAYBE_ line exists.
2084 """
2085 problems = []
Dominic Battre033531052018-09-24 15:45:342086
Sam Maiera6e76d72022-02-11 21:43:502087 # The following two patterns are looked for in tandem - is a test labeled
2088 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
2089 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
2090 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
Dominic Battre033531052018-09-24 15:45:342091
Sam Maiera6e76d72022-02-11 21:43:502092 # This is for the case that a test is disabled on all platforms.
2093 full_disable_pattern = input_api.re.compile(
2094 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
2095 input_api.re.MULTILINE)
Dominic Battre033531052018-09-24 15:45:342096
Sam Maiera6e76d72022-02-11 21:43:502097 for f in input_api.AffectedFiles(False):
2098 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2099 continue
Dominic Battre033531052018-09-24 15:45:342100
Sam Maiera6e76d72022-02-11 21:43:502101 # Search for MABYE_, DISABLE_ pairs.
2102 disable_lines = {} # Maps of test name to line number.
2103 maybe_lines = {}
2104 for line_num, line in f.ChangedContents():
2105 disable_match = disable_pattern.search(line)
2106 if disable_match:
2107 disable_lines[disable_match.group(1)] = line_num
2108 maybe_match = maybe_pattern.search(line)
2109 if maybe_match:
2110 maybe_lines[maybe_match.group(1)] = line_num
Dominic Battre033531052018-09-24 15:45:342111
Sam Maiera6e76d72022-02-11 21:43:502112 # Search for DISABLE_ occurrences within a TEST() macro.
2113 disable_tests = set(disable_lines.keys())
2114 maybe_tests = set(maybe_lines.keys())
2115 for test in disable_tests.intersection(maybe_tests):
2116 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
Dominic Battre033531052018-09-24 15:45:342117
Sam Maiera6e76d72022-02-11 21:43:502118 contents = input_api.ReadFile(f)
2119 full_disable_match = full_disable_pattern.search(contents)
2120 if full_disable_match:
2121 problems.append(' %s' % f.LocalPath())
Dominic Battre033531052018-09-24 15:45:342122
Sam Maiera6e76d72022-02-11 21:43:502123 if not problems:
2124 return []
2125 return [
2126 output_api.PresubmitPromptWarning(
2127 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
2128 '\n'.join(problems))
2129 ]
2130
Dominic Battre033531052018-09-24 15:45:342131
Nina Satragnof7660532021-09-20 18:03:352132def CheckForgettingMAYBEInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502133 """Checks to make sure tests disabled conditionally are not missing a
2134 corresponding MAYBE_ prefix.
2135 """
2136 # Expect at least a lowercase character in the test name. This helps rule out
2137 # false positives with macros wrapping the actual tests name.
2138 define_maybe_pattern = input_api.re.compile(
2139 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
Bruce Dawsonffc55292022-04-20 04:18:192140 # The test_maybe_pattern needs to handle all of these forms. The standard:
2141 # IN_PROC_TEST_F(SyncTest, MAYBE_Start) {
2142 # With a wrapper macro around the test name:
2143 # IN_PROC_TEST_F(SyncTest, E2E_ENABLED(MAYBE_Start)) {
2144 # And the odd-ball NACL_BROWSER_TEST_f format:
2145 # NACL_BROWSER_TEST_F(NaClBrowserTest, SimpleLoad, {
2146 # The optional E2E_ENABLED-style is handled with (\w*\()?
2147 # The NACL_BROWSER_TEST_F pattern is handled by allowing a trailing comma or
2148 # trailing ')'.
2149 test_maybe_pattern = (
2150 r'^\s*\w*TEST[^(]*\(\s*\w+,\s*(\w*\()?MAYBE_{test_name}[\),]')
Sam Maiera6e76d72022-02-11 21:43:502151 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
2152 warnings = []
Nina Satragnof7660532021-09-20 18:03:352153
Sam Maiera6e76d72022-02-11 21:43:502154 # Read the entire files. We can't just read the affected lines, forgetting to
2155 # add MAYBE_ on a change would not show up otherwise.
2156 for f in input_api.AffectedFiles(False):
2157 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2158 continue
2159 contents = input_api.ReadFile(f)
2160 lines = contents.splitlines(True)
2161 current_position = 0
2162 warning_test_names = set()
2163 for line_num, line in enumerate(lines, start=1):
2164 current_position += len(line)
2165 maybe_match = define_maybe_pattern.search(line)
2166 if maybe_match:
2167 test_name = maybe_match.group('test_name')
2168 # Do not warn twice for the same test.
2169 if (test_name in warning_test_names):
2170 continue
2171 warning_test_names.add(test_name)
Nina Satragnof7660532021-09-20 18:03:352172
Sam Maiera6e76d72022-02-11 21:43:502173 # Attempt to find the corresponding MAYBE_ test or suite, starting from
2174 # the current position.
2175 test_match = input_api.re.compile(
2176 test_maybe_pattern.format(test_name=test_name),
2177 input_api.re.MULTILINE).search(contents, current_position)
2178 suite_match = input_api.re.compile(
2179 suite_maybe_pattern.format(test_name=test_name),
2180 input_api.re.MULTILINE).search(contents, current_position)
2181 if not test_match and not suite_match:
2182 warnings.append(
2183 output_api.PresubmitPromptWarning(
2184 '%s:%d found MAYBE_ defined without corresponding test %s'
2185 % (f.LocalPath(), line_num, test_name)))
2186 return warnings
2187
jam@chromium.org72df4e782012-06-21 16:28:182188
Saagar Sanghavifceeaae2020-08-12 16:40:362189def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502190 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
2191 errors = []
Kalvin Lee4a3b79de2022-05-26 16:00:162192 pattern = input_api.re.compile(r'\bDCHECK_IS_ON\b(?!\(\))',
Sam Maiera6e76d72022-02-11 21:43:502193 input_api.re.MULTILINE)
2194 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2195 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
2196 continue
2197 for lnum, line in f.ChangedContents():
2198 if input_api.re.search(pattern, line):
2199 errors.append(
2200 output_api.PresubmitError((
2201 '%s:%d: Use of DCHECK_IS_ON() must be written as "#if '
2202 + 'DCHECK_IS_ON()", not forgetting the parentheses.') %
2203 (f.LocalPath(), lnum)))
2204 return errors
danakj61c1aa22015-10-26 19:55:522205
2206
Weilun Shia487fad2020-10-28 00:10:342207# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
2208# more reliable way. See
2209# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:192210
wnwenbdc444e2016-05-25 13:44:152211
Saagar Sanghavifceeaae2020-08-12 16:40:362212def CheckFlakyTestUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502213 """Check that FlakyTest annotation is our own instead of the android one"""
2214 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
2215 files = []
2216 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2217 if f.LocalPath().endswith('Test.java'):
2218 if pattern.search(input_api.ReadFile(f)):
2219 files.append(f)
2220 if len(files):
2221 return [
2222 output_api.PresubmitError(
2223 'Use org.chromium.base.test.util.FlakyTest instead of '
2224 'android.test.FlakyTest', files)
2225 ]
2226 return []
mcasasb7440c282015-02-04 14:52:192227
wnwenbdc444e2016-05-25 13:44:152228
Saagar Sanghavifceeaae2020-08-12 16:40:362229def CheckNoDEPSGIT(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502230 """Make sure .DEPS.git is never modified manually."""
2231 if any(f.LocalPath().endswith('.DEPS.git')
2232 for f in input_api.AffectedFiles()):
2233 return [
2234 output_api.PresubmitError(
2235 'Never commit changes to .DEPS.git. This file is maintained by an\n'
2236 'automated system based on what\'s in DEPS and your changes will be\n'
2237 'overwritten.\n'
2238 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
2239 'get-the-code#Rolling_DEPS\n'
2240 'for more information')
2241 ]
2242 return []
maruel@chromium.org2a8ac9c2011-10-19 17:20:442243
2244
Sven Zheng76a79ea2022-12-21 21:25:242245def CheckCrosApiNeedBrowserTest(input_api, output_api):
2246 """Check new crosapi should add browser test."""
2247 has_new_crosapi = False
2248 has_browser_test = False
2249 for f in input_api.AffectedFiles():
2250 path = f.LocalPath()
2251 if (path.startswith('chromeos/crosapi/mojom') and
2252 _IsMojomFile(input_api, path) and f.Action() == 'A'):
2253 has_new_crosapi = True
2254 if path.endswith('browsertest.cc') or path.endswith('browser_test.cc'):
2255 has_browser_test = True
2256 if has_new_crosapi and not has_browser_test:
2257 return [
2258 output_api.PresubmitPromptWarning(
2259 'You are adding a new crosapi, but there is no file ends with '
2260 'browsertest.cc file being added or modified. It is important '
2261 'to add crosapi browser test coverage to avoid version '
2262 ' skew issues.\n'
2263 'Check //docs/lacros/test_instructions.md for more information.'
2264 )
2265 ]
2266 return []
2267
2268
Saagar Sanghavifceeaae2020-08-12 16:40:362269def CheckValidHostsInDEPSOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502270 """Checks that DEPS file deps are from allowed_hosts."""
2271 # Run only if DEPS file has been modified to annoy fewer bystanders.
2272 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
2273 return []
2274 # Outsource work to gclient verify
2275 try:
2276 gclient_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
2277 'third_party', 'depot_tools',
2278 'gclient.py')
2279 input_api.subprocess.check_output(
Bruce Dawson8a43cf72022-05-13 17:10:322280 [input_api.python3_executable, gclient_path, 'verify'],
Sam Maiera6e76d72022-02-11 21:43:502281 stderr=input_api.subprocess.STDOUT)
2282 return []
2283 except input_api.subprocess.CalledProcessError as error:
2284 return [
2285 output_api.PresubmitError(
2286 'DEPS file must have only git dependencies.',
2287 long_text=error.output)
2288 ]
tandriief664692014-09-23 14:51:472289
2290
Mario Sanchez Prada2472cab2019-09-18 10:58:312291def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152292 ban_rule):
Allen Bauer84778682022-09-22 16:28:562293 """Helper method for checking for banned constructs.
Mario Sanchez Prada2472cab2019-09-18 10:58:312294
Sam Maiera6e76d72022-02-11 21:43:502295 Returns an string composed of the name of the file, the line number where the
2296 match has been found and the additional text passed as |message| in case the
2297 target type name matches the text inside the line passed as parameter.
2298 """
2299 result = []
Peng Huang9c5949a02020-06-11 19:20:542300
Daniel Chenga44a1bcd2022-03-15 20:00:152301 # Ignore comments about banned types.
2302 if input_api.re.search(r"^ *//", line):
Sam Maiera6e76d72022-02-11 21:43:502303 return result
Daniel Chenga44a1bcd2022-03-15 20:00:152304 # A // nocheck comment will bypass this error.
2305 if line.endswith(" nocheck"):
Sam Maiera6e76d72022-02-11 21:43:502306 return result
2307
2308 matched = False
Daniel Chenga44a1bcd2022-03-15 20:00:152309 if ban_rule.pattern[0:1] == '/':
2310 regex = ban_rule.pattern[1:]
Sam Maiera6e76d72022-02-11 21:43:502311 if input_api.re.search(regex, line):
2312 matched = True
Daniel Chenga44a1bcd2022-03-15 20:00:152313 elif ban_rule.pattern in line:
Sam Maiera6e76d72022-02-11 21:43:502314 matched = True
2315
2316 if matched:
2317 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
Daniel Chenga44a1bcd2022-03-15 20:00:152318 for line in ban_rule.explanation:
2319 result.append(' %s' % line)
Sam Maiera6e76d72022-02-11 21:43:502320
danakjd18e8892020-12-17 17:42:012321 return result
Mario Sanchez Prada2472cab2019-09-18 10:58:312322
2323
Saagar Sanghavifceeaae2020-08-12 16:40:362324def CheckNoBannedFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502325 """Make sure that banned functions are not used."""
2326 warnings = []
2327 errors = []
avi@chromium.org127f18ec2012-06-16 05:05:592328
Sam Maiera6e76d72022-02-11 21:43:502329 def IsExcludedFile(affected_file, excluded_paths):
Daniel Chenga44a1bcd2022-03-15 20:00:152330 if not excluded_paths:
2331 return False
2332
Sam Maiera6e76d72022-02-11 21:43:502333 local_path = affected_file.LocalPath()
Bruce Dawson40fece62022-09-16 19:58:312334 # Consistently use / as path separator to simplify the writing of regex
2335 # expressions.
2336 local_path = local_path.replace(input_api.os_path.sep, '/')
Sam Maiera6e76d72022-02-11 21:43:502337 for item in excluded_paths:
2338 if input_api.re.match(item, local_path):
2339 return True
2340 return False
wnwenbdc444e2016-05-25 13:44:152341
Sam Maiera6e76d72022-02-11 21:43:502342 def IsIosObjcFile(affected_file):
2343 local_path = affected_file.LocalPath()
2344 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m',
2345 '.h'):
2346 return False
2347 basename = input_api.os_path.basename(local_path)
2348 if 'ios' in basename.split('_'):
2349 return True
2350 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
2351 if sep and 'ios' in local_path.split(sep):
2352 return True
2353 return False
Sylvain Defresnea8b73d252018-02-28 15:45:542354
Daniel Chenga44a1bcd2022-03-15 20:00:152355 def CheckForMatch(affected_file, line_num: int, line: str,
2356 ban_rule: BanRule):
2357 if IsExcludedFile(affected_file, ban_rule.excluded_paths):
2358 return
2359
Sam Maiera6e76d72022-02-11 21:43:502360 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152361 ban_rule)
Sam Maiera6e76d72022-02-11 21:43:502362 if problems:
Daniel Chenga44a1bcd2022-03-15 20:00:152363 if ban_rule.treat_as_error is not None and ban_rule.treat_as_error:
Sam Maiera6e76d72022-02-11 21:43:502364 errors.extend(problems)
2365 else:
2366 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:152367
Sam Maiera6e76d72022-02-11 21:43:502368 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2369 for f in input_api.AffectedFiles(file_filter=file_filter):
2370 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152371 for ban_rule in _BANNED_JAVA_FUNCTIONS:
2372 CheckForMatch(f, line_num, line, ban_rule)
Eric Stevensona9a980972017-09-23 00:04:412373
Clement Yan9b330cb2022-11-17 05:25:292374 file_filter = lambda f: f.LocalPath().endswith(('.js', '.ts'))
2375 for f in input_api.AffectedFiles(file_filter=file_filter):
2376 for line_num, line in f.ChangedContents():
2377 for ban_rule in _BANNED_JAVASCRIPT_FUNCTIONS:
2378 CheckForMatch(f, line_num, line, ban_rule)
2379
Sam Maiera6e76d72022-02-11 21:43:502380 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
2381 for f in input_api.AffectedFiles(file_filter=file_filter):
2382 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152383 for ban_rule in _BANNED_OBJC_FUNCTIONS:
2384 CheckForMatch(f, line_num, line, ban_rule)
avi@chromium.org127f18ec2012-06-16 05:05:592385
Sam Maiera6e76d72022-02-11 21:43:502386 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
2387 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152388 for ban_rule in _BANNED_IOS_OBJC_FUNCTIONS:
2389 CheckForMatch(f, line_num, line, ban_rule)
Sylvain Defresnea8b73d252018-02-28 15:45:542390
Sam Maiera6e76d72022-02-11 21:43:502391 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
2392 for f in input_api.AffectedFiles(file_filter=egtest_filter):
2393 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152394 for ban_rule in _BANNED_IOS_EGTEST_FUNCTIONS:
2395 CheckForMatch(f, line_num, line, ban_rule)
Peter K. Lee6c03ccff2019-07-15 14:40:052396
Sam Maiera6e76d72022-02-11 21:43:502397 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
2398 for f in input_api.AffectedFiles(file_filter=file_filter):
2399 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152400 for ban_rule in _BANNED_CPP_FUNCTIONS:
2401 CheckForMatch(f, line_num, line, ban_rule)
avi@chromium.org127f18ec2012-06-16 05:05:592402
Daniel Cheng92c15e32022-03-16 17:48:222403 file_filter = lambda f: f.LocalPath().endswith(('.mojom'))
2404 for f in input_api.AffectedFiles(file_filter=file_filter):
2405 for line_num, line in f.ChangedContents():
2406 for ban_rule in _BANNED_MOJOM_PATTERNS:
2407 CheckForMatch(f, line_num, line, ban_rule)
2408
2409
Sam Maiera6e76d72022-02-11 21:43:502410 result = []
2411 if (warnings):
2412 result.append(
2413 output_api.PresubmitPromptWarning('Banned functions were used.\n' +
2414 '\n'.join(warnings)))
2415 if (errors):
2416 result.append(
2417 output_api.PresubmitError('Banned functions were used.\n' +
2418 '\n'.join(errors)))
2419 return result
avi@chromium.org127f18ec2012-06-16 05:05:592420
Allen Bauer84778682022-09-22 16:28:562421def CheckNoLayoutCallsInTests(input_api, output_api):
2422 """Make sure there are no explicit calls to View::Layout() in tests"""
2423 warnings = []
2424 ban_rule = BanRule(
2425 r'/(\.|->)Layout\(\);',
2426 (
2427 'Direct calls to View::Layout() are not allowed in tests. '
2428 'If the view must be laid out here, use RunScheduledLayout(view). It '
2429 'is found in //ui/views/test/views_test_utils.h. '
2430 'See http://crbug.com/1350521 for more details.',
2431 ),
2432 False,
2433 )
2434 file_filter = lambda f: input_api.re.search(
2435 r'_(unittest|browsertest|ui_test).*\.(cc|mm)$', f.LocalPath())
2436 for f in input_api.AffectedFiles(file_filter = file_filter):
2437 for line_num, line in f.ChangedContents():
2438 problems = _GetMessageForMatchingType(input_api, f,
2439 line_num, line,
2440 ban_rule)
2441 if problems:
2442 warnings.extend(problems)
2443 result = []
2444 if (warnings):
2445 result.append(
2446 output_api.PresubmitPromptWarning(
2447 'Banned call to View::Layout() in tests.\n\n'.join(warnings)))
2448 return result
avi@chromium.org127f18ec2012-06-16 05:05:592449
Michael Thiessen44457642020-02-06 00:24:152450def _CheckAndroidNoBannedImports(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502451 """Make sure that banned java imports are not used."""
2452 errors = []
Michael Thiessen44457642020-02-06 00:24:152453
Sam Maiera6e76d72022-02-11 21:43:502454 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2455 for f in input_api.AffectedFiles(file_filter=file_filter):
2456 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152457 for ban_rule in _BANNED_JAVA_IMPORTS:
2458 # Consider merging this into the above function. There is no
2459 # real difference anymore other than helping with a little
2460 # bit of boilerplate text. Doing so means things like
2461 # `treat_as_error` will also be uniformly handled.
Sam Maiera6e76d72022-02-11 21:43:502462 problems = _GetMessageForMatchingType(input_api, f, line_num,
Daniel Chenga44a1bcd2022-03-15 20:00:152463 line, ban_rule)
Sam Maiera6e76d72022-02-11 21:43:502464 if problems:
2465 errors.extend(problems)
2466 result = []
2467 if (errors):
2468 result.append(
2469 output_api.PresubmitError('Banned imports were used.\n' +
2470 '\n'.join(errors)))
2471 return result
Michael Thiessen44457642020-02-06 00:24:152472
2473
Saagar Sanghavifceeaae2020-08-12 16:40:362474def CheckNoPragmaOnce(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502475 """Make sure that banned functions are not used."""
2476 files = []
2477 pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
2478 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2479 if not f.LocalPath().endswith('.h'):
2480 continue
Bruce Dawson4c4c2922022-05-02 18:07:332481 if f.LocalPath().endswith('com_imported_mstscax.h'):
2482 continue
Sam Maiera6e76d72022-02-11 21:43:502483 contents = input_api.ReadFile(f)
2484 if pattern.search(contents):
2485 files.append(f)
dcheng@chromium.org6c063c62012-07-11 19:11:062486
Sam Maiera6e76d72022-02-11 21:43:502487 if files:
2488 return [
2489 output_api.PresubmitError(
2490 'Do not use #pragma once in header files.\n'
2491 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
2492 files)
2493 ]
2494 return []
dcheng@chromium.org6c063c62012-07-11 19:11:062495
avi@chromium.org127f18ec2012-06-16 05:05:592496
Saagar Sanghavifceeaae2020-08-12 16:40:362497def CheckNoTrinaryTrueFalse(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502498 """Checks to make sure we don't introduce use of foo ? true : false."""
2499 problems = []
2500 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
2501 for f in input_api.AffectedFiles():
2502 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2503 continue
thestig@chromium.orge7479052012-09-19 00:26:122504
Sam Maiera6e76d72022-02-11 21:43:502505 for line_num, line in f.ChangedContents():
2506 if pattern.match(line):
2507 problems.append(' %s:%d' % (f.LocalPath(), line_num))
thestig@chromium.orge7479052012-09-19 00:26:122508
Sam Maiera6e76d72022-02-11 21:43:502509 if not problems:
2510 return []
2511 return [
2512 output_api.PresubmitPromptWarning(
2513 'Please consider avoiding the "? true : false" pattern if possible.\n'
2514 + '\n'.join(problems))
2515 ]
thestig@chromium.orge7479052012-09-19 00:26:122516
2517
Saagar Sanghavifceeaae2020-08-12 16:40:362518def CheckUnwantedDependencies(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502519 """Runs checkdeps on #include and import statements added in this
2520 change. Breaking - rules is an error, breaking ! rules is a
2521 warning.
2522 """
2523 # Return early if no relevant file types were modified.
2524 for f in input_api.AffectedFiles():
2525 path = f.LocalPath()
2526 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path)
2527 or _IsJavaFile(input_api, path)):
2528 break
joi@chromium.org55f9f382012-07-31 11:02:182529 else:
Sam Maiera6e76d72022-02-11 21:43:502530 return []
rhalavati08acd232017-04-03 07:23:282531
Sam Maiera6e76d72022-02-11 21:43:502532 import sys
2533 # We need to wait until we have an input_api object and use this
2534 # roundabout construct to import checkdeps because this file is
2535 # eval-ed and thus doesn't have __file__.
2536 original_sys_path = sys.path
2537 try:
2538 sys.path = sys.path + [
2539 input_api.os_path.join(input_api.PresubmitLocalPath(),
2540 'buildtools', 'checkdeps')
2541 ]
2542 import checkdeps
2543 from rules import Rule
2544 finally:
2545 # Restore sys.path to what it was before.
2546 sys.path = original_sys_path
joi@chromium.org55f9f382012-07-31 11:02:182547
Sam Maiera6e76d72022-02-11 21:43:502548 added_includes = []
2549 added_imports = []
2550 added_java_imports = []
2551 for f in input_api.AffectedFiles():
2552 if _IsCPlusPlusFile(input_api, f.LocalPath()):
2553 changed_lines = [line for _, line in f.ChangedContents()]
2554 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
2555 elif _IsProtoFile(input_api, f.LocalPath()):
2556 changed_lines = [line for _, line in f.ChangedContents()]
2557 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
2558 elif _IsJavaFile(input_api, f.LocalPath()):
2559 changed_lines = [line for _, line in f.ChangedContents()]
2560 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:242561
Sam Maiera6e76d72022-02-11 21:43:502562 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
2563
2564 error_descriptions = []
2565 warning_descriptions = []
2566 error_subjects = set()
2567 warning_subjects = set()
2568
2569 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2570 added_includes):
2571 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2572 description_with_path = '%s\n %s' % (path, rule_description)
2573 if rule_type == Rule.DISALLOW:
2574 error_descriptions.append(description_with_path)
2575 error_subjects.add("#includes")
2576 else:
2577 warning_descriptions.append(description_with_path)
2578 warning_subjects.add("#includes")
2579
2580 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2581 added_imports):
2582 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2583 description_with_path = '%s\n %s' % (path, rule_description)
2584 if rule_type == Rule.DISALLOW:
2585 error_descriptions.append(description_with_path)
2586 error_subjects.add("imports")
2587 else:
2588 warning_descriptions.append(description_with_path)
2589 warning_subjects.add("imports")
2590
2591 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
2592 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
2593 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2594 description_with_path = '%s\n %s' % (path, rule_description)
2595 if rule_type == Rule.DISALLOW:
2596 error_descriptions.append(description_with_path)
2597 error_subjects.add("imports")
2598 else:
2599 warning_descriptions.append(description_with_path)
2600 warning_subjects.add("imports")
2601
2602 results = []
2603 if error_descriptions:
2604 results.append(
2605 output_api.PresubmitError(
2606 'You added one or more %s that violate checkdeps rules.' %
2607 " and ".join(error_subjects), error_descriptions))
2608 if warning_descriptions:
2609 results.append(
2610 output_api.PresubmitPromptOrNotify(
2611 'You added one or more %s of files that are temporarily\n'
2612 'allowed but being removed. Can you avoid introducing the\n'
2613 '%s? See relevant DEPS file(s) for details and contacts.' %
2614 (" and ".join(warning_subjects), "/".join(warning_subjects)),
2615 warning_descriptions))
2616 return results
joi@chromium.org55f9f382012-07-31 11:02:182617
2618
Saagar Sanghavifceeaae2020-08-12 16:40:362619def CheckFilePermissions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502620 """Check that all files have their permissions properly set."""
2621 if input_api.platform == 'win32':
2622 return []
2623 checkperms_tool = input_api.os_path.join(input_api.PresubmitLocalPath(),
2624 'tools', 'checkperms',
2625 'checkperms.py')
2626 args = [
Bruce Dawson8a43cf72022-05-13 17:10:322627 input_api.python3_executable, checkperms_tool, '--root',
Sam Maiera6e76d72022-02-11 21:43:502628 input_api.change.RepositoryRoot()
2629 ]
2630 with input_api.CreateTemporaryFile() as file_list:
2631 for f in input_api.AffectedFiles():
2632 # checkperms.py file/directory arguments must be relative to the
2633 # repository.
2634 file_list.write((f.LocalPath() + '\n').encode('utf8'))
2635 file_list.close()
2636 args += ['--file-list', file_list.name]
2637 try:
2638 input_api.subprocess.check_output(args)
2639 return []
2640 except input_api.subprocess.CalledProcessError as error:
2641 return [
2642 output_api.PresubmitError('checkperms.py failed:',
2643 long_text=error.output.decode(
2644 'utf-8', 'ignore'))
2645 ]
csharp@chromium.orgfbcafe5a2012-08-08 15:31:222646
2647
Saagar Sanghavifceeaae2020-08-12 16:40:362648def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502649 """Makes sure we don't include ui/aura/window_property.h
2650 in header files.
2651 """
2652 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2653 errors = []
2654 for f in input_api.AffectedFiles():
2655 if not f.LocalPath().endswith('.h'):
2656 continue
2657 for line_num, line in f.ChangedContents():
2658 if pattern.match(line):
2659 errors.append(' %s:%d' % (f.LocalPath(), line_num))
oshima@chromium.orgc8278b32012-10-30 20:35:492660
Sam Maiera6e76d72022-02-11 21:43:502661 results = []
2662 if errors:
2663 results.append(
2664 output_api.PresubmitError(
2665 'Header files should not include ui/aura/window_property.h',
2666 errors))
2667 return results
oshima@chromium.orgc8278b32012-10-30 20:35:492668
2669
Omer Katzcc77ea92021-04-26 10:23:282670def CheckNoInternalHeapIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502671 """Makes sure we don't include any headers from
2672 third_party/blink/renderer/platform/heap/impl or
2673 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
2674 third_party/blink/renderer/platform/heap
2675 """
2676 impl_pattern = input_api.re.compile(
2677 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
2678 v8_wrapper_pattern = input_api.re.compile(
2679 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"'
2680 )
Bruce Dawson40fece62022-09-16 19:58:312681 # Consistently use / as path separator to simplify the writing of regex
2682 # expressions.
Sam Maiera6e76d72022-02-11 21:43:502683 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:312684 r"^third_party/blink/renderer/platform/heap/.*",
2685 f.LocalPath().replace(input_api.os_path.sep, '/'))
Sam Maiera6e76d72022-02-11 21:43:502686 errors = []
Omer Katzcc77ea92021-04-26 10:23:282687
Sam Maiera6e76d72022-02-11 21:43:502688 for f in input_api.AffectedFiles(file_filter=file_filter):
2689 for line_num, line in f.ChangedContents():
2690 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
2691 errors.append(' %s:%d' % (f.LocalPath(), line_num))
Omer Katzcc77ea92021-04-26 10:23:282692
Sam Maiera6e76d72022-02-11 21:43:502693 results = []
2694 if errors:
2695 results.append(
2696 output_api.PresubmitError(
2697 'Do not include files from third_party/blink/renderer/platform/heap/impl'
2698 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
2699 'relevant counterparts from third_party/blink/renderer/platform/heap',
2700 errors))
2701 return results
Omer Katzcc77ea92021-04-26 10:23:282702
2703
dbeam@chromium.org70ca77752012-11-20 03:45:032704def _CheckForVersionControlConflictsInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:502705 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2706 errors = []
2707 for line_num, line in f.ChangedContents():
2708 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
2709 # First-level headers in markdown look a lot like version control
2710 # conflict markers. http://daringfireball.net/projects/markdown/basics
2711 continue
2712 if pattern.match(line):
2713 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2714 return errors
dbeam@chromium.org70ca77752012-11-20 03:45:032715
2716
Saagar Sanghavifceeaae2020-08-12 16:40:362717def CheckForVersionControlConflicts(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502718 """Usually this is not intentional and will cause a compile failure."""
2719 errors = []
2720 for f in input_api.AffectedFiles():
2721 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
dbeam@chromium.org70ca77752012-11-20 03:45:032722
Sam Maiera6e76d72022-02-11 21:43:502723 results = []
2724 if errors:
2725 results.append(
2726 output_api.PresubmitError(
2727 'Version control conflict markers found, please resolve.',
2728 errors))
2729 return results
dbeam@chromium.org70ca77752012-11-20 03:45:032730
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202731
Saagar Sanghavifceeaae2020-08-12 16:40:362732def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502733 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2734 errors = []
2735 for f in input_api.AffectedFiles():
2736 for line_num, line in f.ChangedContents():
2737 if pattern.search(line):
2738 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
estadee17314a02017-01-12 16:22:162739
Sam Maiera6e76d72022-02-11 21:43:502740 results = []
2741 if errors:
2742 results.append(
2743 output_api.PresubmitPromptWarning(
2744 'Found Google support URL addressed by answer number. Please replace '
2745 'with a p= identifier instead. See crbug.com/679462\n',
2746 errors))
2747 return results
estadee17314a02017-01-12 16:22:162748
dbeam@chromium.org70ca77752012-11-20 03:45:032749
Saagar Sanghavifceeaae2020-08-12 16:40:362750def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502751 def FilterFile(affected_file):
2752 """Filter function for use with input_api.AffectedSourceFiles,
2753 below. This filters out everything except non-test files from
2754 top-level directories that generally speaking should not hard-code
2755 service URLs (e.g. src/android_webview/, src/content/ and others).
2756 """
2757 return input_api.FilterSourceFile(
2758 affected_file,
Bruce Dawson40fece62022-09-16 19:58:312759 files_to_check=[r'^(android_webview|base|content|net)/.*'],
Sam Maiera6e76d72022-02-11 21:43:502760 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2761 input_api.DEFAULT_FILES_TO_SKIP))
joi@chromium.org06e6d0ff2012-12-11 01:36:442762
Sam Maiera6e76d72022-02-11 21:43:502763 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2764 '\.(com|net)[^"]*"')
2765 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2766 pattern = input_api.re.compile(base_pattern)
2767 problems = [] # items are (filename, line_number, line)
2768 for f in input_api.AffectedSourceFiles(FilterFile):
2769 for line_num, line in f.ChangedContents():
2770 if not comment_pattern.search(line) and pattern.search(line):
2771 problems.append((f.LocalPath(), line_num, line))
joi@chromium.org06e6d0ff2012-12-11 01:36:442772
Sam Maiera6e76d72022-02-11 21:43:502773 if problems:
2774 return [
2775 output_api.PresubmitPromptOrNotify(
2776 'Most layers below src/chrome/ should not hardcode service URLs.\n'
2777 'Are you sure this is correct?', [
2778 ' %s:%d: %s' % (problem[0], problem[1], problem[2])
2779 for problem in problems
2780 ])
2781 ]
2782 else:
2783 return []
joi@chromium.org06e6d0ff2012-12-11 01:36:442784
2785
Saagar Sanghavifceeaae2020-08-12 16:40:362786def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502787 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
James Cook6b6597c2019-11-06 22:05:292788
Sam Maiera6e76d72022-02-11 21:43:502789 def FileFilter(affected_file):
2790 """Includes directories known to be Chrome OS only."""
2791 return input_api.FilterSourceFile(
2792 affected_file,
2793 files_to_check=(
2794 '^ash/',
2795 '^chromeos/', # Top-level src/chromeos.
2796 '.*/chromeos/', # Any path component.
2797 '^components/arc',
2798 '^components/exo'),
2799 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292800
Sam Maiera6e76d72022-02-11 21:43:502801 prefs = []
2802 priority_prefs = []
2803 for f in input_api.AffectedFiles(file_filter=FileFilter):
2804 for line_num, line in f.ChangedContents():
2805 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF',
2806 line):
2807 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2808 prefs.append(' %s' % line)
2809 if input_api.re.search(
2810 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2811 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2812 priority_prefs.append(' %s' % line)
2813
2814 results = []
2815 if (prefs):
2816 results.append(
2817 output_api.PresubmitPromptWarning(
2818 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2819 'by browser sync settings. If these prefs should be controlled by OS '
2820 'sync settings use SYNCABLE_OS_PREF instead.\n' +
2821 '\n'.join(prefs)))
2822 if (priority_prefs):
2823 results.append(
2824 output_api.PresubmitPromptWarning(
2825 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2826 'controlled by browser sync settings. If these prefs should be '
2827 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2828 'instead.\n' + '\n'.join(prefs)))
2829 return results
James Cook6b6597c2019-11-06 22:05:292830
2831
Saagar Sanghavifceeaae2020-08-12 16:40:362832def CheckNoAbbreviationInPngFileName(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502833 """Makes sure there are no abbreviations in the name of PNG files.
2834 The native_client_sdk directory is excluded because it has auto-generated PNG
2835 files for documentation.
2836 """
2837 errors = []
Yuanqing Zhu9eef02832022-12-04 14:42:172838 files_to_check = [r'.*\.png$']
Bruce Dawson40fece62022-09-16 19:58:312839 files_to_skip = [r'^native_client_sdk/',
2840 r'^services/test/',
2841 r'^third_party/blink/web_tests/',
Bruce Dawson3db456212022-05-02 05:34:182842 ]
Sam Maiera6e76d72022-02-11 21:43:502843 file_filter = lambda f: input_api.FilterSourceFile(
2844 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Yuanqing Zhu9eef02832022-12-04 14:42:172845 abbreviation = input_api.re.compile('.+_[a-z]\.png|.+_[a-z]_.*\.png')
Sam Maiera6e76d72022-02-11 21:43:502846 for f in input_api.AffectedFiles(include_deletes=False,
2847 file_filter=file_filter):
Yuanqing Zhu9eef02832022-12-04 14:42:172848 file_name = input_api.os_path.split(f.LocalPath())[1]
2849 if abbreviation.search(file_name):
2850 errors.append(' %s' % f.LocalPath())
oshima@chromium.orgd2530012013-01-25 16:39:272851
Sam Maiera6e76d72022-02-11 21:43:502852 results = []
2853 if errors:
2854 results.append(
2855 output_api.PresubmitError(
2856 'The name of PNG files should not have abbreviations. \n'
2857 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2858 'Contact oshima@chromium.org if you have questions.', errors))
2859 return results
oshima@chromium.orgd2530012013-01-25 16:39:272860
Evan Stade7cd4a2c2022-08-04 23:37:252861def CheckNoProductIconsAddedToPublicRepo(input_api, output_api):
2862 """Heuristically identifies product icons based on their file name and reminds
2863 contributors not to add them to the Chromium repository.
2864 """
2865 errors = []
2866 files_to_check = [r'.*google.*\.png$|.*google.*\.svg$|.*google.*\.icon$']
2867 file_filter = lambda f: input_api.FilterSourceFile(
2868 f, files_to_check=files_to_check)
2869 for f in input_api.AffectedFiles(include_deletes=False,
2870 file_filter=file_filter):
2871 errors.append(' %s' % f.LocalPath())
2872
2873 results = []
2874 if errors:
Bruce Dawson3bcf0c92022-08-12 00:03:082875 # Give warnings instead of errors on presubmit --all and presubmit
2876 # --files.
2877 message_type = (output_api.PresubmitNotifyResult if input_api.no_diffs
2878 else output_api.PresubmitError)
Evan Stade7cd4a2c2022-08-04 23:37:252879 results.append(
Bruce Dawson3bcf0c92022-08-12 00:03:082880 message_type(
Evan Stade7cd4a2c2022-08-04 23:37:252881 'Trademarked images should not be added to the public repo. '
2882 'See crbug.com/944754', errors))
2883 return results
2884
oshima@chromium.orgd2530012013-01-25 16:39:272885
Daniel Cheng4dcdb6b2017-04-13 08:30:172886def _ExtractAddRulesFromParsedDeps(parsed_deps):
Sam Maiera6e76d72022-02-11 21:43:502887 """Extract the rules that add dependencies from a parsed DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172888
Sam Maiera6e76d72022-02-11 21:43:502889 Args:
2890 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2891 add_rules = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172892 add_rules.update([
Sam Maiera6e76d72022-02-11 21:43:502893 rule[1:] for rule in parsed_deps.get('include_rules', [])
Daniel Cheng4dcdb6b2017-04-13 08:30:172894 if rule.startswith('+') or rule.startswith('!')
2895 ])
Sam Maiera6e76d72022-02-11 21:43:502896 for _, rules in parsed_deps.get('specific_include_rules', {}).items():
2897 add_rules.update([
2898 rule[1:] for rule in rules
2899 if rule.startswith('+') or rule.startswith('!')
2900 ])
2901 return add_rules
Daniel Cheng4dcdb6b2017-04-13 08:30:172902
2903
2904def _ParseDeps(contents):
Sam Maiera6e76d72022-02-11 21:43:502905 """Simple helper for parsing DEPS files."""
Daniel Cheng4dcdb6b2017-04-13 08:30:172906
Sam Maiera6e76d72022-02-11 21:43:502907 # Stubs for handling special syntax in the root DEPS file.
2908 class _VarImpl:
2909 def __init__(self, local_scope):
2910 self._local_scope = local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172911
Sam Maiera6e76d72022-02-11 21:43:502912 def Lookup(self, var_name):
2913 """Implements the Var syntax."""
2914 try:
2915 return self._local_scope['vars'][var_name]
2916 except KeyError:
2917 raise Exception('Var is not defined: %s' % var_name)
Daniel Cheng4dcdb6b2017-04-13 08:30:172918
Sam Maiera6e76d72022-02-11 21:43:502919 local_scope = {}
2920 global_scope = {
2921 'Var': _VarImpl(local_scope).Lookup,
2922 'Str': str,
2923 }
Dirk Pranke1b9e06382021-05-14 01:16:222924
Sam Maiera6e76d72022-02-11 21:43:502925 exec(contents, global_scope, local_scope)
2926 return local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172927
2928
2929def _CalculateAddedDeps(os_path, old_contents, new_contents):
Sam Maiera6e76d72022-02-11 21:43:502930 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
2931 a set of DEPS entries that we should look up.
joi@chromium.org14a6131c2014-01-08 01:15:412932
Sam Maiera6e76d72022-02-11 21:43:502933 For a directory (rather than a specific filename) we fake a path to
2934 a specific filename by adding /DEPS. This is chosen as a file that
2935 will seldom or never be subject to per-file include_rules.
2936 """
2937 # We ignore deps entries on auto-generated directories.
2938 AUTO_GENERATED_DIRS = ['grit', 'jni']
tony@chromium.orgf32e2d1e2013-07-26 21:39:082939
Sam Maiera6e76d72022-02-11 21:43:502940 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2941 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
Daniel Cheng4dcdb6b2017-04-13 08:30:172942
Sam Maiera6e76d72022-02-11 21:43:502943 added_deps = new_deps.difference(old_deps)
Daniel Cheng4dcdb6b2017-04-13 08:30:172944
Sam Maiera6e76d72022-02-11 21:43:502945 results = set()
2946 for added_dep in added_deps:
2947 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2948 continue
2949 # Assume that a rule that ends in .h is a rule for a specific file.
2950 if added_dep.endswith('.h'):
2951 results.add(added_dep)
2952 else:
2953 results.add(os_path.join(added_dep, 'DEPS'))
2954 return results
tony@chromium.orgf32e2d1e2013-07-26 21:39:082955
2956
Saagar Sanghavifceeaae2020-08-12 16:40:362957def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502958 """When a dependency prefixed with + is added to a DEPS file, we
2959 want to make sure that the change is reviewed by an OWNER of the
2960 target file or directory, to avoid layering violations from being
2961 introduced. This check verifies that this happens.
2962 """
2963 # We rely on Gerrit's code-owners to check approvals.
2964 # input_api.gerrit is always set for Chromium, but other projects
2965 # might not use Gerrit.
Bruce Dawson344ab262022-06-04 11:35:102966 if not input_api.gerrit or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:502967 return []
Bruce Dawsonb357aeb2022-08-09 15:38:302968 if 'PRESUBMIT_SKIP_NETWORK' in input_api.environ:
Sam Maiera6e76d72022-02-11 21:43:502969 return []
Bruce Dawsonb357aeb2022-08-09 15:38:302970 try:
2971 if (input_api.change.issue and
2972 input_api.gerrit.IsOwnersOverrideApproved(
2973 input_api.change.issue)):
2974 # Skip OWNERS check when Owners-Override label is approved. This is
2975 # intended for global owners, trusted bots, and on-call sheriffs.
2976 # Review is still required for these changes.
2977 return []
2978 except Exception as e:
Sam Maier4cef9242022-10-03 14:21:242979 return [output_api.PresubmitPromptWarning(
2980 'Failed to retrieve owner override status - %s' % str(e))]
Edward Lesmes6fba51082021-01-20 04:20:232981
Sam Maiera6e76d72022-02-11 21:43:502982 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242983
Bruce Dawson40fece62022-09-16 19:58:312984 # Consistently use / as path separator to simplify the writing of regex
2985 # expressions.
Sam Maiera6e76d72022-02-11 21:43:502986 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:312987 r"^third_party/blink/.*",
2988 f.LocalPath().replace(input_api.os_path.sep, '/'))
Sam Maiera6e76d72022-02-11 21:43:502989 for f in input_api.AffectedFiles(include_deletes=False,
2990 file_filter=file_filter):
2991 filename = input_api.os_path.basename(f.LocalPath())
2992 if filename == 'DEPS':
2993 virtual_depended_on_files.update(
2994 _CalculateAddedDeps(input_api.os_path,
2995 '\n'.join(f.OldContents()),
2996 '\n'.join(f.NewContents())))
joi@chromium.orge871964c2013-05-13 14:14:552997
Sam Maiera6e76d72022-02-11 21:43:502998 if not virtual_depended_on_files:
2999 return []
joi@chromium.orge871964c2013-05-13 14:14:553000
Sam Maiera6e76d72022-02-11 21:43:503001 if input_api.is_committing:
3002 if input_api.tbr:
3003 return [
3004 output_api.PresubmitNotifyResult(
3005 '--tbr was specified, skipping OWNERS check for DEPS additions'
3006 )
3007 ]
Daniel Cheng3008dc12022-05-13 04:02:113008 # TODO(dcheng): Make this generate an error on dry runs if the reviewer
3009 # is not added, to prevent review serialization.
Sam Maiera6e76d72022-02-11 21:43:503010 if input_api.dry_run:
3011 return [
3012 output_api.PresubmitNotifyResult(
3013 'This is a dry run, skipping OWNERS check for DEPS additions'
3014 )
3015 ]
3016 if not input_api.change.issue:
3017 return [
3018 output_api.PresubmitError(
3019 "DEPS approval by OWNERS check failed: this change has "
3020 "no change number, so we can't check it for approvals.")
3021 ]
3022 output = output_api.PresubmitError
joi@chromium.org14a6131c2014-01-08 01:15:413023 else:
Sam Maiera6e76d72022-02-11 21:43:503024 output = output_api.PresubmitNotifyResult
joi@chromium.orge871964c2013-05-13 14:14:553025
Sam Maiera6e76d72022-02-11 21:43:503026 owner_email, reviewers = (
3027 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3028 input_api, None, approval_needed=input_api.is_committing))
joi@chromium.orge871964c2013-05-13 14:14:553029
Sam Maiera6e76d72022-02-11 21:43:503030 owner_email = owner_email or input_api.change.author_email
3031
3032 approval_status = input_api.owners_client.GetFilesApprovalStatus(
3033 virtual_depended_on_files, reviewers.union([owner_email]), [])
3034 missing_files = [
3035 f for f in virtual_depended_on_files
3036 if approval_status[f] != input_api.owners_client.APPROVED
3037 ]
3038
3039 # We strip the /DEPS part that was added by
3040 # _FilesToCheckForIncomingDeps to fake a path to a file in a
3041 # directory.
3042 def StripDeps(path):
3043 start_deps = path.rfind('/DEPS')
3044 if start_deps != -1:
3045 return path[:start_deps]
3046 else:
3047 return path
3048
3049 unapproved_dependencies = [
3050 "'+%s'," % StripDeps(path) for path in missing_files
3051 ]
3052
3053 if unapproved_dependencies:
3054 output_list = [
3055 output(
3056 'You need LGTM from owners of depends-on paths in DEPS that were '
3057 'modified in this CL:\n %s' %
3058 '\n '.join(sorted(unapproved_dependencies)))
3059 ]
3060 suggested_owners = input_api.owners_client.SuggestOwners(
3061 missing_files, exclude=[owner_email])
3062 output_list.append(
3063 output('Suggested missing target path OWNERS:\n %s' %
3064 '\n '.join(suggested_owners or [])))
3065 return output_list
3066
3067 return []
joi@chromium.orge871964c2013-05-13 14:14:553068
3069
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493070# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:363071def CheckSpamLogging(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503072 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3073 files_to_skip = (
3074 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3075 input_api.DEFAULT_FILES_TO_SKIP + (
Jaewon Jung2f323bb2022-12-07 23:55:013076 r"^base/fuchsia/scoped_fx_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313077 r"^base/logging\.h$",
3078 r"^base/logging\.cc$",
3079 r"^base/task/thread_pool/task_tracker\.cc$",
3080 r"^chrome/app/chrome_main_delegate\.cc$",
Yao Li359937b2023-02-15 23:43:033081 r"^chrome/browser/ash/arc/enterprise/cert_store/arc_cert_installer\.cc$",
3082 r"^chrome/browser/ash/policy/remote_commands/user_command_arc_job\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313083 r"^chrome/browser/chrome_browser_main\.cc$",
3084 r"^chrome/browser/ui/startup/startup_browser_creator\.cc$",
3085 r"^chrome/browser/browser_switcher/bho/.*",
3086 r"^chrome/browser/diagnostics/diagnostics_writer\.cc$",
3087 r"^chrome/chrome_cleaner/.*",
3088 r"^chrome/chrome_elf/dll_hash/dll_hash_main\.cc$",
3089 r"^chrome/installer/setup/.*",
3090 r"^chromecast/",
Bruce Dawson40fece62022-09-16 19:58:313091 r"^components/media_control/renderer/media_playback_options\.cc$",
Salma Elmahallawy52976452023-01-27 17:04:493092 r"^components/policy/core/common/policy_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313093 r"^components/viz/service/display/"
Sam Maiera6e76d72022-02-11 21:43:503094 r"overlay_strategy_underlay_cast\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313095 r"^components/zucchini/.*",
Sam Maiera6e76d72022-02-11 21:43:503096 # TODO(peter): Remove exception. https://crbug.com/534537
Bruce Dawson40fece62022-09-16 19:58:313097 r"^content/browser/notifications/"
Sam Maiera6e76d72022-02-11 21:43:503098 r"notification_event_dispatcher_impl\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313099 r"^content/common/gpu/client/gl_helper_benchmark\.cc$",
3100 r"^courgette/courgette_minimal_tool\.cc$",
3101 r"^courgette/courgette_tool\.cc$",
3102 r"^extensions/renderer/logging_native_handler\.cc$",
3103 r"^fuchsia_web/common/init_logging\.cc$",
3104 r"^fuchsia_web/runners/common/web_component\.cc$",
Caroline Liua7050132023-02-13 22:23:153105 r"^fuchsia_web/shell/.*\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313106 r"^headless/app/headless_shell\.cc$",
3107 r"^ipc/ipc_logging\.cc$",
3108 r"^native_client_sdk/",
3109 r"^remoting/base/logging\.h$",
3110 r"^remoting/host/.*",
3111 r"^sandbox/linux/.*",
3112 r"^storage/browser/file_system/dump_file_system\.cc$",
3113 r"^tools/",
3114 r"^ui/base/resource/data_pack\.cc$",
3115 r"^ui/aura/bench/bench_main\.cc$",
3116 r"^ui/ozone/platform/cast/",
3117 r"^ui/base/x/xwmstartupcheck/"
Sam Maiera6e76d72022-02-11 21:43:503118 r"xwmstartupcheck\.cc$"))
3119 source_file_filter = lambda x: input_api.FilterSourceFile(
3120 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
thakis@chromium.org85218562013-11-22 07:41:403121
Sam Maiera6e76d72022-02-11 21:43:503122 log_info = set([])
3123 printf = set([])
thakis@chromium.org85218562013-11-22 07:41:403124
Sam Maiera6e76d72022-02-11 21:43:503125 for f in input_api.AffectedSourceFiles(source_file_filter):
3126 for _, line in f.ChangedContents():
3127 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
3128 log_info.add(f.LocalPath())
3129 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
3130 log_info.add(f.LocalPath())
jln@chromium.org18b466b2013-12-02 22:01:373131
Sam Maiera6e76d72022-02-11 21:43:503132 if input_api.re.search(r"\bprintf\(", line):
3133 printf.add(f.LocalPath())
3134 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
3135 printf.add(f.LocalPath())
thakis@chromium.org85218562013-11-22 07:41:403136
Sam Maiera6e76d72022-02-11 21:43:503137 if log_info:
3138 return [
3139 output_api.PresubmitError(
3140 'These files spam the console log with LOG(INFO):',
3141 items=log_info)
3142 ]
3143 if printf:
3144 return [
3145 output_api.PresubmitError(
3146 'These files spam the console log with printf/fprintf:',
3147 items=printf)
3148 ]
3149 return []
thakis@chromium.org85218562013-11-22 07:41:403150
3151
Saagar Sanghavifceeaae2020-08-12 16:40:363152def CheckForAnonymousVariables(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503153 """These types are all expected to hold locks while in scope and
3154 so should never be anonymous (which causes them to be immediately
3155 destroyed)."""
3156 they_who_must_be_named = [
3157 'base::AutoLock',
3158 'base::AutoReset',
3159 'base::AutoUnlock',
3160 'SkAutoAlphaRestore',
3161 'SkAutoBitmapShaderInstall',
3162 'SkAutoBlitterChoose',
3163 'SkAutoBounderCommit',
3164 'SkAutoCallProc',
3165 'SkAutoCanvasRestore',
3166 'SkAutoCommentBlock',
3167 'SkAutoDescriptor',
3168 'SkAutoDisableDirectionCheck',
3169 'SkAutoDisableOvalCheck',
3170 'SkAutoFree',
3171 'SkAutoGlyphCache',
3172 'SkAutoHDC',
3173 'SkAutoLockColors',
3174 'SkAutoLockPixels',
3175 'SkAutoMalloc',
3176 'SkAutoMaskFreeImage',
3177 'SkAutoMutexAcquire',
3178 'SkAutoPathBoundsUpdate',
3179 'SkAutoPDFRelease',
3180 'SkAutoRasterClipValidate',
3181 'SkAutoRef',
3182 'SkAutoTime',
3183 'SkAutoTrace',
3184 'SkAutoUnref',
3185 ]
3186 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
3187 # bad: base::AutoLock(lock.get());
3188 # not bad: base::AutoLock lock(lock.get());
3189 bad_pattern = input_api.re.compile(anonymous)
3190 # good: new base::AutoLock(lock.get())
3191 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
3192 errors = []
enne@chromium.org49aa76a2013-12-04 06:59:163193
Sam Maiera6e76d72022-02-11 21:43:503194 for f in input_api.AffectedFiles():
3195 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
3196 continue
3197 for linenum, line in f.ChangedContents():
3198 if bad_pattern.search(line) and not good_pattern.search(line):
3199 errors.append('%s:%d' % (f.LocalPath(), linenum))
enne@chromium.org49aa76a2013-12-04 06:59:163200
Sam Maiera6e76d72022-02-11 21:43:503201 if errors:
3202 return [
3203 output_api.PresubmitError(
3204 'These lines create anonymous variables that need to be named:',
3205 items=errors)
3206 ]
3207 return []
enne@chromium.org49aa76a2013-12-04 06:59:163208
3209
Saagar Sanghavifceeaae2020-08-12 16:40:363210def CheckUniquePtrOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503211 # Returns whether |template_str| is of the form <T, U...> for some types T
3212 # and U. Assumes that |template_str| is already in the form <...>.
3213 def HasMoreThanOneArg(template_str):
3214 # Level of <...> nesting.
3215 nesting = 0
3216 for c in template_str:
3217 if c == '<':
3218 nesting += 1
3219 elif c == '>':
3220 nesting -= 1
3221 elif c == ',' and nesting == 1:
3222 return True
3223 return False
Vaclav Brozekb7fadb692018-08-30 06:39:533224
Sam Maiera6e76d72022-02-11 21:43:503225 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3226 sources = lambda affected_file: input_api.FilterSourceFile(
3227 affected_file,
3228 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3229 DEFAULT_FILES_TO_SKIP),
3230 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:553231
Sam Maiera6e76d72022-02-11 21:43:503232 # Pattern to capture a single "<...>" block of template arguments. It can
3233 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
3234 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
3235 # latter would likely require counting that < and > match, which is not
3236 # expressible in regular languages. Should the need arise, one can introduce
3237 # limited counting (matching up to a total number of nesting depth), which
3238 # should cover all practical cases for already a low nesting limit.
3239 template_arg_pattern = (
3240 r'<[^>]*' # Opening block of <.
3241 r'>([^<]*>)?') # Closing block of >.
3242 # Prefix expressing that whatever follows is not already inside a <...>
3243 # block.
3244 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
3245 null_construct_pattern = input_api.re.compile(
3246 not_inside_template_arg_pattern + r'\bstd::unique_ptr' +
3247 template_arg_pattern + r'\(\)')
Vaclav Brozeka54c528b2018-04-06 19:23:553248
Sam Maiera6e76d72022-02-11 21:43:503249 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
3250 template_arg_no_array_pattern = (
3251 r'<[^>]*[^]]' # Opening block of <.
3252 r'>([^(<]*[^]]>)?') # Closing block of >.
3253 # Prefix saying that what follows is the start of an expression.
3254 start_of_expr_pattern = r'(=|\breturn|^)\s*'
3255 # Suffix saying that what follows are call parentheses with a non-empty list
3256 # of arguments.
3257 nonempty_arg_list_pattern = r'\(([^)]|$)'
3258 # Put the template argument into a capture group for deeper examination later.
3259 return_construct_pattern = input_api.re.compile(
3260 start_of_expr_pattern + r'std::unique_ptr' + '(?P<template_arg>' +
3261 template_arg_no_array_pattern + ')' + nonempty_arg_list_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:553262
Sam Maiera6e76d72022-02-11 21:43:503263 problems_constructor = []
3264 problems_nullptr = []
3265 for f in input_api.AffectedSourceFiles(sources):
3266 for line_number, line in f.ChangedContents():
3267 # Disallow:
3268 # return std::unique_ptr<T>(foo);
3269 # bar = std::unique_ptr<T>(foo);
3270 # But allow:
3271 # return std::unique_ptr<T[]>(foo);
3272 # bar = std::unique_ptr<T[]>(foo);
3273 # And also allow cases when the second template argument is present. Those
3274 # cases cannot be handled by std::make_unique:
3275 # return std::unique_ptr<T, U>(foo);
3276 # bar = std::unique_ptr<T, U>(foo);
3277 local_path = f.LocalPath()
3278 return_construct_result = return_construct_pattern.search(line)
3279 if return_construct_result and not HasMoreThanOneArg(
3280 return_construct_result.group('template_arg')):
3281 problems_constructor.append(
3282 '%s:%d\n %s' % (local_path, line_number, line.strip()))
3283 # Disallow:
3284 # std::unique_ptr<T>()
3285 if null_construct_pattern.search(line):
3286 problems_nullptr.append(
3287 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Vaclav Brozek851d9602018-04-04 16:13:053288
Sam Maiera6e76d72022-02-11 21:43:503289 errors = []
3290 if problems_nullptr:
3291 errors.append(
3292 output_api.PresubmitPromptWarning(
3293 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
3294 problems_nullptr))
3295 if problems_constructor:
3296 errors.append(
3297 output_api.PresubmitError(
3298 'The following files use explicit std::unique_ptr constructor. '
3299 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
3300 'std::make_unique is not an option.', problems_constructor))
3301 return errors
Peter Kasting4844e46e2018-02-23 07:27:103302
3303
Saagar Sanghavifceeaae2020-08-12 16:40:363304def CheckUserActionUpdate(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503305 """Checks if any new user action has been added."""
3306 if any('actions.xml' == input_api.os_path.basename(f)
3307 for f in input_api.LocalPaths()):
3308 # If actions.xml is already included in the changelist, the PRESUBMIT
3309 # for actions.xml will do a more complete presubmit check.
3310 return []
3311
3312 file_inclusion_pattern = [r'.*\.(cc|mm)$']
3313 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3314 input_api.DEFAULT_FILES_TO_SKIP)
3315 file_filter = lambda f: input_api.FilterSourceFile(
3316 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
3317
3318 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
3319 current_actions = None
3320 for f in input_api.AffectedFiles(file_filter=file_filter):
3321 for line_num, line in f.ChangedContents():
3322 match = input_api.re.search(action_re, line)
3323 if match:
3324 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
3325 # loaded only once.
3326 if not current_actions:
Bruce Dawson6cb2d4d2023-03-01 21:35:093327 with open('tools/metrics/actions/actions.xml',
3328 encoding='utf-8') as actions_f:
Sam Maiera6e76d72022-02-11 21:43:503329 current_actions = actions_f.read()
3330 # Search for the matched user action name in |current_actions|.
3331 for action_name in match.groups():
3332 action = 'name="{0}"'.format(action_name)
3333 if action not in current_actions:
3334 return [
3335 output_api.PresubmitPromptWarning(
3336 'File %s line %d: %s is missing in '
3337 'tools/metrics/actions/actions.xml. Please run '
3338 'tools/metrics/actions/extract_actions.py to update.'
3339 % (f.LocalPath(), line_num, action_name))
3340 ]
yiyaoliu@chromium.org999261d2014-03-03 20:08:083341 return []
3342
yiyaoliu@chromium.org999261d2014-03-03 20:08:083343
Daniel Cheng13ca61a882017-08-25 15:11:253344def _ImportJSONCommentEater(input_api):
Sam Maiera6e76d72022-02-11 21:43:503345 import sys
3346 sys.path = sys.path + [
3347 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3348 'json_comment_eater')
3349 ]
3350 import json_comment_eater
3351 return json_comment_eater
Daniel Cheng13ca61a882017-08-25 15:11:253352
3353
yoz@chromium.org99171a92014-06-03 08:44:473354def _GetJSONParseError(input_api, filename, eat_comments=True):
dchenge07de812016-06-20 19:27:173355 try:
Sam Maiera6e76d72022-02-11 21:43:503356 contents = input_api.ReadFile(filename)
3357 if eat_comments:
3358 json_comment_eater = _ImportJSONCommentEater(input_api)
3359 contents = json_comment_eater.Nom(contents)
dchenge07de812016-06-20 19:27:173360
Sam Maiera6e76d72022-02-11 21:43:503361 input_api.json.loads(contents)
3362 except ValueError as e:
3363 return e
Andrew Grieve4deedb12022-02-03 21:34:503364 return None
3365
3366
Sam Maiera6e76d72022-02-11 21:43:503367def _GetIDLParseError(input_api, filename):
3368 try:
3369 contents = input_api.ReadFile(filename)
Devlin Croninf7582a12022-04-21 21:14:283370 for i, char in enumerate(contents):
Daniel Chenga37c03db2022-05-12 17:20:343371 if not char.isascii():
3372 return (
3373 'Non-ascii character "%s" (ord %d) found at offset %d.' %
3374 (char, ord(char), i))
Sam Maiera6e76d72022-02-11 21:43:503375 idl_schema = input_api.os_path.join(input_api.PresubmitLocalPath(),
3376 'tools', 'json_schema_compiler',
3377 'idl_schema.py')
3378 process = input_api.subprocess.Popen(
Bruce Dawson679fb082022-04-14 00:47:283379 [input_api.python3_executable, idl_schema],
Sam Maiera6e76d72022-02-11 21:43:503380 stdin=input_api.subprocess.PIPE,
3381 stdout=input_api.subprocess.PIPE,
3382 stderr=input_api.subprocess.PIPE,
3383 universal_newlines=True)
3384 (_, error) = process.communicate(input=contents)
3385 return error or None
3386 except ValueError as e:
3387 return e
agrievef32bcc72016-04-04 14:57:403388
agrievef32bcc72016-04-04 14:57:403389
Sam Maiera6e76d72022-02-11 21:43:503390def CheckParseErrors(input_api, output_api):
3391 """Check that IDL and JSON files do not contain syntax errors."""
3392 actions = {
3393 '.idl': _GetIDLParseError,
3394 '.json': _GetJSONParseError,
3395 }
3396 # Most JSON files are preprocessed and support comments, but these do not.
3397 json_no_comments_patterns = [
Bruce Dawson40fece62022-09-16 19:58:313398 r'^testing/',
Sam Maiera6e76d72022-02-11 21:43:503399 ]
3400 # Only run IDL checker on files in these directories.
3401 idl_included_patterns = [
Bruce Dawson40fece62022-09-16 19:58:313402 r'^chrome/common/extensions/api/',
3403 r'^extensions/common/api/',
Sam Maiera6e76d72022-02-11 21:43:503404 ]
agrievef32bcc72016-04-04 14:57:403405
Sam Maiera6e76d72022-02-11 21:43:503406 def get_action(affected_file):
3407 filename = affected_file.LocalPath()
3408 return actions.get(input_api.os_path.splitext(filename)[1])
agrievef32bcc72016-04-04 14:57:403409
Sam Maiera6e76d72022-02-11 21:43:503410 def FilterFile(affected_file):
3411 action = get_action(affected_file)
3412 if not action:
3413 return False
3414 path = affected_file.LocalPath()
agrievef32bcc72016-04-04 14:57:403415
Sam Maiera6e76d72022-02-11 21:43:503416 if _MatchesFile(input_api,
3417 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS, path):
3418 return False
3419
3420 if (action == _GetIDLParseError
3421 and not _MatchesFile(input_api, idl_included_patterns, path)):
3422 return False
3423 return True
3424
3425 results = []
3426 for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
3427 include_deletes=False):
3428 action = get_action(affected_file)
3429 kwargs = {}
3430 if (action == _GetJSONParseError
3431 and _MatchesFile(input_api, json_no_comments_patterns,
3432 affected_file.LocalPath())):
3433 kwargs['eat_comments'] = False
3434 parse_error = action(input_api, affected_file.AbsoluteLocalPath(),
3435 **kwargs)
3436 if parse_error:
3437 results.append(
3438 output_api.PresubmitError(
3439 '%s could not be parsed: %s' %
3440 (affected_file.LocalPath(), parse_error)))
3441 return results
3442
3443
3444def CheckJavaStyle(input_api, output_api):
3445 """Runs checkstyle on changed java files and returns errors if any exist."""
3446
3447 # Return early if no java files were modified.
3448 if not any(
3449 _IsJavaFile(input_api, f.LocalPath())
3450 for f in input_api.AffectedFiles()):
3451 return []
3452
3453 import sys
3454 original_sys_path = sys.path
3455 try:
3456 sys.path = sys.path + [
3457 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3458 'android', 'checkstyle')
3459 ]
3460 import checkstyle
3461 finally:
3462 # Restore sys.path to what it was before.
3463 sys.path = original_sys_path
3464
Andrew Grieve4f88e3ca2022-11-22 19:09:203465 return checkstyle.run_presubmit(
Sam Maiera6e76d72022-02-11 21:43:503466 input_api,
3467 output_api,
Sam Maiera6e76d72022-02-11 21:43:503468 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
3469
3470
3471def CheckPythonDevilInit(input_api, output_api):
3472 """Checks to make sure devil is initialized correctly in python scripts."""
3473 script_common_initialize_pattern = input_api.re.compile(
3474 r'script_common\.InitializeEnvironment\(')
3475 devil_env_config_initialize = input_api.re.compile(
3476 r'devil_env\.config\.Initialize\(')
3477
3478 errors = []
3479
3480 sources = lambda affected_file: input_api.FilterSourceFile(
3481 affected_file,
3482 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:313483 r'^build/android/devil_chromium\.py',
3484 r'^third_party/.*',
Sam Maiera6e76d72022-02-11 21:43:503485 )),
3486 files_to_check=[r'.*\.py$'])
3487
3488 for f in input_api.AffectedSourceFiles(sources):
3489 for line_num, line in f.ChangedContents():
3490 if (script_common_initialize_pattern.search(line)
3491 or devil_env_config_initialize.search(line)):
3492 errors.append("%s:%d" % (f.LocalPath(), line_num))
3493
3494 results = []
3495
3496 if errors:
3497 results.append(
3498 output_api.PresubmitError(
3499 'Devil initialization should always be done using '
3500 'devil_chromium.Initialize() in the chromium project, to use better '
3501 'defaults for dependencies (ex. up-to-date version of adb).',
3502 errors))
3503
3504 return results
3505
3506
3507def _MatchesFile(input_api, patterns, path):
Bruce Dawson40fece62022-09-16 19:58:313508 # Consistently use / as path separator to simplify the writing of regex
3509 # expressions.
3510 path = path.replace(input_api.os_path.sep, '/')
Sam Maiera6e76d72022-02-11 21:43:503511 for pattern in patterns:
3512 if input_api.re.search(pattern, path):
3513 return True
3514 return False
3515
3516
Daniel Chenga37c03db2022-05-12 17:20:343517def _ChangeHasSecurityReviewer(input_api, owners_file):
3518 """Returns True iff the CL has a reviewer from SECURITY_OWNERS.
Sam Maiera6e76d72022-02-11 21:43:503519
Daniel Chenga37c03db2022-05-12 17:20:343520 Args:
3521 input_api: The presubmit input API.
3522 owners_file: OWNERS file with required reviewers. Typically, this is
3523 something like ipc/SECURITY_OWNERS.
3524
3525 Note: if the presubmit is running for commit rather than for upload, this
3526 only returns True if a security reviewer has also approved the CL.
Sam Maiera6e76d72022-02-11 21:43:503527 """
Daniel Chengd88244472022-05-16 09:08:473528 # Owners-Override should bypass all additional OWNERS enforcement checks.
3529 # A CR+1 vote will still be required to land this change.
3530 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
3531 input_api.change.issue)):
3532 return True
3533
Daniel Chenga37c03db2022-05-12 17:20:343534 owner_email, reviewers = (
3535 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
Daniel Cheng3008dc12022-05-13 04:02:113536 input_api,
3537 None,
3538 approval_needed=input_api.is_committing and not input_api.dry_run))
Sam Maiera6e76d72022-02-11 21:43:503539
Daniel Chenga37c03db2022-05-12 17:20:343540 security_owners = input_api.owners_client.ListOwners(owners_file)
3541 return any(owner in reviewers for owner in security_owners)
Sam Maiera6e76d72022-02-11 21:43:503542
Daniel Chenga37c03db2022-05-12 17:20:343543
3544@dataclass
Daniel Cheng171dad8d2022-05-21 00:40:253545class _SecurityProblemWithItems:
3546 problem: str
3547 items: Sequence[str]
3548
3549
3550@dataclass
Daniel Chenga37c03db2022-05-12 17:20:343551class _MissingSecurityOwnersResult:
Daniel Cheng171dad8d2022-05-21 00:40:253552 owners_file_problems: Sequence[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:343553 has_security_sensitive_files: bool
Daniel Cheng171dad8d2022-05-21 00:40:253554 missing_reviewer_problem: Optional[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:343555
3556
3557def _FindMissingSecurityOwners(input_api,
3558 output_api,
3559 file_patterns: Sequence[str],
3560 excluded_patterns: Sequence[str],
3561 required_owners_file: str,
3562 custom_rule_function: Optional[Callable] = None
3563 ) -> _MissingSecurityOwnersResult:
3564 """Find OWNERS files missing per-file rules for security-sensitive files.
3565
3566 Args:
3567 input_api: the PRESUBMIT input API object.
3568 output_api: the PRESUBMIT output API object.
3569 file_patterns: basename patterns that require a corresponding per-file
3570 security restriction.
3571 excluded_patterns: path patterns that should be exempted from
3572 requiring a security restriction.
3573 required_owners_file: path to the required OWNERS file, e.g.
3574 ipc/SECURITY_OWNERS
3575 cc_alias: If not None, email that will be CCed automatically if the
3576 change contains security-sensitive files, as determined by
3577 `file_patterns` and `excluded_patterns`.
3578 custom_rule_function: If not None, will be called with `input_api` and
3579 the current file under consideration. Returning True will add an
3580 exact match per-file rule check for the current file.
3581 """
3582
3583 # `to_check` is a mapping of an OWNERS file path to Patterns.
3584 #
3585 # Patterns is a dictionary mapping glob patterns (suitable for use in
3586 # per-file rules) to a PatternEntry.
3587 #
Sam Maiera6e76d72022-02-11 21:43:503588 # PatternEntry is a dictionary with two keys:
3589 # - 'files': the files that are matched by this pattern
3590 # - 'rules': the per-file rules needed for this pattern
Daniel Chenga37c03db2022-05-12 17:20:343591 #
Sam Maiera6e76d72022-02-11 21:43:503592 # For example, if we expect OWNERS file to contain rules for *.mojom and
3593 # *_struct_traits*.*, Patterns might look like this:
3594 # {
3595 # '*.mojom': {
3596 # 'files': ...,
3597 # 'rules': [
3598 # 'per-file *.mojom=set noparent',
3599 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
3600 # ],
3601 # },
3602 # '*_struct_traits*.*': {
3603 # 'files': ...,
3604 # 'rules': [
3605 # 'per-file *_struct_traits*.*=set noparent',
3606 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
3607 # ],
3608 # },
3609 # }
3610 to_check = {}
Daniel Chenga37c03db2022-05-12 17:20:343611 files_to_review = []
Sam Maiera6e76d72022-02-11 21:43:503612
Daniel Chenga37c03db2022-05-12 17:20:343613 def AddPatternToCheck(file, pattern):
Sam Maiera6e76d72022-02-11 21:43:503614 owners_file = input_api.os_path.join(
Daniel Chengd88244472022-05-16 09:08:473615 input_api.os_path.dirname(file.LocalPath()), 'OWNERS')
Sam Maiera6e76d72022-02-11 21:43:503616 if owners_file not in to_check:
3617 to_check[owners_file] = {}
3618 if pattern not in to_check[owners_file]:
3619 to_check[owners_file][pattern] = {
3620 'files': [],
3621 'rules': [
Daniel Chenga37c03db2022-05-12 17:20:343622 f'per-file {pattern}=set noparent',
3623 f'per-file {pattern}=file://{required_owners_file}',
Sam Maiera6e76d72022-02-11 21:43:503624 ]
3625 }
Daniel Chenged57a162022-05-25 02:56:343626 to_check[owners_file][pattern]['files'].append(file.LocalPath())
Daniel Chenga37c03db2022-05-12 17:20:343627 files_to_review.append(file.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:503628
Daniel Chenga37c03db2022-05-12 17:20:343629 # Only enforce security OWNERS rules for a directory if that directory has a
3630 # file that matches `file_patterns`. For example, if a directory only
3631 # contains *.mojom files and no *_messages*.h files, the check should only
3632 # ensure that rules for *.mojom files are present.
3633 for file in input_api.AffectedFiles(include_deletes=False):
3634 file_basename = input_api.os_path.basename(file.LocalPath())
3635 if custom_rule_function is not None and custom_rule_function(
3636 input_api, file):
3637 AddPatternToCheck(file, file_basename)
3638 continue
Sam Maiera6e76d72022-02-11 21:43:503639
Daniel Chenga37c03db2022-05-12 17:20:343640 if any(
3641 input_api.fnmatch.fnmatch(file.LocalPath(), pattern)
3642 for pattern in excluded_patterns):
Sam Maiera6e76d72022-02-11 21:43:503643 continue
3644
3645 for pattern in file_patterns:
Daniel Chenga37c03db2022-05-12 17:20:343646 # Unlike `excluded_patterns`, `file_patterns` is checked only against the
3647 # file's basename.
3648 if input_api.fnmatch.fnmatch(file_basename, pattern):
3649 AddPatternToCheck(file, pattern)
Sam Maiera6e76d72022-02-11 21:43:503650 break
3651
Daniel Chenga37c03db2022-05-12 17:20:343652 has_security_sensitive_files = bool(to_check)
Daniel Cheng171dad8d2022-05-21 00:40:253653
3654 # Check if any newly added lines in OWNERS files intersect with required
3655 # per-file OWNERS lines. If so, ensure that a security reviewer is included.
3656 # This is a hack, but is needed because the OWNERS check (by design) ignores
3657 # new OWNERS entries; otherwise, a non-owner could add someone as a new
3658 # OWNER and have that newly-added OWNER self-approve their own addition.
3659 newly_covered_files = []
3660 for file in input_api.AffectedFiles(include_deletes=False):
3661 if not file.LocalPath() in to_check:
3662 continue
3663 for _, line in file.ChangedContents():
3664 for _, entry in to_check[file.LocalPath()].items():
3665 if line in entry['rules']:
3666 newly_covered_files.extend(entry['files'])
3667
3668 missing_reviewer_problems = None
3669 if newly_covered_files and not _ChangeHasSecurityReviewer(
Daniel Chenga37c03db2022-05-12 17:20:343670 input_api, required_owners_file):
Daniel Cheng171dad8d2022-05-21 00:40:253671 missing_reviewer_problems = _SecurityProblemWithItems(
3672 f'Review from an owner in {required_owners_file} is required for '
3673 'the following newly-added files:',
3674 [f'{file}' for file in sorted(set(newly_covered_files))])
Sam Maiera6e76d72022-02-11 21:43:503675
3676 # Go through the OWNERS files to check, filtering out rules that are already
3677 # present in that OWNERS file.
3678 for owners_file, patterns in to_check.items():
3679 try:
Daniel Cheng171dad8d2022-05-21 00:40:253680 lines = set(
3681 input_api.ReadFile(
3682 input_api.os_path.join(input_api.change.RepositoryRoot(),
3683 owners_file)).splitlines())
3684 for entry in patterns.values():
3685 entry['rules'] = [
3686 rule for rule in entry['rules'] if rule not in lines
3687 ]
Sam Maiera6e76d72022-02-11 21:43:503688 except IOError:
3689 # No OWNERS file, so all the rules are definitely missing.
3690 continue
3691
3692 # All the remaining lines weren't found in OWNERS files, so emit an error.
Daniel Cheng171dad8d2022-05-21 00:40:253693 owners_file_problems = []
Daniel Chenga37c03db2022-05-12 17:20:343694
Sam Maiera6e76d72022-02-11 21:43:503695 for owners_file, patterns in to_check.items():
3696 missing_lines = []
3697 files = []
3698 for _, entry in patterns.items():
Daniel Chenged57a162022-05-25 02:56:343699 files.extend(entry['files'])
Sam Maiera6e76d72022-02-11 21:43:503700 missing_lines.extend(entry['rules'])
Sam Maiera6e76d72022-02-11 21:43:503701 if missing_lines:
Daniel Cheng171dad8d2022-05-21 00:40:253702 joined_missing_lines = '\n'.join(line for line in missing_lines)
3703 owners_file_problems.append(
3704 _SecurityProblemWithItems(
3705 'Found missing OWNERS lines for security-sensitive files. '
3706 f'Please add the following lines to {owners_file}:\n'
3707 f'{joined_missing_lines}\n\nTo ensure security review for:',
3708 files))
Daniel Chenga37c03db2022-05-12 17:20:343709
Daniel Cheng171dad8d2022-05-21 00:40:253710 return _MissingSecurityOwnersResult(owners_file_problems,
Daniel Chenga37c03db2022-05-12 17:20:343711 has_security_sensitive_files,
Daniel Cheng171dad8d2022-05-21 00:40:253712 missing_reviewer_problems)
Daniel Chenga37c03db2022-05-12 17:20:343713
3714
3715def _CheckChangeForIpcSecurityOwners(input_api, output_api):
3716 # Whether or not a file affects IPC is (mostly) determined by a simple list
3717 # of filename patterns.
3718 file_patterns = [
3719 # Legacy IPC:
3720 '*_messages.cc',
3721 '*_messages*.h',
3722 '*_param_traits*.*',
3723 # Mojo IPC:
3724 '*.mojom',
3725 '*_mojom_traits*.*',
3726 '*_type_converter*.*',
3727 # Android native IPC:
3728 '*.aidl',
3729 ]
3730
Daniel Chenga37c03db2022-05-12 17:20:343731 excluded_patterns = [
Daniel Cheng518943f2022-05-12 22:15:463732 # These third_party directories do not contain IPCs, but contain files
3733 # matching the above patterns, which trigger false positives.
Daniel Chenga37c03db2022-05-12 17:20:343734 'third_party/crashpad/*',
3735 'third_party/blink/renderer/platform/bindings/*',
3736 'third_party/protobuf/benchmarks/python/*',
3737 'third_party/win_build_output/*',
Daniel Chengd88244472022-05-16 09:08:473738 # Enum-only mojoms used for web metrics, so no security review needed.
3739 'third_party/blink/public/mojom/use_counter/metrics/*',
Daniel Chenga37c03db2022-05-12 17:20:343740 # These files are just used to communicate between class loaders running
3741 # in the same process.
3742 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
3743 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
3744 ]
3745
3746 def IsMojoServiceManifestFile(input_api, file):
3747 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
3748 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
3749 if not manifest_pattern.search(file.LocalPath()):
3750 return False
3751
3752 if test_manifest_pattern.search(file.LocalPath()):
3753 return False
3754
3755 # All actual service manifest files should contain at least one
3756 # qualified reference to service_manager::Manifest.
3757 return any('service_manager::Manifest' in line
3758 for line in file.NewContents())
3759
3760 return _FindMissingSecurityOwners(
3761 input_api,
3762 output_api,
3763 file_patterns,
3764 excluded_patterns,
3765 'ipc/SECURITY_OWNERS',
3766 custom_rule_function=IsMojoServiceManifestFile)
3767
3768
3769def _CheckChangeForFuchsiaSecurityOwners(input_api, output_api):
3770 file_patterns = [
3771 # Component specifications.
3772 '*.cml', # Component Framework v2.
3773 '*.cmx', # Component Framework v1.
3774
3775 # Fuchsia IDL protocol specifications.
3776 '*.fidl',
3777 ]
3778
3779 # Don't check for owners files for changes in these directories.
3780 excluded_patterns = [
3781 'third_party/crashpad/*',
3782 ]
3783
3784 return _FindMissingSecurityOwners(input_api, output_api, file_patterns,
3785 excluded_patterns,
3786 'build/fuchsia/SECURITY_OWNERS')
3787
3788
3789def CheckSecurityOwners(input_api, output_api):
3790 """Checks that various security-sensitive files have an IPC OWNERS rule."""
3791 ipc_results = _CheckChangeForIpcSecurityOwners(input_api, output_api)
3792 fuchsia_results = _CheckChangeForFuchsiaSecurityOwners(
3793 input_api, output_api)
3794
3795 if ipc_results.has_security_sensitive_files:
3796 output_api.AppendCC('ipc-security-reviews@chromium.org')
Sam Maiera6e76d72022-02-11 21:43:503797
3798 results = []
Daniel Chenga37c03db2022-05-12 17:20:343799
Daniel Cheng171dad8d2022-05-21 00:40:253800 missing_reviewer_problems = []
3801 if ipc_results.missing_reviewer_problem:
3802 missing_reviewer_problems.append(ipc_results.missing_reviewer_problem)
3803 if fuchsia_results.missing_reviewer_problem:
3804 missing_reviewer_problems.append(
3805 fuchsia_results.missing_reviewer_problem)
Daniel Chenga37c03db2022-05-12 17:20:343806
Daniel Cheng171dad8d2022-05-21 00:40:253807 # Missing reviewers are an error unless there's no issue number
3808 # associated with this branch; in that case, the presubmit is being run
3809 # with --all or --files.
3810 #
3811 # Note that upload should never be an error; otherwise, it would be
3812 # impossible to upload changes at all.
3813 if input_api.is_committing and input_api.change.issue:
3814 make_presubmit_message = output_api.PresubmitError
3815 else:
3816 make_presubmit_message = output_api.PresubmitNotifyResult
3817 for problem in missing_reviewer_problems:
Sam Maiera6e76d72022-02-11 21:43:503818 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:253819 make_presubmit_message(problem.problem, items=problem.items))
Daniel Chenga37c03db2022-05-12 17:20:343820
Daniel Cheng171dad8d2022-05-21 00:40:253821 owners_file_problems = []
3822 owners_file_problems.extend(ipc_results.owners_file_problems)
3823 owners_file_problems.extend(fuchsia_results.owners_file_problems)
Daniel Chenga37c03db2022-05-12 17:20:343824
Daniel Cheng171dad8d2022-05-21 00:40:253825 for problem in owners_file_problems:
Daniel Cheng3008dc12022-05-13 04:02:113826 # Missing per-file rules are always an error. While swarming and caching
3827 # means that uploading a patchset with updated OWNERS files and sending
3828 # it to the CQ again should not have a large incremental cost, it is
3829 # still frustrating to discover the error only after the change has
3830 # already been uploaded.
Daniel Chenga37c03db2022-05-12 17:20:343831 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:253832 output_api.PresubmitError(problem.problem, items=problem.items))
Sam Maiera6e76d72022-02-11 21:43:503833
3834 return results
3835
3836
3837def _GetFilesUsingSecurityCriticalFunctions(input_api):
3838 """Checks affected files for changes to security-critical calls. This
3839 function checks the full change diff, to catch both additions/changes
3840 and removals.
3841
3842 Returns a dict keyed by file name, and the value is a set of detected
3843 functions.
3844 """
3845 # Map of function pretty name (displayed in an error) to the pattern to
3846 # match it with.
3847 _PATTERNS_TO_CHECK = {
3848 'content::GetServiceSandboxType<>()': 'GetServiceSandboxType\\<'
3849 }
3850 _PATTERNS_TO_CHECK = {
3851 k: input_api.re.compile(v)
3852 for k, v in _PATTERNS_TO_CHECK.items()
3853 }
3854
Sam Maiera6e76d72022-02-11 21:43:503855 # We don't want to trigger on strings within this file.
3856 def presubmit_file_filter(f):
Daniel Chenga37c03db2022-05-12 17:20:343857 return 'PRESUBMIT.py' != input_api.os_path.split(f.LocalPath())[1]
Sam Maiera6e76d72022-02-11 21:43:503858
3859 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3860 files_to_functions = {}
3861 for f in input_api.AffectedFiles(file_filter=presubmit_file_filter):
3862 diff = f.GenerateScmDiff()
3863 for line in diff.split('\n'):
3864 # Not using just RightHandSideLines() because removing a
3865 # call to a security-critical function can be just as important
3866 # as adding or changing the arguments.
3867 if line.startswith('-') or (line.startswith('+')
3868 and not line.startswith('++')):
3869 for name, pattern in _PATTERNS_TO_CHECK.items():
3870 if pattern.search(line):
3871 path = f.LocalPath()
3872 if not path in files_to_functions:
3873 files_to_functions[path] = set()
3874 files_to_functions[path].add(name)
3875 return files_to_functions
3876
3877
3878def CheckSecurityChanges(input_api, output_api):
3879 """Checks that changes involving security-critical functions are reviewed
3880 by the security team.
3881 """
3882 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3883 if not len(files_to_functions):
3884 return []
3885
Sam Maiera6e76d72022-02-11 21:43:503886 owners_file = 'ipc/SECURITY_OWNERS'
Daniel Chenga37c03db2022-05-12 17:20:343887 if _ChangeHasSecurityReviewer(input_api, owners_file):
Sam Maiera6e76d72022-02-11 21:43:503888 return []
3889
Daniel Chenga37c03db2022-05-12 17:20:343890 msg = 'The following files change calls to security-sensitive functions\n' \
Sam Maiera6e76d72022-02-11 21:43:503891 'that need to be reviewed by {}.\n'.format(owners_file)
3892 for path, names in files_to_functions.items():
3893 msg += ' {}\n'.format(path)
3894 for name in names:
3895 msg += ' {}\n'.format(name)
3896 msg += '\n'
3897
3898 if input_api.is_committing:
3899 output = output_api.PresubmitError
Mohamed Heikale217fc852020-07-06 19:44:033900 else:
Sam Maiera6e76d72022-02-11 21:43:503901 output = output_api.PresubmitNotifyResult
3902 return [output(msg)]
3903
3904
3905def CheckSetNoParent(input_api, output_api):
3906 """Checks that set noparent is only used together with an OWNERS file in
3907 //build/OWNERS.setnoparent (see also
3908 //docs/code_reviews.md#owners-files-details)
3909 """
3910 # Return early if no OWNERS files were modified.
3911 if not any(f.LocalPath().endswith('OWNERS')
3912 for f in input_api.AffectedFiles(include_deletes=False)):
3913 return []
3914
3915 errors = []
3916
3917 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3918 allowed_owners_files = set()
Bruce Dawson58a45d22023-02-27 11:24:163919 with open(allowed_owners_files_file, 'r', encoding='utf-8') as f:
Sam Maiera6e76d72022-02-11 21:43:503920 for line in f:
3921 line = line.strip()
3922 if not line or line.startswith('#'):
3923 continue
3924 allowed_owners_files.add(line)
3925
3926 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3927
3928 for f in input_api.AffectedFiles(include_deletes=False):
3929 if not f.LocalPath().endswith('OWNERS'):
3930 continue
3931
3932 found_owners_files = set()
3933 found_set_noparent_lines = dict()
3934
3935 # Parse the OWNERS file.
3936 for lineno, line in enumerate(f.NewContents(), 1):
3937 line = line.strip()
3938 if line.startswith('set noparent'):
3939 found_set_noparent_lines[''] = lineno
3940 if line.startswith('file://'):
3941 if line in allowed_owners_files:
3942 found_owners_files.add('')
3943 if line.startswith('per-file'):
3944 match = per_file_pattern.match(line)
3945 if match:
3946 glob = match.group(1).strip()
3947 directive = match.group(2).strip()
3948 if directive == 'set noparent':
3949 found_set_noparent_lines[glob] = lineno
3950 if directive.startswith('file://'):
3951 if directive in allowed_owners_files:
3952 found_owners_files.add(glob)
3953
3954 # Check that every set noparent line has a corresponding file:// line
3955 # listed in build/OWNERS.setnoparent. An exception is made for top level
3956 # directories since src/OWNERS shouldn't review them.
Bruce Dawson6bb0d672022-04-06 15:13:493957 linux_path = f.LocalPath().replace(input_api.os_path.sep, '/')
3958 if (linux_path.count('/') != 1
3959 and (not linux_path in _EXCLUDED_SET_NO_PARENT_PATHS)):
Sam Maiera6e76d72022-02-11 21:43:503960 for set_noparent_line in found_set_noparent_lines:
3961 if set_noparent_line in found_owners_files:
3962 continue
3963 errors.append(' %s:%d' %
Bruce Dawson6bb0d672022-04-06 15:13:493964 (linux_path,
Sam Maiera6e76d72022-02-11 21:43:503965 found_set_noparent_lines[set_noparent_line]))
3966
3967 results = []
3968 if errors:
3969 if input_api.is_committing:
3970 output = output_api.PresubmitError
3971 else:
3972 output = output_api.PresubmitPromptWarning
3973 results.append(
3974 output(
3975 'Found the following "set noparent" restrictions in OWNERS files that '
3976 'do not include owners from build/OWNERS.setnoparent:',
3977 long_text='\n\n'.join(errors)))
3978 return results
3979
3980
3981def CheckUselessForwardDeclarations(input_api, output_api):
3982 """Checks that added or removed lines in non third party affected
3983 header files do not lead to new useless class or struct forward
3984 declaration.
3985 """
3986 results = []
3987 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3988 input_api.re.MULTILINE)
3989 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3990 input_api.re.MULTILINE)
3991 for f in input_api.AffectedFiles(include_deletes=False):
3992 if (f.LocalPath().startswith('third_party')
3993 and not f.LocalPath().startswith('third_party/blink')
3994 and not f.LocalPath().startswith('third_party\\blink')):
3995 continue
3996
3997 if not f.LocalPath().endswith('.h'):
3998 continue
3999
4000 contents = input_api.ReadFile(f)
4001 fwd_decls = input_api.re.findall(class_pattern, contents)
4002 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
4003
4004 useless_fwd_decls = []
4005 for decl in fwd_decls:
4006 count = sum(1 for _ in input_api.re.finditer(
4007 r'\b%s\b' % input_api.re.escape(decl), contents))
4008 if count == 1:
4009 useless_fwd_decls.append(decl)
4010
4011 if not useless_fwd_decls:
4012 continue
4013
4014 for line in f.GenerateScmDiff().splitlines():
4015 if (line.startswith('-') and not line.startswith('--')
4016 or line.startswith('+') and not line.startswith('++')):
4017 for decl in useless_fwd_decls:
4018 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
4019 results.append(
4020 output_api.PresubmitPromptWarning(
4021 '%s: %s forward declaration is no longer needed'
4022 % (f.LocalPath(), decl)))
4023 useless_fwd_decls.remove(decl)
4024
4025 return results
4026
4027
4028def _CheckAndroidDebuggableBuild(input_api, output_api):
4029 """Checks that code uses BuildInfo.isDebugAndroid() instead of
4030 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
4031 this is a debuggable build of Android.
4032 """
4033 build_type_check_pattern = input_api.re.compile(
4034 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
4035
4036 errors = []
4037
4038 sources = lambda affected_file: input_api.FilterSourceFile(
4039 affected_file,
4040 files_to_skip=(
4041 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4042 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314043 r"^android_webview/support_library/boundary_interfaces/",
4044 r"^chrome/android/webapk/.*",
4045 r'^third_party/.*',
4046 r"tools/android/customtabs_benchmark/.*",
4047 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504048 )),
4049 files_to_check=[r'.*\.java$'])
4050
4051 for f in input_api.AffectedSourceFiles(sources):
4052 for line_num, line in f.ChangedContents():
4053 if build_type_check_pattern.search(line):
4054 errors.append("%s:%d" % (f.LocalPath(), line_num))
4055
4056 results = []
4057
4058 if errors:
4059 results.append(
4060 output_api.PresubmitPromptWarning(
4061 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
4062 ' Please use BuildInfo.isDebugAndroid() instead.', errors))
4063
4064 return results
4065
4066# TODO: add unit tests
4067def _CheckAndroidToastUsage(input_api, output_api):
4068 """Checks that code uses org.chromium.ui.widget.Toast instead of
4069 android.widget.Toast (Chromium Toast doesn't force hardware
4070 acceleration on low-end devices, saving memory).
4071 """
4072 toast_import_pattern = input_api.re.compile(
4073 r'^import android\.widget\.Toast;$')
4074
4075 errors = []
4076
4077 sources = lambda affected_file: input_api.FilterSourceFile(
4078 affected_file,
4079 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
Bruce Dawson40fece62022-09-16 19:58:314080 DEFAULT_FILES_TO_SKIP + (r'^chromecast/.*',
4081 r'^remoting/.*')),
Sam Maiera6e76d72022-02-11 21:43:504082 files_to_check=[r'.*\.java$'])
4083
4084 for f in input_api.AffectedSourceFiles(sources):
4085 for line_num, line in f.ChangedContents():
4086 if toast_import_pattern.search(line):
4087 errors.append("%s:%d" % (f.LocalPath(), line_num))
4088
4089 results = []
4090
4091 if errors:
4092 results.append(
4093 output_api.PresubmitError(
4094 'android.widget.Toast usage is detected. Android toasts use hardware'
4095 ' acceleration, and can be\ncostly on low-end devices. Please use'
4096 ' org.chromium.ui.widget.Toast instead.\n'
4097 'Contact dskiba@chromium.org if you have any questions.',
4098 errors))
4099
4100 return results
4101
4102
4103def _CheckAndroidCrLogUsage(input_api, output_api):
4104 """Checks that new logs using org.chromium.base.Log:
4105 - Are using 'TAG' as variable name for the tags (warn)
4106 - Are using a tag that is shorter than 20 characters (error)
4107 """
4108
4109 # Do not check format of logs in the given files
4110 cr_log_check_excluded_paths = [
4111 # //chrome/android/webapk cannot depend on //base
Bruce Dawson40fece62022-09-16 19:58:314112 r"^chrome/android/webapk/.*",
Sam Maiera6e76d72022-02-11 21:43:504113 # WebView license viewer code cannot depend on //base; used in stub APK.
Bruce Dawson40fece62022-09-16 19:58:314114 r"^android_webview/glue/java/src/com/android/"
4115 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504116 # The customtabs_benchmark is a small app that does not depend on Chromium
4117 # java pieces.
Bruce Dawson40fece62022-09-16 19:58:314118 r"tools/android/customtabs_benchmark/.*",
Sam Maiera6e76d72022-02-11 21:43:504119 ]
4120
4121 cr_log_import_pattern = input_api.re.compile(
4122 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
4123 class_in_base_pattern = input_api.re.compile(
4124 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
4125 has_some_log_import_pattern = input_api.re.compile(r'^import .*\.Log;$',
4126 input_api.re.MULTILINE)
4127 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
4128 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
4129 log_decl_pattern = input_api.re.compile(
4130 r'static final String TAG = "(?P<name>(.*))"')
4131 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
4132
4133 REF_MSG = ('See docs/android_logging.md for more info.')
4134 sources = lambda x: input_api.FilterSourceFile(
4135 x,
4136 files_to_check=[r'.*\.java$'],
4137 files_to_skip=cr_log_check_excluded_paths)
4138
4139 tag_decl_errors = []
4140 tag_length_errors = []
4141 tag_errors = []
4142 tag_with_dot_errors = []
4143 util_log_errors = []
4144
4145 for f in input_api.AffectedSourceFiles(sources):
4146 file_content = input_api.ReadFile(f)
4147 has_modified_logs = False
4148 # Per line checks
4149 if (cr_log_import_pattern.search(file_content)
4150 or (class_in_base_pattern.search(file_content)
4151 and not has_some_log_import_pattern.search(file_content))):
4152 # Checks to run for files using cr log
4153 for line_num, line in f.ChangedContents():
4154 if rough_log_decl_pattern.search(line):
4155 has_modified_logs = True
4156
4157 # Check if the new line is doing some logging
4158 match = log_call_pattern.search(line)
4159 if match:
4160 has_modified_logs = True
4161
4162 # Make sure it uses "TAG"
4163 if not match.group('tag') == 'TAG':
4164 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
4165 else:
4166 # Report non cr Log function calls in changed lines
4167 for line_num, line in f.ChangedContents():
4168 if log_call_pattern.search(line):
4169 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
4170
4171 # Per file checks
4172 if has_modified_logs:
4173 # Make sure the tag is using the "cr" prefix and is not too long
4174 match = log_decl_pattern.search(file_content)
4175 tag_name = match.group('name') if match else None
4176 if not tag_name:
4177 tag_decl_errors.append(f.LocalPath())
4178 elif len(tag_name) > 20:
4179 tag_length_errors.append(f.LocalPath())
4180 elif '.' in tag_name:
4181 tag_with_dot_errors.append(f.LocalPath())
4182
4183 results = []
4184 if tag_decl_errors:
4185 results.append(
4186 output_api.PresubmitPromptWarning(
4187 'Please define your tags using the suggested format: .\n'
4188 '"private static final String TAG = "<package tag>".\n'
4189 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
4190 tag_decl_errors))
4191
4192 if tag_length_errors:
4193 results.append(
4194 output_api.PresubmitError(
4195 'The tag length is restricted by the system to be at most '
4196 '20 characters.\n' + REF_MSG, tag_length_errors))
4197
4198 if tag_errors:
4199 results.append(
4200 output_api.PresubmitPromptWarning(
4201 'Please use a variable named "TAG" for your log tags.\n' +
4202 REF_MSG, tag_errors))
4203
4204 if util_log_errors:
4205 results.append(
4206 output_api.PresubmitPromptWarning(
4207 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
4208 util_log_errors))
4209
4210 if tag_with_dot_errors:
4211 results.append(
4212 output_api.PresubmitPromptWarning(
4213 'Dot in log tags cause them to be elided in crash reports.\n' +
4214 REF_MSG, tag_with_dot_errors))
4215
4216 return results
4217
4218
4219def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
4220 """Checks that junit.framework.* is no longer used."""
4221 deprecated_junit_framework_pattern = input_api.re.compile(
4222 r'^import junit\.framework\..*;', input_api.re.MULTILINE)
4223 sources = lambda x: input_api.FilterSourceFile(
4224 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
4225 errors = []
4226 for f in input_api.AffectedFiles(file_filter=sources):
4227 for line_num, line in f.ChangedContents():
4228 if deprecated_junit_framework_pattern.search(line):
4229 errors.append("%s:%d" % (f.LocalPath(), line_num))
4230
4231 results = []
4232 if errors:
4233 results.append(
4234 output_api.PresubmitError(
4235 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
4236 '(org.junit.*) from //third_party/junit. Contact yolandyan@chromium.org'
4237 ' if you have any question.', errors))
4238 return results
4239
4240
4241def _CheckAndroidTestJUnitInheritance(input_api, output_api):
4242 """Checks that if new Java test classes have inheritance.
4243 Either the new test class is JUnit3 test or it is a JUnit4 test class
4244 with a base class, either case is undesirable.
4245 """
4246 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
4247
4248 sources = lambda x: input_api.FilterSourceFile(
4249 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
4250 errors = []
4251 for f in input_api.AffectedFiles(file_filter=sources):
4252 if not f.OldContents():
4253 class_declaration_start_flag = False
4254 for line_num, line in f.ChangedContents():
4255 if class_declaration_pattern.search(line):
4256 class_declaration_start_flag = True
4257 if class_declaration_start_flag and ' extends ' in line:
4258 errors.append('%s:%d' % (f.LocalPath(), line_num))
4259 if '{' in line:
4260 class_declaration_start_flag = False
4261
4262 results = []
4263 if errors:
4264 results.append(
4265 output_api.PresubmitPromptWarning(
4266 'The newly created files include Test classes that inherits from base'
4267 ' class. Please do not use inheritance in JUnit4 tests or add new'
4268 ' JUnit3 tests. Contact yolandyan@chromium.org if you have any'
4269 ' questions.', errors))
4270 return results
4271
4272
4273def _CheckAndroidTestAnnotationUsage(input_api, output_api):
4274 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
4275 deprecated_annotation_import_pattern = input_api.re.compile(
4276 r'^import android\.test\.suitebuilder\.annotation\..*;',
4277 input_api.re.MULTILINE)
4278 sources = lambda x: input_api.FilterSourceFile(
4279 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
4280 errors = []
4281 for f in input_api.AffectedFiles(file_filter=sources):
4282 for line_num, line in f.ChangedContents():
4283 if deprecated_annotation_import_pattern.search(line):
4284 errors.append("%s:%d" % (f.LocalPath(), line_num))
4285
4286 results = []
4287 if errors:
4288 results.append(
4289 output_api.PresubmitError(
4290 'Annotations in android.test.suitebuilder.annotation have been'
Mohamed Heikal3d7a94c2023-03-28 16:55:244291 ' deprecated since API level 24. Please use androidx.test.filters'
4292 ' from //third_party/androidx:androidx_test_runner_java instead.'
Sam Maiera6e76d72022-02-11 21:43:504293 ' Contact yolandyan@chromium.org if you have any questions.',
4294 errors))
4295 return results
4296
4297
4298def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
4299 """Checks if MDPI assets are placed in a correct directory."""
Bruce Dawson6c05e852022-07-21 15:48:514300 file_filter = lambda f: (f.LocalPath().endswith(
4301 '.png') and ('/res/drawable/'.replace('/', input_api.os_path.sep) in f.
4302 LocalPath() or '/res/drawable-ldrtl/'.replace(
4303 '/', input_api.os_path.sep) in f.LocalPath()))
Sam Maiera6e76d72022-02-11 21:43:504304 errors = []
4305 for f in input_api.AffectedFiles(include_deletes=False,
4306 file_filter=file_filter):
4307 errors.append(' %s' % f.LocalPath())
4308
4309 results = []
4310 if errors:
4311 results.append(
4312 output_api.PresubmitError(
4313 'MDPI assets should be placed in /res/drawable-mdpi/ or '
4314 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
4315 '/res/drawable-ldrtl/.\n'
4316 'Contact newt@chromium.org if you have questions.', errors))
4317 return results
4318
4319
4320def _CheckAndroidWebkitImports(input_api, output_api):
4321 """Checks that code uses org.chromium.base.Callback instead of
4322 android.webview.ValueCallback except in the WebView glue layer
4323 and WebLayer.
4324 """
4325 valuecallback_import_pattern = input_api.re.compile(
4326 r'^import android\.webkit\.ValueCallback;$')
4327
4328 errors = []
4329
4330 sources = lambda affected_file: input_api.FilterSourceFile(
4331 affected_file,
4332 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4333 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314334 r'^android_webview/glue/.*',
4335 r'^weblayer/.*',
Sam Maiera6e76d72022-02-11 21:43:504336 )),
4337 files_to_check=[r'.*\.java$'])
4338
4339 for f in input_api.AffectedSourceFiles(sources):
4340 for line_num, line in f.ChangedContents():
4341 if valuecallback_import_pattern.search(line):
4342 errors.append("%s:%d" % (f.LocalPath(), line_num))
4343
4344 results = []
4345
4346 if errors:
4347 results.append(
4348 output_api.PresubmitError(
4349 'android.webkit.ValueCallback usage is detected outside of the glue'
4350 ' layer. To stay compatible with the support library, android.webkit.*'
4351 ' classes should only be used inside the glue layer and'
4352 ' org.chromium.base.Callback should be used instead.', errors))
4353
4354 return results
4355
4356
4357def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
4358 """Checks Android XML styles """
4359
4360 # Return early if no relevant files were modified.
4361 if not any(
4362 _IsXmlOrGrdFile(input_api, f.LocalPath())
4363 for f in input_api.AffectedFiles(include_deletes=False)):
4364 return []
4365
4366 import sys
4367 original_sys_path = sys.path
4368 try:
4369 sys.path = sys.path + [
4370 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4371 'android', 'checkxmlstyle')
4372 ]
4373 import checkxmlstyle
4374 finally:
4375 # Restore sys.path to what it was before.
4376 sys.path = original_sys_path
4377
4378 if is_check_on_upload:
4379 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
4380 else:
4381 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
4382
4383
4384def _CheckAndroidInfoBarDeprecation(input_api, output_api):
4385 """Checks Android Infobar Deprecation """
4386
4387 import sys
4388 original_sys_path = sys.path
4389 try:
4390 sys.path = sys.path + [
4391 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4392 'android', 'infobar_deprecation')
4393 ]
4394 import infobar_deprecation
4395 finally:
4396 # Restore sys.path to what it was before.
4397 sys.path = original_sys_path
4398
4399 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
4400
4401
4402class _PydepsCheckerResult:
4403 def __init__(self, cmd, pydeps_path, process, old_contents):
4404 self._cmd = cmd
4405 self._pydeps_path = pydeps_path
4406 self._process = process
4407 self._old_contents = old_contents
4408
4409 def GetError(self):
4410 """Returns an error message, or None."""
4411 import difflib
4412 if self._process.wait() != 0:
4413 # STDERR should already be printed.
4414 return 'Command failed: ' + self._cmd
4415 new_contents = self._process.stdout.read().splitlines()[2:]
4416 if self._old_contents != new_contents:
4417 diff = '\n'.join(
4418 difflib.context_diff(self._old_contents, new_contents))
4419 return ('File is stale: {}\n'
4420 'Diff (apply to fix):\n'
4421 '{}\n'
4422 'To regenerate, run:\n\n'
4423 ' {}').format(self._pydeps_path, diff, self._cmd)
4424 return None
4425
4426
4427class PydepsChecker:
4428 def __init__(self, input_api, pydeps_files):
4429 self._file_cache = {}
4430 self._input_api = input_api
4431 self._pydeps_files = pydeps_files
4432
4433 def _LoadFile(self, path):
4434 """Returns the list of paths within a .pydeps file relative to //."""
4435 if path not in self._file_cache:
4436 with open(path, encoding='utf-8') as f:
4437 self._file_cache[path] = f.read()
4438 return self._file_cache[path]
4439
4440 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
Gao Shenga79ebd42022-08-08 17:25:594441 """Returns an iterable of paths within the .pydep, relativized to //."""
Sam Maiera6e76d72022-02-11 21:43:504442 pydeps_data = self._LoadFile(pydeps_path)
4443 uses_gn_paths = '--gn-paths' in pydeps_data
4444 entries = (l for l in pydeps_data.splitlines()
4445 if not l.startswith('#'))
4446 if uses_gn_paths:
4447 # Paths look like: //foo/bar/baz
4448 return (e[2:] for e in entries)
4449 else:
4450 # Paths look like: path/relative/to/file.pydeps
4451 os_path = self._input_api.os_path
4452 pydeps_dir = os_path.dirname(pydeps_path)
4453 return (os_path.normpath(os_path.join(pydeps_dir, e))
4454 for e in entries)
4455
4456 def _CreateFilesToPydepsMap(self):
4457 """Returns a map of local_path -> list_of_pydeps."""
4458 ret = {}
4459 for pydep_local_path in self._pydeps_files:
4460 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
4461 ret.setdefault(path, []).append(pydep_local_path)
4462 return ret
4463
4464 def ComputeAffectedPydeps(self):
4465 """Returns an iterable of .pydeps files that might need regenerating."""
4466 affected_pydeps = set()
4467 file_to_pydeps_map = None
4468 for f in self._input_api.AffectedFiles(include_deletes=True):
4469 local_path = f.LocalPath()
4470 # Changes to DEPS can lead to .pydeps changes if any .py files are in
4471 # subrepositories. We can't figure out which files change, so re-check
4472 # all files.
4473 # Changes to print_python_deps.py affect all .pydeps.
4474 if local_path in ('DEPS', 'PRESUBMIT.py'
4475 ) or local_path.endswith('print_python_deps.py'):
4476 return self._pydeps_files
4477 elif local_path.endswith('.pydeps'):
4478 if local_path in self._pydeps_files:
4479 affected_pydeps.add(local_path)
4480 elif local_path.endswith('.py'):
4481 if file_to_pydeps_map is None:
4482 file_to_pydeps_map = self._CreateFilesToPydepsMap()
4483 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
4484 return affected_pydeps
4485
4486 def DetermineIfStaleAsync(self, pydeps_path):
4487 """Runs print_python_deps.py to see if the files is stale."""
4488 import os
4489
4490 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
4491 if old_pydeps_data:
4492 cmd = old_pydeps_data[1][1:].strip()
4493 if '--output' not in cmd:
4494 cmd += ' --output ' + pydeps_path
4495 old_contents = old_pydeps_data[2:]
4496 else:
4497 # A default cmd that should work in most cases (as long as pydeps filename
4498 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
4499 # file is empty/new.
4500 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
4501 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
4502 old_contents = []
4503 env = dict(os.environ)
4504 env['PYTHONDONTWRITEBYTECODE'] = '1'
4505 process = self._input_api.subprocess.Popen(
4506 cmd + ' --output ""',
4507 shell=True,
4508 env=env,
4509 stdout=self._input_api.subprocess.PIPE,
4510 encoding='utf-8')
4511 return _PydepsCheckerResult(cmd, pydeps_path, process, old_contents)
agrievef32bcc72016-04-04 14:57:404512
4513
Tibor Goldschwendt360793f72019-06-25 18:23:494514def _ParseGclientArgs():
Sam Maiera6e76d72022-02-11 21:43:504515 args = {}
4516 with open('build/config/gclient_args.gni', 'r') as f:
4517 for line in f:
4518 line = line.strip()
4519 if not line or line.startswith('#'):
4520 continue
4521 attribute, value = line.split('=')
4522 args[attribute.strip()] = value.strip()
4523 return args
Tibor Goldschwendt360793f72019-06-25 18:23:494524
4525
Saagar Sanghavifceeaae2020-08-12 16:40:364526def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
Sam Maiera6e76d72022-02-11 21:43:504527 """Checks if a .pydeps file needs to be regenerated."""
4528 # This check is for Python dependency lists (.pydeps files), and involves
4529 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
4530 # doesn't work on Windows and Mac, so skip it on other platforms.
4531 if not input_api.platform.startswith('linux'):
4532 return []
Erik Staabc734cd7a2021-11-23 03:11:524533
Sam Maiera6e76d72022-02-11 21:43:504534 results = []
4535 # First, check for new / deleted .pydeps.
4536 for f in input_api.AffectedFiles(include_deletes=True):
4537 # Check whether we are running the presubmit check for a file in src.
4538 # f.LocalPath is relative to repo (src, or internal repo).
4539 # os_path.exists is relative to src repo.
4540 # Therefore if os_path.exists is true, it means f.LocalPath is relative
4541 # to src and we can conclude that the pydeps is in src.
4542 if f.LocalPath().endswith('.pydeps'):
4543 if input_api.os_path.exists(f.LocalPath()):
4544 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
4545 results.append(
4546 output_api.PresubmitError(
4547 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
4548 'remove %s' % f.LocalPath()))
4549 elif f.Action() != 'D' and f.LocalPath(
4550 ) not in _ALL_PYDEPS_FILES:
4551 results.append(
4552 output_api.PresubmitError(
4553 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
4554 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:404555
Sam Maiera6e76d72022-02-11 21:43:504556 if results:
4557 return results
4558
4559 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
4560 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
4561 affected_pydeps = set(checker.ComputeAffectedPydeps())
4562 affected_android_pydeps = affected_pydeps.intersection(
4563 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
4564 if affected_android_pydeps and not is_android:
4565 results.append(
4566 output_api.PresubmitPromptOrNotify(
4567 'You have changed python files that may affect pydeps for android\n'
Gao Shenga79ebd42022-08-08 17:25:594568 'specific scripts. However, the relevant presubmit check cannot be\n'
Sam Maiera6e76d72022-02-11 21:43:504569 'run because you are not using an Android checkout. To validate that\n'
4570 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
4571 'use the android-internal-presubmit optional trybot.\n'
4572 'Possibly stale pydeps files:\n{}'.format(
4573 '\n'.join(affected_android_pydeps))))
4574
4575 all_pydeps = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
4576 pydeps_to_check = affected_pydeps.intersection(all_pydeps)
4577 # Process these concurrently, as each one takes 1-2 seconds.
4578 pydep_results = [checker.DetermineIfStaleAsync(p) for p in pydeps_to_check]
4579 for result in pydep_results:
4580 error_msg = result.GetError()
4581 if error_msg:
4582 results.append(output_api.PresubmitError(error_msg))
4583
agrievef32bcc72016-04-04 14:57:404584 return results
4585
agrievef32bcc72016-04-04 14:57:404586
Saagar Sanghavifceeaae2020-08-12 16:40:364587def CheckSingletonInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504588 """Checks to make sure no header files have |Singleton<|."""
4589
4590 def FileFilter(affected_file):
4591 # It's ok for base/memory/singleton.h to have |Singleton<|.
4592 files_to_skip = (_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
Bruce Dawson40fece62022-09-16 19:58:314593 (r"^base/memory/singleton\.h$",
4594 r"^net/quic/platform/impl/quic_singleton_impl\.h$"))
Sam Maiera6e76d72022-02-11 21:43:504595 return input_api.FilterSourceFile(affected_file,
4596 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:434597
Sam Maiera6e76d72022-02-11 21:43:504598 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
4599 files = []
4600 for f in input_api.AffectedSourceFiles(FileFilter):
4601 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx')
4602 or f.LocalPath().endswith('.hpp')
4603 or f.LocalPath().endswith('.inl')):
4604 contents = input_api.ReadFile(f)
4605 for line in contents.splitlines(False):
4606 if (not line.lstrip().startswith('//')
4607 and # Strip C++ comment.
4608 pattern.search(line)):
4609 files.append(f)
4610 break
glidere61efad2015-02-18 17:39:434611
Sam Maiera6e76d72022-02-11 21:43:504612 if files:
4613 return [
4614 output_api.PresubmitError(
4615 'Found base::Singleton<T> in the following header files.\n' +
4616 'Please move them to an appropriate source file so that the ' +
4617 'template gets instantiated in a single compilation unit.',
4618 files)
4619 ]
4620 return []
glidere61efad2015-02-18 17:39:434621
4622
jchaffraix@chromium.orgfd20b902014-05-09 02:14:534623_DEPRECATED_CSS = [
4624 # Values
4625 ( "-webkit-box", "flex" ),
4626 ( "-webkit-inline-box", "inline-flex" ),
4627 ( "-webkit-flex", "flex" ),
4628 ( "-webkit-inline-flex", "inline-flex" ),
4629 ( "-webkit-min-content", "min-content" ),
4630 ( "-webkit-max-content", "max-content" ),
4631
4632 # Properties
4633 ( "-webkit-background-clip", "background-clip" ),
4634 ( "-webkit-background-origin", "background-origin" ),
4635 ( "-webkit-background-size", "background-size" ),
4636 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:444637 ( "-webkit-user-select", "user-select" ),
jchaffraix@chromium.orgfd20b902014-05-09 02:14:534638
4639 # Functions
4640 ( "-webkit-gradient", "gradient" ),
4641 ( "-webkit-repeating-gradient", "repeating-gradient" ),
4642 ( "-webkit-linear-gradient", "linear-gradient" ),
4643 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
4644 ( "-webkit-radial-gradient", "radial-gradient" ),
4645 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
4646]
4647
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:204648
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:494649# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:364650def CheckNoDeprecatedCss(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504651 """ Make sure that we don't use deprecated CSS
4652 properties, functions or values. Our external
4653 documentation and iOS CSS for dom distiller
4654 (reader mode) are ignored by the hooks as it
4655 needs to be consumed by WebKit. """
4656 results = []
4657 file_inclusion_pattern = [r".+\.css$"]
4658 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
4659 input_api.DEFAULT_FILES_TO_SKIP +
4660 (r"^chrome/common/extensions/docs", r"^chrome/docs",
4661 r"^native_client_sdk"))
4662 file_filter = lambda f: input_api.FilterSourceFile(
4663 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
4664 for fpath in input_api.AffectedFiles(file_filter=file_filter):
4665 for line_num, line in fpath.ChangedContents():
4666 for (deprecated_value, value) in _DEPRECATED_CSS:
4667 if deprecated_value in line:
4668 results.append(
4669 output_api.PresubmitError(
4670 "%s:%d: Use of deprecated CSS %s, use %s instead" %
4671 (fpath.LocalPath(), line_num, deprecated_value,
4672 value)))
4673 return results
jchaffraix@chromium.orgfd20b902014-05-09 02:14:534674
mohan.reddyf21db962014-10-16 12:26:474675
Saagar Sanghavifceeaae2020-08-12 16:40:364676def CheckForRelativeIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504677 bad_files = {}
4678 for f in input_api.AffectedFiles(include_deletes=False):
4679 if (f.LocalPath().startswith('third_party')
4680 and not f.LocalPath().startswith('third_party/blink')
4681 and not f.LocalPath().startswith('third_party\\blink')):
4682 continue
rlanday6802cf632017-05-30 17:48:364683
Sam Maiera6e76d72022-02-11 21:43:504684 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
4685 continue
rlanday6802cf632017-05-30 17:48:364686
Sam Maiera6e76d72022-02-11 21:43:504687 relative_includes = [
4688 line for _, line in f.ChangedContents()
4689 if "#include" in line and "../" in line
4690 ]
4691 if not relative_includes:
4692 continue
4693 bad_files[f.LocalPath()] = relative_includes
rlanday6802cf632017-05-30 17:48:364694
Sam Maiera6e76d72022-02-11 21:43:504695 if not bad_files:
4696 return []
rlanday6802cf632017-05-30 17:48:364697
Sam Maiera6e76d72022-02-11 21:43:504698 error_descriptions = []
4699 for file_path, bad_lines in bad_files.items():
4700 error_description = file_path
4701 for line in bad_lines:
4702 error_description += '\n ' + line
4703 error_descriptions.append(error_description)
rlanday6802cf632017-05-30 17:48:364704
Sam Maiera6e76d72022-02-11 21:43:504705 results = []
4706 results.append(
4707 output_api.PresubmitError(
4708 'You added one or more relative #include paths (including "../").\n'
4709 'These shouldn\'t be used because they can be used to include headers\n'
4710 'from code that\'s not correctly specified as a dependency in the\n'
4711 'relevant BUILD.gn file(s).', error_descriptions))
rlanday6802cf632017-05-30 17:48:364712
Sam Maiera6e76d72022-02-11 21:43:504713 return results
rlanday6802cf632017-05-30 17:48:364714
Takeshi Yoshinoe387aa32017-08-02 13:16:134715
Saagar Sanghavifceeaae2020-08-12 16:40:364716def CheckForCcIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504717 """Check that nobody tries to include a cc file. It's a relatively
4718 common error which results in duplicate symbols in object
4719 files. This may not always break the build until someone later gets
4720 very confusing linking errors."""
4721 results = []
4722 for f in input_api.AffectedFiles(include_deletes=False):
4723 # We let third_party code do whatever it wants
4724 if (f.LocalPath().startswith('third_party')
4725 and not f.LocalPath().startswith('third_party/blink')
4726 and not f.LocalPath().startswith('third_party\\blink')):
4727 continue
Daniel Bratell65b033262019-04-23 08:17:064728
Sam Maiera6e76d72022-02-11 21:43:504729 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
4730 continue
Daniel Bratell65b033262019-04-23 08:17:064731
Sam Maiera6e76d72022-02-11 21:43:504732 for _, line in f.ChangedContents():
4733 if line.startswith('#include "'):
4734 included_file = line.split('"')[1]
4735 if _IsCPlusPlusFile(input_api, included_file):
4736 # The most common naming for external files with C++ code,
4737 # apart from standard headers, is to call them foo.inc, but
4738 # Chromium sometimes uses foo-inc.cc so allow that as well.
4739 if not included_file.endswith(('.h', '-inc.cc')):
4740 results.append(
4741 output_api.PresubmitError(
4742 'Only header files or .inc files should be included in other\n'
4743 'C++ files. Compiling the contents of a cc file more than once\n'
4744 'will cause duplicate information in the build which may later\n'
4745 'result in strange link_errors.\n' +
4746 f.LocalPath() + ':\n ' + line))
Daniel Bratell65b033262019-04-23 08:17:064747
Sam Maiera6e76d72022-02-11 21:43:504748 return results
Daniel Bratell65b033262019-04-23 08:17:064749
4750
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204751def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
Sam Maiera6e76d72022-02-11 21:43:504752 if not isinstance(key, ast.Str):
4753 return 'Key at line %d must be a string literal' % key.lineno
4754 if not isinstance(value, ast.Dict):
4755 return 'Value at line %d must be a dict' % value.lineno
4756 if len(value.keys) != 1:
4757 return 'Dict at line %d must have single entry' % value.lineno
4758 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
4759 return (
4760 'Entry at line %d must have a string literal \'filepath\' as key' %
4761 value.lineno)
4762 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:134763
Takeshi Yoshinoe387aa32017-08-02 13:16:134764
Sergey Ulanov4af16052018-11-08 02:41:464765def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Sam Maiera6e76d72022-02-11 21:43:504766 if not isinstance(key, ast.Str):
4767 return 'Key at line %d must be a string literal' % key.lineno
4768 if not isinstance(value, ast.List):
4769 return 'Value at line %d must be a list' % value.lineno
4770 for element in value.elts:
4771 if not isinstance(element, ast.Str):
4772 return 'Watchlist elements on line %d is not a string' % key.lineno
4773 if not email_regex.match(element.s):
4774 return ('Watchlist element on line %d doesn\'t look like a valid '
4775 + 'email: %s') % (key.lineno, element.s)
4776 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:134777
Takeshi Yoshinoe387aa32017-08-02 13:16:134778
Sergey Ulanov4af16052018-11-08 02:41:464779def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Sam Maiera6e76d72022-02-11 21:43:504780 mismatch_template = (
4781 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
4782 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:134783
Sam Maiera6e76d72022-02-11 21:43:504784 email_regex = input_api.re.compile(
4785 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
Sergey Ulanov4af16052018-11-08 02:41:464786
Sam Maiera6e76d72022-02-11 21:43:504787 ast = input_api.ast
4788 i = 0
4789 last_key = ''
4790 while True:
4791 if i >= len(wd_dict.keys):
4792 if i >= len(w_dict.keys):
4793 return None
4794 return mismatch_template % ('missing',
4795 'line %d' % w_dict.keys[i].lineno)
4796 elif i >= len(w_dict.keys):
4797 return (mismatch_template %
4798 ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:134799
Sam Maiera6e76d72022-02-11 21:43:504800 wd_key = wd_dict.keys[i]
4801 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:134802
Sam Maiera6e76d72022-02-11 21:43:504803 result = _CheckWatchlistDefinitionsEntrySyntax(wd_key,
4804 wd_dict.values[i], ast)
4805 if result is not None:
4806 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:134807
Sam Maiera6e76d72022-02-11 21:43:504808 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast,
4809 email_regex)
4810 if result is not None:
4811 return 'Bad entry in WATCHLISTS dict: %s' % result
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204812
Sam Maiera6e76d72022-02-11 21:43:504813 if wd_key.s != w_key.s:
4814 return mismatch_template % ('%s at line %d' %
4815 (wd_key.s, wd_key.lineno),
4816 '%s at line %d' %
4817 (w_key.s, w_key.lineno))
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204818
Sam Maiera6e76d72022-02-11 21:43:504819 if wd_key.s < last_key:
4820 return (
4821 'WATCHLISTS dict is not sorted lexicographically at line %d and %d'
4822 % (wd_key.lineno, w_key.lineno))
4823 last_key = wd_key.s
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204824
Sam Maiera6e76d72022-02-11 21:43:504825 i = i + 1
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204826
4827
Sergey Ulanov4af16052018-11-08 02:41:464828def _CheckWATCHLISTSSyntax(expression, input_api):
Sam Maiera6e76d72022-02-11 21:43:504829 ast = input_api.ast
4830 if not isinstance(expression, ast.Expression):
4831 return 'WATCHLISTS file must contain a valid expression'
4832 dictionary = expression.body
4833 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
4834 return 'WATCHLISTS file must have single dict with exactly two entries'
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204835
Sam Maiera6e76d72022-02-11 21:43:504836 first_key = dictionary.keys[0]
4837 first_value = dictionary.values[0]
4838 second_key = dictionary.keys[1]
4839 second_value = dictionary.values[1]
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204840
Sam Maiera6e76d72022-02-11 21:43:504841 if (not isinstance(first_key, ast.Str)
4842 or first_key.s != 'WATCHLIST_DEFINITIONS'
4843 or not isinstance(first_value, ast.Dict)):
4844 return ('The first entry of the dict in WATCHLISTS file must be '
4845 'WATCHLIST_DEFINITIONS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204846
Sam Maiera6e76d72022-02-11 21:43:504847 if (not isinstance(second_key, ast.Str) or second_key.s != 'WATCHLISTS'
4848 or not isinstance(second_value, ast.Dict)):
4849 return ('The second entry of the dict in WATCHLISTS file must be '
4850 'WATCHLISTS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204851
Sam Maiera6e76d72022-02-11 21:43:504852 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:134853
4854
Saagar Sanghavifceeaae2020-08-12 16:40:364855def CheckWATCHLISTS(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504856 for f in input_api.AffectedFiles(include_deletes=False):
4857 if f.LocalPath() == 'WATCHLISTS':
4858 contents = input_api.ReadFile(f, 'r')
Takeshi Yoshinoe387aa32017-08-02 13:16:134859
Sam Maiera6e76d72022-02-11 21:43:504860 try:
4861 # First, make sure that it can be evaluated.
4862 input_api.ast.literal_eval(contents)
4863 # Get an AST tree for it and scan the tree for detailed style checking.
4864 expression = input_api.ast.parse(contents,
4865 filename='WATCHLISTS',
4866 mode='eval')
4867 except ValueError as e:
4868 return [
4869 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4870 long_text=repr(e))
4871 ]
4872 except SyntaxError as e:
4873 return [
4874 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4875 long_text=repr(e))
4876 ]
4877 except TypeError as e:
4878 return [
4879 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4880 long_text=repr(e))
4881 ]
Takeshi Yoshinoe387aa32017-08-02 13:16:134882
Sam Maiera6e76d72022-02-11 21:43:504883 result = _CheckWATCHLISTSSyntax(expression, input_api)
4884 if result is not None:
4885 return [output_api.PresubmitError(result)]
4886 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134887
Sam Maiera6e76d72022-02-11 21:43:504888 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:134889
Sean Kaucb7c9b32022-10-25 21:25:524890def CheckGnRebasePath(input_api, output_api):
4891 """Checks that target_gen_dir is not used wtih "//" in rebase_path().
4892
4893 Developers should use root_build_dir instead of "//" when using target_gen_dir because
4894 Chromium is sometimes built outside of the source tree.
4895 """
4896
4897 def gn_files(f):
4898 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
4899
4900 rebase_path_regex = input_api.re.compile(r'rebase_path\(("\$target_gen_dir"|target_gen_dir), ("/"|"//")\)')
4901 problems = []
4902 for f in input_api.AffectedSourceFiles(gn_files):
4903 for line_num, line in f.ChangedContents():
4904 if rebase_path_regex.search(line):
4905 problems.append(
4906 'Absolute path in rebase_path() in %s:%d' %
4907 (f.LocalPath(), line_num))
4908
4909 if problems:
4910 return [
4911 output_api.PresubmitPromptWarning(
4912 'Using an absolute path in rebase_path()',
4913 items=sorted(problems),
4914 long_text=(
4915 'rebase_path() should use root_build_dir instead of "/" ',
4916 'since builds can be initiated from outside of the source ',
4917 'root.'))
4918 ]
4919 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:134920
Andrew Grieve1b290e4a22020-11-24 20:07:014921def CheckGnGlobForward(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504922 """Checks that forward_variables_from(invoker, "*") follows best practices.
Andrew Grieve1b290e4a22020-11-24 20:07:014923
Sam Maiera6e76d72022-02-11 21:43:504924 As documented at //build/docs/writing_gn_templates.md
4925 """
Andrew Grieve1b290e4a22020-11-24 20:07:014926
Sam Maiera6e76d72022-02-11 21:43:504927 def gn_files(f):
4928 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
Andrew Grieve1b290e4a22020-11-24 20:07:014929
Sam Maiera6e76d72022-02-11 21:43:504930 problems = []
4931 for f in input_api.AffectedSourceFiles(gn_files):
4932 for line_num, line in f.ChangedContents():
4933 if 'forward_variables_from(invoker, "*")' in line:
4934 problems.append(
4935 'Bare forward_variables_from(invoker, "*") in %s:%d' %
4936 (f.LocalPath(), line_num))
4937
4938 if problems:
4939 return [
4940 output_api.PresubmitPromptWarning(
4941 'forward_variables_from("*") without exclusions',
4942 items=sorted(problems),
4943 long_text=(
Gao Shenga79ebd42022-08-08 17:25:594944 'The variables "visibility" and "test_only" should be '
Sam Maiera6e76d72022-02-11 21:43:504945 'explicitly listed in forward_variables_from(). For more '
4946 'details, see:\n'
4947 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
4948 'build/docs/writing_gn_templates.md'
4949 '#Using-forward_variables_from'))
4950 ]
4951 return []
Andrew Grieve1b290e4a22020-11-24 20:07:014952
Saagar Sanghavifceeaae2020-08-12 16:40:364953def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504954 """Checks that newly added header files have corresponding GN changes.
4955 Note that this is only a heuristic. To be precise, run script:
4956 build/check_gn_headers.py.
4957 """
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194958
Sam Maiera6e76d72022-02-11 21:43:504959 def headers(f):
4960 return input_api.FilterSourceFile(
4961 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194962
Sam Maiera6e76d72022-02-11 21:43:504963 new_headers = []
4964 for f in input_api.AffectedSourceFiles(headers):
4965 if f.Action() != 'A':
4966 continue
4967 new_headers.append(f.LocalPath())
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194968
Sam Maiera6e76d72022-02-11 21:43:504969 def gn_files(f):
4970 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194971
Sam Maiera6e76d72022-02-11 21:43:504972 all_gn_changed_contents = ''
4973 for f in input_api.AffectedSourceFiles(gn_files):
4974 for _, line in f.ChangedContents():
4975 all_gn_changed_contents += line
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194976
Sam Maiera6e76d72022-02-11 21:43:504977 problems = []
4978 for header in new_headers:
4979 basename = input_api.os_path.basename(header)
4980 if basename not in all_gn_changed_contents:
4981 problems.append(header)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194982
Sam Maiera6e76d72022-02-11 21:43:504983 if problems:
4984 return [
4985 output_api.PresubmitPromptWarning(
4986 'Missing GN changes for new header files',
4987 items=sorted(problems),
4988 long_text=
4989 'Please double check whether newly added header files need '
4990 'corresponding changes in gn or gni files.\nThis checking is only a '
4991 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4992 'Read https://crbug.com/661774 for more info.')
4993 ]
4994 return []
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194995
4996
Saagar Sanghavifceeaae2020-08-12 16:40:364997def CheckCorrectProductNameInMessages(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504998 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
Michael Giuffridad3bc8672018-10-25 22:48:024999
Sam Maiera6e76d72022-02-11 21:43:505000 This assumes we won't intentionally reference one product from the other
5001 product.
5002 """
5003 all_problems = []
5004 test_cases = [{
5005 "filename_postfix": "google_chrome_strings.grd",
5006 "correct_name": "Chrome",
5007 "incorrect_name": "Chromium",
5008 }, {
5009 "filename_postfix": "chromium_strings.grd",
5010 "correct_name": "Chromium",
5011 "incorrect_name": "Chrome",
5012 }]
Michael Giuffridad3bc8672018-10-25 22:48:025013
Sam Maiera6e76d72022-02-11 21:43:505014 for test_case in test_cases:
5015 problems = []
5016 filename_filter = lambda x: x.LocalPath().endswith(test_case[
5017 "filename_postfix"])
Michael Giuffridad3bc8672018-10-25 22:48:025018
Sam Maiera6e76d72022-02-11 21:43:505019 # Check each new line. Can yield false positives in multiline comments, but
5020 # easier than trying to parse the XML because messages can have nested
5021 # children, and associating message elements with affected lines is hard.
5022 for f in input_api.AffectedSourceFiles(filename_filter):
5023 for line_num, line in f.ChangedContents():
5024 if "<message" in line or "<!--" in line or "-->" in line:
5025 continue
5026 if test_case["incorrect_name"] in line:
5027 problems.append("Incorrect product name in %s:%d" %
5028 (f.LocalPath(), line_num))
Michael Giuffridad3bc8672018-10-25 22:48:025029
Sam Maiera6e76d72022-02-11 21:43:505030 if problems:
5031 message = (
5032 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
5033 % (test_case["correct_name"], test_case["correct_name"],
5034 test_case["incorrect_name"]))
5035 all_problems.append(
5036 output_api.PresubmitPromptWarning(message, items=problems))
Michael Giuffridad3bc8672018-10-25 22:48:025037
Sam Maiera6e76d72022-02-11 21:43:505038 return all_problems
Michael Giuffridad3bc8672018-10-25 22:48:025039
5040
Saagar Sanghavifceeaae2020-08-12 16:40:365041def CheckForTooLargeFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505042 """Avoid large files, especially binary files, in the repository since
5043 git doesn't scale well for those. They will be in everyone's repo
5044 clones forever, forever making Chromium slower to clone and work
5045 with."""
Daniel Bratell93eb6c62019-04-29 20:13:365046
Sam Maiera6e76d72022-02-11 21:43:505047 # Uploading files to cloud storage is not trivial so we don't want
5048 # to set the limit too low, but the upper limit for "normal" large
5049 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
5050 # anything over 20 MB is exceptional.
Bruce Dawsonbb414db2022-12-27 20:21:255051 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024
Daniel Bratell93eb6c62019-04-29 20:13:365052
Sam Maiera6e76d72022-02-11 21:43:505053 too_large_files = []
5054 for f in input_api.AffectedFiles():
5055 # Check both added and modified files (but not deleted files).
5056 if f.Action() in ('A', 'M'):
5057 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Joe DeBlasio10a832f2023-04-21 20:20:185058 if size > TOO_LARGE_FILE_SIZE_LIMIT:
Sam Maiera6e76d72022-02-11 21:43:505059 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
Daniel Bratell93eb6c62019-04-29 20:13:365060
Sam Maiera6e76d72022-02-11 21:43:505061 if too_large_files:
5062 message = (
5063 'Do not commit large files to git since git scales badly for those.\n'
5064 +
5065 'Instead put the large files in cloud storage and use DEPS to\n' +
5066 'fetch them.\n' + '\n'.join(too_large_files))
5067 return [
5068 output_api.PresubmitError('Too large files found in commit',
5069 long_text=message + '\n')
5070 ]
5071 else:
5072 return []
Daniel Bratell93eb6c62019-04-29 20:13:365073
Max Morozb47503b2019-08-08 21:03:275074
Saagar Sanghavifceeaae2020-08-12 16:40:365075def CheckFuzzTargetsOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505076 """Checks specific for fuzz target sources."""
5077 EXPORTED_SYMBOLS = [
5078 'LLVMFuzzerInitialize',
5079 'LLVMFuzzerCustomMutator',
5080 'LLVMFuzzerCustomCrossOver',
5081 'LLVMFuzzerMutate',
5082 ]
Max Morozb47503b2019-08-08 21:03:275083
Sam Maiera6e76d72022-02-11 21:43:505084 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
Max Morozb47503b2019-08-08 21:03:275085
Sam Maiera6e76d72022-02-11 21:43:505086 def FilterFile(affected_file):
5087 """Ignore libFuzzer source code."""
5088 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
Bruce Dawson40fece62022-09-16 19:58:315089 files_to_skip = r"^third_party/libFuzzer"
Max Morozb47503b2019-08-08 21:03:275090
Sam Maiera6e76d72022-02-11 21:43:505091 return input_api.FilterSourceFile(affected_file,
5092 files_to_check=[files_to_check],
5093 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:275094
Sam Maiera6e76d72022-02-11 21:43:505095 files_with_missing_header = []
5096 for f in input_api.AffectedSourceFiles(FilterFile):
5097 contents = input_api.ReadFile(f, 'r')
5098 if REQUIRED_HEADER in contents:
5099 continue
Max Morozb47503b2019-08-08 21:03:275100
Sam Maiera6e76d72022-02-11 21:43:505101 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
5102 files_with_missing_header.append(f.LocalPath())
Max Morozb47503b2019-08-08 21:03:275103
Sam Maiera6e76d72022-02-11 21:43:505104 if not files_with_missing_header:
5105 return []
Max Morozb47503b2019-08-08 21:03:275106
Sam Maiera6e76d72022-02-11 21:43:505107 long_text = (
5108 'If you define any of the libFuzzer optional functions (%s), it is '
5109 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
5110 'work incorrectly on Mac (crbug.com/687076).\nNote that '
5111 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
5112 'to access command line arguments passed to the fuzzer. Instead, prefer '
5113 'static initialization and shared resources as documented in '
5114 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
5115 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n'
5116 % (', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER))
Max Morozb47503b2019-08-08 21:03:275117
Sam Maiera6e76d72022-02-11 21:43:505118 return [
5119 output_api.PresubmitPromptWarning(message="Missing '%s' in:" %
5120 REQUIRED_HEADER,
5121 items=files_with_missing_header,
5122 long_text=long_text)
5123 ]
Max Morozb47503b2019-08-08 21:03:275124
5125
Mohamed Heikald048240a2019-11-12 16:57:375126def _CheckNewImagesWarning(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505127 """
5128 Warns authors who add images into the repo to make sure their images are
5129 optimized before committing.
5130 """
5131 images_added = False
5132 image_paths = []
5133 errors = []
5134 filter_lambda = lambda x: input_api.FilterSourceFile(
5135 x,
5136 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
5137 DEFAULT_FILES_TO_SKIP),
5138 files_to_check=[r'.*\/(drawable|mipmap)'])
5139 for f in input_api.AffectedFiles(include_deletes=False,
5140 file_filter=filter_lambda):
5141 local_path = f.LocalPath().lower()
5142 if any(
5143 local_path.endswith(extension)
5144 for extension in _IMAGE_EXTENSIONS):
5145 images_added = True
5146 image_paths.append(f)
5147 if images_added:
5148 errors.append(
5149 output_api.PresubmitPromptWarning(
5150 'It looks like you are trying to commit some images. If these are '
5151 'non-test-only images, please make sure to read and apply the tips in '
5152 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
5153 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
5154 'FYI only and will not block your CL on the CQ.', image_paths))
5155 return errors
Mohamed Heikald048240a2019-11-12 16:57:375156
5157
Saagar Sanghavifceeaae2020-08-12 16:40:365158def ChecksAndroidSpecificOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505159 """Groups upload checks that target android code."""
5160 results = []
5161 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
5162 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
5163 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
5164 results.extend(_CheckAndroidToastUsage(input_api, output_api))
5165 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
5166 results.extend(_CheckAndroidTestJUnitFrameworkImport(
5167 input_api, output_api))
5168 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
5169 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
5170 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
5171 results.extend(_CheckNewImagesWarning(input_api, output_api))
5172 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
5173 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
5174 return results
5175
Becky Zhou7c69b50992018-12-10 19:37:575176
Saagar Sanghavifceeaae2020-08-12 16:40:365177def ChecksAndroidSpecificOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505178 """Groups commit checks that target android code."""
5179 results = []
5180 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
5181 return results
dgnaa68d5e2015-06-10 10:08:225182
Chris Hall59f8d0c72020-05-01 07:31:195183# TODO(chrishall): could we additionally match on any path owned by
5184# ui/accessibility/OWNERS ?
5185_ACCESSIBILITY_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:315186 r"^chrome/browser.*/accessibility/",
5187 r"^chrome/browser/extensions/api/automation.*/",
5188 r"^chrome/renderer/extensions/accessibility_.*",
5189 r"^chrome/tests/data/accessibility/",
Katie Dektar58ef07b2022-09-27 13:19:175190 r"^components/services/screen_ai/",
Bruce Dawson40fece62022-09-16 19:58:315191 r"^content/browser/accessibility/",
5192 r"^content/renderer/accessibility/",
5193 r"^content/tests/data/accessibility/",
5194 r"^extensions/renderer/api/automation/",
Katie Dektar58ef07b2022-09-27 13:19:175195 r"^services/accessibility/",
Bruce Dawson40fece62022-09-16 19:58:315196 r"^ui/accessibility/",
5197 r"^ui/views/accessibility/",
Chris Hall59f8d0c72020-05-01 07:31:195198)
5199
Saagar Sanghavifceeaae2020-08-12 16:40:365200def CheckAccessibilityRelnotesField(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505201 """Checks that commits to accessibility code contain an AX-Relnotes field in
5202 their commit message."""
Chris Hall59f8d0c72020-05-01 07:31:195203
Sam Maiera6e76d72022-02-11 21:43:505204 def FileFilter(affected_file):
5205 paths = _ACCESSIBILITY_PATHS
5206 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:195207
Sam Maiera6e76d72022-02-11 21:43:505208 # Only consider changes affecting accessibility paths.
5209 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
5210 return []
Akihiro Ota08108e542020-05-20 15:30:535211
Sam Maiera6e76d72022-02-11 21:43:505212 # AX-Relnotes can appear in either the description or the footer.
5213 # When searching the description, require 'AX-Relnotes:' to appear at the
5214 # beginning of a line.
5215 ax_regex = input_api.re.compile('ax-relnotes[:=]')
5216 description_has_relnotes = any(
5217 ax_regex.match(line)
5218 for line in input_api.change.DescriptionText().lower().splitlines())
Chris Hall59f8d0c72020-05-01 07:31:195219
Sam Maiera6e76d72022-02-11 21:43:505220 footer_relnotes = input_api.change.GitFootersFromDescription().get(
5221 'AX-Relnotes', [])
5222 if description_has_relnotes or footer_relnotes:
5223 return []
Chris Hall59f8d0c72020-05-01 07:31:195224
Sam Maiera6e76d72022-02-11 21:43:505225 # TODO(chrishall): link to Relnotes documentation in message.
5226 message = (
5227 "Missing 'AX-Relnotes:' field required for accessibility changes"
5228 "\n please add 'AX-Relnotes: [release notes].' to describe any "
5229 "user-facing changes"
5230 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
5231 "user-facing effects"
5232 "\n if this is confusing or annoying then please contact members "
5233 "of ui/accessibility/OWNERS.")
5234
5235 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:225236
Mark Schillacie5a0be22022-01-19 00:38:395237
5238_ACCESSIBILITY_EVENTS_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315239 r"^content/test/data/accessibility/event/.*\.html",
Mark Schillacie5a0be22022-01-19 00:38:395240)
5241
5242_ACCESSIBILITY_TREE_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315243 r"^content/test/data/accessibility/accname/.*\.html",
5244 r"^content/test/data/accessibility/aria/.*\.html",
5245 r"^content/test/data/accessibility/css/.*\.html",
5246 r"^content/test/data/accessibility/html/.*\.html",
Mark Schillacie5a0be22022-01-19 00:38:395247)
5248
5249_ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315250 r"^.*/WebContentsAccessibilityEventsTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:395251)
5252
5253_ACCESSIBILITY_ANDROID_TREE_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315254 r"^.*/WebContentsAccessibilityTreeTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:395255)
5256
5257def CheckAccessibilityEventsTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505258 """Checks that commits that include a newly added, renamed/moved, or deleted
5259 test in the DumpAccessibilityEventsTest suite also includes a corresponding
5260 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:395261
Sam Maiera6e76d72022-02-11 21:43:505262 def FilePathFilter(affected_file):
5263 paths = _ACCESSIBILITY_EVENTS_TEST_PATH
5264 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395265
Sam Maiera6e76d72022-02-11 21:43:505266 def AndroidFilePathFilter(affected_file):
5267 paths = _ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH
5268 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395269
Sam Maiera6e76d72022-02-11 21:43:505270 # Only consider changes in the events test data path with html type.
5271 if not any(
5272 input_api.AffectedFiles(include_deletes=True,
5273 file_filter=FilePathFilter)):
5274 return []
Mark Schillacie5a0be22022-01-19 00:38:395275
Sam Maiera6e76d72022-02-11 21:43:505276 # If the commit contains any change to the Android test file, ignore.
5277 if any(
5278 input_api.AffectedFiles(include_deletes=True,
5279 file_filter=AndroidFilePathFilter)):
5280 return []
Mark Schillacie5a0be22022-01-19 00:38:395281
Sam Maiera6e76d72022-02-11 21:43:505282 # Only consider changes that are adding/renaming or deleting a file
5283 message = []
5284 for f in input_api.AffectedFiles(include_deletes=True,
5285 file_filter=FilePathFilter):
5286 if f.Action() == 'A' or f.Action() == 'D':
5287 message = (
5288 "It appears that you are adding, renaming or deleting"
5289 "\na dump_accessibility_events* test, but have not included"
5290 "\na corresponding change for Android."
5291 "\nPlease include (or remove) the test from:"
5292 "\n content/public/android/javatests/src/org/chromium/"
5293 "content/browser/accessibility/"
5294 "WebContentsAccessibilityEventsTest.java"
5295 "\nIf this message is confusing or annoying, please contact"
5296 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:395297
Sam Maiera6e76d72022-02-11 21:43:505298 # If no message was set, return empty.
5299 if not len(message):
5300 return []
5301
5302 return [output_api.PresubmitPromptWarning(message)]
5303
Mark Schillacie5a0be22022-01-19 00:38:395304
5305def CheckAccessibilityTreeTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505306 """Checks that commits that include a newly added, renamed/moved, or deleted
5307 test in the DumpAccessibilityTreeTest suite also includes a corresponding
5308 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:395309
Sam Maiera6e76d72022-02-11 21:43:505310 def FilePathFilter(affected_file):
5311 paths = _ACCESSIBILITY_TREE_TEST_PATH
5312 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395313
Sam Maiera6e76d72022-02-11 21:43:505314 def AndroidFilePathFilter(affected_file):
5315 paths = _ACCESSIBILITY_ANDROID_TREE_TEST_PATH
5316 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395317
Sam Maiera6e76d72022-02-11 21:43:505318 # Only consider changes in the various tree test data paths with html type.
5319 if not any(
5320 input_api.AffectedFiles(include_deletes=True,
5321 file_filter=FilePathFilter)):
5322 return []
Mark Schillacie5a0be22022-01-19 00:38:395323
Sam Maiera6e76d72022-02-11 21:43:505324 # If the commit contains any change to the Android test file, ignore.
5325 if any(
5326 input_api.AffectedFiles(include_deletes=True,
5327 file_filter=AndroidFilePathFilter)):
5328 return []
Mark Schillacie5a0be22022-01-19 00:38:395329
Sam Maiera6e76d72022-02-11 21:43:505330 # Only consider changes that are adding/renaming or deleting a file
5331 message = []
5332 for f in input_api.AffectedFiles(include_deletes=True,
5333 file_filter=FilePathFilter):
5334 if f.Action() == 'A' or f.Action() == 'D':
5335 message = (
5336 "It appears that you are adding, renaming or deleting"
5337 "\na dump_accessibility_tree* test, but have not included"
5338 "\na corresponding change for Android."
5339 "\nPlease include (or remove) the test from:"
5340 "\n content/public/android/javatests/src/org/chromium/"
5341 "content/browser/accessibility/"
5342 "WebContentsAccessibilityTreeTest.java"
5343 "\nIf this message is confusing or annoying, please contact"
5344 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:395345
Sam Maiera6e76d72022-02-11 21:43:505346 # If no message was set, return empty.
5347 if not len(message):
5348 return []
5349
5350 return [output_api.PresubmitPromptWarning(message)]
Mark Schillacie5a0be22022-01-19 00:38:395351
5352
Bruce Dawson33806592022-11-16 01:44:515353def CheckEsLintConfigChanges(input_api, output_api):
5354 """Suggest using "git cl presubmit --files" when .eslintrc.js files are
5355 modified. This is important because enabling an error in .eslintrc.js can
5356 trigger errors in any .js or .ts files in its directory, leading to hidden
5357 presubmit errors."""
5358 results = []
5359 eslint_filter = lambda f: input_api.FilterSourceFile(
5360 f, files_to_check=[r'.*\.eslintrc\.js$'])
5361 for f in input_api.AffectedFiles(include_deletes=False,
5362 file_filter=eslint_filter):
5363 local_dir = input_api.os_path.dirname(f.LocalPath())
5364 # Use / characters so that the commands printed work on any OS.
5365 local_dir = local_dir.replace(input_api.os_path.sep, '/')
5366 if local_dir:
5367 local_dir += '/'
5368 results.append(
5369 output_api.PresubmitNotifyResult(
5370 '%(file)s modified. Consider running \'git cl presubmit --files '
5371 '"%(dir)s*.js;%(dir)s*.ts"\' in order to check and fix the affected '
5372 'files before landing this change.' %
5373 { 'file' : f.LocalPath(), 'dir' : local_dir}))
5374 return results
5375
5376
seanmccullough4a9356252021-04-08 19:54:095377# string pattern, sequence of strings to show when pattern matches,
5378# error flag. True if match is a presubmit error, otherwise it's a warning.
5379_NON_INCLUSIVE_TERMS = (
5380 (
5381 # Note that \b pattern in python re is pretty particular. In this
5382 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
5383 # ...' will not. This may require some tweaking to catch these cases
5384 # without triggering a lot of false positives. Leaving it naive and
5385 # less matchy for now.
seanmccullough56d1e3cf2021-12-03 18:18:325386 r'/\b(?i)((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:095387 (
5388 'Please don\'t use blacklist, whitelist, ' # nocheck
5389 'or slave in your', # nocheck
5390 'code and make every effort to use other terms. Using "// nocheck"',
5391 '"# nocheck" or "<!-- nocheck -->"',
5392 'at the end of the offending line will bypass this PRESUBMIT error',
5393 'but avoid using this whenever possible. Reach out to',
5394 'community@chromium.org if you have questions'),
5395 True),)
5396
Saagar Sanghavifceeaae2020-08-12 16:40:365397def ChecksCommon(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505398 """Checks common to both upload and commit."""
5399 results = []
Eric Boren6fd2b932018-01-25 15:05:085400 results.extend(
Sam Maiera6e76d72022-02-11 21:43:505401 input_api.canned_checks.PanProjectChecks(
5402 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:085403
Sam Maiera6e76d72022-02-11 21:43:505404 author = input_api.change.author_email
5405 if author and author not in _KNOWN_ROBOTS:
5406 results.extend(
5407 input_api.canned_checks.CheckAuthorizedAuthor(
5408 input_api, output_api))
marja@chromium.org2299dcf2012-11-15 19:56:245409
Sam Maiera6e76d72022-02-11 21:43:505410 results.extend(
5411 input_api.canned_checks.CheckChangeHasNoTabs(
5412 input_api,
5413 output_api,
5414 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
5415 results.extend(
5416 input_api.RunTests(
5417 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Edward Lesmesce51df52020-08-04 22:10:175418
Bruce Dawsonc8054482022-03-28 15:33:375419 dirmd = 'dirmd.bat' if input_api.is_windows else 'dirmd'
Sam Maiera6e76d72022-02-11 21:43:505420 dirmd_bin = input_api.os_path.join(input_api.PresubmitLocalPath(),
Bruce Dawsonc8054482022-03-28 15:33:375421 'third_party', 'depot_tools', dirmd)
Sam Maiera6e76d72022-02-11 21:43:505422 results.extend(
5423 input_api.RunTests(
5424 input_api.canned_checks.CheckDirMetadataFormat(
5425 input_api, output_api, dirmd_bin)))
5426 results.extend(
5427 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
5428 input_api, output_api))
5429 results.extend(
5430 input_api.canned_checks.CheckNoNewMetadataInOwners(
5431 input_api, output_api))
5432 results.extend(
5433 input_api.canned_checks.CheckInclusiveLanguage(
5434 input_api,
5435 output_api,
5436 excluded_directories_relative_path=[
5437 'infra', 'inclusive_language_presubmit_exempt_dirs.txt'
5438 ],
5439 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Dirk Prankee3c9c62d2021-05-18 18:35:595440
Aleksey Khoroshilov2978c942022-06-13 16:14:125441 presubmit_py_filter = lambda f: input_api.FilterSourceFile(
Bruce Dawson696963f2022-09-13 01:15:475442 f, files_to_check=[r'.*PRESUBMIT\.py$'])
Aleksey Khoroshilov2978c942022-06-13 16:14:125443 for f in input_api.AffectedFiles(include_deletes=False,
5444 file_filter=presubmit_py_filter):
5445 full_path = input_api.os_path.dirname(f.AbsoluteLocalPath())
5446 test_file = input_api.os_path.join(full_path, 'PRESUBMIT_test.py')
5447 # The PRESUBMIT.py file (and the directory containing it) might have
5448 # been affected by being moved or removed, so only try to run the tests
5449 # if they still exist.
5450 if not input_api.os_path.exists(test_file):
5451 continue
Sam Maiera6e76d72022-02-11 21:43:505452
Aleksey Khoroshilov2978c942022-06-13 16:14:125453 use_python3 = False
Bruce Dawson58a45d22023-02-27 11:24:165454 with open(f.LocalPath(), encoding='utf-8') as fp:
Aleksey Khoroshilov2978c942022-06-13 16:14:125455 use_python3 = any(
5456 line.startswith('USE_PYTHON3 = True')
5457 for line in fp.readlines())
5458
5459 results.extend(
5460 input_api.canned_checks.RunUnitTestsInDirectory(
5461 input_api,
5462 output_api,
5463 full_path,
5464 files_to_check=[r'^PRESUBMIT_test\.py$'],
5465 run_on_python2=not use_python3,
5466 run_on_python3=use_python3,
5467 skip_shebang_check=True))
Sam Maiera6e76d72022-02-11 21:43:505468 return results
maruel@chromium.org1f7b4172010-01-28 01:17:345469
maruel@chromium.orgb337cb5b2011-01-23 21:24:055470
Saagar Sanghavifceeaae2020-08-12 16:40:365471def CheckPatchFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505472 problems = [
5473 f.LocalPath() for f in input_api.AffectedFiles()
5474 if f.LocalPath().endswith(('.orig', '.rej'))
5475 ]
5476 # Cargo.toml.orig files are part of third-party crates downloaded from
5477 # crates.io and should be included.
5478 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
5479 if problems:
5480 return [
5481 output_api.PresubmitError("Don't commit .rej and .orig files.",
5482 problems)
5483 ]
5484 else:
5485 return []
enne@chromium.orgb8079ae4a2012-12-05 19:56:495486
5487
Saagar Sanghavifceeaae2020-08-12 16:40:365488def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505489 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
5490 macro_re = input_api.re.compile(
5491 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
5492 include_re = input_api.re.compile(r'^#include\s+"build/build_config.h"',
5493 input_api.re.MULTILINE)
5494 extension_re = input_api.re.compile(r'\.[a-z]+$')
5495 errors = []
Bruce Dawsonf7679202022-08-09 20:24:005496 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:505497 for f in input_api.AffectedFiles(include_deletes=False):
Bruce Dawsonf7679202022-08-09 20:24:005498 # The build-config macros are allowed to be used in build_config.h
5499 # without including itself.
5500 if f.LocalPath() == config_h_file:
5501 continue
Sam Maiera6e76d72022-02-11 21:43:505502 if not f.LocalPath().endswith(
5503 ('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
5504 continue
5505 found_line_number = None
5506 found_macro = None
5507 all_lines = input_api.ReadFile(f, 'r').splitlines()
5508 for line_num, line in enumerate(all_lines):
5509 match = macro_re.search(line)
5510 if match:
5511 found_line_number = line_num
5512 found_macro = match.group(2)
5513 break
5514 if not found_line_number:
5515 continue
Kent Tamura5a8755d2017-06-29 23:37:075516
Sam Maiera6e76d72022-02-11 21:43:505517 found_include_line = -1
5518 for line_num, line in enumerate(all_lines):
5519 if include_re.search(line):
5520 found_include_line = line_num
5521 break
5522 if found_include_line >= 0 and found_include_line < found_line_number:
5523 continue
Kent Tamura5a8755d2017-06-29 23:37:075524
Sam Maiera6e76d72022-02-11 21:43:505525 if not f.LocalPath().endswith('.h'):
5526 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
5527 try:
5528 content = input_api.ReadFile(primary_header_path, 'r')
5529 if include_re.search(content):
5530 continue
5531 except IOError:
5532 pass
5533 errors.append('%s:%d %s macro is used without first including build/'
5534 'build_config.h.' %
5535 (f.LocalPath(), found_line_number, found_macro))
5536 if errors:
5537 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
5538 return []
Kent Tamura5a8755d2017-06-29 23:37:075539
5540
Lei Zhang1c12a22f2021-05-12 11:28:455541def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505542 stl_include_re = input_api.re.compile(r'^#include\s+<('
5543 r'algorithm|'
5544 r'array|'
5545 r'limits|'
5546 r'list|'
5547 r'map|'
5548 r'memory|'
5549 r'queue|'
5550 r'set|'
5551 r'string|'
5552 r'unordered_map|'
5553 r'unordered_set|'
5554 r'utility|'
5555 r'vector)>')
5556 std_namespace_re = input_api.re.compile(r'std::')
5557 errors = []
5558 for f in input_api.AffectedFiles():
5559 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
5560 continue
Lei Zhang1c12a22f2021-05-12 11:28:455561
Sam Maiera6e76d72022-02-11 21:43:505562 uses_std_namespace = False
5563 has_stl_include = False
5564 for line in f.NewContents():
5565 if has_stl_include and uses_std_namespace:
5566 break
Lei Zhang1c12a22f2021-05-12 11:28:455567
Sam Maiera6e76d72022-02-11 21:43:505568 if not has_stl_include and stl_include_re.search(line):
5569 has_stl_include = True
5570 continue
Lei Zhang1c12a22f2021-05-12 11:28:455571
Bruce Dawson4a5579a2022-04-08 17:11:365572 if not uses_std_namespace and (std_namespace_re.search(line)
5573 or 'no-std-usage-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:505574 uses_std_namespace = True
5575 continue
Lei Zhang1c12a22f2021-05-12 11:28:455576
Sam Maiera6e76d72022-02-11 21:43:505577 if has_stl_include and not uses_std_namespace:
5578 errors.append(
5579 '%s: Includes STL header(s) but does not reference std::' %
5580 f.LocalPath())
5581 if errors:
5582 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
5583 return []
Lei Zhang1c12a22f2021-05-12 11:28:455584
5585
Xiaohan Wang42d96c22022-01-20 17:23:115586def _CheckForDeprecatedOSMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:505587 """Check for sensible looking, totally invalid OS macros."""
5588 preprocessor_statement = input_api.re.compile(r'^\s*#')
5589 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
5590 results = []
5591 for lnum, line in f.ChangedContents():
5592 if preprocessor_statement.search(line):
5593 for match in os_macro.finditer(line):
5594 results.append(
5595 ' %s:%d: %s' %
5596 (f.LocalPath(), lnum, 'defined(OS_' + match.group(1) +
5597 ') -> BUILDFLAG(IS_' + match.group(1) + ')'))
5598 return results
dbeam@chromium.orgb00342e7f2013-03-26 16:21:545599
5600
Xiaohan Wang42d96c22022-01-20 17:23:115601def CheckForDeprecatedOSMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505602 """Check all affected files for invalid OS macros."""
5603 bad_macros = []
Bruce Dawsonf7679202022-08-09 20:24:005604 # The OS_ macros are allowed to be used in build/build_config.h.
5605 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:505606 for f in input_api.AffectedSourceFiles(None):
Bruce Dawsonf7679202022-08-09 20:24:005607 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')) \
5608 and f.LocalPath() != config_h_file:
Sam Maiera6e76d72022-02-11 21:43:505609 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
dbeam@chromium.orgb00342e7f2013-03-26 16:21:545610
Sam Maiera6e76d72022-02-11 21:43:505611 if not bad_macros:
5612 return []
dbeam@chromium.orgb00342e7f2013-03-26 16:21:545613
Sam Maiera6e76d72022-02-11 21:43:505614 return [
5615 output_api.PresubmitError(
5616 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
5617 'defined in build_config.h):', bad_macros)
5618 ]
dbeam@chromium.orgb00342e7f2013-03-26 16:21:545619
lliabraa35bab3932014-10-01 12:16:445620
5621def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:505622 """Check all affected files for invalid "if defined" macros."""
5623 ALWAYS_DEFINED_MACROS = (
5624 "TARGET_CPU_PPC",
5625 "TARGET_CPU_PPC64",
5626 "TARGET_CPU_68K",
5627 "TARGET_CPU_X86",
5628 "TARGET_CPU_ARM",
5629 "TARGET_CPU_MIPS",
5630 "TARGET_CPU_SPARC",
5631 "TARGET_CPU_ALPHA",
5632 "TARGET_IPHONE_SIMULATOR",
5633 "TARGET_OS_EMBEDDED",
5634 "TARGET_OS_IPHONE",
5635 "TARGET_OS_MAC",
5636 "TARGET_OS_UNIX",
5637 "TARGET_OS_WIN32",
5638 )
5639 ifdef_macro = input_api.re.compile(
5640 r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
5641 results = []
5642 for lnum, line in f.ChangedContents():
5643 for match in ifdef_macro.finditer(line):
5644 if match.group(1) in ALWAYS_DEFINED_MACROS:
5645 always_defined = ' %s is always defined. ' % match.group(1)
5646 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
5647 results.append(
5648 ' %s:%d %s\n\t%s' %
5649 (f.LocalPath(), lnum, always_defined, did_you_mean))
5650 return results
lliabraa35bab3932014-10-01 12:16:445651
5652
Saagar Sanghavifceeaae2020-08-12 16:40:365653def CheckForInvalidIfDefinedMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505654 """Check all affected files for invalid "if defined" macros."""
5655 bad_macros = []
5656 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
5657 for f in input_api.AffectedFiles():
5658 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
5659 continue
5660 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
5661 bad_macros.extend(
5662 _CheckForInvalidIfDefinedMacrosInFile(input_api, f))
lliabraa35bab3932014-10-01 12:16:445663
Sam Maiera6e76d72022-02-11 21:43:505664 if not bad_macros:
5665 return []
lliabraa35bab3932014-10-01 12:16:445666
Sam Maiera6e76d72022-02-11 21:43:505667 return [
5668 output_api.PresubmitError(
5669 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
5670 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
5671 bad_macros)
5672 ]
lliabraa35bab3932014-10-01 12:16:445673
5674
Saagar Sanghavifceeaae2020-08-12 16:40:365675def CheckForIPCRules(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505676 """Check for same IPC rules described in
5677 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
5678 """
5679 base_pattern = r'IPC_ENUM_TRAITS\('
5680 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
5681 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
mlamouria82272622014-09-16 18:45:045682
Sam Maiera6e76d72022-02-11 21:43:505683 problems = []
5684 for f in input_api.AffectedSourceFiles(None):
5685 local_path = f.LocalPath()
5686 if not local_path.endswith('.h'):
5687 continue
5688 for line_number, line in f.ChangedContents():
5689 if inclusion_pattern.search(
5690 line) and not comment_pattern.search(line):
5691 problems.append('%s:%d\n %s' %
5692 (local_path, line_number, line.strip()))
mlamouria82272622014-09-16 18:45:045693
Sam Maiera6e76d72022-02-11 21:43:505694 if problems:
5695 return [
5696 output_api.PresubmitPromptWarning(_IPC_ENUM_TRAITS_DEPRECATED,
5697 problems)
5698 ]
5699 else:
5700 return []
mlamouria82272622014-09-16 18:45:045701
dbeam@chromium.orgb00342e7f2013-03-26 16:21:545702
Saagar Sanghavifceeaae2020-08-12 16:40:365703def CheckForLongPathnames(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505704 """Check to make sure no files being submitted have long paths.
5705 This causes issues on Windows.
5706 """
5707 problems = []
5708 for f in input_api.AffectedTestableFiles():
5709 local_path = f.LocalPath()
5710 # Windows has a path limit of 260 characters. Limit path length to 200 so
5711 # that we have some extra for the prefix on dev machines and the bots.
5712 if len(local_path) > 200:
5713 problems.append(local_path)
Stephen Martinis97a394142018-06-07 23:06:055714
Sam Maiera6e76d72022-02-11 21:43:505715 if problems:
5716 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
5717 else:
5718 return []
Stephen Martinis97a394142018-06-07 23:06:055719
5720
Saagar Sanghavifceeaae2020-08-12 16:40:365721def CheckForIncludeGuards(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505722 """Check that header files have proper guards against multiple inclusion.
5723 If a file should not have such guards (and it probably should) then it
Bruce Dawson4a5579a2022-04-08 17:11:365724 should include the string "no-include-guard-because-multiply-included" or
5725 "no-include-guard-because-pch-file".
Sam Maiera6e76d72022-02-11 21:43:505726 """
Daniel Bratell8ba52722018-03-02 16:06:145727
Sam Maiera6e76d72022-02-11 21:43:505728 def is_chromium_header_file(f):
5729 # We only check header files under the control of the Chromium
5730 # project. That is, those outside third_party apart from
5731 # third_party/blink.
5732 # We also exclude *_message_generator.h headers as they use
5733 # include guards in a special, non-typical way.
5734 file_with_path = input_api.os_path.normpath(f.LocalPath())
5735 return (file_with_path.endswith('.h')
5736 and not file_with_path.endswith('_message_generator.h')
Bruce Dawson4c4c2922022-05-02 18:07:335737 and not file_with_path.endswith('com_imported_mstscax.h')
Sam Maiera6e76d72022-02-11 21:43:505738 and (not file_with_path.startswith('third_party')
5739 or file_with_path.startswith(
5740 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:145741
Sam Maiera6e76d72022-02-11 21:43:505742 def replace_special_with_underscore(string):
5743 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:145744
Sam Maiera6e76d72022-02-11 21:43:505745 errors = []
Daniel Bratell8ba52722018-03-02 16:06:145746
Sam Maiera6e76d72022-02-11 21:43:505747 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
5748 guard_name = None
5749 guard_line_number = None
5750 seen_guard_end = False
Daniel Bratell8ba52722018-03-02 16:06:145751
Sam Maiera6e76d72022-02-11 21:43:505752 file_with_path = input_api.os_path.normpath(f.LocalPath())
5753 base_file_name = input_api.os_path.splitext(
5754 input_api.os_path.basename(file_with_path))[0]
5755 upper_base_file_name = base_file_name.upper()
Daniel Bratell8ba52722018-03-02 16:06:145756
Sam Maiera6e76d72022-02-11 21:43:505757 expected_guard = replace_special_with_underscore(
5758 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:145759
Sam Maiera6e76d72022-02-11 21:43:505760 # For "path/elem/file_name.h" we should really only accept
5761 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
5762 # are too many (1000+) files with slight deviations from the
5763 # coding style. The most important part is that the include guard
5764 # is there, and that it's unique, not the name so this check is
5765 # forgiving for existing files.
5766 #
5767 # As code becomes more uniform, this could be made stricter.
Daniel Bratell8ba52722018-03-02 16:06:145768
Sam Maiera6e76d72022-02-11 21:43:505769 guard_name_pattern_list = [
5770 # Anything with the right suffix (maybe with an extra _).
5771 r'\w+_H__?',
Daniel Bratell8ba52722018-03-02 16:06:145772
Sam Maiera6e76d72022-02-11 21:43:505773 # To cover include guards with old Blink style.
5774 r'\w+_h',
Daniel Bratell8ba52722018-03-02 16:06:145775
Sam Maiera6e76d72022-02-11 21:43:505776 # Anything including the uppercase name of the file.
5777 r'\w*' + input_api.re.escape(
5778 replace_special_with_underscore(upper_base_file_name)) +
5779 r'\w*',
5780 ]
5781 guard_name_pattern = '|'.join(guard_name_pattern_list)
5782 guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
5783 guard_name_pattern + ')')
Daniel Bratell8ba52722018-03-02 16:06:145784
Sam Maiera6e76d72022-02-11 21:43:505785 for line_number, line in enumerate(f.NewContents()):
Bruce Dawson4a5579a2022-04-08 17:11:365786 if ('no-include-guard-because-multiply-included' in line
5787 or 'no-include-guard-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:505788 guard_name = 'DUMMY' # To not trigger check outside the loop.
5789 break
Daniel Bratell8ba52722018-03-02 16:06:145790
Sam Maiera6e76d72022-02-11 21:43:505791 if guard_name is None:
5792 match = guard_pattern.match(line)
5793 if match:
5794 guard_name = match.group(1)
5795 guard_line_number = line_number
Daniel Bratell8ba52722018-03-02 16:06:145796
Sam Maiera6e76d72022-02-11 21:43:505797 # We allow existing files to use include guards whose names
5798 # don't match the chromium style guide, but new files should
5799 # get it right.
Bruce Dawson6cc154e2022-04-12 20:39:495800 if guard_name != expected_guard:
Bruce Dawson95eb7562022-09-14 15:27:165801 if f.Action() == 'A': # If file was just 'A'dded
Sam Maiera6e76d72022-02-11 21:43:505802 errors.append(
5803 output_api.PresubmitPromptWarning(
5804 'Header using the wrong include guard name %s'
5805 % guard_name, [
5806 '%s:%d' %
5807 (f.LocalPath(), line_number + 1)
5808 ], 'Expected: %r\nFound: %r' %
5809 (expected_guard, guard_name)))
5810 else:
5811 # The line after #ifndef should have a #define of the same name.
5812 if line_number == guard_line_number + 1:
5813 expected_line = '#define %s' % guard_name
5814 if line != expected_line:
5815 errors.append(
5816 output_api.PresubmitPromptWarning(
5817 'Missing "%s" for include guard' %
5818 expected_line,
5819 ['%s:%d' % (f.LocalPath(), line_number + 1)],
5820 'Expected: %r\nGot: %r' %
5821 (expected_line, line)))
Daniel Bratell8ba52722018-03-02 16:06:145822
Sam Maiera6e76d72022-02-11 21:43:505823 if not seen_guard_end and line == '#endif // %s' % guard_name:
5824 seen_guard_end = True
5825 elif seen_guard_end:
5826 if line.strip() != '':
5827 errors.append(
5828 output_api.PresubmitPromptWarning(
5829 'Include guard %s not covering the whole file'
5830 % (guard_name), [f.LocalPath()]))
5831 break # Nothing else to check and enough to warn once.
Daniel Bratell8ba52722018-03-02 16:06:145832
Sam Maiera6e76d72022-02-11 21:43:505833 if guard_name is None:
5834 errors.append(
5835 output_api.PresubmitPromptWarning(
Bruce Dawson32114b62022-04-11 16:45:495836 'Missing include guard in %s\n'
Sam Maiera6e76d72022-02-11 21:43:505837 'Recommended name: %s\n'
5838 'This check can be disabled by having the string\n'
Bruce Dawson4a5579a2022-04-08 17:11:365839 '"no-include-guard-because-multiply-included" or\n'
5840 '"no-include-guard-because-pch-file" in the header.'
Sam Maiera6e76d72022-02-11 21:43:505841 % (f.LocalPath(), expected_guard)))
5842
5843 return errors
Daniel Bratell8ba52722018-03-02 16:06:145844
5845
Saagar Sanghavifceeaae2020-08-12 16:40:365846def CheckForWindowsLineEndings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505847 """Check source code and known ascii text files for Windows style line
5848 endings.
5849 """
Bruce Dawson5efbdc652022-04-11 19:29:515850 known_text_files = r'.*\.(txt|html|htm|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:235851
Sam Maiera6e76d72022-02-11 21:43:505852 file_inclusion_pattern = (known_text_files,
5853 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
5854 r'.+%s' % _HEADER_EXTENSIONS)
mostynbb639aca52015-01-07 20:31:235855
Sam Maiera6e76d72022-02-11 21:43:505856 problems = []
5857 source_file_filter = lambda f: input_api.FilterSourceFile(
5858 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
5859 for f in input_api.AffectedSourceFiles(source_file_filter):
Bruce Dawson5efbdc652022-04-11 19:29:515860 # Ignore test files that contain crlf intentionally.
5861 if f.LocalPath().endswith('crlf.txt'):
Daniel Chenga37c03db2022-05-12 17:20:345862 continue
Sam Maiera6e76d72022-02-11 21:43:505863 include_file = False
5864 for line in input_api.ReadFile(f, 'r').splitlines(True):
5865 if line.endswith('\r\n'):
5866 include_file = True
5867 if include_file:
5868 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:235869
Sam Maiera6e76d72022-02-11 21:43:505870 if problems:
5871 return [
5872 output_api.PresubmitPromptWarning(
5873 'Are you sure that you want '
5874 'these files to contain Windows style line endings?\n' +
5875 '\n'.join(problems))
5876 ]
mostynbb639aca52015-01-07 20:31:235877
Sam Maiera6e76d72022-02-11 21:43:505878 return []
5879
mostynbb639aca52015-01-07 20:31:235880
Evan Stade6cfc964c12021-05-18 20:21:165881def CheckIconFilesForLicenseHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505882 """Check that .icon files (which are fragments of C++) have license headers.
5883 """
Evan Stade6cfc964c12021-05-18 20:21:165884
Sam Maiera6e76d72022-02-11 21:43:505885 icon_files = (r'.*\.icon$', )
Evan Stade6cfc964c12021-05-18 20:21:165886
Sam Maiera6e76d72022-02-11 21:43:505887 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
5888 return input_api.canned_checks.CheckLicense(input_api,
5889 output_api,
5890 source_file_filter=icons)
5891
Evan Stade6cfc964c12021-05-18 20:21:165892
Jose Magana2b456f22021-03-09 23:26:405893def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505894 """Check source code for use of Chrome App technologies being
5895 deprecated.
5896 """
Jose Magana2b456f22021-03-09 23:26:405897
Sam Maiera6e76d72022-02-11 21:43:505898 def _CheckForDeprecatedTech(input_api,
5899 output_api,
5900 detection_list,
5901 files_to_check=None,
5902 files_to_skip=None):
Jose Magana2b456f22021-03-09 23:26:405903
Sam Maiera6e76d72022-02-11 21:43:505904 if (files_to_check or files_to_skip):
5905 source_file_filter = lambda f: input_api.FilterSourceFile(
5906 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
5907 else:
5908 source_file_filter = None
5909
5910 problems = []
5911
5912 for f in input_api.AffectedSourceFiles(source_file_filter):
5913 if f.Action() == 'D':
5914 continue
5915 for _, line in f.ChangedContents():
5916 if any(detect in line for detect in detection_list):
5917 problems.append(f.LocalPath())
5918
5919 return problems
5920
5921 # to avoid this presubmit script triggering warnings
5922 files_to_skip = ['PRESUBMIT.py', 'PRESUBMIT_test.py']
Jose Magana2b456f22021-03-09 23:26:405923
5924 problems = []
5925
Sam Maiera6e76d72022-02-11 21:43:505926 # NMF: any files with extensions .nmf or NMF
5927 _NMF_FILES = r'\.(nmf|NMF)$'
5928 problems += _CheckForDeprecatedTech(
5929 input_api,
5930 output_api,
5931 detection_list=[''], # any change to the file will trigger warning
5932 files_to_check=[r'.+%s' % _NMF_FILES])
Jose Magana2b456f22021-03-09 23:26:405933
Sam Maiera6e76d72022-02-11 21:43:505934 # MANIFEST: any manifest.json that in its diff includes "app":
5935 _MANIFEST_FILES = r'(manifest\.json)$'
5936 problems += _CheckForDeprecatedTech(
5937 input_api,
5938 output_api,
5939 detection_list=['"app":'],
5940 files_to_check=[r'.*%s' % _MANIFEST_FILES])
Jose Magana2b456f22021-03-09 23:26:405941
Sam Maiera6e76d72022-02-11 21:43:505942 # NaCl / PNaCl: any file that in its diff contains the strings in the list
5943 problems += _CheckForDeprecatedTech(
5944 input_api,
5945 output_api,
5946 detection_list=['config=nacl', 'enable-nacl', 'cpu=pnacl', 'nacl_io'],
Bruce Dawson40fece62022-09-16 19:58:315947 files_to_skip=files_to_skip + [r"^native_client_sdk/"])
Jose Magana2b456f22021-03-09 23:26:405948
Gao Shenga79ebd42022-08-08 17:25:595949 # PPAPI: any C/C++ file that in its diff includes a ppapi library
Sam Maiera6e76d72022-02-11 21:43:505950 problems += _CheckForDeprecatedTech(
5951 input_api,
5952 output_api,
5953 detection_list=['#include "ppapi', '#include <ppapi'],
5954 files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,
5955 r'.+%s' % _IMPLEMENTATION_EXTENSIONS),
Bruce Dawson40fece62022-09-16 19:58:315956 files_to_skip=[r"^ppapi/"])
Jose Magana2b456f22021-03-09 23:26:405957
Sam Maiera6e76d72022-02-11 21:43:505958 if problems:
5959 return [
5960 output_api.PresubmitPromptWarning(
5961 'You are adding/modifying code'
5962 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
5963 ' PNaCl, PPAPI). See this blog post for more details:\n'
5964 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
5965 'and this documentation for options to replace these technologies:\n'
5966 'https://developer.chrome.com/docs/apps/migration/\n' +
5967 '\n'.join(problems))
5968 ]
Jose Magana2b456f22021-03-09 23:26:405969
Sam Maiera6e76d72022-02-11 21:43:505970 return []
Jose Magana2b456f22021-03-09 23:26:405971
mostynbb639aca52015-01-07 20:31:235972
Saagar Sanghavifceeaae2020-08-12 16:40:365973def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
Sam Maiera6e76d72022-02-11 21:43:505974 """Checks that all source files use SYSLOG properly."""
5975 syslog_files = []
5976 for f in input_api.AffectedSourceFiles(src_file_filter):
5977 for line_number, line in f.ChangedContents():
5978 if 'SYSLOG' in line:
5979 syslog_files.append(f.LocalPath() + ':' + str(line_number))
pastarmovj032ba5bc2017-01-12 10:41:565980
Sam Maiera6e76d72022-02-11 21:43:505981 if syslog_files:
5982 return [
5983 output_api.PresubmitPromptWarning(
5984 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
5985 ' calls.\nFiles to check:\n',
5986 items=syslog_files)
5987 ]
5988 return []
pastarmovj89f7ee12016-09-20 14:58:135989
5990
maruel@chromium.org1f7b4172010-01-28 01:17:345991def CheckChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505992 if input_api.version < [2, 0, 0]:
5993 return [
5994 output_api.PresubmitError(
5995 "Your depot_tools is out of date. "
5996 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5997 "but your version is %d.%d.%d" % tuple(input_api.version))
5998 ]
5999 results = []
6000 results.extend(
6001 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
6002 return results
maruel@chromium.orgca8d19842009-02-19 16:33:126003
6004
6005def CheckChangeOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506006 if input_api.version < [2, 0, 0]:
6007 return [
6008 output_api.PresubmitError(
6009 "Your depot_tools is out of date. "
6010 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
6011 "but your version is %d.%d.%d" % tuple(input_api.version))
6012 ]
Saagar Sanghavifceeaae2020-08-12 16:40:366013
Sam Maiera6e76d72022-02-11 21:43:506014 results = []
6015 # Make sure the tree is 'open'.
6016 results.extend(
6017 input_api.canned_checks.CheckTreeIsOpen(
6018 input_api,
6019 output_api,
6020 json_url='http://chromium-status.appspot.com/current?format=json'))
maruel@chromium.org806e98e2010-03-19 17:49:276021
Sam Maiera6e76d72022-02-11 21:43:506022 results.extend(
6023 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
6024 results.extend(
6025 input_api.canned_checks.CheckChangeHasBugField(input_api, output_api))
6026 results.extend(
6027 input_api.canned_checks.CheckChangeHasNoUnwantedTags(
6028 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:506029 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146030
6031
Saagar Sanghavifceeaae2020-08-12 16:40:366032def CheckStrings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506033 """Check string ICU syntax validity and if translation screenshots exist."""
6034 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
6035 # footer is set to true.
6036 git_footers = input_api.change.GitFootersFromDescription()
6037 skip_screenshot_check_footer = [
6038 footer.lower() for footer in git_footers.get(
6039 u'Skip-Translation-Screenshots-Check', [])
6040 ]
6041 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:026042
Sam Maiera6e76d72022-02-11 21:43:506043 import os
6044 import re
6045 import sys
6046 from io import StringIO
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146047
Sam Maiera6e76d72022-02-11 21:43:506048 new_or_added_paths = set(f.LocalPath() for f in input_api.AffectedFiles()
6049 if (f.Action() == 'A' or f.Action() == 'M'))
6050 removed_paths = set(f.LocalPath()
6051 for f in input_api.AffectedFiles(include_deletes=True)
6052 if f.Action() == 'D')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146053
Sam Maiera6e76d72022-02-11 21:43:506054 affected_grds = [
6055 f for f in input_api.AffectedFiles()
6056 if f.LocalPath().endswith(('.grd', '.grdp'))
6057 ]
6058 affected_grds = [
6059 f for f in affected_grds if not 'testdata' in f.LocalPath()
6060 ]
6061 if not affected_grds:
6062 return []
meacer8c0d3832019-12-26 21:46:166063
Sam Maiera6e76d72022-02-11 21:43:506064 affected_png_paths = [
6065 f.AbsoluteLocalPath() for f in input_api.AffectedFiles()
6066 if (f.LocalPath().endswith('.png'))
6067 ]
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146068
Sam Maiera6e76d72022-02-11 21:43:506069 # Check for screenshots. Developers can upload screenshots using
6070 # tools/translation/upload_screenshots.py which finds and uploads
6071 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
6072 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
6073 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
6074 #
6075 # The logic here is as follows:
6076 #
6077 # - If the CL has a .png file under the screenshots directory for a grd
6078 # file, warn the developer. Actual images should never be checked into the
6079 # Chrome repo.
6080 #
6081 # - If the CL contains modified or new messages in grd files and doesn't
6082 # contain the corresponding .sha1 files, warn the developer to add images
6083 # and upload them via tools/translation/upload_screenshots.py.
6084 #
6085 # - If the CL contains modified or new messages in grd files and the
6086 # corresponding .sha1 files, everything looks good.
6087 #
6088 # - If the CL contains removed messages in grd files but the corresponding
6089 # .sha1 files aren't removed, warn the developer to remove them.
6090 unnecessary_screenshots = []
Jens Mueller054652c2023-05-10 15:12:306091 invalid_sha1 = []
Sam Maiera6e76d72022-02-11 21:43:506092 missing_sha1 = []
Bruce Dawson55776c42022-12-09 17:23:476093 missing_sha1_modified = []
Sam Maiera6e76d72022-02-11 21:43:506094 unnecessary_sha1_files = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146095
Sam Maiera6e76d72022-02-11 21:43:506096 # This checks verifies that the ICU syntax of messages this CL touched is
6097 # valid, and reports any found syntax errors.
6098 # Without this presubmit check, ICU syntax errors in Chromium strings can land
6099 # without developers being aware of them. Later on, such ICU syntax errors
6100 # break message extraction for translation, hence would block Chromium
6101 # translations until they are fixed.
6102 icu_syntax_errors = []
Jens Mueller054652c2023-05-10 15:12:306103 sha1_pattern = input_api.re.compile(r'^[a-fA-F0-9]{40}$',
6104 input_api.re.MULTILINE)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146105
Sam Maiera6e76d72022-02-11 21:43:506106 def _CheckScreenshotAdded(screenshots_dir, message_id):
6107 sha1_path = input_api.os_path.join(screenshots_dir,
6108 message_id + '.png.sha1')
6109 if sha1_path not in new_or_added_paths:
6110 missing_sha1.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306111 elif not _CheckValidSha1(sha1_path):
6112 invalid_sha1.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146113
Bruce Dawson55776c42022-12-09 17:23:476114 def _CheckScreenshotModified(screenshots_dir, message_id):
6115 sha1_path = input_api.os_path.join(screenshots_dir,
6116 message_id + '.png.sha1')
6117 if sha1_path not in new_or_added_paths:
6118 missing_sha1_modified.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306119 elif not _CheckValidSha1(sha1_path):
6120 invalid_sha1.append(sha1_path)
6121
6122 def _CheckValidSha1(sha1_path):
6123 return sha1_pattern.search(
6124 next(
6125 "\n".join(f.NewContents())
6126 for f in input_api.AffectedFiles()
6127 if f.LocalPath() == sha1_path
6128 )
6129 )
Bruce Dawson55776c42022-12-09 17:23:476130
Sam Maiera6e76d72022-02-11 21:43:506131 def _CheckScreenshotRemoved(screenshots_dir, message_id):
6132 sha1_path = input_api.os_path.join(screenshots_dir,
6133 message_id + '.png.sha1')
6134 if input_api.os_path.exists(
6135 sha1_path) and sha1_path not in removed_paths:
6136 unnecessary_sha1_files.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146137
Sam Maiera6e76d72022-02-11 21:43:506138 def _ValidateIcuSyntax(text, level, signatures):
6139 """Validates ICU syntax of a text string.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146140
Sam Maiera6e76d72022-02-11 21:43:506141 Check if text looks similar to ICU and checks for ICU syntax correctness
6142 in this case. Reports various issues with ICU syntax and values of
6143 variants. Supports checking of nested messages. Accumulate information of
6144 each ICU messages found in the text for further checking.
Rainhard Findlingfc31844c52020-05-15 09:58:266145
Sam Maiera6e76d72022-02-11 21:43:506146 Args:
6147 text: a string to check.
6148 level: a number of current nesting level.
6149 signatures: an accumulator, a list of tuple of (level, variable,
6150 kind, variants).
Rainhard Findlingfc31844c52020-05-15 09:58:266151
Sam Maiera6e76d72022-02-11 21:43:506152 Returns:
6153 None if a string is not ICU or no issue detected.
6154 A tuple of (message, start index, end index) if an issue detected.
6155 """
6156 valid_types = {
6157 'plural': (frozenset(
6158 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
6159 'other']), frozenset(['=1', 'other'])),
6160 'selectordinal': (frozenset(
6161 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
6162 'other']), frozenset(['one', 'other'])),
6163 'select': (frozenset(), frozenset(['other'])),
6164 }
Rainhard Findlingfc31844c52020-05-15 09:58:266165
Sam Maiera6e76d72022-02-11 21:43:506166 # Check if the message looks like an attempt to use ICU
6167 # plural. If yes - check if its syntax strictly matches ICU format.
6168 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b',
6169 text)
6170 if not like:
6171 signatures.append((level, None, None, None))
6172 return
Rainhard Findlingfc31844c52020-05-15 09:58:266173
Sam Maiera6e76d72022-02-11 21:43:506174 # Check for valid prefix and suffix
6175 m = re.match(
6176 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
6177 r'(plural|selectordinal|select),\s*'
6178 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
6179 if not m:
6180 return (('This message looks like an ICU plural, '
6181 'but does not follow ICU syntax.'), like.start(),
6182 like.end())
6183 starting, variable, kind, variant_pairs = m.groups()
6184 variants, depth, last_pos = _ParseIcuVariants(variant_pairs,
6185 m.start(4))
6186 if depth:
6187 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
6188 len(text))
6189 first = text[0]
6190 ending = text[last_pos:]
6191 if not starting:
6192 return ('Invalid ICU format. No initial opening bracket',
6193 last_pos - 1, last_pos)
6194 if not ending or '}' not in ending:
6195 return ('Invalid ICU format. No final closing bracket',
6196 last_pos - 1, last_pos)
6197 elif first != '{':
6198 return ((
6199 'Invalid ICU format. Extra characters at the start of a complex '
6200 'message (go/icu-message-migration): "%s"') % starting, 0,
6201 len(starting))
6202 elif ending != '}':
6203 return ((
6204 'Invalid ICU format. Extra characters at the end of a complex '
6205 'message (go/icu-message-migration): "%s"') % ending,
6206 last_pos - 1, len(text) - 1)
6207 if kind not in valid_types:
6208 return (('Unknown ICU message type %s. '
6209 'Valid types are: plural, select, selectordinal') % kind,
6210 0, 0)
6211 known, required = valid_types[kind]
6212 defined_variants = set()
6213 for variant, variant_range, value, value_range in variants:
6214 start, end = variant_range
6215 if variant in defined_variants:
6216 return ('Variant "%s" is defined more than once' % variant,
6217 start, end)
6218 elif known and variant not in known:
6219 return ('Variant "%s" is not valid for %s message' %
6220 (variant, kind), start, end)
6221 defined_variants.add(variant)
6222 # Check for nested structure
6223 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
6224 if res:
6225 return (res[0], res[1] + value_range[0] + 1,
6226 res[2] + value_range[0] + 1)
6227 missing = required - defined_variants
6228 if missing:
6229 return ('Required variants missing: %s' % ', '.join(missing), 0,
6230 len(text))
6231 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:266232
Sam Maiera6e76d72022-02-11 21:43:506233 def _ParseIcuVariants(text, offset=0):
6234 """Parse variants part of ICU complex message.
Rainhard Findlingfc31844c52020-05-15 09:58:266235
Sam Maiera6e76d72022-02-11 21:43:506236 Builds a tuple of variant names and values, as well as
6237 their offsets in the input string.
Rainhard Findlingfc31844c52020-05-15 09:58:266238
Sam Maiera6e76d72022-02-11 21:43:506239 Args:
6240 text: a string to parse
6241 offset: additional offset to add to positions in the text to get correct
6242 position in the complete ICU string.
Rainhard Findlingfc31844c52020-05-15 09:58:266243
Sam Maiera6e76d72022-02-11 21:43:506244 Returns:
6245 List of tuples, each tuple consist of four fields: variant name,
6246 variant name span (tuple of two integers), variant value, value
6247 span (tuple of two integers).
6248 """
6249 depth, start, end = 0, -1, -1
6250 variants = []
6251 key = None
6252 for idx, char in enumerate(text):
6253 if char == '{':
6254 if not depth:
6255 start = idx
6256 chunk = text[end + 1:start]
6257 key = chunk.strip()
6258 pos = offset + end + 1 + chunk.find(key)
6259 span = (pos, pos + len(key))
6260 depth += 1
6261 elif char == '}':
6262 if not depth:
6263 return variants, depth, offset + idx
6264 depth -= 1
6265 if not depth:
6266 end = idx
6267 variants.append((key, span, text[start:end + 1],
6268 (offset + start, offset + end + 1)))
6269 return variants, depth, offset + end + 1
Rainhard Findlingfc31844c52020-05-15 09:58:266270
Sam Maiera6e76d72022-02-11 21:43:506271 try:
6272 old_sys_path = sys.path
6273 sys.path = sys.path + [
6274 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
6275 'translation')
6276 ]
6277 from helper import grd_helper
6278 finally:
6279 sys.path = old_sys_path
Rainhard Findlingfc31844c52020-05-15 09:58:266280
Sam Maiera6e76d72022-02-11 21:43:506281 for f in affected_grds:
6282 file_path = f.LocalPath()
6283 old_id_to_msg_map = {}
6284 new_id_to_msg_map = {}
6285 # Note that this code doesn't check if the file has been deleted. This is
6286 # OK because it only uses the old and new file contents and doesn't load
6287 # the file via its path.
6288 # It's also possible that a file's content refers to a renamed or deleted
6289 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
6290 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
6291 # .grdp files.
6292 if file_path.endswith('.grdp'):
6293 if f.OldContents():
6294 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6295 '\n'.join(f.OldContents()))
6296 if f.NewContents():
6297 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6298 '\n'.join(f.NewContents()))
6299 else:
6300 file_dir = input_api.os_path.dirname(file_path) or '.'
6301 if f.OldContents():
6302 old_id_to_msg_map = grd_helper.GetGrdMessages(
6303 StringIO('\n'.join(f.OldContents())), file_dir)
6304 if f.NewContents():
6305 new_id_to_msg_map = grd_helper.GetGrdMessages(
6306 StringIO('\n'.join(f.NewContents())), file_dir)
Rainhard Findlingfc31844c52020-05-15 09:58:266307
Sam Maiera6e76d72022-02-11 21:43:506308 grd_name, ext = input_api.os_path.splitext(
6309 input_api.os_path.basename(file_path))
6310 screenshots_dir = input_api.os_path.join(
6311 input_api.os_path.dirname(file_path),
6312 grd_name + ext.replace('.', '_'))
Rainhard Findlingfc31844c52020-05-15 09:58:266313
Sam Maiera6e76d72022-02-11 21:43:506314 # Compute added, removed and modified message IDs.
6315 old_ids = set(old_id_to_msg_map)
6316 new_ids = set(new_id_to_msg_map)
6317 added_ids = new_ids - old_ids
6318 removed_ids = old_ids - new_ids
6319 modified_ids = set([])
6320 for key in old_ids.intersection(new_ids):
6321 if (old_id_to_msg_map[key].ContentsAsXml('', True) !=
6322 new_id_to_msg_map[key].ContentsAsXml('', True)):
6323 # The message content itself changed. Require an updated screenshot.
6324 modified_ids.add(key)
6325 elif old_id_to_msg_map[key].attrs['meaning'] != \
6326 new_id_to_msg_map[key].attrs['meaning']:
Jens Mueller054652c2023-05-10 15:12:306327 # The message meaning changed. We later check for a screenshot.
6328 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146329
Sam Maiera6e76d72022-02-11 21:43:506330 if run_screenshot_check:
6331 # Check the screenshot directory for .png files. Warn if there is any.
6332 for png_path in affected_png_paths:
6333 if png_path.startswith(screenshots_dir):
6334 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146335
Sam Maiera6e76d72022-02-11 21:43:506336 for added_id in added_ids:
6337 _CheckScreenshotAdded(screenshots_dir, added_id)
Rainhard Findlingd8d04372020-08-13 13:30:096338
Sam Maiera6e76d72022-02-11 21:43:506339 for modified_id in modified_ids:
Bruce Dawson55776c42022-12-09 17:23:476340 _CheckScreenshotModified(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146341
Sam Maiera6e76d72022-02-11 21:43:506342 for removed_id in removed_ids:
6343 _CheckScreenshotRemoved(screenshots_dir, removed_id)
6344
6345 # Check new and changed strings for ICU syntax errors.
6346 for key in added_ids.union(modified_ids):
6347 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
6348 err = _ValidateIcuSyntax(msg, 0, [])
6349 if err is not None:
6350 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
6351
6352 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:266353 if run_screenshot_check:
Sam Maiera6e76d72022-02-11 21:43:506354 if unnecessary_screenshots:
6355 results.append(
6356 output_api.PresubmitError(
6357 'Do not include actual screenshots in the changelist. Run '
6358 'tools/translate/upload_screenshots.py to upload them instead:',
6359 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146360
Sam Maiera6e76d72022-02-11 21:43:506361 if missing_sha1:
6362 results.append(
6363 output_api.PresubmitError(
Bruce Dawson55776c42022-12-09 17:23:476364 'You are adding UI strings.\n'
Sam Maiera6e76d72022-02-11 21:43:506365 'To ensure the best translations, take screenshots of the relevant UI '
6366 '(https://g.co/chrome/translation) and add these files to your '
6367 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146368
Jens Mueller054652c2023-05-10 15:12:306369 if invalid_sha1:
6370 results.append(
6371 output_api.PresubmitError(
6372 'The following files do not seem to contain valid sha1 hashes. '
6373 'Make sure they contain hashes created by '
6374 'tools/translate/upload_screenshots.py:', sorted(invalid_sha1)))
6375
Bruce Dawson55776c42022-12-09 17:23:476376 if missing_sha1_modified:
6377 results.append(
6378 output_api.PresubmitError(
6379 'You are modifying UI strings or their meanings.\n'
6380 'To ensure the best translations, take screenshots of the relevant UI '
6381 '(https://g.co/chrome/translation) and add these files to your '
6382 'changelist:', sorted(missing_sha1_modified)))
6383
Sam Maiera6e76d72022-02-11 21:43:506384 if unnecessary_sha1_files:
6385 results.append(
6386 output_api.PresubmitError(
6387 'You removed strings associated with these files. Remove:',
6388 sorted(unnecessary_sha1_files)))
6389 else:
6390 results.append(
6391 output_api.PresubmitPromptOrNotify('Skipping translation '
6392 'screenshots check.'))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146393
Sam Maiera6e76d72022-02-11 21:43:506394 if icu_syntax_errors:
6395 results.append(
6396 output_api.PresubmitPromptWarning(
6397 'ICU syntax errors were found in the following strings (problems or '
6398 'feedback? Contact rainhard@chromium.org):',
6399 items=icu_syntax_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:266400
Sam Maiera6e76d72022-02-11 21:43:506401 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:126402
6403
Saagar Sanghavifceeaae2020-08-12 16:40:366404def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:126405 repo_root=None,
6406 translation_expectations_path=None,
6407 grd_files=None):
Sam Maiera6e76d72022-02-11 21:43:506408 import sys
6409 affected_grds = [
6410 f for f in input_api.AffectedFiles()
6411 if (f.LocalPath().endswith('.grd') or f.LocalPath().endswith('.grdp'))
6412 ]
6413 if not affected_grds:
6414 return []
6415
6416 try:
6417 old_sys_path = sys.path
6418 sys.path = sys.path + [
6419 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
6420 'translation')
6421 ]
6422 from helper import git_helper
6423 from helper import translation_helper
6424 finally:
6425 sys.path = old_sys_path
6426
6427 # Check that translation expectations can be parsed and we can get a list of
6428 # translatable grd files. |repo_root| and |translation_expectations_path| are
6429 # only passed by tests.
6430 if not repo_root:
6431 repo_root = input_api.PresubmitLocalPath()
6432 if not translation_expectations_path:
6433 translation_expectations_path = input_api.os_path.join(
6434 repo_root, 'tools', 'gritsettings', 'translation_expectations.pyl')
6435 if not grd_files:
6436 grd_files = git_helper.list_grds_in_repository(repo_root)
6437
6438 # Ignore bogus grd files used only for testing
Gao Shenga79ebd42022-08-08 17:25:596439 # ui/webui/resources/tools/generate_grd.py.
Sam Maiera6e76d72022-02-11 21:43:506440 ignore_path = input_api.os_path.join('ui', 'webui', 'resources', 'tools',
6441 'tests')
6442 grd_files = [p for p in grd_files if ignore_path not in p]
6443
6444 try:
6445 translation_helper.get_translatable_grds(
6446 repo_root, grd_files, translation_expectations_path)
6447 except Exception as e:
6448 return [
6449 output_api.PresubmitNotifyResult(
6450 'Failed to get a list of translatable grd files. This happens when:\n'
6451 ' - One of the modified grd or grdp files cannot be parsed or\n'
6452 ' - %s is not updated.\n'
6453 'Stack:\n%s' % (translation_expectations_path, str(e)))
6454 ]
Mustafa Emre Acer51f2f742020-03-09 19:41:126455 return []
6456
Ken Rockotc31f4832020-05-29 18:58:516457
Saagar Sanghavifceeaae2020-08-12 16:40:366458def CheckStableMojomChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506459 """Changes to [Stable] mojom types must preserve backward-compatibility."""
6460 changed_mojoms = input_api.AffectedFiles(
6461 include_deletes=True,
6462 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:526463
Bruce Dawson344ab262022-06-04 11:35:106464 if not changed_mojoms or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:506465 return []
6466
6467 delta = []
6468 for mojom in changed_mojoms:
Sam Maiera6e76d72022-02-11 21:43:506469 delta.append({
6470 'filename': mojom.LocalPath(),
6471 'old': '\n'.join(mojom.OldContents()) or None,
6472 'new': '\n'.join(mojom.NewContents()) or None,
6473 })
6474
6475 process = input_api.subprocess.Popen([
Takuto Ikutadca10222022-04-13 02:51:216476 input_api.python3_executable,
Sam Maiera6e76d72022-02-11 21:43:506477 input_api.os_path.join(
6478 input_api.PresubmitLocalPath(), 'mojo', 'public', 'tools', 'mojom',
6479 'check_stable_mojom_compatibility.py'), '--src-root',
6480 input_api.PresubmitLocalPath()
6481 ],
6482 stdin=input_api.subprocess.PIPE,
6483 stdout=input_api.subprocess.PIPE,
6484 stderr=input_api.subprocess.PIPE,
6485 universal_newlines=True)
6486 (x, error) = process.communicate(input=input_api.json.dumps(delta))
6487 if process.returncode:
6488 return [
6489 output_api.PresubmitError(
6490 'One or more [Stable] mojom definitions appears to have been changed '
6491 'in a way that is not backward-compatible.',
6492 long_text=error)
6493 ]
Erik Staabc734cd7a2021-11-23 03:11:526494 return []
6495
Dominic Battre645d42342020-12-04 16:14:106496def CheckDeprecationOfPreferences(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506497 """Removing a preference should come with a deprecation."""
Dominic Battre645d42342020-12-04 16:14:106498
Sam Maiera6e76d72022-02-11 21:43:506499 def FilterFile(affected_file):
6500 """Accept only .cc files and the like."""
6501 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
6502 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
6503 input_api.DEFAULT_FILES_TO_SKIP)
6504 return input_api.FilterSourceFile(
6505 affected_file,
6506 files_to_check=file_inclusion_pattern,
6507 files_to_skip=files_to_skip)
Dominic Battre645d42342020-12-04 16:14:106508
Sam Maiera6e76d72022-02-11 21:43:506509 def ModifiedLines(affected_file):
6510 """Returns a list of tuples (line number, line text) of added and removed
6511 lines.
Dominic Battre645d42342020-12-04 16:14:106512
Sam Maiera6e76d72022-02-11 21:43:506513 Deleted lines share the same line number as the previous line.
Dominic Battre645d42342020-12-04 16:14:106514
Sam Maiera6e76d72022-02-11 21:43:506515 This relies on the scm diff output describing each changed code section
6516 with a line of the form
Dominic Battre645d42342020-12-04 16:14:106517
Sam Maiera6e76d72022-02-11 21:43:506518 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
6519 """
6520 line_num = 0
6521 modified_lines = []
6522 for line in affected_file.GenerateScmDiff().splitlines():
6523 # Extract <new line num> of the patch fragment (see format above).
6524 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@',
6525 line)
6526 if m:
6527 line_num = int(m.groups(1)[0])
6528 continue
6529 if ((line.startswith('+') and not line.startswith('++'))
6530 or (line.startswith('-') and not line.startswith('--'))):
6531 modified_lines.append((line_num, line))
Dominic Battre645d42342020-12-04 16:14:106532
Sam Maiera6e76d72022-02-11 21:43:506533 if not line.startswith('-'):
6534 line_num += 1
6535 return modified_lines
Dominic Battre645d42342020-12-04 16:14:106536
Sam Maiera6e76d72022-02-11 21:43:506537 def FindLineWith(lines, needle):
6538 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
Dominic Battre645d42342020-12-04 16:14:106539
Sam Maiera6e76d72022-02-11 21:43:506540 If 0 or >1 lines contain `needle`, -1 is returned.
6541 """
6542 matching_line_numbers = [
6543 # + 1 for 1-based counting of line numbers.
6544 i + 1 for i, line in enumerate(lines) if needle in line
6545 ]
6546 return matching_line_numbers[0] if len(
6547 matching_line_numbers) == 1 else -1
Dominic Battre645d42342020-12-04 16:14:106548
Sam Maiera6e76d72022-02-11 21:43:506549 def ModifiedPrefMigration(affected_file):
6550 """Returns whether the MigrateObsolete.*Pref functions were modified."""
6551 # Determine first and last lines of MigrateObsolete.*Pref functions.
6552 new_contents = affected_file.NewContents()
6553 range_1 = (FindLineWith(new_contents,
6554 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
6555 FindLineWith(new_contents,
6556 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
6557 range_2 = (FindLineWith(new_contents,
6558 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
6559 FindLineWith(new_contents,
6560 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
6561 if (-1 in range_1 + range_2):
6562 raise Exception(
6563 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.'
6564 )
Dominic Battre645d42342020-12-04 16:14:106565
Sam Maiera6e76d72022-02-11 21:43:506566 # Check whether any of the modified lines are part of the
6567 # MigrateObsolete.*Pref functions.
6568 for line_nr, line in ModifiedLines(affected_file):
6569 if (range_1[0] <= line_nr <= range_1[1]
6570 or range_2[0] <= line_nr <= range_2[1]):
6571 return True
6572 return False
Dominic Battre645d42342020-12-04 16:14:106573
Sam Maiera6e76d72022-02-11 21:43:506574 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
6575 browser_prefs_file_pattern = input_api.re.compile(
6576 r'chrome/browser/prefs/browser_prefs.cc')
Dominic Battre645d42342020-12-04 16:14:106577
Sam Maiera6e76d72022-02-11 21:43:506578 changes = input_api.AffectedFiles(include_deletes=True,
6579 file_filter=FilterFile)
6580 potential_problems = []
6581 for f in changes:
6582 for line in f.GenerateScmDiff().splitlines():
6583 # Check deleted lines for pref registrations.
6584 if (line.startswith('-') and not line.startswith('--')
6585 and register_pref_pattern.search(line)):
6586 potential_problems.append('%s: %s' % (f.LocalPath(), line))
Dominic Battre645d42342020-12-04 16:14:106587
Sam Maiera6e76d72022-02-11 21:43:506588 if browser_prefs_file_pattern.search(f.LocalPath()):
6589 # If the developer modified the MigrateObsolete.*Prefs() functions, we
6590 # assume that they knew that they have to deprecate preferences and don't
6591 # warn.
6592 try:
6593 if ModifiedPrefMigration(f):
6594 return []
6595 except Exception as e:
6596 return [output_api.PresubmitError(str(e))]
Dominic Battre645d42342020-12-04 16:14:106597
Sam Maiera6e76d72022-02-11 21:43:506598 if potential_problems:
6599 return [
6600 output_api.PresubmitPromptWarning(
6601 'Discovered possible removal of preference registrations.\n\n'
6602 'Please make sure to properly deprecate preferences by clearing their\n'
6603 'value for a couple of milestones before finally removing the code.\n'
6604 'Otherwise data may stay in the preferences files forever. See\n'
6605 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
6606 'chrome/browser/prefs/README.md for examples.\n'
6607 'This may be a false positive warning (e.g. if you move preference\n'
6608 'registrations to a different place).\n', potential_problems)
6609 ]
6610 return []
6611
Matt Stark6ef08872021-07-29 01:21:466612
6613def CheckConsistentGrdChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506614 """Changes to GRD files must be consistent for tools to read them."""
6615 changed_grds = input_api.AffectedFiles(
6616 include_deletes=False,
6617 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
6618 errors = []
6619 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
6620 for matcher, msg in _INVALID_GRD_FILE_LINE]
6621 for grd in changed_grds:
6622 for i, line in enumerate(grd.NewContents()):
6623 for matcher, msg in invalid_file_regexes:
6624 if matcher.search(line):
6625 errors.append(
6626 output_api.PresubmitError(
6627 'Problem on {grd}:{i} - {msg}'.format(
6628 grd=grd.LocalPath(), i=i + 1, msg=msg)))
6629 return errors
6630
Kevin McNee967dd2d22021-11-15 16:09:296631
Henrique Ferreiro2a4b55942021-11-29 23:45:366632def CheckAssertAshOnlyCode(input_api, output_api):
6633 """Errors if a BUILD.gn file in an ash/ directory doesn't include
6634 assert(is_chromeos_ash).
6635 """
6636
6637 def FileFilter(affected_file):
6638 """Includes directories known to be Ash only."""
6639 return input_api.FilterSourceFile(
6640 affected_file,
6641 files_to_check=(
6642 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
6643 r'.*/ash/.*BUILD\.gn'), # Any path component.
6644 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
6645
6646 errors = []
6647 pattern = input_api.re.compile(r'assert\(is_chromeos_ash')
Jameson Thies0ce669f2021-12-09 15:56:566648 for f in input_api.AffectedFiles(include_deletes=False,
6649 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:366650 if (not pattern.search(input_api.ReadFile(f))):
6651 errors.append(
6652 output_api.PresubmitError(
6653 'Please add assert(is_chromeos_ash) to %s. If that\'s not '
6654 'possible, please create and issue and add a comment such '
6655 'as:\n # TODO(https://crbug.com/XXX): add '
6656 'assert(is_chromeos_ash) when ...' % f.LocalPath()))
6657 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:276658
6659
6660def _IsRendererOnlyCppFile(input_api, affected_file):
Sam Maiera6e76d72022-02-11 21:43:506661 path = affected_file.LocalPath()
6662 if not _IsCPlusPlusFile(input_api, path):
6663 return False
6664
6665 # Any code under a "renderer" subdirectory is assumed to be Renderer-only.
6666 if "/renderer/" in path:
6667 return True
6668
6669 # Blink's public/web API is only used/included by Renderer-only code. Note
6670 # that public/platform API may be used in non-Renderer processes (e.g. there
6671 # are some includes in code used by Utility, PDF, or Plugin processes).
6672 if "/blink/public/web/" in path:
6673 return True
6674
6675 # We assume that everything else may be used outside of Renderer processes.
Lukasz Anforowicz7016d05e2021-11-30 03:56:276676 return False
6677
Lukasz Anforowicz7016d05e2021-11-30 03:56:276678# TODO(https://crbug.com/1273182): Remove these checks, once they are replaced
6679# by the Chromium Clang Plugin (which will be preferable because it will
6680# 1) report errors earlier - at compile-time and 2) cover more rules).
6681def CheckRawPtrUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506682 """Rough checks that raw_ptr<T> usage guidelines are followed."""
6683 errors = []
6684 # The regex below matches "raw_ptr<" following a word boundary, but not in a
6685 # C++ comment.
6686 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
6687 file_filter = lambda f: _IsRendererOnlyCppFile(input_api, f)
6688 for f, line_num, line in input_api.RightHandSideLines(file_filter):
6689 if raw_ptr_matcher.search(line):
6690 errors.append(
6691 output_api.PresubmitError(
6692 'Problem on {path}:{line} - '\
6693 'raw_ptr<T> should not be used in Renderer-only code '\
6694 '(as documented in the "Pointers to unprotected memory" '\
6695 'section in //base/memory/raw_ptr.md)'.format(
6696 path=f.LocalPath(), line=line_num)))
6697 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:566698
6699
6700def CheckPythonShebang(input_api, output_api):
6701 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
6702 system-wide python.
6703 """
6704 errors = []
6705 sources = lambda affected_file: input_api.FilterSourceFile(
6706 affected_file,
6707 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
6708 r'third_party/blink/web_tests/external/') + input_api.
6709 DEFAULT_FILES_TO_SKIP),
6710 files_to_check=[r'.*\.py$'])
6711 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:276712 for line_num, line in f.ChangedContents():
6713 if line_num == 1 and line.startswith('#!/usr/bin/python'):
6714 errors.append(f.LocalPath())
6715 break
Henrique Ferreirof9819f2e32021-11-30 13:31:566716
6717 result = []
6718 for file in errors:
6719 result.append(
6720 output_api.PresubmitError(
6721 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
6722 file))
6723 return result
James Shen81cc0e22022-06-15 21:10:456724
6725
6726def CheckBatchAnnotation(input_api, output_api):
6727 """Checks that tests have either @Batch or @DoNotBatch annotation. If this
6728 is not an instrumentation test, disregard."""
6729
6730 batch_annotation = input_api.re.compile(r'^\s*@Batch')
6731 do_not_batch_annotation = input_api.re.compile(r'^\s*@DoNotBatch')
6732 robolectric_test = input_api.re.compile(r'[rR]obolectric')
6733 test_class_declaration = input_api.re.compile(r'^\s*public\sclass.*Test')
6734 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
6735
ckitagawae8fd23b2022-06-17 15:29:386736 missing_annotation_errors = []
6737 extra_annotation_errors = []
James Shen81cc0e22022-06-15 21:10:456738
6739 def _FilterFile(affected_file):
6740 return input_api.FilterSourceFile(
6741 affected_file,
6742 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
6743 files_to_check=[r'.*Test\.java$'])
6744
6745 for f in input_api.AffectedSourceFiles(_FilterFile):
6746 batch_matched = None
6747 do_not_batch_matched = None
6748 is_instrumentation_test = True
6749 for line in f.NewContents():
6750 if robolectric_test.search(line) or uiautomator_test.search(line):
6751 # Skip Robolectric and UiAutomator tests.
6752 is_instrumentation_test = False
6753 break
6754 if not batch_matched:
6755 batch_matched = batch_annotation.search(line)
6756 if not do_not_batch_matched:
6757 do_not_batch_matched = do_not_batch_annotation.search(line)
6758 test_class_declaration_matched = test_class_declaration.search(
6759 line)
6760 if test_class_declaration_matched:
6761 break
6762 if (is_instrumentation_test and
6763 not batch_matched and
6764 not do_not_batch_matched):
Sam Maier4cef9242022-10-03 14:21:246765 missing_annotation_errors.append(str(f.LocalPath()))
ckitagawae8fd23b2022-06-17 15:29:386766 if (not is_instrumentation_test and
6767 (batch_matched or
6768 do_not_batch_matched)):
Sam Maier4cef9242022-10-03 14:21:246769 extra_annotation_errors.append(str(f.LocalPath()))
James Shen81cc0e22022-06-15 21:10:456770
6771 results = []
6772
ckitagawae8fd23b2022-06-17 15:29:386773 if missing_annotation_errors:
James Shen81cc0e22022-06-15 21:10:456774 results.append(
6775 output_api.PresubmitPromptWarning(
6776 """
Henrique Nakashimacb4c55a2023-01-30 20:09:096777Instrumentation tests should use either @Batch or @DoNotBatch. Use
6778@Batch(Batch.PER_CLASS) in most cases. Use @Batch(Batch.UNIT_TESTS) when tests
6779have no side-effects. If the tests are not safe to run in batch, please use
6780@DoNotBatch with reasons.
Jens Mueller2085ff82023-02-27 11:54:496781See https://source.chromium.org/chromium/chromium/src/+/main:docs/testing/batching_instrumentation_tests.md
ckitagawae8fd23b2022-06-17 15:29:386782""", missing_annotation_errors))
6783 if extra_annotation_errors:
6784 results.append(
6785 output_api.PresubmitPromptWarning(
6786 """
6787Robolectric tests do not need a @Batch or @DoNotBatch annotations.
6788""", extra_annotation_errors))
James Shen81cc0e22022-06-15 21:10:456789
6790 return results
Sam Maier4cef9242022-10-03 14:21:246791
6792
6793def CheckMockAnnotation(input_api, output_api):
6794 """Checks that we have annotated all Mockito.mock()-ed or Mockito.spy()-ed
6795 classes with @Mock or @Spy. If this is not an instrumentation test,
6796 disregard."""
6797
6798 # This is just trying to be approximately correct. We are not writing a
6799 # Java parser, so special cases like statically importing mock() then
6800 # calling an unrelated non-mockito spy() function will cause a false
6801 # positive.
6802 package_name = input_api.re.compile(r'^package\s+(\w+(?:\.\w+)+);')
6803 mock_static_import = input_api.re.compile(
6804 r'^import\s+static\s+org.mockito.Mockito.(?:mock|spy);')
6805 import_class = input_api.re.compile(r'import\s+((?:\w+\.)+)(\w+);')
6806 mock_annotation = input_api.re.compile(r'^\s*@(?:Mock|Spy)')
6807 field_type = input_api.re.compile(r'(\w+)(?:<\w+>)?\s+\w+\s*(?:;|=)')
6808 mock_or_spy_function_call = r'(?:mock|spy)\(\s*(?:new\s*)?(\w+)(?:\.class|\()'
6809 fully_qualified_mock_function = input_api.re.compile(
6810 r'Mockito\.' + mock_or_spy_function_call)
6811 statically_imported_mock_function = input_api.re.compile(
6812 r'\W' + mock_or_spy_function_call)
6813 robolectric_test = input_api.re.compile(r'[rR]obolectric')
6814 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
6815
6816 def _DoClassLookup(class_name, class_name_map, package):
6817 found = class_name_map.get(class_name)
6818 if found is not None:
6819 return found
6820 else:
6821 return package + '.' + class_name
6822
6823 def _FilterFile(affected_file):
6824 return input_api.FilterSourceFile(
6825 affected_file,
6826 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
6827 files_to_check=[r'.*Test\.java$'])
6828
6829 mocked_by_function_classes = set()
6830 mocked_by_annotation_classes = set()
6831 class_to_filename = {}
6832 for f in input_api.AffectedSourceFiles(_FilterFile):
6833 mock_function_regex = fully_qualified_mock_function
6834 next_line_is_annotated = False
6835 fully_qualified_class_map = {}
6836 package = None
6837
6838 for line in f.NewContents():
6839 if robolectric_test.search(line) or uiautomator_test.search(line):
6840 # Skip Robolectric and UiAutomator tests.
6841 break
6842
6843 m = package_name.search(line)
6844 if m:
6845 package = m.group(1)
6846 continue
6847
6848 if mock_static_import.search(line):
6849 mock_function_regex = statically_imported_mock_function
6850 continue
6851
6852 m = import_class.search(line)
6853 if m:
6854 fully_qualified_class_map[m.group(2)] = m.group(1) + m.group(2)
6855 continue
6856
6857 if next_line_is_annotated:
6858 next_line_is_annotated = False
6859 fully_qualified_class = _DoClassLookup(
6860 field_type.search(line).group(1), fully_qualified_class_map,
6861 package)
6862 mocked_by_annotation_classes.add(fully_qualified_class)
6863 continue
6864
6865 if mock_annotation.search(line):
6866 next_line_is_annotated = True
6867 continue
6868
6869 m = mock_function_regex.search(line)
6870 if m:
6871 fully_qualified_class = _DoClassLookup(m.group(1),
6872 fully_qualified_class_map, package)
6873 # Skipping builtin classes, since they don't get optimized.
6874 if fully_qualified_class.startswith(
6875 'android.') or fully_qualified_class.startswith(
6876 'java.'):
6877 continue
6878 class_to_filename[fully_qualified_class] = str(f.LocalPath())
6879 mocked_by_function_classes.add(fully_qualified_class)
6880
6881 results = []
6882 missed_classes = mocked_by_function_classes - mocked_by_annotation_classes
6883 if missed_classes:
6884 error_locations = []
6885 for c in missed_classes:
6886 error_locations.append(c + ' in ' + class_to_filename[c])
6887 results.append(
6888 output_api.PresubmitPromptWarning(
6889 """
6890Mockito.mock()/spy() cause issues with our Java optimizer. You have 3 options:
68911) If the mocked variable can be a class member, annotate the member with
6892 @Mock/@Spy.
68932) If the mocked variable cannot be a class member, create a dummy member
6894 variable of that type, annotated with @Mock/@Spy. This dummy does not need
6895 to be used or initialized in any way.
68963) If the mocked type is definitely not going to be optimized, whether it's a
6897 builtin type which we don't ship, or a class you know R8 will treat
6898 specially, you can ignore this warning.
6899""", error_locations))
6900
6901 return results
Mike Dougherty1b8be712022-10-20 00:15:136902
6903def CheckNoJsInIos(input_api, output_api):
6904 """Checks to make sure that JavaScript files are not used on iOS."""
6905
6906 def _FilterFile(affected_file):
6907 return input_api.FilterSourceFile(
6908 affected_file,
6909 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP +
Mike Dougherty7bc8a812023-05-02 06:55:216910 (r'^ios/third_party/*', r'^ios/tools/*', r'^third_party/*'),
Mike Dougherty1b8be712022-10-20 00:15:136911 files_to_check=[r'^ios/.*\.js$', r'.*/ios/.*\.js$'])
6912
Mike Dougherty4d1050b2023-03-14 15:59:536913 deleted_files = []
6914
6915 # Collect filenames of all removed JS files.
6916 for f in input_api.AffectedSourceFiles(_FilterFile):
6917 local_path = f.LocalPath()
6918
6919 if input_api.os_path.splitext(local_path)[1] == '.js' and f.Action() == 'D':
6920 deleted_files.append(input_api.os_path.basename(local_path))
6921
Mike Dougherty1b8be712022-10-20 00:15:136922 error_paths = []
Mike Dougherty4d1050b2023-03-14 15:59:536923 moved_paths = []
Mike Dougherty1b8be712022-10-20 00:15:136924 warning_paths = []
6925
6926 for f in input_api.AffectedSourceFiles(_FilterFile):
6927 local_path = f.LocalPath()
6928
6929 if input_api.os_path.splitext(local_path)[1] == '.js':
6930 if f.Action() == 'A':
Mike Dougherty4d1050b2023-03-14 15:59:536931 if input_api.os_path.basename(local_path) in deleted_files:
6932 # This script was probably moved rather than newly created.
6933 # Present a warning instead of an error for these cases.
6934 moved_paths.append(local_path)
6935 else:
6936 error_paths.append(local_path)
Mike Dougherty1b8be712022-10-20 00:15:136937 elif f.Action() != 'D':
6938 warning_paths.append(local_path)
6939
6940 results = []
6941
6942 if warning_paths:
6943 results.append(output_api.PresubmitPromptWarning(
6944 'TypeScript is now fully supported for iOS feature scripts. '
6945 'Consider converting JavaScript files to TypeScript. See '
6946 '//ios/web/public/js_messaging/README.md for more details.',
6947 warning_paths))
6948
Mike Dougherty4d1050b2023-03-14 15:59:536949 if moved_paths:
6950 results.append(output_api.PresubmitPromptWarning(
6951 'Do not use JavaScript on iOS for new files as TypeScript is '
6952 'fully supported. (If this is a moved file, you may leave the '
6953 'script unconverted.) See //ios/web/public/js_messaging/README.md '
6954 'for help using scripts on iOS.', moved_paths))
6955
Mike Dougherty1b8be712022-10-20 00:15:136956 if error_paths:
6957 results.append(output_api.PresubmitError(
6958 'Do not use JavaScript on iOS as TypeScript is fully supported. '
6959 'See //ios/web/public/js_messaging/README.md for help using '
6960 'scripts on iOS.', error_paths))
6961
6962 return results
Hans Wennborg23a81d52023-03-24 16:38:136963
6964def CheckLibcxxRevisionsMatch(input_api, output_api):
6965 """Check to make sure the libc++ version matches across deps files."""
Andrew Grieve21bb6792023-03-27 19:06:486966 # Disable check for changes to sub-repositories.
6967 if input_api.PresubmitLocalPath() != input_api.change.RepositoryRoot():
6968 return []
Hans Wennborg23a81d52023-03-24 16:38:136969
6970 DEPS_FILES = [ 'DEPS', 'buildtools/deps_revisions.gni' ]
6971
6972 file_filter = lambda f: f.LocalPath().replace(
6973 input_api.os_path.sep, '/') in DEPS_FILES
6974 changed_deps_files = input_api.AffectedFiles(file_filter=file_filter)
6975 if not changed_deps_files:
6976 return []
6977
6978 def LibcxxRevision(file):
6979 file = input_api.os_path.join(input_api.PresubmitLocalPath(),
6980 *file.split('/'))
6981 return input_api.re.search(
6982 r'libcxx_revision.*[:=].*[\'"](\w+)[\'"]',
6983 input_api.ReadFile(file)).group(1)
6984
6985 if len(set([LibcxxRevision(f) for f in DEPS_FILES])) == 1:
6986 return []
6987
6988 return [output_api.PresubmitError(
6989 'libcxx_revision not equal across %s' % ', '.join(DEPS_FILES),
6990 changed_deps_files)]