blob: 0ec633767a7137e174ccbb54c574dc3aa3166d0e [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
maruel@chromium.org379e7dd2010-01-28 17:39:2119_EXCLUDED_PATHS = (
Bruce Dawson7f8566b2022-05-06 16:22:1820 # Generated file
Bruce Dawson40fece62022-09-16 19:58:3121 (r"chrome/android/webapk/shell_apk/src/org/chromium"
22 r"/webapk/lib/runtime_library/IWebApkApi.java"),
Mila Greene3aa7222021-09-07 16:34:0823 # File needs to write to stdout to emulate a tool it's replacing.
Bruce Dawson40fece62022-09-16 19:58:3124 r"chrome/updater/mac/keystone/ksadmin.mm",
Ilya Shermane8a7d2d2020-07-25 04:33:4725 # Generated file.
Bruce Dawson40fece62022-09-16 19:58:3126 (r"^components/variations/proto/devtools/"
Ilya Shermanc167a962020-08-18 18:40:2627 r"client_variations.js"),
Bruce Dawson3bd976c2022-05-06 22:47:5228 # These are video files, not typescript.
Bruce Dawson40fece62022-09-16 19:58:3129 r"^media/test/data/.*.ts",
30 r"^native_client_sdksrc/build_tools/make_rules.py",
31 r"^native_client_sdk/src/build_tools/make_simple.py",
32 r"^native_client_sdk/src/tools/.*.mk",
33 r"^net/tools/spdyshark/.*",
34 r"^skia/.*",
35 r"^third_party/blink/.*",
36 r"^third_party/breakpad/.*",
Darwin Huangd74a9d32019-07-17 17:58:4637 # sqlite is an imported third party dependency.
Bruce Dawson40fece62022-09-16 19:58:3138 r"^third_party/sqlite/.*",
39 r"^v8/.*",
maruel@chromium.org3e4eb112011-01-18 03:29:5440 r".*MakeFile$",
gman@chromium.org1084ccc2012-03-14 03:22:5341 r".+_autogen\.h$",
Yue Shecf1380552022-08-23 20:59:2042 r".+_pb2(_grpc)?\.py$",
Bruce Dawson40fece62022-09-16 19:58:3143 r".+/pnacl_shim\.c$",
44 r"^gpu/config/.*_list_json\.cc$",
45 r"tools/md_browser/.*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1446 # Test pages for Maps telemetry tests.
Bruce Dawson40fece62022-09-16 19:58:3147 r"tools/perf/page_sets/maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5448 # Test pages for WebRTC telemetry tests.
Bruce Dawson40fece62022-09-16 19:58:3149 r"tools/perf/page_sets/webrtc_cases.*",
dpapad2efd4452023-04-06 01:43:4550 # Test file compared with generated output.
51 r"tools/polymer/tests/html_to_wrapper/.*.html.ts$",
maruel@chromium.org4306417642009-06-11 00:33:4052)
maruel@chromium.orgca8d19842009-02-19 16:33:1253
John Abd-El-Malek759fea62021-03-13 03:41:1454_EXCLUDED_SET_NO_PARENT_PATHS = (
55 # It's for historical reasons that blink isn't a top level directory, where
56 # it would be allowed to have "set noparent" to avoid top level owners
57 # accidentally +1ing changes.
58 'third_party/blink/OWNERS',
59)
60
wnwenbdc444e2016-05-25 13:44:1561
joi@chromium.org06e6d0ff2012-12-11 01:36:4462# Fragment of a regular expression that matches C++ and Objective-C++
63# implementation files.
64_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
65
wnwenbdc444e2016-05-25 13:44:1566
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1967# Fragment of a regular expression that matches C++ and Objective-C++
68# header files.
69_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
70
71
Aleksey Khoroshilov9b28c032022-06-03 16:35:3272# Paths with sources that don't use //base.
73_NON_BASE_DEPENDENT_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:3174 r"^chrome/browser/browser_switcher/bho/",
75 r"^tools/win/",
Aleksey Khoroshilov9b28c032022-06-03 16:35:3276)
77
78
joi@chromium.org06e6d0ff2012-12-11 01:36:4479# Regular expression that matches code only used for test binaries
80# (best effort).
81_TEST_CODE_EXCLUDED_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:3182 r'.*/(fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
joi@chromium.org06e6d0ff2012-12-11 01:36:4483 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
James Cook1b4dc132021-03-09 22:45:1384 # Test suite files, like:
85 # foo_browsertest.cc
86 # bar_unittest_mac.cc (suffix)
87 # baz_unittests.cc (plural)
88 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(s)?(_[a-z]+)?%s' %
danakj@chromium.orge2d7e6f2013-04-23 12:57:1289 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1890 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
Victor Hugo Vianna Silvac22e0202021-06-09 19:46:2191 r'.+sync_service_impl_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Bruce Dawson40fece62022-09-16 19:58:3192 r'.*/(test|tool(s)?)/.*',
danakj89f47082020-09-02 17:53:4393 # content_shell is used for running content_browsertests.
Bruce Dawson40fece62022-09-16 19:58:3194 r'content/shell/.*',
danakj89f47082020-09-02 17:53:4395 # Web test harness.
Bruce Dawson40fece62022-09-16 19:58:3196 r'content/web_test/.*',
darin@chromium.org7b054982013-11-27 00:44:4797 # Non-production example code.
Bruce Dawson40fece62022-09-16 19:58:3198 r'mojo/examples/.*',
lliabraa@chromium.org8176de12014-06-20 19:07:0899 # Launcher for running iOS tests on the simulator.
Bruce Dawson40fece62022-09-16 19:58:31100 r'testing/iossim/iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:41101 # EarlGrey app side code for tests.
Bruce Dawson40fece62022-09-16 19:58:31102 r'ios/.*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:17103 # Views Examples code
Bruce Dawson40fece62022-09-16 19:58:31104 r'ui/views/examples/.*',
Austin Sullivan33da70a2020-10-07 15:39:41105 # Chromium Codelab
Bruce Dawson40fece62022-09-16 19:58:31106 r'codelabs/*'
joi@chromium.org06e6d0ff2012-12-11 01:36:44107)
maruel@chromium.orgca8d19842009-02-19 16:33:12108
Daniel Bratell609102be2019-03-27 20:53:21109_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:15110
joi@chromium.orgeea609a2011-11-18 13:10:12111_TEST_ONLY_WARNING = (
112 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:55113 'production code. If you are doing this from inside another method\n'
114 'named as *ForTesting(), then consider exposing things to have tests\n'
115 'make that same call directly.\n'
116 'If that is not possible, you may put a comment on the same line with\n'
117 ' // IN-TEST \n'
118 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
119 'method and can be ignored. Do not do this inside production code.\n'
120 'The android-binary-size trybot will block if the method exists in the\n'
121 'release apk.')
joi@chromium.orgeea609a2011-11-18 13:10:12122
123
Daniel Chenga44a1bcd2022-03-15 20:00:15124@dataclass
125class BanRule:
Daniel Chenga37c03db2022-05-12 17:20:34126 # String pattern. If the pattern begins with a slash, the pattern will be
127 # treated as a regular expression instead.
128 pattern: str
129 # Explanation as a sequence of strings. Each string in the sequence will be
130 # printed on its own line.
131 explanation: Sequence[str]
132 # Whether or not to treat this ban as a fatal error. If unspecified,
133 # defaults to true.
134 treat_as_error: Optional[bool] = None
135 # Paths that should be excluded from the ban check. Each string is a regular
136 # expression that will be matched against the path of the file being checked
137 # relative to the root of the source tree.
138 excluded_paths: Optional[Sequence[str]] = None
marja@chromium.orgcf9b78f2012-11-14 11:40:28139
Daniel Chenga44a1bcd2022-03-15 20:00:15140
Daniel Cheng917ce542022-03-15 20:46:57141_BANNED_JAVA_IMPORTS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15142 BanRule(
143 'import java.net.URI;',
144 (
145 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
146 ),
147 excluded_paths=(
148 (r'net/android/javatests/src/org/chromium/net/'
149 'AndroidProxySelectorTest\.java'),
150 r'components/cronet/',
151 r'third_party/robolectric/local/',
152 ),
Michael Thiessen44457642020-02-06 00:24:15153 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15154 BanRule(
155 'import android.annotation.TargetApi;',
156 (
157 'Do not use TargetApi, use @androidx.annotation.RequiresApi instead. '
158 'RequiresApi ensures that any calls are guarded by the appropriate '
159 'SDK_INT check. See https://crbug.com/1116486.',
160 ),
161 ),
162 BanRule(
Mohamed Heikal3d7a94c2023-03-28 16:55:24163 'import androidx.test.rule.UiThreadTestRule;',
Daniel Chenga44a1bcd2022-03-15 20:00:15164 (
165 'Do not use UiThreadTestRule, just use '
166 '@org.chromium.base.test.UiThreadTest on test methods that should run '
167 'on the UI thread. See https://crbug.com/1111893.',
168 ),
169 ),
170 BanRule(
Mohamed Heikal3d7a94c2023-03-28 16:55:24171 'import androidx.test.annotation.UiThreadTest;',
172 ('Do not use androidx.test.annotation.UiThreadTest, use '
Daniel Chenga44a1bcd2022-03-15 20:00:15173 'org.chromium.base.test.UiThreadTest instead. See '
174 'https://crbug.com/1111893.',
175 ),
176 ),
177 BanRule(
Mohamed Heikal3d7a94c2023-03-28 16:55:24178 'import androidx.test.rule.ActivityTestRule;',
Daniel Chenga44a1bcd2022-03-15 20:00:15179 (
180 'Do not use ActivityTestRule, use '
181 'org.chromium.base.test.BaseActivityTestRule instead.',
182 ),
183 excluded_paths=(
184 'components/cronet/',
185 ),
186 ),
Min Qinbc44383c2023-02-22 17:25:26187 BanRule(
188 'import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;',
189 (
190 'Do not use VectorDrawableCompat, use getResources().getDrawable() to '
191 'avoid extra indirections. Please also add trace event as the call '
192 'might take more than 20 ms to complete.',
193 ),
194 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15195)
wnwenbdc444e2016-05-25 13:44:15196
Daniel Cheng917ce542022-03-15 20:46:57197_BANNED_JAVA_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15198 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41199 'StrictMode.allowThreadDiskReads()',
200 (
201 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
202 'directly.',
203 ),
204 False,
205 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15206 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41207 'StrictMode.allowThreadDiskWrites()',
208 (
209 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
210 'directly.',
211 ),
212 False,
213 ),
Daniel Cheng917ce542022-03-15 20:46:57214 BanRule(
Michael Thiessen0f2547e2020-07-27 21:55:36215 '.waitForIdleSync()',
216 (
217 'Do not use waitForIdleSync as it masks underlying issues. There is '
218 'almost always something else you should wait on instead.',
219 ),
220 False,
221 ),
Ashley Newson09cbd602022-10-26 11:40:14222 BanRule(
Ashley Newsoneb6f5ced2022-10-26 14:45:42223 r'/(?<!\bsuper\.)(?<!\bIntent )\bregisterReceiver\(',
Ashley Newson09cbd602022-10-26 11:40:14224 (
225 'Do not call android.content.Context.registerReceiver (or an override) '
226 'directly. Use one of the wrapper methods defined in '
227 'org.chromium.base.ContextUtils, such as '
228 'registerProtectedBroadcastReceiver, '
229 'registerExportedBroadcastReceiver, or '
230 'registerNonExportedBroadcastReceiver. See their documentation for '
231 'which one to use.',
232 ),
233 True,
234 excluded_paths=(
Ashley Newson22bc26d2022-11-01 20:30:57235 r'.*Test[^a-z]',
236 r'third_party/',
Ashley Newson09cbd602022-10-26 11:40:14237 'base/android/java/src/org/chromium/base/ContextUtils.java',
Brandon Mousseau7e76a9c2022-12-08 22:08:38238 'chromecast/browser/android/apk/src/org/chromium/chromecast/shell/BroadcastReceiverScope.java',
Ashley Newson09cbd602022-10-26 11:40:14239 ),
240 ),
Ted Chocd5b327b12022-11-05 02:13:22241 BanRule(
242 r'/(?:extends|new)\s*(?:android.util.)?Property<[A-Za-z.]+,\s*(?:Integer|Float)>',
243 (
244 'Do not use Property<..., Integer|Float>, but use FloatProperty or '
245 'IntProperty because it will avoid unnecessary autoboxing of '
246 'primitives.',
247 ),
248 ),
Peilin Wangbba4a8652022-11-10 16:33:57249 BanRule(
250 'requestLayout()',
251 (
252 'Layouts can be expensive. Prefer using ViewUtils.requestLayout(), '
253 'which emits a trace event with additional information to help with '
254 'scroll jank investigations. See http://crbug.com/1354176.',
255 ),
256 False,
257 excluded_paths=(
258 'ui/android/java/src/org/chromium/ui/base/ViewUtils.java',
259 ),
260 ),
Ted Chocf40ea9152023-02-14 19:02:39261 BanRule(
262 'Profile.getLastUsedRegularProfile()',
263 (
264 'Prefer passing in the Profile reference instead of relying on the '
265 'static getLastUsedRegularProfile() call. Only top level entry points '
266 '(e.g. Activities) should call this method. Otherwise, the Profile '
267 'should either be passed in explicitly or retreived from an existing '
268 'entity with a reference to the Profile (e.g. WebContents).',
269 ),
270 False,
271 excluded_paths=(
272 r'.*Test[A-Z]?.*\.java',
273 ),
274 ),
Min Qinbc44383c2023-02-22 17:25:26275 BanRule(
276 r'/(ResourcesCompat|getResources\(\))\.getDrawable\(\)',
277 (
278 'getDrawable() can be expensive. If you have a lot of calls to '
279 'GetDrawable() or your code may introduce janks, please put your calls '
280 'inside a trace().',
281 ),
282 False,
283 excluded_paths=(
284 r'.*Test[A-Z]?.*\.java',
285 ),
286 ),
Henrique Nakashimabbf2b262023-03-10 17:21:39287 BanRule(
288 r'/RecordHistogram\.getHistogram(ValueCount|TotalCount|Samples)ForTesting\(',
289 (
290 'Raw histogram counts are easy to misuse; for example they don\'t reset '
291 'between batched tests. Use HistogramWatcher to check histogram records instead.',
292 ),
293 False,
294 excluded_paths=(
295 'base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java',
296 'base/test/android/javatests/src/org/chromium/base/test/util/HistogramWatcher.java',
297 ),
298 ),
Eric Stevensona9a980972017-09-23 00:04:41299)
300
Clement Yan9b330cb2022-11-17 05:25:29301_BANNED_JAVASCRIPT_FUNCTIONS : Sequence [BanRule] = (
302 BanRule(
303 r'/\bchrome\.send\b',
304 (
305 '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).',
306 'Please use mojo instead for new webuis. https://docs.google.com/document/d/1RF-GSUoveYa37eoyZ9EhwMtaIwoW7Z88pIgNZ9YzQi4/edit#heading=h.gkk22wgk6wff',
307 ),
308 True,
309 (
310 r'^(?!ash\/webui).+',
311 # TODO(crbug.com/1385601): pre-existing violations still need to be
312 # cleaned up.
Rebekah Potter57aa94df2022-12-13 20:30:58313 'ash/webui/common/resources/cr.m.js',
Clement Yan9b330cb2022-11-17 05:25:29314 'ash/webui/common/resources/multidevice_setup/multidevice_setup_browser_proxy.js',
Martin Bidlingmaiera921fee72023-06-03 07:52:22315 'ash/webui/common/resources/quick_unlock/lock_screen_constants.ts',
Clement Yan9b330cb2022-11-17 05:25:29316 'ash/webui/common/resources/smb_shares/smb_browser_proxy.js',
317 'ash/webui/connectivity_diagnostics/resources/connectivity_diagnostics.js',
318 'ash/webui/diagnostics_ui/resources/diagnostics_browser_proxy.ts',
319 'ash/webui/multidevice_debug/resources/logs.js',
320 'ash/webui/multidevice_debug/resources/webui.js',
321 'ash/webui/projector_app/resources/annotator/trusted/annotator_browser_proxy.js',
322 'ash/webui/projector_app/resources/app/trusted/projector_browser_proxy.js',
323 'ash/webui/scanning/resources/scanning_browser_proxy.js',
324 ),
325 ),
326)
327
Daniel Cheng917ce542022-03-15 20:46:57328_BANNED_OBJC_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15329 BanRule(
avi@chromium.org127f18ec2012-06-16 05:05:59330 'addTrackingRect:',
avi@chromium.org23e6cbc2012-06-16 18:51:20331 (
332 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
avi@chromium.org127f18ec2012-06-16 05:05:59333 'prohibited. Please use CrTrackingArea instead.',
334 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
335 ),
336 False,
337 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15338 BanRule(
leng@chromium.orgeaae1972014-04-16 04:17:26339 r'/NSTrackingArea\W',
avi@chromium.org23e6cbc2012-06-16 18:51:20340 (
341 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
avi@chromium.org127f18ec2012-06-16 05:05:59342 'instead.',
343 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
344 ),
345 False,
346 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15347 BanRule(
avi@chromium.org127f18ec2012-06-16 05:05:59348 'convertPointFromBase:',
avi@chromium.org23e6cbc2012-06-16 18:51:20349 (
350 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
avi@chromium.org127f18ec2012-06-16 05:05:59351 'Please use |convertPoint:(point) fromView:nil| instead.',
352 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
353 ),
354 True,
355 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15356 BanRule(
avi@chromium.org127f18ec2012-06-16 05:05:59357 'convertPointToBase:',
avi@chromium.org23e6cbc2012-06-16 18:51:20358 (
359 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
avi@chromium.org127f18ec2012-06-16 05:05:59360 'Please use |convertPoint:(point) toView:nil| instead.',
361 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
362 ),
363 True,
364 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15365 BanRule(
avi@chromium.org127f18ec2012-06-16 05:05:59366 'convertRectFromBase:',
avi@chromium.org23e6cbc2012-06-16 18:51:20367 (
368 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
avi@chromium.org127f18ec2012-06-16 05:05:59369 'Please use |convertRect:(point) fromView:nil| instead.',
370 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
371 ),
372 True,
373 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15374 BanRule(
avi@chromium.org127f18ec2012-06-16 05:05:59375 'convertRectToBase:',
avi@chromium.org23e6cbc2012-06-16 18:51:20376 (
377 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
avi@chromium.org127f18ec2012-06-16 05:05:59378 'Please use |convertRect:(point) toView:nil| instead.',
379 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
380 ),
381 True,
382 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15383 BanRule(
avi@chromium.org127f18ec2012-06-16 05:05:59384 'convertSizeFromBase:',
avi@chromium.org23e6cbc2012-06-16 18:51:20385 (
386 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
avi@chromium.org127f18ec2012-06-16 05:05:59387 'Please use |convertSize:(point) fromView:nil| instead.',
388 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
389 ),
390 True,
391 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15392 BanRule(
avi@chromium.org127f18ec2012-06-16 05:05:59393 'convertSizeToBase:',
avi@chromium.org23e6cbc2012-06-16 18:51:20394 (
395 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
avi@chromium.org127f18ec2012-06-16 05:05:59396 'Please use |convertSize:(point) toView:nil| instead.',
397 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
398 ),
399 True,
400 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15401 BanRule(
jif65398702016-10-27 10:19:48402 r"/\s+UTF8String\s*]",
403 (
404 'The use of -[NSString UTF8String] is dangerous as it can return null',
405 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
406 'Please use |SysNSStringToUTF8| instead.',
407 ),
408 True,
409 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15410 BanRule(
Sylvain Defresne4cf1d182017-09-18 14:16:34411 r'__unsafe_unretained',
412 (
413 'The use of __unsafe_unretained is almost certainly wrong, unless',
414 'when interacting with NSFastEnumeration or NSInvocation.',
415 'Please use __weak in files build with ARC, nothing otherwise.',
416 ),
417 False,
418 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15419 BanRule(
Avi Drissman7382afa02019-04-29 23:27:13420 'freeWhenDone:NO',
421 (
422 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
423 'Foundation types is prohibited.',
424 ),
425 True,
426 ),
avi@chromium.org127f18ec2012-06-16 05:05:59427)
428
Sylvain Defresnea8b73d252018-02-28 15:45:54429_BANNED_IOS_OBJC_FUNCTIONS = (
Daniel Chenga44a1bcd2022-03-15 20:00:15430 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54431 r'/\bTEST[(]',
432 (
433 'TEST() macro should not be used in Objective-C++ code as it does not ',
434 'drain the autorelease pool at the end of the test. Use TEST_F() ',
435 'macro instead with a fixture inheriting from PlatformTest (or a ',
436 'typedef).'
437 ),
438 True,
439 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15440 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54441 r'/\btesting::Test\b',
442 (
443 'testing::Test should not be used in Objective-C++ code as it does ',
444 'not drain the autorelease pool at the end of the test. Use ',
445 'PlatformTest instead.'
446 ),
447 True,
448 ),
Ewann2ecc8d72022-07-18 07:41:23449 BanRule(
450 ' systemImageNamed:',
451 (
452 '+[UIImage systemImageNamed:] should not be used to create symbols.',
453 'Instead use a wrapper defined in:',
Victor Vianna77a40f62023-01-31 19:04:53454 'ios/chrome/browser/ui/icons/symbol_helpers.h'
Ewann2ecc8d72022-07-18 07:41:23455 ),
456 True,
Ewann450a2ef2022-07-19 14:38:23457 excluded_paths=(
Gauthier Ambard4d8756b2023-04-07 17:26:41458 'ios/chrome/browser/shared/ui/symbols/symbol_helpers.mm',
Gauthier Ambardd36c10b12023-03-16 08:45:03459 'ios/chrome/search_widget_extension/',
Ewann450a2ef2022-07-19 14:38:23460 ),
Ewann2ecc8d72022-07-18 07:41:23461 ),
Sylvain Defresnea8b73d252018-02-28 15:45:54462)
463
Daniel Cheng917ce542022-03-15 20:46:57464_BANNED_IOS_EGTEST_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15465 BanRule(
Peter K. Lee6c03ccff2019-07-15 14:40:05466 r'/\bEXPECT_OCMOCK_VERIFY\b',
467 (
468 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
469 'it is meant for GTests. Use [mock verify] instead.'
470 ),
471 True,
472 ),
473)
474
Daniel Cheng917ce542022-03-15 20:46:57475_BANNED_CPP_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15476 BanRule(
Peter Kasting94a56c42019-10-25 21:54:04477 r'/\busing namespace ',
478 (
479 'Using directives ("using namespace x") are banned by the Google Style',
480 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
481 'Explicitly qualify symbols or use using declarations ("using x::foo").',
482 ),
483 True,
484 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
485 ),
Antonio Gomes07300d02019-03-13 20:59:57486 # Make sure that gtest's FRIEND_TEST() macro is not used; the
487 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
488 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
Daniel Chenga44a1bcd2022-03-15 20:00:15489 BanRule(
avi@chromium.org23e6cbc2012-06-16 18:51:20490 'FRIEND_TEST(',
491 (
jam@chromium.orge3c945502012-06-26 20:01:49492 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
avi@chromium.org23e6cbc2012-06-16 18:51:20493 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
494 ),
495 False,
jochen@chromium.org7345da02012-11-27 14:31:49496 (),
avi@chromium.org23e6cbc2012-06-16 18:51:20497 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15498 BanRule(
tomhudsone2c14d552016-05-26 17:07:46499 'setMatrixClip',
500 (
501 'Overriding setMatrixClip() is prohibited; ',
502 'the base function is deprecated. ',
503 ),
504 True,
505 (),
506 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15507 BanRule(
enne@chromium.org52657f62013-05-20 05:30:31508 'SkRefPtr',
509 (
510 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22511 'Please use sk_sp<> instead.'
enne@chromium.org52657f62013-05-20 05:30:31512 ),
513 True,
514 (),
515 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15516 BanRule(
enne@chromium.org52657f62013-05-20 05:30:31517 'SkAutoRef',
518 (
519 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22520 'Please use sk_sp<> instead.'
enne@chromium.org52657f62013-05-20 05:30:31521 ),
522 True,
523 (),
524 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15525 BanRule(
enne@chromium.org52657f62013-05-20 05:30:31526 'SkAutoTUnref',
527 (
528 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22529 'converts to a raw pointer. Please use sk_sp<> instead.'
enne@chromium.org52657f62013-05-20 05:30:31530 ),
531 True,
532 (),
533 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15534 BanRule(
enne@chromium.org52657f62013-05-20 05:30:31535 'SkAutoUnref',
536 (
537 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
538 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22539 'Please use sk_sp<> instead.'
enne@chromium.org52657f62013-05-20 05:30:31540 ),
541 True,
542 (),
543 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15544 BanRule(
mark@chromium.orgd89eec82013-12-03 14:10:59545 r'/HANDLE_EINTR\(.*close',
546 (
547 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
548 'descriptor will be closed, and it is incorrect to retry the close.',
549 'Either call close directly and ignore its return value, or wrap close',
550 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
551 ),
552 True,
553 (),
554 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15555 BanRule(
mark@chromium.orgd89eec82013-12-03 14:10:59556 r'/IGNORE_EINTR\((?!.*close)',
557 (
558 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
559 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
560 ),
561 True,
562 (
563 # Files that #define IGNORE_EINTR.
Bruce Dawson40fece62022-09-16 19:58:31564 r'^base/posix/eintr_wrapper\.h$',
565 r'^ppapi/tests/test_broker\.cc$',
mark@chromium.orgd89eec82013-12-03 14:10:59566 ),
567 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15568 BanRule(
jochen@chromium.orgec5b3f02014-04-04 18:43:43569 r'/v8::Extension\(',
570 (
571 'Do not introduce new v8::Extensions into the code base, use',
572 'gin::Wrappable instead. See http://crbug.com/334679',
573 ),
574 True,
rockot@chromium.orgf55c90ee62014-04-12 00:50:03575 (
Bruce Dawson40fece62022-09-16 19:58:31576 r'extensions/renderer/safe_builtins\.*',
rockot@chromium.orgf55c90ee62014-04-12 00:50:03577 ),
jochen@chromium.orgec5b3f02014-04-04 18:43:43578 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15579 BanRule(
jame2d1a952016-04-02 00:27:10580 '#pragma comment(lib,',
581 (
582 'Specify libraries to link with in build files and not in the source.',
583 ),
584 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41585 (
Bruce Dawson40fece62022-09-16 19:58:31586 r'^base/third_party/symbolize/.*',
587 r'^third_party/abseil-cpp/.*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41588 ),
jame2d1a952016-04-02 00:27:10589 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15590 BanRule(
Gabriel Charette7cc6c432018-04-25 20:52:02591 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59592 (
593 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
594 ),
595 False,
596 (),
597 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15598 BanRule(
Gabriel Charette7cc6c432018-04-25 20:52:02599 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59600 (
601 'Consider using THREAD_CHECKER macros instead of the class directly.',
602 ),
603 False,
604 (),
605 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15606 BanRule(
Sean Maher03efef12022-09-23 22:43:13607 r'/\b(?!(Sequenced|SingleThread))\w*TaskRunner::(GetCurrentDefault|CurrentDefaultHandle)',
608 (
609 'It is not allowed to call these methods from the subclasses ',
610 'of Sequenced or SingleThread task runners.',
611 ),
612 True,
613 (),
614 ),
615 BanRule(
Yuri Wiitala2f8de5c2017-07-21 00:11:06616 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
617 (
618 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
619 'deprecated (http://crbug.com/634507). Please avoid converting away',
620 'from the Time types in Chromium code, especially if any math is',
621 'being done on time values. For interfacing with platform/library',
622 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
623 'type converter methods instead. For faking TimeXXX values (for unit',
Peter Kasting53fd6ee2021-10-05 20:40:48624 'testing only), use TimeXXX() + Microseconds(N). For',
Yuri Wiitala2f8de5c2017-07-21 00:11:06625 'other use cases, please contact base/time/OWNERS.',
626 ),
627 False,
628 (),
629 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15630 BanRule(
dbeamb6f4fde2017-06-15 04:03:06631 'CallJavascriptFunctionUnsafe',
632 (
633 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
634 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
635 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
636 ),
637 False,
638 (
Bruce Dawson40fece62022-09-16 19:58:31639 r'^content/browser/webui/web_ui_impl\.(cc|h)$',
640 r'^content/public/browser/web_ui\.h$',
641 r'^content/public/test/test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06642 ),
643 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15644 BanRule(
dskiba1474c2bfd62017-07-20 02:19:24645 'leveldb::DB::Open',
646 (
647 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
648 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
649 "Chrome's tracing, making their memory usage visible.",
650 ),
651 True,
652 (
653 r'^third_party/leveldatabase/.*\.(cc|h)$',
654 ),
Gabriel Charette0592c3a2017-07-26 12:02:04655 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15656 BanRule(
Chris Mumfordc38afb62017-10-09 17:55:08657 'leveldb::NewMemEnv',
658 (
659 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58660 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
661 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08662 ),
663 True,
664 (
665 r'^third_party/leveldatabase/.*\.(cc|h)$',
666 ),
667 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15668 BanRule(
Gabriel Charetted9839bc2017-07-29 14:17:47669 'RunLoop::QuitCurrent',
670 (
Robert Liao64b7ab22017-08-04 23:03:43671 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
672 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47673 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41674 False,
Gabriel Charetted9839bc2017-07-29 14:17:47675 (),
Gabriel Charettea44975052017-08-21 23:14:04676 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15677 BanRule(
Gabriel Charettea44975052017-08-21 23:14:04678 'base::ScopedMockTimeMessageLoopTaskRunner',
679 (
Gabriel Charette87cc1af2018-04-25 20:52:51680 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11681 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51682 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
683 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
684 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04685 ),
Gabriel Charette87cc1af2018-04-25 20:52:51686 False,
Gabriel Charettea44975052017-08-21 23:14:04687 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57688 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15689 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44690 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57691 (
692 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02693 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57694 ),
695 True,
Danil Chapovalov7bc42a72020-12-09 18:20:16696 # Abseil's benchmarks never linked into chrome.
697 ['third_party/abseil-cpp/.*_benchmark.cc'],
Francois Doray43670e32017-09-27 12:40:38698 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15699 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:08700 r'/\bstd::sto(i|l|ul|ll|ull)\b',
Peter Kasting991618a62019-06-17 22:00:09701 (
Peter Kastinge2c5ee82023-02-15 17:23:08702 'std::sto{i,l,ul,ll,ull}() use exceptions to communicate results. ',
703 'Use base::StringTo[U]Int[64]() instead.',
Peter Kasting991618a62019-06-17 22:00:09704 ),
705 True,
706 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
707 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15708 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:08709 r'/\bstd::sto(f|d|ld)\b',
Peter Kasting991618a62019-06-17 22:00:09710 (
Peter Kastinge2c5ee82023-02-15 17:23:08711 'std::sto{f,d,ld}() use exceptions to communicate results. ',
Peter Kasting991618a62019-06-17 22:00:09712 'For locale-independent values, e.g. reading numbers from disk',
713 'profiles, use base::StringToDouble().',
714 'For user-visible values, parse using ICU.',
715 ),
716 True,
717 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
718 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15719 BanRule(
Daniel Bratell69334cc2019-03-26 11:07:45720 r'/\bstd::to_string\b',
721 (
Peter Kastinge2c5ee82023-02-15 17:23:08722 'std::to_string() is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09723 'For locale-independent strings, e.g. writing numbers to disk',
724 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45725 'For user-visible strings, use base::FormatNumber() and',
726 'the related functions in base/i18n/number_formatting.h.',
727 ),
Peter Kasting991618a62019-06-17 22:00:09728 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21729 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45730 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15731 BanRule(
Daniel Bratell69334cc2019-03-26 11:07:45732 r'/\bstd::shared_ptr\b',
733 (
Peter Kastinge2c5ee82023-02-15 17:23:08734 'std::shared_ptr is banned. Use scoped_refptr instead.',
Daniel Bratell69334cc2019-03-26 11:07:45735 ),
736 True,
Ulan Degenbaev947043882021-02-10 14:02:31737 [
738 # Needed for interop with third-party library.
739 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
Alex Chau9eb03cdd52020-07-13 21:04:57740 'array_buffer_contents\.(cc|h)',
Ben Kelly39bf6bef2021-10-04 22:54:58741 '^third_party/blink/renderer/bindings/core/v8/' +
742 'v8_wasm_response_extensions.cc',
Wez5f56be52021-05-04 09:30:58743 '^gin/array_buffer\.(cc|h)',
744 '^chrome/services/sharing/nearby/',
Stephen Nuskoe09c8ef22022-09-29 00:47:28745 # Needed for interop with third-party library libunwindstack.
Stephen Nuskoe51c1382022-09-26 15:49:03746 '^base/profiler/libunwindstack_unwinder_android\.(cc|h)',
Bob Beck03509d282022-12-07 21:49:05747 # Needed for interop with third-party boringssl cert verifier
748 '^third_party/boringssl/',
749 '^net/cert/',
750 '^net/tools/cert_verify_tool/',
751 '^services/cert_verifier/',
752 '^components/certificate_transparency/',
753 '^components/media_router/common/providers/cast/certificate/',
Meilin Wang00efc7c2021-05-13 01:12:42754 # gRPC provides some C++ libraries that use std::shared_ptr<>.
Yeunjoo Choi1b644402022-08-25 02:36:10755 '^chromeos/ash/services/libassistant/grpc/',
Vigen Issahhanjanfdf9de52021-12-22 21:13:59756 '^chromecast/cast_core/grpc',
757 '^chromecast/cast_core/runtime/browser',
Yue Shef83d95202022-09-26 20:23:45758 '^ios/chrome/test/earl_grey/chrome_egtest_plugin_client\.(mm|h)',
Wez5f56be52021-05-04 09:30:58759 # Fuchsia provides C++ libraries that use std::shared_ptr<>.
Wez6da2e412022-11-23 11:28:48760 '^base/fuchsia/.*\.(cc|h)',
Wez5f56be52021-05-04 09:30:58761 '.*fuchsia.*test\.(cc|h)',
miktb599ed12023-05-26 07:03:56762 # Clang plugins have different build config.
763 '^tools/clang/plugins/',
Alex Chau9eb03cdd52020-07-13 21:04:57764 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21765 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15766 BanRule(
Peter Kasting991618a62019-06-17 22:00:09767 r'/\bstd::weak_ptr\b',
768 (
Peter Kastinge2c5ee82023-02-15 17:23:08769 'std::weak_ptr is banned. Use base::WeakPtr instead.',
Peter Kasting991618a62019-06-17 22:00:09770 ),
771 True,
772 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
773 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15774 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21775 r'/\blong long\b',
776 (
Peter Kastinge2c5ee82023-02-15 17:23:08777 'long long is banned. Use [u]int64_t instead.',
Daniel Bratell609102be2019-03-27 20:53:21778 ),
779 False, # Only a warning since it is already used.
780 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
781 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15782 BanRule(
Daniel Cheng192683f2022-11-01 20:52:44783 r'/\b(absl|std)::any\b',
Daniel Chengc05fcc62022-01-12 16:54:29784 (
Peter Kastinge2c5ee82023-02-15 17:23:08785 '{absl,std}::any are banned due to incompatibility with the component ',
786 'build.',
Daniel Chengc05fcc62022-01-12 16:54:29787 ),
788 True,
789 # Not an error in third party folders, though it probably should be :)
790 [_THIRD_PARTY_EXCEPT_BLINK],
791 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15792 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21793 r'/\bstd::bind\b',
794 (
Peter Kastinge2c5ee82023-02-15 17:23:08795 'std::bind() is banned because of lifetime risks. Use ',
796 'base::Bind{Once,Repeating}() instead.',
Daniel Bratell609102be2019-03-27 20:53:21797 ),
798 True,
799 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
800 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15801 BanRule(
Daniel Cheng192683f2022-11-01 20:52:44802 (
Peter Kastingc7460d982023-03-14 21:01:42803 r'/\bstd::(?:'
804 r'linear_congruential_engine|mersenne_twister_engine|'
805 r'subtract_with_carry_engine|discard_block_engine|'
806 r'independent_bits_engine|shuffle_order_engine|'
807 r'minstd_rand0?|mt19937(_64)?|ranlux(24|48)(_base)?|knuth_b|'
808 r'default_random_engine|'
809 r'random_device|'
810 r'seed_seq'
Daniel Cheng192683f2022-11-01 20:52:44811 r')\b'
812 ),
813 (
814 'STL random number engines and generators are banned. Use the ',
815 'helpers in base/rand_util.h instead, e.g. base::RandBytes() or ',
816 'base::RandomBitGenerator.'
817 ),
818 True,
819 [
820 # Not an error in third_party folders.
821 _THIRD_PARTY_EXCEPT_BLINK,
822 # Various tools which build outside of Chrome.
823 r'testing/libfuzzer',
824 r'tools/android/io_benchmark/',
825 # Fuzzers are allowed to use standard library random number generators
826 # since fuzzing speed + reproducibility is important.
827 r'tools/ipc_fuzzer/',
828 r'.+_fuzzer\.cc$',
829 r'.+_fuzzertest\.cc$',
830 # TODO(https://crbug.com/1380528): These are all unsanctioned uses of
831 # the standard library's random number generators, and should be
832 # migrated to the //base equivalent.
833 r'ash/ambient/model/ambient_topic_queue\.cc',
834 r'base/allocator/partition_allocator/partition_alloc_unittest\.cc',
835 r'base/ranges/algorithm_unittest\.cc',
836 r'base/test/launcher/test_launcher\.cc',
837 r'cc/metrics/video_playback_roughness_reporter_unittest\.cc',
838 r'chrome/browser/apps/app_service/metrics/website_metrics\.cc',
839 r'chrome/browser/ash/power/auto_screen_brightness/monotone_cubic_spline_unittest\.cc',
840 r'chrome/browser/ash/printing/zeroconf_printer_detector_unittest\.cc',
841 r'chrome/browser/nearby_sharing/contacts/nearby_share_contact_manager_impl_unittest\.cc',
842 r'chrome/browser/nearby_sharing/contacts/nearby_share_contacts_sorter_unittest\.cc',
843 r'chrome/browser/privacy_budget/mesa_distribution_unittest\.cc',
844 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
845 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
846 r'chrome/browser/win/conflicts/module_blocklist_cache_util_unittest\.cc',
847 r'chrome/chrome_cleaner/logging/detailed_info_sampler\.cc',
848 r'chromeos/ash/components/memory/userspace_swap/swap_storage_unittest\.cc',
849 r'chromeos/ash/components/memory/userspace_swap/userspace_swap\.cc',
850 r'components/metrics/metrics_state_manager\.cc',
851 r'components/omnibox/browser/history_quick_provider_performance_unittest\.cc',
852 r'components/zucchini/disassembler_elf_unittest\.cc',
853 r'content/browser/webid/federated_auth_request_impl\.cc',
854 r'content/browser/webid/federated_auth_request_impl\.cc',
855 r'media/cast/test/utility/udp_proxy\.h',
856 r'sql/recover_module/module_unittest\.cc',
857 ],
858 ),
859 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:08860 r'/\b(absl,std)::bind_front\b',
Peter Kasting4f35bfc2022-10-18 18:39:12861 (
Peter Kastinge2c5ee82023-02-15 17:23:08862 '{absl,std}::bind_front() are banned. Use base::Bind{Once,Repeating}() '
863 'instead.',
Peter Kasting4f35bfc2022-10-18 18:39:12864 ),
865 True,
866 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
867 ),
868 BanRule(
869 r'/\bABSL_FLAG\b',
870 (
871 'ABSL_FLAG is banned. Use base::CommandLine instead.',
872 ),
873 True,
874 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
875 ),
876 BanRule(
877 r'/\babsl::c_',
878 (
Peter Kastinge2c5ee82023-02-15 17:23:08879 'Abseil container utilities are banned. Use base/ranges/algorithm.h ',
Peter Kasting4f35bfc2022-10-18 18:39:12880 'instead.',
881 ),
882 True,
883 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
884 ),
885 BanRule(
886 r'/\babsl::FunctionRef\b',
887 (
888 'absl::FunctionRef is banned. Use base::FunctionRef instead.',
889 ),
890 True,
891 [
892 # base::Bind{Once,Repeating} references absl::FunctionRef to disallow
893 # interoperability.
894 r'^base/functional/bind_internal\.h',
895 # base::FunctionRef is implemented on top of absl::FunctionRef.
896 r'^base/functional/function_ref.*\..+',
897 # Not an error in third_party folders.
898 _THIRD_PARTY_EXCEPT_BLINK,
899 ],
900 ),
901 BanRule(
902 r'/\babsl::(Insecure)?BitGen\b',
903 (
Daniel Cheng192683f2022-11-01 20:52:44904 'absl random number generators are banned. Use the helpers in '
905 'base/rand_util.h instead, e.g. base::RandBytes() or ',
906 'base::RandomBitGenerator.'
Peter Kasting4f35bfc2022-10-18 18:39:12907 ),
908 True,
909 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
910 ),
911 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:08912 r'/(\babsl::Span\b|#include <span>)',
Peter Kasting4f35bfc2022-10-18 18:39:12913 (
Peter Kastinge2c5ee82023-02-15 17:23:08914 'absl::Span is banned and <span> is not allowed yet ',
915 '(https://crbug.com/1414652). Use base::span instead.',
Peter Kasting4f35bfc2022-10-18 18:39:12916 ),
917 True,
Victor Vasiliev23b9ea6a2023-01-05 19:42:29918 [
919 # Needed to use QUICHE API.
920 r'services/network/web_transport\.cc',
Brianna Goldstein846d8002023-05-16 19:24:30921 r'chrome/browser/ip_protection/.*',
Victor Vasiliev23b9ea6a2023-01-05 19:42:29922 # Not an error in third_party folders.
923 _THIRD_PARTY_EXCEPT_BLINK
924 ],
Peter Kasting4f35bfc2022-10-18 18:39:12925 ),
926 BanRule(
927 r'/\babsl::StatusOr\b',
928 (
929 'absl::StatusOr is banned. Use base::expected instead.',
930 ),
931 True,
Adithya Srinivasanb2041882022-10-21 19:34:20932 [
933 # Needed to use liburlpattern API.
934 r'third_party/blink/renderer/core/url_pattern/.*',
Louise Brettc6d23872023-04-11 02:48:32935 r'third_party/blink/renderer/modules/manifest/manifest_parser\.cc',
Brianna Goldstein846d8002023-05-16 19:24:30936 # Needed to use QUICHE API.
937 r'chrome/browser/ip_protection/.*',
Adithya Srinivasanb2041882022-10-21 19:34:20938 # Not an error in third_party folders.
939 _THIRD_PARTY_EXCEPT_BLINK
940 ],
Peter Kasting4f35bfc2022-10-18 18:39:12941 ),
942 BanRule(
943 r'/\babsl::StrFormat\b',
944 (
Peter Kastinge2c5ee82023-02-15 17:23:08945 'absl::StrFormat() is not allowed yet (https://crbug.com/1371963). ',
946 'Use base::StringPrintf() instead.',
Peter Kasting4f35bfc2022-10-18 18:39:12947 ),
948 True,
949 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
950 ),
951 BanRule(
David Benjaminea985a22023-04-18 22:05:01952 r'/\babsl::string_view\b',
Peter Kasting4f35bfc2022-10-18 18:39:12953 (
David Benjaminea985a22023-04-18 22:05:01954 'absl::string_view is a legacy spelling of std::string_view, which is ',
955 'not allowed yet (https://crbug.com/691162). Use base::StringPiece ',
956 'instead, unless std::string_view is needed to use with an external ',
957 'API.',
958 ),
959 True,
960 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
961 ),
962 BanRule(
963 r'/\bstd::(u16)?string_view\b',
964 (
965 'std::[u16]string_view is not yet allowed (crbug.com/691162). Use ',
966 'base::StringPiece[16] instead, unless std::[u16]string_view is ',
967 'needed to use an external API.',
Peter Kasting4f35bfc2022-10-18 18:39:12968 ),
969 True,
Adithya Srinivasanb2041882022-10-21 19:34:20970 [
David Benjaminea985a22023-04-18 22:05:01971 # Needed to implement and test std::string_view interoperability.
972 r'base/strings/string_piece.*',
Xiaochen Zhouf19c97f2023-04-28 13:04:32973 # Needed to use re2::RE2 regular expression library.
974 r'third_party/blink/common/interest_group/ad_display_size_utils.cc',
Adithya Srinivasanb2041882022-10-21 19:34:20975 # Needed to use liburlpattern API.
976 r'third_party/blink/renderer/core/url_pattern/.*',
Louise Brettc6d23872023-04-11 02:48:32977 r'third_party/blink/renderer/modules/manifest/manifest_parser\.cc',
David Benjamin3a305f12022-11-19 00:10:03978 # Needed to use QUICHE API.
Victor Vasilieva13f1932022-12-02 15:27:24979 r'net/quic/.*',
980 r'net/spdy/.*',
David Benjamin3a305f12022-11-19 00:10:03981 r'net/test/embedded_test_server/.*',
Victor Vasilieva13f1932022-12-02 15:27:24982 r'net/third_party/quiche/.*',
983 r'services/network/web_transport\.cc',
David Benjaminea985a22023-04-18 22:05:01984 # This code is in the process of being extracted into an external
985 # library, where //base will be unavailable.
986 r'net/cert/pki/.*',
987 r'net/der/.*',
988 # Needed to use APIs from the above.
989 r'net/cert/.*',
Samuel Huangd3e740c2023-05-26 19:06:29990 # Needed by Caspian, which compiles to WASM.
991 r'tools/binary_size/libsupersize/viewer/caspian/.*',
Adithya Srinivasanb2041882022-10-21 19:34:20992 # Not an error in third_party folders.
993 _THIRD_PARTY_EXCEPT_BLINK
994 ],
Peter Kasting4f35bfc2022-10-18 18:39:12995 ),
996 BanRule(
997 r'/\babsl::(StrSplit|StrJoin|StrCat|StrAppend|Substitute|StrContains)\b',
998 (
999 'Abseil string utilities are banned. Use base/strings instead.',
1000 ),
1001 True,
1002 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1003 ),
1004 BanRule(
1005 r'/\babsl::(Mutex|CondVar|Notification|Barrier|BlockingCounter)\b',
1006 (
1007 'Abseil synchronization primitives are banned. Use',
1008 'base/synchronization instead.',
1009 ),
1010 True,
1011 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1012 ),
1013 BanRule(
1014 r'/\babsl::(Duration|Time|TimeZone|CivilDay)\b',
1015 (
1016 'Abseil\'s time library is banned. Use base/time instead.',
1017 ),
1018 True,
1019 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1020 ),
1021 BanRule(
Avi Drissman48ee39e2022-02-16 16:31:031022 r'/\bstd::optional\b',
1023 (
Peter Kastinge2c5ee82023-02-15 17:23:081024 'std::optional is not allowed yet (https://crbug.com/1373619). Use ',
1025 'absl::optional instead.',
Avi Drissman48ee39e2022-02-16 16:31:031026 ),
1027 True,
miktb599ed12023-05-26 07:03:561028 [
1029 # Clang plugins have different build config.
1030 '^tools/clang/plugins/',
1031 # Not an error in third_party folders.
1032 _THIRD_PARTY_EXCEPT_BLINK,
1033 ],
Avi Drissman48ee39e2022-02-16 16:31:031034 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151035 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081036 r'/#include <chrono>',
Daniel Bratell609102be2019-03-27 20:53:211037 (
Peter Kastinge2c5ee82023-02-15 17:23:081038 '<chrono> is banned. Use base/time instead.',
Daniel Bratell609102be2019-03-27 20:53:211039 ),
1040 True,
1041 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1042 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151043 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081044 r'/#include <exception>',
Daniel Bratell609102be2019-03-27 20:53:211045 (
1046 'Exceptions are banned and disabled in Chromium.',
1047 ),
1048 True,
1049 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1050 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151051 BanRule(
Daniel Bratell609102be2019-03-27 20:53:211052 r'/\bstd::function\b',
1053 (
Peter Kastinge2c5ee82023-02-15 17:23:081054 'std::function is banned. Use base::{Once,Repeating}Callback instead.',
Daniel Bratell609102be2019-03-27 20:53:211055 ),
Daniel Chenge5583e3c2022-09-22 00:19:411056 True,
Daniel Chengcd23b8b2022-09-16 17:16:241057 [
1058 # Has tests that template trait helpers don't unintentionally match
1059 # std::function.
Daniel Chenge5583e3c2022-09-22 00:19:411060 r'base/functional/callback_helpers_unittest\.cc',
1061 # Required to implement interfaces from the third-party perfetto
1062 # library.
1063 r'base/tracing/perfetto_task_runner\.cc',
1064 r'base/tracing/perfetto_task_runner\.h',
1065 # Needed for interop with the third-party nearby library type
1066 # location::nearby::connections::ResultCallback.
1067 'chrome/services/sharing/nearby/nearby_connections_conversions\.cc'
1068 # Needed for interop with the internal libassistant library.
1069 'chromeos/ash/services/libassistant/callback_utils\.h',
1070 # Needed for interop with Fuchsia fidl APIs.
1071 'fuchsia_web/webengine/browser/context_impl_browsertest\.cc',
1072 'fuchsia_web/webengine/browser/cookie_manager_impl_unittest\.cc',
1073 'fuchsia_web/webengine/browser/media_player_impl_unittest\.cc',
1074 # Required to interop with interfaces from the third-party perfetto
1075 # library.
1076 'services/tracing/public/cpp/perfetto/custom_event_recorder\.cc',
1077 'services/tracing/public/cpp/perfetto/perfetto_traced_process\.cc',
1078 'services/tracing/public/cpp/perfetto/perfetto_traced_process\.h',
1079 'services/tracing/public/cpp/perfetto/perfetto_tracing_backend\.cc',
1080 'services/tracing/public/cpp/perfetto/producer_client\.cc',
1081 'services/tracing/public/cpp/perfetto/producer_client\.h',
1082 'services/tracing/public/cpp/perfetto/producer_test_utils\.cc',
1083 'services/tracing/public/cpp/perfetto/producer_test_utils\.h',
1084 # Required for interop with the third-party webrtc library.
1085 'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.cc',
1086 'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.h',
Bob Beck5fc0be82022-12-12 23:32:521087 # This code is in the process of being extracted into a third-party library.
1088 # See https://crbug.com/1322914
1089 '^net/cert/pki/path_builder_unittest\.cc',
Brianna Goldstein846d8002023-05-16 19:24:301090 # Needed to use QUICHE API
1091 r'chrome/browser/ip_protection/.*',
Daniel Chenge5583e3c2022-09-22 00:19:411092 # TODO(https://crbug.com/1364577): Various uses that should be
1093 # migrated to something else.
1094 # Should use base::OnceCallback or base::RepeatingCallback.
1095 'base/allocator/dispatcher/initializer_unittest\.cc',
1096 'chrome/browser/ash/accessibility/speech_monitor\.cc',
1097 'chrome/browser/ash/accessibility/speech_monitor\.h',
1098 'chrome/browser/ash/login/ash_hud_login_browsertest\.cc',
1099 'chromecast/base/observer_unittest\.cc',
1100 'chromecast/browser/cast_web_view\.h',
1101 'chromecast/public/cast_media_shlib\.h',
1102 'device/bluetooth/floss/exported_callback_manager\.h',
1103 'device/bluetooth/floss/floss_dbus_client\.h',
1104 'device/fido/cable/v2_handshake_unittest\.cc',
1105 'device/fido/pin\.cc',
1106 'services/tracing/perfetto/test_utils\.h',
1107 # Should use base::FunctionRef.
1108 'chrome/browser/media/webrtc/test_stats_dictionary\.cc',
1109 'chrome/browser/media/webrtc/test_stats_dictionary\.h',
1110 'chromeos/ash/services/libassistant/device_settings_controller\.cc',
1111 'components/browser_ui/client_certificate/android/ssl_client_certificate_request\.cc',
1112 'components/gwp_asan/client/sampling_malloc_shims_unittest\.cc',
1113 'content/browser/font_unique_name_lookup/font_unique_name_lookup_unittest\.cc',
1114 # Does not need std::function at all.
1115 'components/omnibox/browser/autocomplete_result\.cc',
1116 'device/fido/win/webauthn_api\.cc',
1117 'media/audio/alsa/alsa_util\.cc',
1118 'media/remoting/stream_provider\.h',
1119 'sql/vfs_wrapper\.cc',
1120 # TODO(https://crbug.com/1364585): Remove usage and exception list
1121 # entries.
1122 'extensions/renderer/api/automation/automation_internal_custom_bindings\.cc',
1123 'extensions/renderer/api/automation/automation_internal_custom_bindings\.h',
1124 # TODO(https://crbug.com/1364579): Remove usage and exception list
1125 # entry.
1126 'ui/views/controls/focus_ring\.h',
1127
1128 # Various pre-existing uses in //tools that is low-priority to fix.
1129 'tools/binary_size/libsupersize/viewer/caspian/diff\.cc',
1130 'tools/binary_size/libsupersize/viewer/caspian/model\.cc',
1131 'tools/binary_size/libsupersize/viewer/caspian/model\.h',
1132 'tools/binary_size/libsupersize/viewer/caspian/tree_builder\.h',
1133 'tools/clang/base_bind_rewriters/BaseBindRewriters\.cpp',
1134
Daniel Chengcd23b8b2022-09-16 17:16:241135 # Not an error in third_party folders.
1136 _THIRD_PARTY_EXCEPT_BLINK
1137 ],
Daniel Bratell609102be2019-03-27 20:53:211138 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151139 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081140 r'/#include <X11/',
Tom Andersona95e12042020-09-09 23:08:001141 (
1142 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
1143 ),
1144 True,
1145 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1146 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151147 BanRule(
Daniel Bratell609102be2019-03-27 20:53:211148 r'/\bstd::ratio\b',
1149 (
1150 'std::ratio is banned by the Google Style Guide.',
1151 ),
1152 True,
1153 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:451154 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151155 BanRule(
Peter Kasting6d77e9d2023-02-09 21:58:181156 r'/\bstd::aligned_alloc\b',
1157 (
Peter Kastinge2c5ee82023-02-15 17:23:081158 'std::aligned_alloc() is not yet allowed (crbug.com/1412818). Use ',
1159 'base::AlignedAlloc() instead.',
Peter Kasting6d77e9d2023-02-09 21:58:181160 ),
1161 True,
1162 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1163 ),
1164 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081165 r'/#include <(barrier|latch|semaphore|stop_token)>',
Peter Kasting6d77e9d2023-02-09 21:58:181166 (
Peter Kastinge2c5ee82023-02-15 17:23:081167 'The thread support library is banned. Use base/synchronization '
1168 'instead.',
Peter Kasting6d77e9d2023-02-09 21:58:181169 ),
1170 True,
1171 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1172 ),
1173 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081174 r'/\bstd::(c8rtomb|mbrtoc8)\b',
Peter Kasting6d77e9d2023-02-09 21:58:181175 (
Peter Kastinge2c5ee82023-02-15 17:23:081176 'std::c8rtomb() and std::mbrtoc8() are banned.',
Peter Kasting6d77e9d2023-02-09 21:58:181177 ),
1178 True,
1179 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1180 ),
1181 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081182 r'/\bchar8_t|std::u8string\b',
Peter Kasting6d77e9d2023-02-09 21:58:181183 (
Peter Kastinge2c5ee82023-02-15 17:23:081184 'char8_t and std::u8string are not yet allowed. Can you use [unsigned]',
1185 ' char and std::string instead?',
1186 ),
1187 True,
Daniel Cheng893c563f2023-04-21 09:54:521188 [
1189 # The demangler does not use this type but needs to know about it.
1190 'base/third_party/symbolize/demangle\.cc',
1191 # Don't warn in third_party folders.
1192 _THIRD_PARTY_EXCEPT_BLINK
1193 ],
Peter Kastinge2c5ee82023-02-15 17:23:081194 ),
1195 BanRule(
1196 r'/(\b(co_await|co_return|co_yield)\b|#include <coroutine>)',
1197 (
1198 'Coroutines are not yet allowed (https://crbug.com/1403840).',
1199 ),
1200 True,
1201 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1202 ),
1203 BanRule(
Peter Kastingcc152522023-03-22 20:17:371204 r'/^\s*(export\s|import\s+["<:\w]|module(;|\s+[:\w]))',
Peter Kasting69357dc2023-03-14 01:34:291205 (
1206 'Modules are disallowed for now due to lack of toolchain support.',
1207 ),
1208 True,
1209 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1210 ),
1211 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081212 r'/\[\[(un)?likely\]\]',
1213 (
1214 '[[likely]] and [[unlikely]] are not yet allowed ',
1215 '(https://crbug.com/1414620). Use [UN]LIKELY instead.',
1216 ),
1217 True,
1218 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1219 ),
1220 BanRule(
1221 r'/#include <format>',
1222 (
1223 '<format> is not yet allowed. Use base::StringPrintf() instead.',
1224 ),
1225 True,
1226 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1227 ),
1228 BanRule(
1229 r'/#include <ranges>',
1230 (
1231 '<ranges> is not yet allowed. Use base/ranges/algorithm.h instead.',
1232 ),
1233 True,
1234 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1235 ),
1236 BanRule(
1237 r'/#include <source_location>',
1238 (
1239 '<source_location> is not yet allowed. Use base/location.h instead.',
1240 ),
1241 True,
1242 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1243 ),
1244 BanRule(
1245 r'/#include <syncstream>',
1246 (
1247 '<syncstream> is banned.',
Peter Kasting6d77e9d2023-02-09 21:58:181248 ),
1249 True,
1250 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1251 ),
1252 BanRule(
Michael Giuffrida7f93d6922019-04-19 14:39:581253 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:191254 (
1255 'RunMessageLoop is deprecated, use RunLoop instead.',
1256 ),
1257 False,
1258 (),
1259 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151260 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441261 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:191262 (
1263 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
1264 "if you're convinced you need this.",
1265 ),
1266 False,
1267 (),
1268 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151269 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441270 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:191271 (
1272 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:041273 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:191274 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
1275 'async events instead of flushing threads.',
1276 ),
1277 False,
1278 (),
1279 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151280 BanRule(
Gabriel Charette147335ea2018-03-22 15:59:191281 r'MessageLoopRunner',
1282 (
1283 'MessageLoopRunner is deprecated, use RunLoop instead.',
1284 ),
1285 False,
1286 (),
1287 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151288 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441289 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:191290 (
1291 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
1292 "gab@ if you found a use case where this is the only solution.",
1293 ),
1294 False,
1295 (),
1296 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151297 BanRule(
Victor Costane48a2e82019-03-15 22:02:341298 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:161299 (
Victor Costane48a2e82019-03-15 22:02:341300 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:161301 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
1302 ),
1303 True,
1304 (
1305 r'^sql/initialization\.(cc|h)$',
1306 r'^third_party/sqlite/.*\.(c|cc|h)$',
1307 ),
1308 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151309 BanRule(
Austin Sullivand661ab52022-11-16 08:55:151310 'CREATE VIEW',
1311 (
1312 'SQL views are disabled in Chromium feature code',
1313 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-views',
1314 ),
1315 True,
1316 (
1317 _THIRD_PARTY_EXCEPT_BLINK,
1318 # sql/ itself uses views when using memory-mapped IO.
1319 r'^sql/.*',
1320 # Various performance tools that do not build as part of Chrome.
1321 r'^infra/.*',
1322 r'^tools/perf.*',
1323 r'.*perfetto.*',
1324 ),
1325 ),
1326 BanRule(
1327 'CREATE VIRTUAL TABLE',
1328 (
1329 'SQL virtual tables are disabled in Chromium feature code',
1330 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-virtual-tables',
1331 ),
1332 True,
1333 (
1334 _THIRD_PARTY_EXCEPT_BLINK,
1335 # sql/ itself uses virtual tables in the recovery module and tests.
1336 r'^sql/.*',
1337 # TODO(https://crbug.com/695592): Remove once WebSQL is deprecated.
1338 r'third_party/blink/web_tests/storage/websql/.*'
1339 # Various performance tools that do not build as part of Chrome.
1340 r'^tools/perf.*',
1341 r'.*perfetto.*',
1342 ),
1343 ),
1344 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441345 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:471346 (
1347 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
1348 'base::RandomShuffle instead.'
1349 ),
1350 True,
1351 (),
1352 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151353 BanRule(
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:241354 'ios/web/public/test/http_server',
1355 (
1356 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
1357 ),
1358 False,
1359 (),
1360 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151361 BanRule(
Robert Liao764c9492019-01-24 18:46:281362 'GetAddressOf',
1363 (
1364 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:531365 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:111366 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:531367 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:281368 ),
1369 True,
1370 (),
1371 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151372 BanRule(
Ben Lewisa9514602019-04-29 17:53:051373 'SHFileOperation',
1374 (
1375 'SHFileOperation was deprecated in Windows Vista, and there are less ',
1376 'complex functions to achieve the same goals. Use IFileOperation for ',
1377 'any esoteric actions instead.'
1378 ),
1379 True,
1380 (),
1381 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151382 BanRule(
Cliff Smolinsky81951642019-04-30 21:39:511383 'StringFromGUID2',
1384 (
1385 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241386 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511387 ),
1388 True,
1389 (
Daniel Chenga44a1bcd2022-03-15 20:00:151390 r'/base/win/win_util_unittest.cc',
Cliff Smolinsky81951642019-04-30 21:39:511391 ),
1392 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151393 BanRule(
Cliff Smolinsky81951642019-04-30 21:39:511394 'StringFromCLSID',
1395 (
1396 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241397 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511398 ),
1399 True,
1400 (
Daniel Chenga44a1bcd2022-03-15 20:00:151401 r'/base/win/win_util_unittest.cc',
Cliff Smolinsky81951642019-04-30 21:39:511402 ),
1403 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151404 BanRule(
Avi Drissman7382afa02019-04-29 23:27:131405 'kCFAllocatorNull',
1406 (
1407 'The use of kCFAllocatorNull with the NoCopy creation of ',
1408 'CoreFoundation types is prohibited.',
1409 ),
1410 True,
1411 (),
1412 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151413 BanRule(
Oksana Zhuravlovafd247772019-05-16 16:57:291414 'mojo::ConvertTo',
1415 (
1416 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1417 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1418 'StringTraits if you would like to convert between custom types and',
1419 'the wire format of mojom types.'
1420 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221421 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291422 (
David Dorwin13dc48b2022-06-03 21:18:421423 r'^fuchsia_web/webengine/browser/url_request_rewrite_rules_manager\.cc$',
1424 r'^fuchsia_web/webengine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291425 r'^third_party/blink/.*\.(cc|h)$',
1426 r'^content/renderer/.*\.(cc|h)$',
1427 ),
1428 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151429 BanRule(
Oksana Zhuravlovac8222d22019-12-19 19:21:161430 'GetInterfaceProvider',
1431 (
1432 'InterfaceProvider is deprecated.',
1433 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1434 'or Platform::GetBrowserInterfaceBroker.'
1435 ),
1436 False,
1437 (),
1438 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151439 BanRule(
Robert Liao1d78df52019-11-11 20:02:011440 'CComPtr',
1441 (
1442 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1443 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1444 'details.'
1445 ),
1446 False,
1447 (),
1448 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151449 BanRule(
Xiaohan Wang72bd2ba2020-02-18 21:38:201450 r'/\b(IFACE|STD)METHOD_?\(',
1451 (
1452 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1453 'Instead, always use IFACEMETHODIMP in the declaration.'
1454 ),
1455 False,
1456 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1457 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151458 BanRule(
Allen Bauer53b43fb12020-03-12 17:21:471459 'set_owned_by_client',
1460 (
1461 'set_owned_by_client is deprecated.',
1462 'views::View already owns the child views by default. This introduces ',
1463 'a competing ownership model which makes the code difficult to reason ',
1464 'about. See http://crbug.com/1044687 for more details.'
1465 ),
1466 False,
1467 (),
1468 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151469 BanRule(
Peter Boström7ff41522021-07-29 03:43:271470 'RemoveAllChildViewsWithoutDeleting',
1471 (
1472 'RemoveAllChildViewsWithoutDeleting is deprecated.',
1473 'This method is deemed dangerous as, unless raw pointers are re-added,',
1474 'calls to this method introduce memory leaks.'
1475 ),
1476 False,
1477 (),
1478 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151479 BanRule(
Eric Secklerbe6f48d2020-05-06 18:09:121480 r'/\bTRACE_EVENT_ASYNC_',
1481 (
1482 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1483 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1484 ),
1485 False,
1486 (
1487 r'^base/trace_event/.*',
1488 r'^base/tracing/.*',
1489 ),
1490 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151491 BanRule(
Aditya Kushwah5a286b72022-02-10 04:54:431492 r'/\bbase::debug::DumpWithoutCrashingUnthrottled[(][)]',
1493 (
1494 'base::debug::DumpWithoutCrashingUnthrottled() does not throttle',
1495 'dumps and may spam crash reports. Consider if the throttled',
1496 'variants suffice instead.',
1497 ),
1498 False,
1499 (),
1500 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151501 BanRule(
Robert Liao22f66a52021-04-10 00:57:521502 'RoInitialize',
1503 (
Robert Liao48018922021-04-16 23:03:021504 'Improper use of [base::win]::RoInitialize() has been implicated in a ',
Robert Liao22f66a52021-04-10 00:57:521505 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
1506 'instead. See http://crbug.com/1197722 for more information.'
1507 ),
1508 True,
Robert Liao48018922021-04-16 23:03:021509 (
Bruce Dawson40fece62022-09-16 19:58:311510 r'^base/win/scoped_winrt_initializer\.cc$',
Danil Chapovalov07694382023-05-24 17:55:211511 r'^third_party/abseil-cpp/absl/.*',
Robert Liao48018922021-04-16 23:03:021512 ),
Robert Liao22f66a52021-04-10 00:57:521513 ),
Patrick Monettec343bb982022-06-01 17:18:451514 BanRule(
1515 r'base::Watchdog',
1516 (
1517 'base::Watchdog is deprecated because it creates its own thread.',
1518 'Instead, manually start a timer on a SequencedTaskRunner.',
1519 ),
1520 False,
1521 (),
1522 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091523 BanRule(
1524 'base::Passed',
1525 (
1526 'Do not use base::Passed. It is a legacy helper for capturing ',
1527 'move-only types with base::BindRepeating, but invoking the ',
1528 'resulting RepeatingCallback moves the captured value out of ',
1529 'the callback storage, and subsequent invocations may pass the ',
1530 'value in a valid but undefined state. Prefer base::BindOnce().',
1531 'See http://crbug.com/1326449 for context.'
1532 ),
1533 False,
Daniel Cheng91f6fbaf2022-09-16 12:07:481534 (
1535 # False positive, but it is also fine to let bind internals reference
1536 # base::Passed.
Daniel Chengcd23b8b2022-09-16 17:16:241537 r'^base[\\/]functional[\\/]bind\.h',
Daniel Cheng91f6fbaf2022-09-16 12:07:481538 r'^base[\\/]functional[\\/]bind_internal\.h',
1539 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091540 ),
Daniel Cheng2248b332022-07-27 06:16:591541 BanRule(
Daniel Chengba3bc2e2022-10-03 02:45:431542 r'base::Feature k',
1543 (
1544 'Please use BASE_DECLARE_FEATURE() or BASE_FEATURE() instead of ',
1545 'directly declaring/defining features.'
1546 ),
1547 True,
1548 [
1549 _THIRD_PARTY_EXCEPT_BLINK,
1550 ],
1551 ),
Robert Ogden92101dcb2022-10-19 23:49:361552 BanRule(
Arthur Sonzogni1da65fa2023-03-27 16:01:521553 r'/\bchartorune\b',
Robert Ogden92101dcb2022-10-19 23:49:361554 (
1555 'chartorune is not memory-safe, unless you can guarantee the input ',
1556 'string is always null-terminated. Otherwise, please use charntorune ',
1557 'from libphonenumber instead.'
1558 ),
1559 True,
1560 [
1561 _THIRD_PARTY_EXCEPT_BLINK,
1562 # Exceptions to this rule should have a fuzzer.
1563 ],
1564 ),
Arthur Sonzogni1da65fa2023-03-27 16:01:521565 BanRule(
1566 r'/\b#include "base/atomicops\.h"\b',
1567 (
1568 'Do not use base::subtle atomics, but std::atomic, which are simpler '
1569 'to use, have better understood, clearer and richer semantics, and are '
1570 'harder to mis-use. See details in base/atomicops.h.',
1571 ),
1572 False,
1573 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Benoit Lize79cf0592023-01-27 10:01:571574 ),
Arthur Sonzogni60348572e2023-04-07 10:22:521575 BanRule(
1576 r'CrossThreadPersistent<',
1577 (
1578 'Do not use blink::CrossThreadPersistent, but '
1579 'blink::CrossThreadHandle. It is harder to mis-use.',
1580 'More info: '
1581 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1582 'Please contact platform-architecture-dev@ before adding new instances.'
1583 ),
1584 False,
1585 []
1586 ),
1587 BanRule(
1588 r'CrossThreadWeakPersistent<',
1589 (
1590 'Do not use blink::CrossThreadWeakPersistent, but '
1591 'blink::CrossThreadWeakHandle. It is harder to mis-use.',
1592 'More info: '
1593 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1594 'Please contact platform-architecture-dev@ before adding new instances.'
1595 ),
1596 False,
1597 []
1598 ),
Avi Drissman491617c2023-04-13 17:33:151599 BanRule(
1600 r'objc/objc.h',
1601 (
1602 'Do not include <objc/objc.h>. It defines away ARC lifetime '
1603 'annotations, and is thus dangerous.',
1604 'Please use the pimpl pattern; search for `ObjCStorage` for examples.',
1605 'For further reading on how to safely mix C++ and Obj-C, see',
1606 'https://chromium.googlesource.com/chromium/src/+/main/docs/mac/mixing_cpp_and_objc.md'
1607 ),
1608 True,
1609 []
1610 ),
Grace Park8d59b54b2023-04-26 17:53:351611 BanRule(
1612 r'/#include <filesystem>',
1613 (
1614 'libc++ <filesystem> is banned per the Google C++ styleguide.',
1615 ),
1616 True,
1617 # This fuzzing framework is a standalone open source project and
1618 # cannot rely on Chromium base.
1619 (r'third_party/centipede'),
1620 ),
Daniel Cheng72153e02023-05-18 21:18:141621 BanRule(
1622 r'TopDocument()',
1623 (
1624 'TopDocument() does not work correctly with out-of-process iframes. '
1625 'Please do not introduce new uses.',
1626 ),
1627 True,
1628 (
1629 # TODO(crbug.com/617677): Remove all remaining uses.
1630 r'^third_party/blink/renderer/core/dom/document\.cc',
1631 r'^third_party/blink/renderer/core/dom/document\.h',
1632 r'^third_party/blink/renderer/core/dom/element\.cc',
1633 r'^third_party/blink/renderer/core/exported/web_disallow_transition_scope_test\.cc',
1634 r'^third_party/blink/renderer/core/exported/web_document_test\.cc',
Daniel Cheng72153e02023-05-18 21:18:141635 r'^third_party/blink/renderer/core/html/html_anchor_element\.cc',
1636 r'^third_party/blink/renderer/core/html/html_dialog_element\.cc',
1637 r'^third_party/blink/renderer/core/html/html_element\.cc',
1638 r'^third_party/blink/renderer/core/html/html_frame_owner_element\.cc',
1639 r'^third_party/blink/renderer/core/html/media/video_wake_lock\.cc',
1640 r'^third_party/blink/renderer/core/loader/anchor_element_interaction_tracker\.cc',
1641 r'^third_party/blink/renderer/core/page/scrolling/root_scroller_controller\.cc',
1642 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.cc',
1643 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.h',
1644 r'^third_party/blink/renderer/core/script/classic_pending_script\.cc',
1645 r'^third_party/blink/renderer/core/script/script_loader\.cc',
1646 ),
1647 ),
avi@chromium.org127f18ec2012-06-16 05:05:591648)
1649
Daniel Cheng92c15e32022-03-16 17:48:221650_BANNED_MOJOM_PATTERNS : Sequence[BanRule] = (
1651 BanRule(
1652 'handle<shared_buffer>',
1653 (
1654 'Please use one of the more specific shared memory types instead:',
1655 ' mojo_base.mojom.ReadOnlySharedMemoryRegion',
1656 ' mojo_base.mojom.WritableSharedMemoryRegion',
1657 ' mojo_base.mojom.UnsafeSharedMemoryRegion',
1658 ),
1659 True,
1660 ),
1661)
1662
mlamouria82272622014-09-16 18:45:041663_IPC_ENUM_TRAITS_DEPRECATED = (
1664 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501665 'See http://www.chromium.org/Home/chromium-security/education/'
1666 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041667
Stephen Martinis97a394142018-06-07 23:06:051668_LONG_PATH_ERROR = (
1669 'Some files included in this CL have file names that are too long (> 200'
1670 ' characters). If committed, these files will cause issues on Windows. See'
1671 ' https://crbug.com/612667 for more details.'
1672)
1673
Shenghua Zhangbfaa38b82017-11-16 21:58:021674_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Bruce Dawson40fece62022-09-16 19:58:311675 r".*/AppHooksImpl\.java",
1676 r".*/BuildHooksAndroidImpl\.java",
1677 r".*/LicenseContentProvider\.java",
1678 r".*/PlatformServiceBridgeImpl.java",
1679 r".*chrome/android/feed/dummy/.*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021680]
avi@chromium.org127f18ec2012-06-16 05:05:591681
Mohamed Heikald048240a2019-11-12 16:57:371682# List of image extensions that are used as resources in chromium.
1683_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1684
Sean Kau46e29bc2017-08-28 16:31:161685# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401686_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Bruce Dawson40fece62022-09-16 19:58:311687 r'test/data/',
1688 r'testing/buildbot/',
1689 r'^components/policy/resources/policy_templates\.json$',
1690 r'^third_party/protobuf/',
Camillo Bruni1411a352023-05-24 12:39:031691 r'^third_party/blink/perf_tests/speedometer.*/resources/todomvc/learn\.json',
Bruce Dawson40fece62022-09-16 19:58:311692 r'^third_party/blink/renderer/devtools/protocol\.json$',
1693 r'^third_party/blink/web_tests/external/wpt/',
1694 r'^tools/perf/',
1695 r'^tools/traceline/svgui/startup-release.json',
Daniel Cheng2d4c2d192022-07-01 01:38:311696 # vscode configuration files allow comments
Bruce Dawson40fece62022-09-16 19:58:311697 r'^tools/vscode/',
Sean Kau46e29bc2017-08-28 16:31:161698]
1699
Andrew Grieveb773bad2020-06-05 18:00:381700# These are not checked on the public chromium-presubmit trybot.
1701# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041702# checkouts.
agrievef32bcc72016-04-04 14:57:401703_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381704 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381705]
1706
1707
1708_GENERIC_PYDEPS_FILES = [
Bruce Dawson853b739e62022-05-03 23:03:101709 'android_webview/test/components/run_webview_component_smoketest.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041710 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361711 'base/android/jni_generator/jni_generator.pydeps',
1712 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361713 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041714 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361715 'build/android/gyp/aar.pydeps',
1716 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271717 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361718 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381719 'build/android/gyp/assert_static_initializers.pydeps',
Mohamed Heikal133e1f22023-04-18 20:04:371720 'build/android/gyp/binary_baseline_profile.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361721 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021722 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:221723 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111724 'build/android/gyp/compile_java.pydeps',
Peter Weneaa963f2023-01-20 19:40:301725 'build/android/gyp/compile_kt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361726 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361727 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361728 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111729 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041730 'build/android/gyp/create_app_bundle_apks.pydeps',
1731 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361732 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121733 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091734 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221735 'build/android/gyp/create_size_info_files.pydeps',
Peter Wene6e017e2022-07-27 21:40:401736 'build/android/gyp/create_test_apk_wrapper_script.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001737 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361738 'build/android/gyp/dex.pydeps',
1739 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361740 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:211741 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361742 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361743 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361744 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581745 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361746 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141747 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261748 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:471749 'build/android/gyp/java_google_api_keys.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041750 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361751 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361752 'build/android/gyp/merge_manifest.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:101753 'build/android/gyp/optimize_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361754 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221755 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361756 'build/android/gyp/proguard.pydeps',
Andrew Grievee3a775ab2022-05-16 15:59:221757 'build/android/gyp/system_image_apks.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:101758 'build/android/gyp/trace_event_bytecode_rewriter.pydeps',
Peter Wen578730b2020-03-19 19:55:461759 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:301760 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241761 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361762 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461763 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561764 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361765 'build/android/incremental_install/generate_android_manifest.pydeps',
1766 'build/android/incremental_install/write_installer_json.pydeps',
Stephanie Kim392913b452022-06-15 17:25:321767 'build/android/pylib/results/presentation/test_results_presentation.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041768 'build/android/resource_sizes.pydeps',
1769 'build/android/test_runner.pydeps',
1770 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361771 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361772 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321773 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271774 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1775 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:041776 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001777 'components/cronet/tools/generate_javadoc.pydeps',
1778 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381779 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001780 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381781 'net/tools/testserver/testserver.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181782 'testing/scripts/run_isolated_script_test.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411783 'testing/merge_scripts/standard_isolated_script_merge.pydeps',
1784 'testing/merge_scripts/standard_gtest_merge.pydeps',
1785 'testing/merge_scripts/code_coverage/merge_results.pydeps',
1786 'testing/merge_scripts/code_coverage/merge_steps.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041787 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421788 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
Yuki Shiino38eeaad12022-08-11 06:40:251789 'third_party/blink/renderer/bindings/scripts/check_generated_file_list.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421790 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131791 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:501792 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411793 'third_party/blink/tools/blinkpy/web_tests/merge_results.pydeps',
1794 'third_party/blink/tools/merge_web_test_results.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061795 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221796 'tools/binary_size/supersize.pydeps',
Ben Pastene028104a2022-08-10 19:17:451797 'tools/perf/process_perf_results.pydeps',
agrievef32bcc72016-04-04 14:57:401798]
1799
wnwenbdc444e2016-05-25 13:44:151800
agrievef32bcc72016-04-04 14:57:401801_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1802
1803
Eric Boren6fd2b932018-01-25 15:05:081804# Bypass the AUTHORS check for these accounts.
1805_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591806 ) | set('%s@appspot.gserviceaccount.com' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451807 ) | set('%s@developer.gserviceaccount.com' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591808 ) | set('%s@chops-service-accounts.iam.gserviceaccount.com' % s
smutde797052019-12-04 02:03:521809 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:231810 'wpt-autoroller', 'chrome-weblayer-builder',
Garrett Beaty4d4fcf62021-11-24 17:57:471811 'lacros-version-skew-roller', 'skylab-test-cros-roller',
Sven Zheng722960ba2022-07-18 16:40:461812 'infra-try-recipes-tester', 'lacros-tracking-roller',
Brian Sheedy1c951e62022-10-27 01:16:181813 'lacros-sdk-version-roller', 'chrome-automated-expectation',
Stephanie Kimb49bdd242023-04-28 16:46:041814 'chromium-automated-expectation', 'chrome-branch-day',
1815 'chromium-autosharder')
Eric Boren835d71f2018-09-07 21:09:041816 ) | set('%s@skia-public.iam.gserviceaccount.com' % s
Eric Boren66150e52020-01-08 11:20:271817 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041818 ) | set('%s@skia-corp.google.com.iam.gserviceaccount.com' % s
Yulan Lineb0cfba2021-04-09 18:43:161819 for s in ('chromium-internal-autoroll',)
1820 ) | set('%s@owners-cleanup-prod.google.com.iam.gserviceaccount.com' % s
Chong Gub277e342022-10-15 03:30:551821 for s in ('swarming-tasks',)
1822 ) | set('%s@fuchsia-infra.iam.gserviceaccount.com' % s
1823 for s in ('global-integration-try-builder',
1824 'global-integration-ci-builder'))
Eric Boren6fd2b932018-01-25 15:05:081825
Matt Stark6ef08872021-07-29 01:21:461826_INVALID_GRD_FILE_LINE = [
1827 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
1828]
Eric Boren6fd2b932018-01-25 15:05:081829
Daniel Bratell65b033262019-04-23 08:17:061830def _IsCPlusPlusFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501831 """Returns True if this file contains C++-like code (and not Python,
1832 Go, Java, MarkDown, ...)"""
Daniel Bratell65b033262019-04-23 08:17:061833
Sam Maiera6e76d72022-02-11 21:43:501834 ext = input_api.os_path.splitext(file_path)[1]
1835 # This list is compatible with CppChecker.IsCppFile but we should
1836 # consider adding ".c" to it. If we do that we can use this function
1837 # at more places in the code.
1838 return ext in (
1839 '.h',
1840 '.cc',
1841 '.cpp',
1842 '.m',
1843 '.mm',
1844 )
1845
Daniel Bratell65b033262019-04-23 08:17:061846
1847def _IsCPlusPlusHeaderFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501848 return input_api.os_path.splitext(file_path)[1] == ".h"
Daniel Bratell65b033262019-04-23 08:17:061849
1850
1851def _IsJavaFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501852 return input_api.os_path.splitext(file_path)[1] == ".java"
Daniel Bratell65b033262019-04-23 08:17:061853
1854
1855def _IsProtoFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501856 return input_api.os_path.splitext(file_path)[1] == ".proto"
Daniel Bratell65b033262019-04-23 08:17:061857
Mohamed Heikal5e5b7922020-10-29 18:57:591858
Erik Staabc734cd7a2021-11-23 03:11:521859def _IsXmlOrGrdFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501860 ext = input_api.os_path.splitext(file_path)[1]
1861 return ext in ('.grd', '.xml')
Erik Staabc734cd7a2021-11-23 03:11:521862
1863
Sven Zheng76a79ea2022-12-21 21:25:241864def _IsMojomFile(input_api, file_path):
1865 return input_api.os_path.splitext(file_path)[1] == ".mojom"
1866
1867
Mohamed Heikal5e5b7922020-10-29 18:57:591868def CheckNoUpstreamDepsOnClank(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501869 """Prevent additions of dependencies from the upstream repo on //clank."""
1870 # clank can depend on clank
1871 if input_api.change.RepositoryRoot().endswith('clank'):
1872 return []
1873 build_file_patterns = [
1874 r'(.+/)?BUILD\.gn',
1875 r'.+\.gni',
1876 ]
1877 excluded_files = [r'build[/\\]config[/\\]android[/\\]config\.gni']
1878 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
Mohamed Heikal5e5b7922020-10-29 18:57:591879
Sam Maiera6e76d72022-02-11 21:43:501880 error_message = 'Disallowed import on //clank in an upstream build file:'
Mohamed Heikal5e5b7922020-10-29 18:57:591881
Sam Maiera6e76d72022-02-11 21:43:501882 def FilterFile(affected_file):
1883 return input_api.FilterSourceFile(affected_file,
1884 files_to_check=build_file_patterns,
1885 files_to_skip=excluded_files)
Mohamed Heikal5e5b7922020-10-29 18:57:591886
Sam Maiera6e76d72022-02-11 21:43:501887 problems = []
1888 for f in input_api.AffectedSourceFiles(FilterFile):
1889 local_path = f.LocalPath()
1890 for line_number, line in f.ChangedContents():
1891 if (bad_pattern.search(line)):
1892 problems.append('%s:%d\n %s' %
1893 (local_path, line_number, line.strip()))
1894 if problems:
1895 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1896 else:
1897 return []
Mohamed Heikal5e5b7922020-10-29 18:57:591898
1899
Saagar Sanghavifceeaae2020-08-12 16:40:361900def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501901 """Attempts to prevent use of functions intended only for testing in
1902 non-testing code. For now this is just a best-effort implementation
1903 that ignores header files and may have some false positives. A
1904 better implementation would probably need a proper C++ parser.
1905 """
1906 # We only scan .cc files and the like, as the declaration of
1907 # for-testing functions in header files are hard to distinguish from
1908 # calls to such functions without a proper C++ parser.
1909 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
joi@chromium.org55459852011-08-10 15:17:191910
Sam Maiera6e76d72022-02-11 21:43:501911 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
1912 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' %
1913 base_function_pattern)
1914 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
1915 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
1916 exclusion_pattern = input_api.re.compile(
1917 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' %
1918 (base_function_pattern, base_function_pattern))
1919 # Avoid a false positive in this case, where the method name, the ::, and
1920 # the closing { are all on different lines due to line wrapping.
1921 # HelperClassForTesting::
1922 # HelperClassForTesting(
1923 # args)
1924 # : member(0) {}
1925 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
joi@chromium.org55459852011-08-10 15:17:191926
Sam Maiera6e76d72022-02-11 21:43:501927 def FilterFile(affected_file):
1928 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1929 input_api.DEFAULT_FILES_TO_SKIP)
1930 return input_api.FilterSourceFile(
1931 affected_file,
1932 files_to_check=file_inclusion_pattern,
1933 files_to_skip=files_to_skip)
joi@chromium.org55459852011-08-10 15:17:191934
Sam Maiera6e76d72022-02-11 21:43:501935 problems = []
1936 for f in input_api.AffectedSourceFiles(FilterFile):
1937 local_path = f.LocalPath()
1938 in_method_defn = False
1939 for line_number, line in f.ChangedContents():
1940 if (inclusion_pattern.search(line)
1941 and not comment_pattern.search(line)
1942 and not exclusion_pattern.search(line)
1943 and not allowlist_pattern.search(line)
1944 and not in_method_defn):
1945 problems.append('%s:%d\n %s' %
1946 (local_path, line_number, line.strip()))
1947 in_method_defn = method_defn_pattern.search(line)
joi@chromium.org55459852011-08-10 15:17:191948
Sam Maiera6e76d72022-02-11 21:43:501949 if problems:
1950 return [
1951 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
1952 ]
1953 else:
1954 return []
joi@chromium.org55459852011-08-10 15:17:191955
1956
Saagar Sanghavifceeaae2020-08-12 16:40:361957def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501958 """This is a simplified version of
1959 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
1960 """
1961 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1962 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1963 name_pattern = r'ForTest(s|ing)?'
1964 # Describes an occurrence of "ForTest*" inside a // comment.
1965 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
1966 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
1967 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
1968 # Catch calls.
1969 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1970 # Ignore definitions. (Comments are ignored separately.)
1971 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
Vaclav Brozek7dbc28c2018-03-27 08:35:231972
Sam Maiera6e76d72022-02-11 21:43:501973 problems = []
1974 sources = lambda x: input_api.FilterSourceFile(
1975 x,
1976 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
1977 DEFAULT_FILES_TO_SKIP),
1978 files_to_check=[r'.*\.java$'])
1979 for f in input_api.AffectedFiles(include_deletes=False,
1980 file_filter=sources):
1981 local_path = f.LocalPath()
Vaclav Brozek7dbc28c2018-03-27 08:35:231982 is_inside_javadoc = False
Sam Maiera6e76d72022-02-11 21:43:501983 for line_number, line in f.ChangedContents():
1984 if is_inside_javadoc and javadoc_end_re.search(line):
1985 is_inside_javadoc = False
1986 if not is_inside_javadoc and javadoc_start_re.search(line):
1987 is_inside_javadoc = True
1988 if is_inside_javadoc:
1989 continue
1990 if (inclusion_re.search(line) and not comment_re.search(line)
1991 and not annotation_re.search(line)
1992 and not exclusion_re.search(line)):
1993 problems.append('%s:%d\n %s' %
1994 (local_path, line_number, line.strip()))
Vaclav Brozek7dbc28c2018-03-27 08:35:231995
Sam Maiera6e76d72022-02-11 21:43:501996 if problems:
1997 return [
1998 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
1999 ]
2000 else:
2001 return []
Vaclav Brozek7dbc28c2018-03-27 08:35:232002
2003
Saagar Sanghavifceeaae2020-08-12 16:40:362004def CheckNoIOStreamInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502005 """Checks to make sure no .h files include <iostream>."""
2006 files = []
2007 pattern = input_api.re.compile(r'^#include\s*<iostream>',
2008 input_api.re.MULTILINE)
2009 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2010 if not f.LocalPath().endswith('.h'):
2011 continue
2012 contents = input_api.ReadFile(f)
2013 if pattern.search(contents):
2014 files.append(f)
thakis@chromium.org10689ca2011-09-02 02:31:542015
Sam Maiera6e76d72022-02-11 21:43:502016 if len(files):
2017 return [
2018 output_api.PresubmitError(
2019 'Do not #include <iostream> in header files, since it inserts static '
2020 'initialization into every file including the header. Instead, '
2021 '#include <ostream>. See http://crbug.com/94794', files)
2022 ]
2023 return []
2024
thakis@chromium.org10689ca2011-09-02 02:31:542025
Aleksey Khoroshilov9b28c032022-06-03 16:35:322026def CheckNoStrCatRedefines(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502027 """Checks no windows headers with StrCat redefined are included directly."""
2028 files = []
Aleksey Khoroshilov9b28c032022-06-03 16:35:322029 files_to_check = (r'.+%s' % _HEADER_EXTENSIONS,
2030 r'.+%s' % _IMPLEMENTATION_EXTENSIONS)
2031 files_to_skip = (input_api.DEFAULT_FILES_TO_SKIP +
2032 _NON_BASE_DEPENDENT_PATHS)
2033 sources_filter = lambda f: input_api.FilterSourceFile(
2034 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
2035
Sam Maiera6e76d72022-02-11 21:43:502036 pattern_deny = input_api.re.compile(
2037 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
2038 input_api.re.MULTILINE)
2039 pattern_allow = input_api.re.compile(
2040 r'^#include\s"base/win/windows_defines.inc"', input_api.re.MULTILINE)
Aleksey Khoroshilov9b28c032022-06-03 16:35:322041 for f in input_api.AffectedSourceFiles(sources_filter):
Sam Maiera6e76d72022-02-11 21:43:502042 contents = input_api.ReadFile(f)
2043 if pattern_deny.search(
2044 contents) and not pattern_allow.search(contents):
2045 files.append(f.LocalPath())
Danil Chapovalov3518f362018-08-11 16:13:432046
Sam Maiera6e76d72022-02-11 21:43:502047 if len(files):
2048 return [
2049 output_api.PresubmitError(
2050 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
2051 'directly since they pollute code with StrCat macro. Instead, '
2052 'include matching header from base/win. See http://crbug.com/856536',
2053 files)
2054 ]
2055 return []
Danil Chapovalov3518f362018-08-11 16:13:432056
thakis@chromium.org10689ca2011-09-02 02:31:542057
Saagar Sanghavifceeaae2020-08-12 16:40:362058def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502059 """Checks to make sure no source files use UNIT_TEST."""
2060 problems = []
2061 for f in input_api.AffectedFiles():
2062 if (not f.LocalPath().endswith(('.cc', '.mm'))):
2063 continue
jam@chromium.org72df4e782012-06-21 16:28:182064
Sam Maiera6e76d72022-02-11 21:43:502065 for line_num, line in f.ChangedContents():
2066 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
2067 problems.append(' %s:%d' % (f.LocalPath(), line_num))
jam@chromium.org72df4e782012-06-21 16:28:182068
Sam Maiera6e76d72022-02-11 21:43:502069 if not problems:
2070 return []
2071 return [
2072 output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
2073 '\n'.join(problems))
2074 ]
2075
jam@chromium.org72df4e782012-06-21 16:28:182076
Saagar Sanghavifceeaae2020-08-12 16:40:362077def CheckNoDISABLETypoInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502078 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
Dominic Battre033531052018-09-24 15:45:342079
Sam Maiera6e76d72022-02-11 21:43:502080 This test warns if somebody tries to disable a test with the DISABLE_ prefix
2081 instead of DISABLED_. To filter false positives, reports are only generated
2082 if a corresponding MAYBE_ line exists.
2083 """
2084 problems = []
Dominic Battre033531052018-09-24 15:45:342085
Sam Maiera6e76d72022-02-11 21:43:502086 # The following two patterns are looked for in tandem - is a test labeled
2087 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
2088 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
2089 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
Dominic Battre033531052018-09-24 15:45:342090
Sam Maiera6e76d72022-02-11 21:43:502091 # This is for the case that a test is disabled on all platforms.
2092 full_disable_pattern = input_api.re.compile(
2093 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
2094 input_api.re.MULTILINE)
Dominic Battre033531052018-09-24 15:45:342095
Sam Maiera6e76d72022-02-11 21:43:502096 for f in input_api.AffectedFiles(False):
2097 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2098 continue
Dominic Battre033531052018-09-24 15:45:342099
Sam Maiera6e76d72022-02-11 21:43:502100 # Search for MABYE_, DISABLE_ pairs.
2101 disable_lines = {} # Maps of test name to line number.
2102 maybe_lines = {}
2103 for line_num, line in f.ChangedContents():
2104 disable_match = disable_pattern.search(line)
2105 if disable_match:
2106 disable_lines[disable_match.group(1)] = line_num
2107 maybe_match = maybe_pattern.search(line)
2108 if maybe_match:
2109 maybe_lines[maybe_match.group(1)] = line_num
Dominic Battre033531052018-09-24 15:45:342110
Sam Maiera6e76d72022-02-11 21:43:502111 # Search for DISABLE_ occurrences within a TEST() macro.
2112 disable_tests = set(disable_lines.keys())
2113 maybe_tests = set(maybe_lines.keys())
2114 for test in disable_tests.intersection(maybe_tests):
2115 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
Dominic Battre033531052018-09-24 15:45:342116
Sam Maiera6e76d72022-02-11 21:43:502117 contents = input_api.ReadFile(f)
2118 full_disable_match = full_disable_pattern.search(contents)
2119 if full_disable_match:
2120 problems.append(' %s' % f.LocalPath())
Dominic Battre033531052018-09-24 15:45:342121
Sam Maiera6e76d72022-02-11 21:43:502122 if not problems:
2123 return []
2124 return [
2125 output_api.PresubmitPromptWarning(
2126 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
2127 '\n'.join(problems))
2128 ]
2129
Dominic Battre033531052018-09-24 15:45:342130
Nina Satragnof7660532021-09-20 18:03:352131def CheckForgettingMAYBEInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502132 """Checks to make sure tests disabled conditionally are not missing a
2133 corresponding MAYBE_ prefix.
2134 """
2135 # Expect at least a lowercase character in the test name. This helps rule out
2136 # false positives with macros wrapping the actual tests name.
2137 define_maybe_pattern = input_api.re.compile(
2138 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
Bruce Dawsonffc55292022-04-20 04:18:192139 # The test_maybe_pattern needs to handle all of these forms. The standard:
2140 # IN_PROC_TEST_F(SyncTest, MAYBE_Start) {
2141 # With a wrapper macro around the test name:
2142 # IN_PROC_TEST_F(SyncTest, E2E_ENABLED(MAYBE_Start)) {
2143 # And the odd-ball NACL_BROWSER_TEST_f format:
2144 # NACL_BROWSER_TEST_F(NaClBrowserTest, SimpleLoad, {
2145 # The optional E2E_ENABLED-style is handled with (\w*\()?
2146 # The NACL_BROWSER_TEST_F pattern is handled by allowing a trailing comma or
2147 # trailing ')'.
2148 test_maybe_pattern = (
2149 r'^\s*\w*TEST[^(]*\(\s*\w+,\s*(\w*\()?MAYBE_{test_name}[\),]')
Sam Maiera6e76d72022-02-11 21:43:502150 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
2151 warnings = []
Nina Satragnof7660532021-09-20 18:03:352152
Sam Maiera6e76d72022-02-11 21:43:502153 # Read the entire files. We can't just read the affected lines, forgetting to
2154 # add MAYBE_ on a change would not show up otherwise.
2155 for f in input_api.AffectedFiles(False):
2156 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2157 continue
2158 contents = input_api.ReadFile(f)
2159 lines = contents.splitlines(True)
2160 current_position = 0
2161 warning_test_names = set()
2162 for line_num, line in enumerate(lines, start=1):
2163 current_position += len(line)
2164 maybe_match = define_maybe_pattern.search(line)
2165 if maybe_match:
2166 test_name = maybe_match.group('test_name')
2167 # Do not warn twice for the same test.
2168 if (test_name in warning_test_names):
2169 continue
2170 warning_test_names.add(test_name)
Nina Satragnof7660532021-09-20 18:03:352171
Sam Maiera6e76d72022-02-11 21:43:502172 # Attempt to find the corresponding MAYBE_ test or suite, starting from
2173 # the current position.
2174 test_match = input_api.re.compile(
2175 test_maybe_pattern.format(test_name=test_name),
2176 input_api.re.MULTILINE).search(contents, current_position)
2177 suite_match = input_api.re.compile(
2178 suite_maybe_pattern.format(test_name=test_name),
2179 input_api.re.MULTILINE).search(contents, current_position)
2180 if not test_match and not suite_match:
2181 warnings.append(
2182 output_api.PresubmitPromptWarning(
2183 '%s:%d found MAYBE_ defined without corresponding test %s'
2184 % (f.LocalPath(), line_num, test_name)))
2185 return warnings
2186
jam@chromium.org72df4e782012-06-21 16:28:182187
Saagar Sanghavifceeaae2020-08-12 16:40:362188def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502189 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
2190 errors = []
Kalvin Lee4a3b79de2022-05-26 16:00:162191 pattern = input_api.re.compile(r'\bDCHECK_IS_ON\b(?!\(\))',
Sam Maiera6e76d72022-02-11 21:43:502192 input_api.re.MULTILINE)
2193 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2194 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
2195 continue
2196 for lnum, line in f.ChangedContents():
2197 if input_api.re.search(pattern, line):
2198 errors.append(
2199 output_api.PresubmitError((
2200 '%s:%d: Use of DCHECK_IS_ON() must be written as "#if '
2201 + 'DCHECK_IS_ON()", not forgetting the parentheses.') %
2202 (f.LocalPath(), lnum)))
2203 return errors
danakj61c1aa22015-10-26 19:55:522204
2205
Weilun Shia487fad2020-10-28 00:10:342206# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
2207# more reliable way. See
2208# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:192209
wnwenbdc444e2016-05-25 13:44:152210
Saagar Sanghavifceeaae2020-08-12 16:40:362211def CheckFlakyTestUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502212 """Check that FlakyTest annotation is our own instead of the android one"""
2213 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
2214 files = []
2215 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2216 if f.LocalPath().endswith('Test.java'):
2217 if pattern.search(input_api.ReadFile(f)):
2218 files.append(f)
2219 if len(files):
2220 return [
2221 output_api.PresubmitError(
2222 'Use org.chromium.base.test.util.FlakyTest instead of '
2223 'android.test.FlakyTest', files)
2224 ]
2225 return []
mcasasb7440c282015-02-04 14:52:192226
wnwenbdc444e2016-05-25 13:44:152227
Saagar Sanghavifceeaae2020-08-12 16:40:362228def CheckNoDEPSGIT(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502229 """Make sure .DEPS.git is never modified manually."""
2230 if any(f.LocalPath().endswith('.DEPS.git')
2231 for f in input_api.AffectedFiles()):
2232 return [
2233 output_api.PresubmitError(
2234 'Never commit changes to .DEPS.git. This file is maintained by an\n'
2235 'automated system based on what\'s in DEPS and your changes will be\n'
2236 'overwritten.\n'
2237 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
2238 'get-the-code#Rolling_DEPS\n'
2239 'for more information')
2240 ]
2241 return []
maruel@chromium.org2a8ac9c2011-10-19 17:20:442242
2243
Sven Zheng76a79ea2022-12-21 21:25:242244def CheckCrosApiNeedBrowserTest(input_api, output_api):
2245 """Check new crosapi should add browser test."""
2246 has_new_crosapi = False
2247 has_browser_test = False
2248 for f in input_api.AffectedFiles():
2249 path = f.LocalPath()
2250 if (path.startswith('chromeos/crosapi/mojom') and
2251 _IsMojomFile(input_api, path) and f.Action() == 'A'):
2252 has_new_crosapi = True
2253 if path.endswith('browsertest.cc') or path.endswith('browser_test.cc'):
2254 has_browser_test = True
2255 if has_new_crosapi and not has_browser_test:
2256 return [
2257 output_api.PresubmitPromptWarning(
2258 'You are adding a new crosapi, but there is no file ends with '
2259 'browsertest.cc file being added or modified. It is important '
2260 'to add crosapi browser test coverage to avoid version '
2261 ' skew issues.\n'
2262 'Check //docs/lacros/test_instructions.md for more information.'
2263 )
2264 ]
2265 return []
2266
2267
Saagar Sanghavifceeaae2020-08-12 16:40:362268def CheckValidHostsInDEPSOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502269 """Checks that DEPS file deps are from allowed_hosts."""
2270 # Run only if DEPS file has been modified to annoy fewer bystanders.
2271 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
2272 return []
2273 # Outsource work to gclient verify
2274 try:
2275 gclient_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
2276 'third_party', 'depot_tools',
2277 'gclient.py')
2278 input_api.subprocess.check_output(
Bruce Dawson8a43cf72022-05-13 17:10:322279 [input_api.python3_executable, gclient_path, 'verify'],
Sam Maiera6e76d72022-02-11 21:43:502280 stderr=input_api.subprocess.STDOUT)
2281 return []
2282 except input_api.subprocess.CalledProcessError as error:
2283 return [
2284 output_api.PresubmitError(
2285 'DEPS file must have only git dependencies.',
2286 long_text=error.output)
2287 ]
tandriief664692014-09-23 14:51:472288
2289
Mario Sanchez Prada2472cab2019-09-18 10:58:312290def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152291 ban_rule):
Allen Bauer84778682022-09-22 16:28:562292 """Helper method for checking for banned constructs.
Mario Sanchez Prada2472cab2019-09-18 10:58:312293
Sam Maiera6e76d72022-02-11 21:43:502294 Returns an string composed of the name of the file, the line number where the
2295 match has been found and the additional text passed as |message| in case the
2296 target type name matches the text inside the line passed as parameter.
2297 """
2298 result = []
Peng Huang9c5949a02020-06-11 19:20:542299
Daniel Chenga44a1bcd2022-03-15 20:00:152300 # Ignore comments about banned types.
2301 if input_api.re.search(r"^ *//", line):
Sam Maiera6e76d72022-02-11 21:43:502302 return result
Daniel Chenga44a1bcd2022-03-15 20:00:152303 # A // nocheck comment will bypass this error.
2304 if line.endswith(" nocheck"):
Sam Maiera6e76d72022-02-11 21:43:502305 return result
2306
2307 matched = False
Daniel Chenga44a1bcd2022-03-15 20:00:152308 if ban_rule.pattern[0:1] == '/':
2309 regex = ban_rule.pattern[1:]
Sam Maiera6e76d72022-02-11 21:43:502310 if input_api.re.search(regex, line):
2311 matched = True
Daniel Chenga44a1bcd2022-03-15 20:00:152312 elif ban_rule.pattern in line:
Sam Maiera6e76d72022-02-11 21:43:502313 matched = True
2314
2315 if matched:
2316 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
Daniel Chenga44a1bcd2022-03-15 20:00:152317 for line in ban_rule.explanation:
2318 result.append(' %s' % line)
Sam Maiera6e76d72022-02-11 21:43:502319
danakjd18e8892020-12-17 17:42:012320 return result
Mario Sanchez Prada2472cab2019-09-18 10:58:312321
2322
Saagar Sanghavifceeaae2020-08-12 16:40:362323def CheckNoBannedFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502324 """Make sure that banned functions are not used."""
2325 warnings = []
2326 errors = []
avi@chromium.org127f18ec2012-06-16 05:05:592327
Sam Maiera6e76d72022-02-11 21:43:502328 def IsExcludedFile(affected_file, excluded_paths):
Daniel Chenga44a1bcd2022-03-15 20:00:152329 if not excluded_paths:
2330 return False
2331
Sam Maiera6e76d72022-02-11 21:43:502332 local_path = affected_file.LocalPath()
Bruce Dawson40fece62022-09-16 19:58:312333 # Consistently use / as path separator to simplify the writing of regex
2334 # expressions.
2335 local_path = local_path.replace(input_api.os_path.sep, '/')
Sam Maiera6e76d72022-02-11 21:43:502336 for item in excluded_paths:
2337 if input_api.re.match(item, local_path):
2338 return True
2339 return False
wnwenbdc444e2016-05-25 13:44:152340
Sam Maiera6e76d72022-02-11 21:43:502341 def IsIosObjcFile(affected_file):
2342 local_path = affected_file.LocalPath()
2343 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m',
2344 '.h'):
2345 return False
2346 basename = input_api.os_path.basename(local_path)
2347 if 'ios' in basename.split('_'):
2348 return True
2349 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
2350 if sep and 'ios' in local_path.split(sep):
2351 return True
2352 return False
Sylvain Defresnea8b73d252018-02-28 15:45:542353
Daniel Chenga44a1bcd2022-03-15 20:00:152354 def CheckForMatch(affected_file, line_num: int, line: str,
2355 ban_rule: BanRule):
2356 if IsExcludedFile(affected_file, ban_rule.excluded_paths):
2357 return
2358
Sam Maiera6e76d72022-02-11 21:43:502359 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152360 ban_rule)
Sam Maiera6e76d72022-02-11 21:43:502361 if problems:
Daniel Chenga44a1bcd2022-03-15 20:00:152362 if ban_rule.treat_as_error is not None and ban_rule.treat_as_error:
Sam Maiera6e76d72022-02-11 21:43:502363 errors.extend(problems)
2364 else:
2365 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:152366
Sam Maiera6e76d72022-02-11 21:43:502367 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2368 for f in input_api.AffectedFiles(file_filter=file_filter):
2369 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152370 for ban_rule in _BANNED_JAVA_FUNCTIONS:
2371 CheckForMatch(f, line_num, line, ban_rule)
Eric Stevensona9a980972017-09-23 00:04:412372
Clement Yan9b330cb2022-11-17 05:25:292373 file_filter = lambda f: f.LocalPath().endswith(('.js', '.ts'))
2374 for f in input_api.AffectedFiles(file_filter=file_filter):
2375 for line_num, line in f.ChangedContents():
2376 for ban_rule in _BANNED_JAVASCRIPT_FUNCTIONS:
2377 CheckForMatch(f, line_num, line, ban_rule)
2378
Sam Maiera6e76d72022-02-11 21:43:502379 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
2380 for f in input_api.AffectedFiles(file_filter=file_filter):
2381 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152382 for ban_rule in _BANNED_OBJC_FUNCTIONS:
2383 CheckForMatch(f, line_num, line, ban_rule)
avi@chromium.org127f18ec2012-06-16 05:05:592384
Sam Maiera6e76d72022-02-11 21:43:502385 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
2386 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152387 for ban_rule in _BANNED_IOS_OBJC_FUNCTIONS:
2388 CheckForMatch(f, line_num, line, ban_rule)
Sylvain Defresnea8b73d252018-02-28 15:45:542389
Sam Maiera6e76d72022-02-11 21:43:502390 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
2391 for f in input_api.AffectedFiles(file_filter=egtest_filter):
2392 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152393 for ban_rule in _BANNED_IOS_EGTEST_FUNCTIONS:
2394 CheckForMatch(f, line_num, line, ban_rule)
Peter K. Lee6c03ccff2019-07-15 14:40:052395
Sam Maiera6e76d72022-02-11 21:43:502396 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
2397 for f in input_api.AffectedFiles(file_filter=file_filter):
2398 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152399 for ban_rule in _BANNED_CPP_FUNCTIONS:
2400 CheckForMatch(f, line_num, line, ban_rule)
avi@chromium.org127f18ec2012-06-16 05:05:592401
Daniel Cheng92c15e32022-03-16 17:48:222402 file_filter = lambda f: f.LocalPath().endswith(('.mojom'))
2403 for f in input_api.AffectedFiles(file_filter=file_filter):
2404 for line_num, line in f.ChangedContents():
2405 for ban_rule in _BANNED_MOJOM_PATTERNS:
2406 CheckForMatch(f, line_num, line, ban_rule)
2407
2408
Sam Maiera6e76d72022-02-11 21:43:502409 result = []
2410 if (warnings):
2411 result.append(
2412 output_api.PresubmitPromptWarning('Banned functions were used.\n' +
2413 '\n'.join(warnings)))
2414 if (errors):
2415 result.append(
2416 output_api.PresubmitError('Banned functions were used.\n' +
2417 '\n'.join(errors)))
2418 return result
avi@chromium.org127f18ec2012-06-16 05:05:592419
Allen Bauer84778682022-09-22 16:28:562420def CheckNoLayoutCallsInTests(input_api, output_api):
2421 """Make sure there are no explicit calls to View::Layout() in tests"""
2422 warnings = []
2423 ban_rule = BanRule(
2424 r'/(\.|->)Layout\(\);',
2425 (
2426 'Direct calls to View::Layout() are not allowed in tests. '
2427 'If the view must be laid out here, use RunScheduledLayout(view). It '
2428 'is found in //ui/views/test/views_test_utils.h. '
2429 'See http://crbug.com/1350521 for more details.',
2430 ),
2431 False,
2432 )
2433 file_filter = lambda f: input_api.re.search(
2434 r'_(unittest|browsertest|ui_test).*\.(cc|mm)$', f.LocalPath())
2435 for f in input_api.AffectedFiles(file_filter = file_filter):
2436 for line_num, line in f.ChangedContents():
2437 problems = _GetMessageForMatchingType(input_api, f,
2438 line_num, line,
2439 ban_rule)
2440 if problems:
2441 warnings.extend(problems)
2442 result = []
2443 if (warnings):
2444 result.append(
2445 output_api.PresubmitPromptWarning(
2446 'Banned call to View::Layout() in tests.\n\n'.join(warnings)))
2447 return result
avi@chromium.org127f18ec2012-06-16 05:05:592448
Michael Thiessen44457642020-02-06 00:24:152449def _CheckAndroidNoBannedImports(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502450 """Make sure that banned java imports are not used."""
2451 errors = []
Michael Thiessen44457642020-02-06 00:24:152452
Sam Maiera6e76d72022-02-11 21:43:502453 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2454 for f in input_api.AffectedFiles(file_filter=file_filter):
2455 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152456 for ban_rule in _BANNED_JAVA_IMPORTS:
2457 # Consider merging this into the above function. There is no
2458 # real difference anymore other than helping with a little
2459 # bit of boilerplate text. Doing so means things like
2460 # `treat_as_error` will also be uniformly handled.
Sam Maiera6e76d72022-02-11 21:43:502461 problems = _GetMessageForMatchingType(input_api, f, line_num,
Daniel Chenga44a1bcd2022-03-15 20:00:152462 line, ban_rule)
Sam Maiera6e76d72022-02-11 21:43:502463 if problems:
2464 errors.extend(problems)
2465 result = []
2466 if (errors):
2467 result.append(
2468 output_api.PresubmitError('Banned imports were used.\n' +
2469 '\n'.join(errors)))
2470 return result
Michael Thiessen44457642020-02-06 00:24:152471
2472
Saagar Sanghavifceeaae2020-08-12 16:40:362473def CheckNoPragmaOnce(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502474 """Make sure that banned functions are not used."""
2475 files = []
2476 pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
2477 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2478 if not f.LocalPath().endswith('.h'):
2479 continue
Bruce Dawson4c4c2922022-05-02 18:07:332480 if f.LocalPath().endswith('com_imported_mstscax.h'):
2481 continue
Sam Maiera6e76d72022-02-11 21:43:502482 contents = input_api.ReadFile(f)
2483 if pattern.search(contents):
2484 files.append(f)
dcheng@chromium.org6c063c62012-07-11 19:11:062485
Sam Maiera6e76d72022-02-11 21:43:502486 if files:
2487 return [
2488 output_api.PresubmitError(
2489 'Do not use #pragma once in header files.\n'
2490 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
2491 files)
2492 ]
2493 return []
dcheng@chromium.org6c063c62012-07-11 19:11:062494
avi@chromium.org127f18ec2012-06-16 05:05:592495
Saagar Sanghavifceeaae2020-08-12 16:40:362496def CheckNoTrinaryTrueFalse(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502497 """Checks to make sure we don't introduce use of foo ? true : false."""
2498 problems = []
2499 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
2500 for f in input_api.AffectedFiles():
2501 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2502 continue
thestig@chromium.orge7479052012-09-19 00:26:122503
Sam Maiera6e76d72022-02-11 21:43:502504 for line_num, line in f.ChangedContents():
2505 if pattern.match(line):
2506 problems.append(' %s:%d' % (f.LocalPath(), line_num))
thestig@chromium.orge7479052012-09-19 00:26:122507
Sam Maiera6e76d72022-02-11 21:43:502508 if not problems:
2509 return []
2510 return [
2511 output_api.PresubmitPromptWarning(
2512 'Please consider avoiding the "? true : false" pattern if possible.\n'
2513 + '\n'.join(problems))
2514 ]
thestig@chromium.orge7479052012-09-19 00:26:122515
2516
Saagar Sanghavifceeaae2020-08-12 16:40:362517def CheckUnwantedDependencies(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502518 """Runs checkdeps on #include and import statements added in this
2519 change. Breaking - rules is an error, breaking ! rules is a
2520 warning.
2521 """
2522 # Return early if no relevant file types were modified.
2523 for f in input_api.AffectedFiles():
2524 path = f.LocalPath()
2525 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path)
2526 or _IsJavaFile(input_api, path)):
2527 break
joi@chromium.org55f9f382012-07-31 11:02:182528 else:
Sam Maiera6e76d72022-02-11 21:43:502529 return []
rhalavati08acd232017-04-03 07:23:282530
Sam Maiera6e76d72022-02-11 21:43:502531 import sys
2532 # We need to wait until we have an input_api object and use this
2533 # roundabout construct to import checkdeps because this file is
2534 # eval-ed and thus doesn't have __file__.
2535 original_sys_path = sys.path
2536 try:
2537 sys.path = sys.path + [
2538 input_api.os_path.join(input_api.PresubmitLocalPath(),
2539 'buildtools', 'checkdeps')
2540 ]
2541 import checkdeps
2542 from rules import Rule
2543 finally:
2544 # Restore sys.path to what it was before.
2545 sys.path = original_sys_path
joi@chromium.org55f9f382012-07-31 11:02:182546
Sam Maiera6e76d72022-02-11 21:43:502547 added_includes = []
2548 added_imports = []
2549 added_java_imports = []
2550 for f in input_api.AffectedFiles():
2551 if _IsCPlusPlusFile(input_api, f.LocalPath()):
2552 changed_lines = [line for _, line in f.ChangedContents()]
2553 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
2554 elif _IsProtoFile(input_api, f.LocalPath()):
2555 changed_lines = [line for _, line in f.ChangedContents()]
2556 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
2557 elif _IsJavaFile(input_api, f.LocalPath()):
2558 changed_lines = [line for _, line in f.ChangedContents()]
2559 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:242560
Sam Maiera6e76d72022-02-11 21:43:502561 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
2562
2563 error_descriptions = []
2564 warning_descriptions = []
2565 error_subjects = set()
2566 warning_subjects = set()
2567
2568 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2569 added_includes):
2570 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2571 description_with_path = '%s\n %s' % (path, rule_description)
2572 if rule_type == Rule.DISALLOW:
2573 error_descriptions.append(description_with_path)
2574 error_subjects.add("#includes")
2575 else:
2576 warning_descriptions.append(description_with_path)
2577 warning_subjects.add("#includes")
2578
2579 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2580 added_imports):
2581 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2582 description_with_path = '%s\n %s' % (path, rule_description)
2583 if rule_type == Rule.DISALLOW:
2584 error_descriptions.append(description_with_path)
2585 error_subjects.add("imports")
2586 else:
2587 warning_descriptions.append(description_with_path)
2588 warning_subjects.add("imports")
2589
2590 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
2591 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
2592 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2593 description_with_path = '%s\n %s' % (path, rule_description)
2594 if rule_type == Rule.DISALLOW:
2595 error_descriptions.append(description_with_path)
2596 error_subjects.add("imports")
2597 else:
2598 warning_descriptions.append(description_with_path)
2599 warning_subjects.add("imports")
2600
2601 results = []
2602 if error_descriptions:
2603 results.append(
2604 output_api.PresubmitError(
2605 'You added one or more %s that violate checkdeps rules.' %
2606 " and ".join(error_subjects), error_descriptions))
2607 if warning_descriptions:
2608 results.append(
2609 output_api.PresubmitPromptOrNotify(
2610 'You added one or more %s of files that are temporarily\n'
2611 'allowed but being removed. Can you avoid introducing the\n'
2612 '%s? See relevant DEPS file(s) for details and contacts.' %
2613 (" and ".join(warning_subjects), "/".join(warning_subjects)),
2614 warning_descriptions))
2615 return results
joi@chromium.org55f9f382012-07-31 11:02:182616
2617
Saagar Sanghavifceeaae2020-08-12 16:40:362618def CheckFilePermissions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502619 """Check that all files have their permissions properly set."""
2620 if input_api.platform == 'win32':
2621 return []
2622 checkperms_tool = input_api.os_path.join(input_api.PresubmitLocalPath(),
2623 'tools', 'checkperms',
2624 'checkperms.py')
2625 args = [
Bruce Dawson8a43cf72022-05-13 17:10:322626 input_api.python3_executable, checkperms_tool, '--root',
Sam Maiera6e76d72022-02-11 21:43:502627 input_api.change.RepositoryRoot()
2628 ]
2629 with input_api.CreateTemporaryFile() as file_list:
2630 for f in input_api.AffectedFiles():
2631 # checkperms.py file/directory arguments must be relative to the
2632 # repository.
2633 file_list.write((f.LocalPath() + '\n').encode('utf8'))
2634 file_list.close()
2635 args += ['--file-list', file_list.name]
2636 try:
2637 input_api.subprocess.check_output(args)
2638 return []
2639 except input_api.subprocess.CalledProcessError as error:
2640 return [
2641 output_api.PresubmitError('checkperms.py failed:',
2642 long_text=error.output.decode(
2643 'utf-8', 'ignore'))
2644 ]
csharp@chromium.orgfbcafe5a2012-08-08 15:31:222645
2646
Saagar Sanghavifceeaae2020-08-12 16:40:362647def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502648 """Makes sure we don't include ui/aura/window_property.h
2649 in header files.
2650 """
2651 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2652 errors = []
2653 for f in input_api.AffectedFiles():
2654 if not f.LocalPath().endswith('.h'):
2655 continue
2656 for line_num, line in f.ChangedContents():
2657 if pattern.match(line):
2658 errors.append(' %s:%d' % (f.LocalPath(), line_num))
oshima@chromium.orgc8278b32012-10-30 20:35:492659
Sam Maiera6e76d72022-02-11 21:43:502660 results = []
2661 if errors:
2662 results.append(
2663 output_api.PresubmitError(
2664 'Header files should not include ui/aura/window_property.h',
2665 errors))
2666 return results
oshima@chromium.orgc8278b32012-10-30 20:35:492667
2668
Omer Katzcc77ea92021-04-26 10:23:282669def CheckNoInternalHeapIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502670 """Makes sure we don't include any headers from
2671 third_party/blink/renderer/platform/heap/impl or
2672 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
2673 third_party/blink/renderer/platform/heap
2674 """
2675 impl_pattern = input_api.re.compile(
2676 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
2677 v8_wrapper_pattern = input_api.re.compile(
2678 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"'
2679 )
Bruce Dawson40fece62022-09-16 19:58:312680 # Consistently use / as path separator to simplify the writing of regex
2681 # expressions.
Sam Maiera6e76d72022-02-11 21:43:502682 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:312683 r"^third_party/blink/renderer/platform/heap/.*",
2684 f.LocalPath().replace(input_api.os_path.sep, '/'))
Sam Maiera6e76d72022-02-11 21:43:502685 errors = []
Omer Katzcc77ea92021-04-26 10:23:282686
Sam Maiera6e76d72022-02-11 21:43:502687 for f in input_api.AffectedFiles(file_filter=file_filter):
2688 for line_num, line in f.ChangedContents():
2689 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
2690 errors.append(' %s:%d' % (f.LocalPath(), line_num))
Omer Katzcc77ea92021-04-26 10:23:282691
Sam Maiera6e76d72022-02-11 21:43:502692 results = []
2693 if errors:
2694 results.append(
2695 output_api.PresubmitError(
2696 'Do not include files from third_party/blink/renderer/platform/heap/impl'
2697 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
2698 'relevant counterparts from third_party/blink/renderer/platform/heap',
2699 errors))
2700 return results
Omer Katzcc77ea92021-04-26 10:23:282701
2702
dbeam@chromium.org70ca77752012-11-20 03:45:032703def _CheckForVersionControlConflictsInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:502704 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2705 errors = []
2706 for line_num, line in f.ChangedContents():
2707 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
2708 # First-level headers in markdown look a lot like version control
2709 # conflict markers. http://daringfireball.net/projects/markdown/basics
2710 continue
2711 if pattern.match(line):
2712 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2713 return errors
dbeam@chromium.org70ca77752012-11-20 03:45:032714
2715
Saagar Sanghavifceeaae2020-08-12 16:40:362716def CheckForVersionControlConflicts(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502717 """Usually this is not intentional and will cause a compile failure."""
2718 errors = []
2719 for f in input_api.AffectedFiles():
2720 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
dbeam@chromium.org70ca77752012-11-20 03:45:032721
Sam Maiera6e76d72022-02-11 21:43:502722 results = []
2723 if errors:
2724 results.append(
2725 output_api.PresubmitError(
2726 'Version control conflict markers found, please resolve.',
2727 errors))
2728 return results
dbeam@chromium.org70ca77752012-11-20 03:45:032729
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202730
Saagar Sanghavifceeaae2020-08-12 16:40:362731def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502732 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2733 errors = []
2734 for f in input_api.AffectedFiles():
2735 for line_num, line in f.ChangedContents():
2736 if pattern.search(line):
2737 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
estadee17314a02017-01-12 16:22:162738
Sam Maiera6e76d72022-02-11 21:43:502739 results = []
2740 if errors:
2741 results.append(
2742 output_api.PresubmitPromptWarning(
2743 'Found Google support URL addressed by answer number. Please replace '
2744 'with a p= identifier instead. See crbug.com/679462\n',
2745 errors))
2746 return results
estadee17314a02017-01-12 16:22:162747
dbeam@chromium.org70ca77752012-11-20 03:45:032748
Saagar Sanghavifceeaae2020-08-12 16:40:362749def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502750 def FilterFile(affected_file):
2751 """Filter function for use with input_api.AffectedSourceFiles,
2752 below. This filters out everything except non-test files from
2753 top-level directories that generally speaking should not hard-code
2754 service URLs (e.g. src/android_webview/, src/content/ and others).
2755 """
2756 return input_api.FilterSourceFile(
2757 affected_file,
Bruce Dawson40fece62022-09-16 19:58:312758 files_to_check=[r'^(android_webview|base|content|net)/.*'],
Sam Maiera6e76d72022-02-11 21:43:502759 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2760 input_api.DEFAULT_FILES_TO_SKIP))
joi@chromium.org06e6d0ff2012-12-11 01:36:442761
Sam Maiera6e76d72022-02-11 21:43:502762 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2763 '\.(com|net)[^"]*"')
2764 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2765 pattern = input_api.re.compile(base_pattern)
2766 problems = [] # items are (filename, line_number, line)
2767 for f in input_api.AffectedSourceFiles(FilterFile):
2768 for line_num, line in f.ChangedContents():
2769 if not comment_pattern.search(line) and pattern.search(line):
2770 problems.append((f.LocalPath(), line_num, line))
joi@chromium.org06e6d0ff2012-12-11 01:36:442771
Sam Maiera6e76d72022-02-11 21:43:502772 if problems:
2773 return [
2774 output_api.PresubmitPromptOrNotify(
2775 'Most layers below src/chrome/ should not hardcode service URLs.\n'
2776 'Are you sure this is correct?', [
2777 ' %s:%d: %s' % (problem[0], problem[1], problem[2])
2778 for problem in problems
2779 ])
2780 ]
2781 else:
2782 return []
joi@chromium.org06e6d0ff2012-12-11 01:36:442783
2784
Saagar Sanghavifceeaae2020-08-12 16:40:362785def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502786 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
James Cook6b6597c2019-11-06 22:05:292787
Sam Maiera6e76d72022-02-11 21:43:502788 def FileFilter(affected_file):
2789 """Includes directories known to be Chrome OS only."""
2790 return input_api.FilterSourceFile(
2791 affected_file,
2792 files_to_check=(
2793 '^ash/',
2794 '^chromeos/', # Top-level src/chromeos.
2795 '.*/chromeos/', # Any path component.
2796 '^components/arc',
2797 '^components/exo'),
2798 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292799
Sam Maiera6e76d72022-02-11 21:43:502800 prefs = []
2801 priority_prefs = []
2802 for f in input_api.AffectedFiles(file_filter=FileFilter):
2803 for line_num, line in f.ChangedContents():
2804 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF',
2805 line):
2806 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2807 prefs.append(' %s' % line)
2808 if input_api.re.search(
2809 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2810 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2811 priority_prefs.append(' %s' % line)
2812
2813 results = []
2814 if (prefs):
2815 results.append(
2816 output_api.PresubmitPromptWarning(
2817 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2818 'by browser sync settings. If these prefs should be controlled by OS '
2819 'sync settings use SYNCABLE_OS_PREF instead.\n' +
2820 '\n'.join(prefs)))
2821 if (priority_prefs):
2822 results.append(
2823 output_api.PresubmitPromptWarning(
2824 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2825 'controlled by browser sync settings. If these prefs should be '
2826 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2827 'instead.\n' + '\n'.join(prefs)))
2828 return results
James Cook6b6597c2019-11-06 22:05:292829
2830
Saagar Sanghavifceeaae2020-08-12 16:40:362831def CheckNoAbbreviationInPngFileName(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502832 """Makes sure there are no abbreviations in the name of PNG files.
2833 The native_client_sdk directory is excluded because it has auto-generated PNG
2834 files for documentation.
2835 """
2836 errors = []
Yuanqing Zhu9eef02832022-12-04 14:42:172837 files_to_check = [r'.*\.png$']
Bruce Dawson40fece62022-09-16 19:58:312838 files_to_skip = [r'^native_client_sdk/',
2839 r'^services/test/',
2840 r'^third_party/blink/web_tests/',
Bruce Dawson3db456212022-05-02 05:34:182841 ]
Sam Maiera6e76d72022-02-11 21:43:502842 file_filter = lambda f: input_api.FilterSourceFile(
2843 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Yuanqing Zhu9eef02832022-12-04 14:42:172844 abbreviation = input_api.re.compile('.+_[a-z]\.png|.+_[a-z]_.*\.png')
Sam Maiera6e76d72022-02-11 21:43:502845 for f in input_api.AffectedFiles(include_deletes=False,
2846 file_filter=file_filter):
Yuanqing Zhu9eef02832022-12-04 14:42:172847 file_name = input_api.os_path.split(f.LocalPath())[1]
2848 if abbreviation.search(file_name):
2849 errors.append(' %s' % f.LocalPath())
oshima@chromium.orgd2530012013-01-25 16:39:272850
Sam Maiera6e76d72022-02-11 21:43:502851 results = []
2852 if errors:
2853 results.append(
2854 output_api.PresubmitError(
2855 'The name of PNG files should not have abbreviations. \n'
2856 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2857 'Contact oshima@chromium.org if you have questions.', errors))
2858 return results
oshima@chromium.orgd2530012013-01-25 16:39:272859
Evan Stade7cd4a2c2022-08-04 23:37:252860def CheckNoProductIconsAddedToPublicRepo(input_api, output_api):
2861 """Heuristically identifies product icons based on their file name and reminds
2862 contributors not to add them to the Chromium repository.
2863 """
2864 errors = []
2865 files_to_check = [r'.*google.*\.png$|.*google.*\.svg$|.*google.*\.icon$']
2866 file_filter = lambda f: input_api.FilterSourceFile(
2867 f, files_to_check=files_to_check)
2868 for f in input_api.AffectedFiles(include_deletes=False,
2869 file_filter=file_filter):
2870 errors.append(' %s' % f.LocalPath())
2871
2872 results = []
2873 if errors:
Bruce Dawson3bcf0c92022-08-12 00:03:082874 # Give warnings instead of errors on presubmit --all and presubmit
2875 # --files.
2876 message_type = (output_api.PresubmitNotifyResult if input_api.no_diffs
2877 else output_api.PresubmitError)
Evan Stade7cd4a2c2022-08-04 23:37:252878 results.append(
Bruce Dawson3bcf0c92022-08-12 00:03:082879 message_type(
Evan Stade7cd4a2c2022-08-04 23:37:252880 'Trademarked images should not be added to the public repo. '
2881 'See crbug.com/944754', errors))
2882 return results
2883
oshima@chromium.orgd2530012013-01-25 16:39:272884
Daniel Cheng4dcdb6b2017-04-13 08:30:172885def _ExtractAddRulesFromParsedDeps(parsed_deps):
Sam Maiera6e76d72022-02-11 21:43:502886 """Extract the rules that add dependencies from a parsed DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172887
Sam Maiera6e76d72022-02-11 21:43:502888 Args:
2889 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2890 add_rules = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172891 add_rules.update([
Sam Maiera6e76d72022-02-11 21:43:502892 rule[1:] for rule in parsed_deps.get('include_rules', [])
Daniel Cheng4dcdb6b2017-04-13 08:30:172893 if rule.startswith('+') or rule.startswith('!')
2894 ])
Sam Maiera6e76d72022-02-11 21:43:502895 for _, rules in parsed_deps.get('specific_include_rules', {}).items():
2896 add_rules.update([
2897 rule[1:] for rule in rules
2898 if rule.startswith('+') or rule.startswith('!')
2899 ])
2900 return add_rules
Daniel Cheng4dcdb6b2017-04-13 08:30:172901
2902
2903def _ParseDeps(contents):
Sam Maiera6e76d72022-02-11 21:43:502904 """Simple helper for parsing DEPS files."""
Daniel Cheng4dcdb6b2017-04-13 08:30:172905
Sam Maiera6e76d72022-02-11 21:43:502906 # Stubs for handling special syntax in the root DEPS file.
2907 class _VarImpl:
2908 def __init__(self, local_scope):
2909 self._local_scope = local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172910
Sam Maiera6e76d72022-02-11 21:43:502911 def Lookup(self, var_name):
2912 """Implements the Var syntax."""
2913 try:
2914 return self._local_scope['vars'][var_name]
2915 except KeyError:
2916 raise Exception('Var is not defined: %s' % var_name)
Daniel Cheng4dcdb6b2017-04-13 08:30:172917
Sam Maiera6e76d72022-02-11 21:43:502918 local_scope = {}
2919 global_scope = {
2920 'Var': _VarImpl(local_scope).Lookup,
2921 'Str': str,
2922 }
Dirk Pranke1b9e06382021-05-14 01:16:222923
Sam Maiera6e76d72022-02-11 21:43:502924 exec(contents, global_scope, local_scope)
2925 return local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172926
2927
2928def _CalculateAddedDeps(os_path, old_contents, new_contents):
Sam Maiera6e76d72022-02-11 21:43:502929 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
2930 a set of DEPS entries that we should look up.
joi@chromium.org14a6131c2014-01-08 01:15:412931
Sam Maiera6e76d72022-02-11 21:43:502932 For a directory (rather than a specific filename) we fake a path to
2933 a specific filename by adding /DEPS. This is chosen as a file that
2934 will seldom or never be subject to per-file include_rules.
2935 """
2936 # We ignore deps entries on auto-generated directories.
2937 AUTO_GENERATED_DIRS = ['grit', 'jni']
tony@chromium.orgf32e2d1e2013-07-26 21:39:082938
Sam Maiera6e76d72022-02-11 21:43:502939 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2940 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
Daniel Cheng4dcdb6b2017-04-13 08:30:172941
Sam Maiera6e76d72022-02-11 21:43:502942 added_deps = new_deps.difference(old_deps)
Daniel Cheng4dcdb6b2017-04-13 08:30:172943
Sam Maiera6e76d72022-02-11 21:43:502944 results = set()
2945 for added_dep in added_deps:
2946 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2947 continue
2948 # Assume that a rule that ends in .h is a rule for a specific file.
2949 if added_dep.endswith('.h'):
2950 results.add(added_dep)
2951 else:
2952 results.add(os_path.join(added_dep, 'DEPS'))
2953 return results
tony@chromium.orgf32e2d1e2013-07-26 21:39:082954
2955
Saagar Sanghavifceeaae2020-08-12 16:40:362956def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502957 """When a dependency prefixed with + is added to a DEPS file, we
2958 want to make sure that the change is reviewed by an OWNER of the
2959 target file or directory, to avoid layering violations from being
2960 introduced. This check verifies that this happens.
2961 """
2962 # We rely on Gerrit's code-owners to check approvals.
2963 # input_api.gerrit is always set for Chromium, but other projects
2964 # might not use Gerrit.
Bruce Dawson344ab262022-06-04 11:35:102965 if not input_api.gerrit or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:502966 return []
Bruce Dawsonb357aeb2022-08-09 15:38:302967 if 'PRESUBMIT_SKIP_NETWORK' in input_api.environ:
Sam Maiera6e76d72022-02-11 21:43:502968 return []
Bruce Dawsonb357aeb2022-08-09 15:38:302969 try:
2970 if (input_api.change.issue and
2971 input_api.gerrit.IsOwnersOverrideApproved(
2972 input_api.change.issue)):
2973 # Skip OWNERS check when Owners-Override label is approved. This is
2974 # intended for global owners, trusted bots, and on-call sheriffs.
2975 # Review is still required for these changes.
2976 return []
2977 except Exception as e:
Sam Maier4cef9242022-10-03 14:21:242978 return [output_api.PresubmitPromptWarning(
2979 'Failed to retrieve owner override status - %s' % str(e))]
Edward Lesmes6fba51082021-01-20 04:20:232980
Sam Maiera6e76d72022-02-11 21:43:502981 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242982
Bruce Dawson40fece62022-09-16 19:58:312983 # Consistently use / as path separator to simplify the writing of regex
2984 # expressions.
Sam Maiera6e76d72022-02-11 21:43:502985 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:312986 r"^third_party/blink/.*",
2987 f.LocalPath().replace(input_api.os_path.sep, '/'))
Sam Maiera6e76d72022-02-11 21:43:502988 for f in input_api.AffectedFiles(include_deletes=False,
2989 file_filter=file_filter):
2990 filename = input_api.os_path.basename(f.LocalPath())
2991 if filename == 'DEPS':
2992 virtual_depended_on_files.update(
2993 _CalculateAddedDeps(input_api.os_path,
2994 '\n'.join(f.OldContents()),
2995 '\n'.join(f.NewContents())))
joi@chromium.orge871964c2013-05-13 14:14:552996
Sam Maiera6e76d72022-02-11 21:43:502997 if not virtual_depended_on_files:
2998 return []
joi@chromium.orge871964c2013-05-13 14:14:552999
Sam Maiera6e76d72022-02-11 21:43:503000 if input_api.is_committing:
3001 if input_api.tbr:
3002 return [
3003 output_api.PresubmitNotifyResult(
3004 '--tbr was specified, skipping OWNERS check for DEPS additions'
3005 )
3006 ]
Daniel Cheng3008dc12022-05-13 04:02:113007 # TODO(dcheng): Make this generate an error on dry runs if the reviewer
3008 # is not added, to prevent review serialization.
Sam Maiera6e76d72022-02-11 21:43:503009 if input_api.dry_run:
3010 return [
3011 output_api.PresubmitNotifyResult(
3012 'This is a dry run, skipping OWNERS check for DEPS additions'
3013 )
3014 ]
3015 if not input_api.change.issue:
3016 return [
3017 output_api.PresubmitError(
3018 "DEPS approval by OWNERS check failed: this change has "
3019 "no change number, so we can't check it for approvals.")
3020 ]
3021 output = output_api.PresubmitError
joi@chromium.org14a6131c2014-01-08 01:15:413022 else:
Sam Maiera6e76d72022-02-11 21:43:503023 output = output_api.PresubmitNotifyResult
joi@chromium.orge871964c2013-05-13 14:14:553024
Sam Maiera6e76d72022-02-11 21:43:503025 owner_email, reviewers = (
3026 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3027 input_api, None, approval_needed=input_api.is_committing))
joi@chromium.orge871964c2013-05-13 14:14:553028
Sam Maiera6e76d72022-02-11 21:43:503029 owner_email = owner_email or input_api.change.author_email
3030
3031 approval_status = input_api.owners_client.GetFilesApprovalStatus(
3032 virtual_depended_on_files, reviewers.union([owner_email]), [])
3033 missing_files = [
3034 f for f in virtual_depended_on_files
3035 if approval_status[f] != input_api.owners_client.APPROVED
3036 ]
3037
3038 # We strip the /DEPS part that was added by
3039 # _FilesToCheckForIncomingDeps to fake a path to a file in a
3040 # directory.
3041 def StripDeps(path):
3042 start_deps = path.rfind('/DEPS')
3043 if start_deps != -1:
3044 return path[:start_deps]
3045 else:
3046 return path
3047
3048 unapproved_dependencies = [
3049 "'+%s'," % StripDeps(path) for path in missing_files
3050 ]
3051
3052 if unapproved_dependencies:
3053 output_list = [
3054 output(
3055 'You need LGTM from owners of depends-on paths in DEPS that were '
3056 'modified in this CL:\n %s' %
3057 '\n '.join(sorted(unapproved_dependencies)))
3058 ]
3059 suggested_owners = input_api.owners_client.SuggestOwners(
3060 missing_files, exclude=[owner_email])
3061 output_list.append(
3062 output('Suggested missing target path OWNERS:\n %s' %
3063 '\n '.join(suggested_owners or [])))
3064 return output_list
3065
3066 return []
joi@chromium.orge871964c2013-05-13 14:14:553067
3068
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493069# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:363070def CheckSpamLogging(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503071 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3072 files_to_skip = (
3073 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3074 input_api.DEFAULT_FILES_TO_SKIP + (
Jaewon Jung2f323bb2022-12-07 23:55:013075 r"^base/fuchsia/scoped_fx_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313076 r"^base/logging\.h$",
3077 r"^base/logging\.cc$",
3078 r"^base/task/thread_pool/task_tracker\.cc$",
3079 r"^chrome/app/chrome_main_delegate\.cc$",
Yao Li359937b2023-02-15 23:43:033080 r"^chrome/browser/ash/arc/enterprise/cert_store/arc_cert_installer\.cc$",
3081 r"^chrome/browser/ash/policy/remote_commands/user_command_arc_job\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313082 r"^chrome/browser/chrome_browser_main\.cc$",
3083 r"^chrome/browser/ui/startup/startup_browser_creator\.cc$",
3084 r"^chrome/browser/browser_switcher/bho/.*",
3085 r"^chrome/browser/diagnostics/diagnostics_writer\.cc$",
3086 r"^chrome/chrome_cleaner/.*",
3087 r"^chrome/chrome_elf/dll_hash/dll_hash_main\.cc$",
3088 r"^chrome/installer/setup/.*",
3089 r"^chromecast/",
Bruce Dawson40fece62022-09-16 19:58:313090 r"^components/media_control/renderer/media_playback_options\.cc$",
Salma Elmahallawy52976452023-01-27 17:04:493091 r"^components/policy/core/common/policy_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313092 r"^components/viz/service/display/"
Sam Maiera6e76d72022-02-11 21:43:503093 r"overlay_strategy_underlay_cast\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313094 r"^components/zucchini/.*",
Sam Maiera6e76d72022-02-11 21:43:503095 # TODO(peter): Remove exception. https://crbug.com/534537
Bruce Dawson40fece62022-09-16 19:58:313096 r"^content/browser/notifications/"
Sam Maiera6e76d72022-02-11 21:43:503097 r"notification_event_dispatcher_impl\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313098 r"^content/common/gpu/client/gl_helper_benchmark\.cc$",
3099 r"^courgette/courgette_minimal_tool\.cc$",
3100 r"^courgette/courgette_tool\.cc$",
3101 r"^extensions/renderer/logging_native_handler\.cc$",
3102 r"^fuchsia_web/common/init_logging\.cc$",
3103 r"^fuchsia_web/runners/common/web_component\.cc$",
Caroline Liua7050132023-02-13 22:23:153104 r"^fuchsia_web/shell/.*\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313105 r"^headless/app/headless_shell\.cc$",
3106 r"^ipc/ipc_logging\.cc$",
3107 r"^native_client_sdk/",
3108 r"^remoting/base/logging\.h$",
3109 r"^remoting/host/.*",
3110 r"^sandbox/linux/.*",
3111 r"^storage/browser/file_system/dump_file_system\.cc$",
3112 r"^tools/",
3113 r"^ui/base/resource/data_pack\.cc$",
3114 r"^ui/aura/bench/bench_main\.cc$",
3115 r"^ui/ozone/platform/cast/",
3116 r"^ui/base/x/xwmstartupcheck/"
Sam Maiera6e76d72022-02-11 21:43:503117 r"xwmstartupcheck\.cc$"))
3118 source_file_filter = lambda x: input_api.FilterSourceFile(
3119 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
thakis@chromium.org85218562013-11-22 07:41:403120
Sam Maiera6e76d72022-02-11 21:43:503121 log_info = set([])
3122 printf = set([])
thakis@chromium.org85218562013-11-22 07:41:403123
Sam Maiera6e76d72022-02-11 21:43:503124 for f in input_api.AffectedSourceFiles(source_file_filter):
3125 for _, line in f.ChangedContents():
3126 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
3127 log_info.add(f.LocalPath())
3128 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
3129 log_info.add(f.LocalPath())
jln@chromium.org18b466b2013-12-02 22:01:373130
Sam Maiera6e76d72022-02-11 21:43:503131 if input_api.re.search(r"\bprintf\(", line):
3132 printf.add(f.LocalPath())
3133 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
3134 printf.add(f.LocalPath())
thakis@chromium.org85218562013-11-22 07:41:403135
Sam Maiera6e76d72022-02-11 21:43:503136 if log_info:
3137 return [
3138 output_api.PresubmitError(
3139 'These files spam the console log with LOG(INFO):',
3140 items=log_info)
3141 ]
3142 if printf:
3143 return [
3144 output_api.PresubmitError(
3145 'These files spam the console log with printf/fprintf:',
3146 items=printf)
3147 ]
3148 return []
thakis@chromium.org85218562013-11-22 07:41:403149
3150
Saagar Sanghavifceeaae2020-08-12 16:40:363151def CheckForAnonymousVariables(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503152 """These types are all expected to hold locks while in scope and
3153 so should never be anonymous (which causes them to be immediately
3154 destroyed)."""
3155 they_who_must_be_named = [
3156 'base::AutoLock',
3157 'base::AutoReset',
3158 'base::AutoUnlock',
3159 'SkAutoAlphaRestore',
3160 'SkAutoBitmapShaderInstall',
3161 'SkAutoBlitterChoose',
3162 'SkAutoBounderCommit',
3163 'SkAutoCallProc',
3164 'SkAutoCanvasRestore',
3165 'SkAutoCommentBlock',
3166 'SkAutoDescriptor',
3167 'SkAutoDisableDirectionCheck',
3168 'SkAutoDisableOvalCheck',
3169 'SkAutoFree',
3170 'SkAutoGlyphCache',
3171 'SkAutoHDC',
3172 'SkAutoLockColors',
3173 'SkAutoLockPixels',
3174 'SkAutoMalloc',
3175 'SkAutoMaskFreeImage',
3176 'SkAutoMutexAcquire',
3177 'SkAutoPathBoundsUpdate',
3178 'SkAutoPDFRelease',
3179 'SkAutoRasterClipValidate',
3180 'SkAutoRef',
3181 'SkAutoTime',
3182 'SkAutoTrace',
3183 'SkAutoUnref',
3184 ]
3185 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
3186 # bad: base::AutoLock(lock.get());
3187 # not bad: base::AutoLock lock(lock.get());
3188 bad_pattern = input_api.re.compile(anonymous)
3189 # good: new base::AutoLock(lock.get())
3190 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
3191 errors = []
enne@chromium.org49aa76a2013-12-04 06:59:163192
Sam Maiera6e76d72022-02-11 21:43:503193 for f in input_api.AffectedFiles():
3194 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
3195 continue
3196 for linenum, line in f.ChangedContents():
3197 if bad_pattern.search(line) and not good_pattern.search(line):
3198 errors.append('%s:%d' % (f.LocalPath(), linenum))
enne@chromium.org49aa76a2013-12-04 06:59:163199
Sam Maiera6e76d72022-02-11 21:43:503200 if errors:
3201 return [
3202 output_api.PresubmitError(
3203 'These lines create anonymous variables that need to be named:',
3204 items=errors)
3205 ]
3206 return []
enne@chromium.org49aa76a2013-12-04 06:59:163207
3208
Saagar Sanghavifceeaae2020-08-12 16:40:363209def CheckUniquePtrOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503210 # Returns whether |template_str| is of the form <T, U...> for some types T
3211 # and U. Assumes that |template_str| is already in the form <...>.
3212 def HasMoreThanOneArg(template_str):
3213 # Level of <...> nesting.
3214 nesting = 0
3215 for c in template_str:
3216 if c == '<':
3217 nesting += 1
3218 elif c == '>':
3219 nesting -= 1
3220 elif c == ',' and nesting == 1:
3221 return True
3222 return False
Vaclav Brozekb7fadb692018-08-30 06:39:533223
Sam Maiera6e76d72022-02-11 21:43:503224 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3225 sources = lambda affected_file: input_api.FilterSourceFile(
3226 affected_file,
3227 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3228 DEFAULT_FILES_TO_SKIP),
3229 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:553230
Sam Maiera6e76d72022-02-11 21:43:503231 # Pattern to capture a single "<...>" block of template arguments. It can
3232 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
3233 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
3234 # latter would likely require counting that < and > match, which is not
3235 # expressible in regular languages. Should the need arise, one can introduce
3236 # limited counting (matching up to a total number of nesting depth), which
3237 # should cover all practical cases for already a low nesting limit.
3238 template_arg_pattern = (
3239 r'<[^>]*' # Opening block of <.
3240 r'>([^<]*>)?') # Closing block of >.
3241 # Prefix expressing that whatever follows is not already inside a <...>
3242 # block.
3243 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
3244 null_construct_pattern = input_api.re.compile(
3245 not_inside_template_arg_pattern + r'\bstd::unique_ptr' +
3246 template_arg_pattern + r'\(\)')
Vaclav Brozeka54c528b2018-04-06 19:23:553247
Sam Maiera6e76d72022-02-11 21:43:503248 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
3249 template_arg_no_array_pattern = (
3250 r'<[^>]*[^]]' # Opening block of <.
3251 r'>([^(<]*[^]]>)?') # Closing block of >.
3252 # Prefix saying that what follows is the start of an expression.
3253 start_of_expr_pattern = r'(=|\breturn|^)\s*'
3254 # Suffix saying that what follows are call parentheses with a non-empty list
3255 # of arguments.
3256 nonempty_arg_list_pattern = r'\(([^)]|$)'
3257 # Put the template argument into a capture group for deeper examination later.
3258 return_construct_pattern = input_api.re.compile(
3259 start_of_expr_pattern + r'std::unique_ptr' + '(?P<template_arg>' +
3260 template_arg_no_array_pattern + ')' + nonempty_arg_list_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:553261
Sam Maiera6e76d72022-02-11 21:43:503262 problems_constructor = []
3263 problems_nullptr = []
3264 for f in input_api.AffectedSourceFiles(sources):
3265 for line_number, line in f.ChangedContents():
3266 # Disallow:
3267 # return std::unique_ptr<T>(foo);
3268 # bar = std::unique_ptr<T>(foo);
3269 # But allow:
3270 # return std::unique_ptr<T[]>(foo);
3271 # bar = std::unique_ptr<T[]>(foo);
3272 # And also allow cases when the second template argument is present. Those
3273 # cases cannot be handled by std::make_unique:
3274 # return std::unique_ptr<T, U>(foo);
3275 # bar = std::unique_ptr<T, U>(foo);
3276 local_path = f.LocalPath()
3277 return_construct_result = return_construct_pattern.search(line)
3278 if return_construct_result and not HasMoreThanOneArg(
3279 return_construct_result.group('template_arg')):
3280 problems_constructor.append(
3281 '%s:%d\n %s' % (local_path, line_number, line.strip()))
3282 # Disallow:
3283 # std::unique_ptr<T>()
3284 if null_construct_pattern.search(line):
3285 problems_nullptr.append(
3286 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Vaclav Brozek851d9602018-04-04 16:13:053287
Sam Maiera6e76d72022-02-11 21:43:503288 errors = []
3289 if problems_nullptr:
3290 errors.append(
3291 output_api.PresubmitPromptWarning(
3292 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
3293 problems_nullptr))
3294 if problems_constructor:
3295 errors.append(
3296 output_api.PresubmitError(
3297 'The following files use explicit std::unique_ptr constructor. '
3298 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
3299 'std::make_unique is not an option.', problems_constructor))
3300 return errors
Peter Kasting4844e46e2018-02-23 07:27:103301
3302
Saagar Sanghavifceeaae2020-08-12 16:40:363303def CheckUserActionUpdate(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503304 """Checks if any new user action has been added."""
3305 if any('actions.xml' == input_api.os_path.basename(f)
3306 for f in input_api.LocalPaths()):
3307 # If actions.xml is already included in the changelist, the PRESUBMIT
3308 # for actions.xml will do a more complete presubmit check.
3309 return []
3310
3311 file_inclusion_pattern = [r'.*\.(cc|mm)$']
3312 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3313 input_api.DEFAULT_FILES_TO_SKIP)
3314 file_filter = lambda f: input_api.FilterSourceFile(
3315 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
3316
3317 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
3318 current_actions = None
3319 for f in input_api.AffectedFiles(file_filter=file_filter):
3320 for line_num, line in f.ChangedContents():
3321 match = input_api.re.search(action_re, line)
3322 if match:
3323 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
3324 # loaded only once.
3325 if not current_actions:
Bruce Dawson6cb2d4d2023-03-01 21:35:093326 with open('tools/metrics/actions/actions.xml',
3327 encoding='utf-8') as actions_f:
Sam Maiera6e76d72022-02-11 21:43:503328 current_actions = actions_f.read()
3329 # Search for the matched user action name in |current_actions|.
3330 for action_name in match.groups():
3331 action = 'name="{0}"'.format(action_name)
3332 if action not in current_actions:
3333 return [
3334 output_api.PresubmitPromptWarning(
3335 'File %s line %d: %s is missing in '
3336 'tools/metrics/actions/actions.xml. Please run '
3337 'tools/metrics/actions/extract_actions.py to update.'
3338 % (f.LocalPath(), line_num, action_name))
3339 ]
yiyaoliu@chromium.org999261d2014-03-03 20:08:083340 return []
3341
yiyaoliu@chromium.org999261d2014-03-03 20:08:083342
Daniel Cheng13ca61a882017-08-25 15:11:253343def _ImportJSONCommentEater(input_api):
Sam Maiera6e76d72022-02-11 21:43:503344 import sys
3345 sys.path = sys.path + [
3346 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3347 'json_comment_eater')
3348 ]
3349 import json_comment_eater
3350 return json_comment_eater
Daniel Cheng13ca61a882017-08-25 15:11:253351
3352
yoz@chromium.org99171a92014-06-03 08:44:473353def _GetJSONParseError(input_api, filename, eat_comments=True):
dchenge07de812016-06-20 19:27:173354 try:
Sam Maiera6e76d72022-02-11 21:43:503355 contents = input_api.ReadFile(filename)
3356 if eat_comments:
3357 json_comment_eater = _ImportJSONCommentEater(input_api)
3358 contents = json_comment_eater.Nom(contents)
dchenge07de812016-06-20 19:27:173359
Sam Maiera6e76d72022-02-11 21:43:503360 input_api.json.loads(contents)
3361 except ValueError as e:
3362 return e
Andrew Grieve4deedb12022-02-03 21:34:503363 return None
3364
3365
Sam Maiera6e76d72022-02-11 21:43:503366def _GetIDLParseError(input_api, filename):
3367 try:
3368 contents = input_api.ReadFile(filename)
Devlin Croninf7582a12022-04-21 21:14:283369 for i, char in enumerate(contents):
Daniel Chenga37c03db2022-05-12 17:20:343370 if not char.isascii():
3371 return (
3372 'Non-ascii character "%s" (ord %d) found at offset %d.' %
3373 (char, ord(char), i))
Sam Maiera6e76d72022-02-11 21:43:503374 idl_schema = input_api.os_path.join(input_api.PresubmitLocalPath(),
3375 'tools', 'json_schema_compiler',
3376 'idl_schema.py')
3377 process = input_api.subprocess.Popen(
Bruce Dawson679fb082022-04-14 00:47:283378 [input_api.python3_executable, idl_schema],
Sam Maiera6e76d72022-02-11 21:43:503379 stdin=input_api.subprocess.PIPE,
3380 stdout=input_api.subprocess.PIPE,
3381 stderr=input_api.subprocess.PIPE,
3382 universal_newlines=True)
3383 (_, error) = process.communicate(input=contents)
3384 return error or None
3385 except ValueError as e:
3386 return e
agrievef32bcc72016-04-04 14:57:403387
agrievef32bcc72016-04-04 14:57:403388
Sam Maiera6e76d72022-02-11 21:43:503389def CheckParseErrors(input_api, output_api):
3390 """Check that IDL and JSON files do not contain syntax errors."""
3391 actions = {
3392 '.idl': _GetIDLParseError,
3393 '.json': _GetJSONParseError,
3394 }
3395 # Most JSON files are preprocessed and support comments, but these do not.
3396 json_no_comments_patterns = [
Bruce Dawson40fece62022-09-16 19:58:313397 r'^testing/',
Sam Maiera6e76d72022-02-11 21:43:503398 ]
3399 # Only run IDL checker on files in these directories.
3400 idl_included_patterns = [
Bruce Dawson40fece62022-09-16 19:58:313401 r'^chrome/common/extensions/api/',
3402 r'^extensions/common/api/',
Sam Maiera6e76d72022-02-11 21:43:503403 ]
agrievef32bcc72016-04-04 14:57:403404
Sam Maiera6e76d72022-02-11 21:43:503405 def get_action(affected_file):
3406 filename = affected_file.LocalPath()
3407 return actions.get(input_api.os_path.splitext(filename)[1])
agrievef32bcc72016-04-04 14:57:403408
Sam Maiera6e76d72022-02-11 21:43:503409 def FilterFile(affected_file):
3410 action = get_action(affected_file)
3411 if not action:
3412 return False
3413 path = affected_file.LocalPath()
agrievef32bcc72016-04-04 14:57:403414
Sam Maiera6e76d72022-02-11 21:43:503415 if _MatchesFile(input_api,
3416 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS, path):
3417 return False
3418
3419 if (action == _GetIDLParseError
3420 and not _MatchesFile(input_api, idl_included_patterns, path)):
3421 return False
3422 return True
3423
3424 results = []
3425 for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
3426 include_deletes=False):
3427 action = get_action(affected_file)
3428 kwargs = {}
3429 if (action == _GetJSONParseError
3430 and _MatchesFile(input_api, json_no_comments_patterns,
3431 affected_file.LocalPath())):
3432 kwargs['eat_comments'] = False
3433 parse_error = action(input_api, affected_file.AbsoluteLocalPath(),
3434 **kwargs)
3435 if parse_error:
3436 results.append(
3437 output_api.PresubmitError(
3438 '%s could not be parsed: %s' %
3439 (affected_file.LocalPath(), parse_error)))
3440 return results
3441
3442
3443def CheckJavaStyle(input_api, output_api):
3444 """Runs checkstyle on changed java files and returns errors if any exist."""
3445
3446 # Return early if no java files were modified.
3447 if not any(
3448 _IsJavaFile(input_api, f.LocalPath())
3449 for f in input_api.AffectedFiles()):
3450 return []
3451
3452 import sys
3453 original_sys_path = sys.path
3454 try:
3455 sys.path = sys.path + [
3456 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3457 'android', 'checkstyle')
3458 ]
3459 import checkstyle
3460 finally:
3461 # Restore sys.path to what it was before.
3462 sys.path = original_sys_path
3463
Andrew Grieve4f88e3ca2022-11-22 19:09:203464 return checkstyle.run_presubmit(
Sam Maiera6e76d72022-02-11 21:43:503465 input_api,
3466 output_api,
Sam Maiera6e76d72022-02-11 21:43:503467 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
3468
3469
3470def CheckPythonDevilInit(input_api, output_api):
3471 """Checks to make sure devil is initialized correctly in python scripts."""
3472 script_common_initialize_pattern = input_api.re.compile(
3473 r'script_common\.InitializeEnvironment\(')
3474 devil_env_config_initialize = input_api.re.compile(
3475 r'devil_env\.config\.Initialize\(')
3476
3477 errors = []
3478
3479 sources = lambda affected_file: input_api.FilterSourceFile(
3480 affected_file,
3481 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:313482 r'^build/android/devil_chromium\.py',
3483 r'^third_party/.*',
Sam Maiera6e76d72022-02-11 21:43:503484 )),
3485 files_to_check=[r'.*\.py$'])
3486
3487 for f in input_api.AffectedSourceFiles(sources):
3488 for line_num, line in f.ChangedContents():
3489 if (script_common_initialize_pattern.search(line)
3490 or devil_env_config_initialize.search(line)):
3491 errors.append("%s:%d" % (f.LocalPath(), line_num))
3492
3493 results = []
3494
3495 if errors:
3496 results.append(
3497 output_api.PresubmitError(
3498 'Devil initialization should always be done using '
3499 'devil_chromium.Initialize() in the chromium project, to use better '
3500 'defaults for dependencies (ex. up-to-date version of adb).',
3501 errors))
3502
3503 return results
3504
3505
3506def _MatchesFile(input_api, patterns, path):
Bruce Dawson40fece62022-09-16 19:58:313507 # Consistently use / as path separator to simplify the writing of regex
3508 # expressions.
3509 path = path.replace(input_api.os_path.sep, '/')
Sam Maiera6e76d72022-02-11 21:43:503510 for pattern in patterns:
3511 if input_api.re.search(pattern, path):
3512 return True
3513 return False
3514
3515
Daniel Chenga37c03db2022-05-12 17:20:343516def _ChangeHasSecurityReviewer(input_api, owners_file):
3517 """Returns True iff the CL has a reviewer from SECURITY_OWNERS.
Sam Maiera6e76d72022-02-11 21:43:503518
Daniel Chenga37c03db2022-05-12 17:20:343519 Args:
3520 input_api: The presubmit input API.
3521 owners_file: OWNERS file with required reviewers. Typically, this is
3522 something like ipc/SECURITY_OWNERS.
3523
3524 Note: if the presubmit is running for commit rather than for upload, this
3525 only returns True if a security reviewer has also approved the CL.
Sam Maiera6e76d72022-02-11 21:43:503526 """
Daniel Chengd88244472022-05-16 09:08:473527 # Owners-Override should bypass all additional OWNERS enforcement checks.
3528 # A CR+1 vote will still be required to land this change.
3529 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
3530 input_api.change.issue)):
3531 return True
3532
Daniel Chenga37c03db2022-05-12 17:20:343533 owner_email, reviewers = (
3534 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
Daniel Cheng3008dc12022-05-13 04:02:113535 input_api,
3536 None,
3537 approval_needed=input_api.is_committing and not input_api.dry_run))
Sam Maiera6e76d72022-02-11 21:43:503538
Daniel Chenga37c03db2022-05-12 17:20:343539 security_owners = input_api.owners_client.ListOwners(owners_file)
3540 return any(owner in reviewers for owner in security_owners)
Sam Maiera6e76d72022-02-11 21:43:503541
Daniel Chenga37c03db2022-05-12 17:20:343542
3543@dataclass
Daniel Cheng171dad8d2022-05-21 00:40:253544class _SecurityProblemWithItems:
3545 problem: str
3546 items: Sequence[str]
3547
3548
3549@dataclass
Daniel Chenga37c03db2022-05-12 17:20:343550class _MissingSecurityOwnersResult:
Daniel Cheng171dad8d2022-05-21 00:40:253551 owners_file_problems: Sequence[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:343552 has_security_sensitive_files: bool
Daniel Cheng171dad8d2022-05-21 00:40:253553 missing_reviewer_problem: Optional[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:343554
3555
3556def _FindMissingSecurityOwners(input_api,
3557 output_api,
3558 file_patterns: Sequence[str],
3559 excluded_patterns: Sequence[str],
3560 required_owners_file: str,
3561 custom_rule_function: Optional[Callable] = None
3562 ) -> _MissingSecurityOwnersResult:
3563 """Find OWNERS files missing per-file rules for security-sensitive files.
3564
3565 Args:
3566 input_api: the PRESUBMIT input API object.
3567 output_api: the PRESUBMIT output API object.
3568 file_patterns: basename patterns that require a corresponding per-file
3569 security restriction.
3570 excluded_patterns: path patterns that should be exempted from
3571 requiring a security restriction.
3572 required_owners_file: path to the required OWNERS file, e.g.
3573 ipc/SECURITY_OWNERS
3574 cc_alias: If not None, email that will be CCed automatically if the
3575 change contains security-sensitive files, as determined by
3576 `file_patterns` and `excluded_patterns`.
3577 custom_rule_function: If not None, will be called with `input_api` and
3578 the current file under consideration. Returning True will add an
3579 exact match per-file rule check for the current file.
3580 """
3581
3582 # `to_check` is a mapping of an OWNERS file path to Patterns.
3583 #
3584 # Patterns is a dictionary mapping glob patterns (suitable for use in
3585 # per-file rules) to a PatternEntry.
3586 #
Sam Maiera6e76d72022-02-11 21:43:503587 # PatternEntry is a dictionary with two keys:
3588 # - 'files': the files that are matched by this pattern
3589 # - 'rules': the per-file rules needed for this pattern
Daniel Chenga37c03db2022-05-12 17:20:343590 #
Sam Maiera6e76d72022-02-11 21:43:503591 # For example, if we expect OWNERS file to contain rules for *.mojom and
3592 # *_struct_traits*.*, Patterns might look like this:
3593 # {
3594 # '*.mojom': {
3595 # 'files': ...,
3596 # 'rules': [
3597 # 'per-file *.mojom=set noparent',
3598 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
3599 # ],
3600 # },
3601 # '*_struct_traits*.*': {
3602 # 'files': ...,
3603 # 'rules': [
3604 # 'per-file *_struct_traits*.*=set noparent',
3605 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
3606 # ],
3607 # },
3608 # }
3609 to_check = {}
Daniel Chenga37c03db2022-05-12 17:20:343610 files_to_review = []
Sam Maiera6e76d72022-02-11 21:43:503611
Daniel Chenga37c03db2022-05-12 17:20:343612 def AddPatternToCheck(file, pattern):
Sam Maiera6e76d72022-02-11 21:43:503613 owners_file = input_api.os_path.join(
Daniel Chengd88244472022-05-16 09:08:473614 input_api.os_path.dirname(file.LocalPath()), 'OWNERS')
Sam Maiera6e76d72022-02-11 21:43:503615 if owners_file not in to_check:
3616 to_check[owners_file] = {}
3617 if pattern not in to_check[owners_file]:
3618 to_check[owners_file][pattern] = {
3619 'files': [],
3620 'rules': [
Daniel Chenga37c03db2022-05-12 17:20:343621 f'per-file {pattern}=set noparent',
3622 f'per-file {pattern}=file://{required_owners_file}',
Sam Maiera6e76d72022-02-11 21:43:503623 ]
3624 }
Daniel Chenged57a162022-05-25 02:56:343625 to_check[owners_file][pattern]['files'].append(file.LocalPath())
Daniel Chenga37c03db2022-05-12 17:20:343626 files_to_review.append(file.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:503627
Daniel Chenga37c03db2022-05-12 17:20:343628 # Only enforce security OWNERS rules for a directory if that directory has a
3629 # file that matches `file_patterns`. For example, if a directory only
3630 # contains *.mojom files and no *_messages*.h files, the check should only
3631 # ensure that rules for *.mojom files are present.
3632 for file in input_api.AffectedFiles(include_deletes=False):
3633 file_basename = input_api.os_path.basename(file.LocalPath())
3634 if custom_rule_function is not None and custom_rule_function(
3635 input_api, file):
3636 AddPatternToCheck(file, file_basename)
3637 continue
Sam Maiera6e76d72022-02-11 21:43:503638
Daniel Chenga37c03db2022-05-12 17:20:343639 if any(
3640 input_api.fnmatch.fnmatch(file.LocalPath(), pattern)
3641 for pattern in excluded_patterns):
Sam Maiera6e76d72022-02-11 21:43:503642 continue
3643
3644 for pattern in file_patterns:
Daniel Chenga37c03db2022-05-12 17:20:343645 # Unlike `excluded_patterns`, `file_patterns` is checked only against the
3646 # file's basename.
3647 if input_api.fnmatch.fnmatch(file_basename, pattern):
3648 AddPatternToCheck(file, pattern)
Sam Maiera6e76d72022-02-11 21:43:503649 break
3650
Daniel Chenga37c03db2022-05-12 17:20:343651 has_security_sensitive_files = bool(to_check)
Daniel Cheng171dad8d2022-05-21 00:40:253652
3653 # Check if any newly added lines in OWNERS files intersect with required
3654 # per-file OWNERS lines. If so, ensure that a security reviewer is included.
3655 # This is a hack, but is needed because the OWNERS check (by design) ignores
3656 # new OWNERS entries; otherwise, a non-owner could add someone as a new
3657 # OWNER and have that newly-added OWNER self-approve their own addition.
3658 newly_covered_files = []
3659 for file in input_api.AffectedFiles(include_deletes=False):
3660 if not file.LocalPath() in to_check:
3661 continue
3662 for _, line in file.ChangedContents():
3663 for _, entry in to_check[file.LocalPath()].items():
3664 if line in entry['rules']:
3665 newly_covered_files.extend(entry['files'])
3666
3667 missing_reviewer_problems = None
3668 if newly_covered_files and not _ChangeHasSecurityReviewer(
Daniel Chenga37c03db2022-05-12 17:20:343669 input_api, required_owners_file):
Daniel Cheng171dad8d2022-05-21 00:40:253670 missing_reviewer_problems = _SecurityProblemWithItems(
3671 f'Review from an owner in {required_owners_file} is required for '
3672 'the following newly-added files:',
3673 [f'{file}' for file in sorted(set(newly_covered_files))])
Sam Maiera6e76d72022-02-11 21:43:503674
3675 # Go through the OWNERS files to check, filtering out rules that are already
3676 # present in that OWNERS file.
3677 for owners_file, patterns in to_check.items():
3678 try:
Daniel Cheng171dad8d2022-05-21 00:40:253679 lines = set(
3680 input_api.ReadFile(
3681 input_api.os_path.join(input_api.change.RepositoryRoot(),
3682 owners_file)).splitlines())
3683 for entry in patterns.values():
3684 entry['rules'] = [
3685 rule for rule in entry['rules'] if rule not in lines
3686 ]
Sam Maiera6e76d72022-02-11 21:43:503687 except IOError:
3688 # No OWNERS file, so all the rules are definitely missing.
3689 continue
3690
3691 # All the remaining lines weren't found in OWNERS files, so emit an error.
Daniel Cheng171dad8d2022-05-21 00:40:253692 owners_file_problems = []
Daniel Chenga37c03db2022-05-12 17:20:343693
Sam Maiera6e76d72022-02-11 21:43:503694 for owners_file, patterns in to_check.items():
3695 missing_lines = []
3696 files = []
3697 for _, entry in patterns.items():
Daniel Chenged57a162022-05-25 02:56:343698 files.extend(entry['files'])
Sam Maiera6e76d72022-02-11 21:43:503699 missing_lines.extend(entry['rules'])
Sam Maiera6e76d72022-02-11 21:43:503700 if missing_lines:
Daniel Cheng171dad8d2022-05-21 00:40:253701 joined_missing_lines = '\n'.join(line for line in missing_lines)
3702 owners_file_problems.append(
3703 _SecurityProblemWithItems(
3704 'Found missing OWNERS lines for security-sensitive files. '
3705 f'Please add the following lines to {owners_file}:\n'
3706 f'{joined_missing_lines}\n\nTo ensure security review for:',
3707 files))
Daniel Chenga37c03db2022-05-12 17:20:343708
Daniel Cheng171dad8d2022-05-21 00:40:253709 return _MissingSecurityOwnersResult(owners_file_problems,
Daniel Chenga37c03db2022-05-12 17:20:343710 has_security_sensitive_files,
Daniel Cheng171dad8d2022-05-21 00:40:253711 missing_reviewer_problems)
Daniel Chenga37c03db2022-05-12 17:20:343712
3713
3714def _CheckChangeForIpcSecurityOwners(input_api, output_api):
3715 # Whether or not a file affects IPC is (mostly) determined by a simple list
3716 # of filename patterns.
3717 file_patterns = [
3718 # Legacy IPC:
3719 '*_messages.cc',
3720 '*_messages*.h',
3721 '*_param_traits*.*',
3722 # Mojo IPC:
3723 '*.mojom',
3724 '*_mojom_traits*.*',
3725 '*_type_converter*.*',
3726 # Android native IPC:
3727 '*.aidl',
3728 ]
3729
Daniel Chenga37c03db2022-05-12 17:20:343730 excluded_patterns = [
Daniel Cheng518943f2022-05-12 22:15:463731 # These third_party directories do not contain IPCs, but contain files
3732 # matching the above patterns, which trigger false positives.
Daniel Chenga37c03db2022-05-12 17:20:343733 'third_party/crashpad/*',
3734 'third_party/blink/renderer/platform/bindings/*',
3735 'third_party/protobuf/benchmarks/python/*',
3736 'third_party/win_build_output/*',
Daniel Chengd88244472022-05-16 09:08:473737 # Enum-only mojoms used for web metrics, so no security review needed.
3738 'third_party/blink/public/mojom/use_counter/metrics/*',
Daniel Chenga37c03db2022-05-12 17:20:343739 # These files are just used to communicate between class loaders running
3740 # in the same process.
3741 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
3742 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
3743 ]
3744
3745 def IsMojoServiceManifestFile(input_api, file):
3746 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
3747 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
3748 if not manifest_pattern.search(file.LocalPath()):
3749 return False
3750
3751 if test_manifest_pattern.search(file.LocalPath()):
3752 return False
3753
3754 # All actual service manifest files should contain at least one
3755 # qualified reference to service_manager::Manifest.
3756 return any('service_manager::Manifest' in line
3757 for line in file.NewContents())
3758
3759 return _FindMissingSecurityOwners(
3760 input_api,
3761 output_api,
3762 file_patterns,
3763 excluded_patterns,
3764 'ipc/SECURITY_OWNERS',
3765 custom_rule_function=IsMojoServiceManifestFile)
3766
3767
3768def _CheckChangeForFuchsiaSecurityOwners(input_api, output_api):
3769 file_patterns = [
3770 # Component specifications.
3771 '*.cml', # Component Framework v2.
3772 '*.cmx', # Component Framework v1.
3773
3774 # Fuchsia IDL protocol specifications.
3775 '*.fidl',
3776 ]
3777
3778 # Don't check for owners files for changes in these directories.
3779 excluded_patterns = [
3780 'third_party/crashpad/*',
3781 ]
3782
3783 return _FindMissingSecurityOwners(input_api, output_api, file_patterns,
3784 excluded_patterns,
3785 'build/fuchsia/SECURITY_OWNERS')
3786
3787
3788def CheckSecurityOwners(input_api, output_api):
3789 """Checks that various security-sensitive files have an IPC OWNERS rule."""
3790 ipc_results = _CheckChangeForIpcSecurityOwners(input_api, output_api)
3791 fuchsia_results = _CheckChangeForFuchsiaSecurityOwners(
3792 input_api, output_api)
3793
3794 if ipc_results.has_security_sensitive_files:
3795 output_api.AppendCC('ipc-security-reviews@chromium.org')
Sam Maiera6e76d72022-02-11 21:43:503796
3797 results = []
Daniel Chenga37c03db2022-05-12 17:20:343798
Daniel Cheng171dad8d2022-05-21 00:40:253799 missing_reviewer_problems = []
3800 if ipc_results.missing_reviewer_problem:
3801 missing_reviewer_problems.append(ipc_results.missing_reviewer_problem)
3802 if fuchsia_results.missing_reviewer_problem:
3803 missing_reviewer_problems.append(
3804 fuchsia_results.missing_reviewer_problem)
Daniel Chenga37c03db2022-05-12 17:20:343805
Daniel Cheng171dad8d2022-05-21 00:40:253806 # Missing reviewers are an error unless there's no issue number
3807 # associated with this branch; in that case, the presubmit is being run
3808 # with --all or --files.
3809 #
3810 # Note that upload should never be an error; otherwise, it would be
3811 # impossible to upload changes at all.
3812 if input_api.is_committing and input_api.change.issue:
3813 make_presubmit_message = output_api.PresubmitError
3814 else:
3815 make_presubmit_message = output_api.PresubmitNotifyResult
3816 for problem in missing_reviewer_problems:
Sam Maiera6e76d72022-02-11 21:43:503817 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:253818 make_presubmit_message(problem.problem, items=problem.items))
Daniel Chenga37c03db2022-05-12 17:20:343819
Daniel Cheng171dad8d2022-05-21 00:40:253820 owners_file_problems = []
3821 owners_file_problems.extend(ipc_results.owners_file_problems)
3822 owners_file_problems.extend(fuchsia_results.owners_file_problems)
Daniel Chenga37c03db2022-05-12 17:20:343823
Daniel Cheng171dad8d2022-05-21 00:40:253824 for problem in owners_file_problems:
Daniel Cheng3008dc12022-05-13 04:02:113825 # Missing per-file rules are always an error. While swarming and caching
3826 # means that uploading a patchset with updated OWNERS files and sending
3827 # it to the CQ again should not have a large incremental cost, it is
3828 # still frustrating to discover the error only after the change has
3829 # already been uploaded.
Daniel Chenga37c03db2022-05-12 17:20:343830 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:253831 output_api.PresubmitError(problem.problem, items=problem.items))
Sam Maiera6e76d72022-02-11 21:43:503832
3833 return results
3834
3835
3836def _GetFilesUsingSecurityCriticalFunctions(input_api):
3837 """Checks affected files for changes to security-critical calls. This
3838 function checks the full change diff, to catch both additions/changes
3839 and removals.
3840
3841 Returns a dict keyed by file name, and the value is a set of detected
3842 functions.
3843 """
3844 # Map of function pretty name (displayed in an error) to the pattern to
3845 # match it with.
3846 _PATTERNS_TO_CHECK = {
3847 'content::GetServiceSandboxType<>()': 'GetServiceSandboxType\\<'
3848 }
3849 _PATTERNS_TO_CHECK = {
3850 k: input_api.re.compile(v)
3851 for k, v in _PATTERNS_TO_CHECK.items()
3852 }
3853
Sam Maiera6e76d72022-02-11 21:43:503854 # We don't want to trigger on strings within this file.
3855 def presubmit_file_filter(f):
Daniel Chenga37c03db2022-05-12 17:20:343856 return 'PRESUBMIT.py' != input_api.os_path.split(f.LocalPath())[1]
Sam Maiera6e76d72022-02-11 21:43:503857
3858 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3859 files_to_functions = {}
3860 for f in input_api.AffectedFiles(file_filter=presubmit_file_filter):
3861 diff = f.GenerateScmDiff()
3862 for line in diff.split('\n'):
3863 # Not using just RightHandSideLines() because removing a
3864 # call to a security-critical function can be just as important
3865 # as adding or changing the arguments.
3866 if line.startswith('-') or (line.startswith('+')
3867 and not line.startswith('++')):
3868 for name, pattern in _PATTERNS_TO_CHECK.items():
3869 if pattern.search(line):
3870 path = f.LocalPath()
3871 if not path in files_to_functions:
3872 files_to_functions[path] = set()
3873 files_to_functions[path].add(name)
3874 return files_to_functions
3875
3876
3877def CheckSecurityChanges(input_api, output_api):
3878 """Checks that changes involving security-critical functions are reviewed
3879 by the security team.
3880 """
3881 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3882 if not len(files_to_functions):
3883 return []
3884
Sam Maiera6e76d72022-02-11 21:43:503885 owners_file = 'ipc/SECURITY_OWNERS'
Daniel Chenga37c03db2022-05-12 17:20:343886 if _ChangeHasSecurityReviewer(input_api, owners_file):
Sam Maiera6e76d72022-02-11 21:43:503887 return []
3888
Daniel Chenga37c03db2022-05-12 17:20:343889 msg = 'The following files change calls to security-sensitive functions\n' \
Sam Maiera6e76d72022-02-11 21:43:503890 'that need to be reviewed by {}.\n'.format(owners_file)
3891 for path, names in files_to_functions.items():
3892 msg += ' {}\n'.format(path)
3893 for name in names:
3894 msg += ' {}\n'.format(name)
3895 msg += '\n'
3896
3897 if input_api.is_committing:
3898 output = output_api.PresubmitError
Mohamed Heikale217fc852020-07-06 19:44:033899 else:
Sam Maiera6e76d72022-02-11 21:43:503900 output = output_api.PresubmitNotifyResult
3901 return [output(msg)]
3902
3903
3904def CheckSetNoParent(input_api, output_api):
3905 """Checks that set noparent is only used together with an OWNERS file in
3906 //build/OWNERS.setnoparent (see also
3907 //docs/code_reviews.md#owners-files-details)
3908 """
3909 # Return early if no OWNERS files were modified.
3910 if not any(f.LocalPath().endswith('OWNERS')
3911 for f in input_api.AffectedFiles(include_deletes=False)):
3912 return []
3913
3914 errors = []
3915
3916 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3917 allowed_owners_files = set()
Bruce Dawson58a45d22023-02-27 11:24:163918 with open(allowed_owners_files_file, 'r', encoding='utf-8') as f:
Sam Maiera6e76d72022-02-11 21:43:503919 for line in f:
3920 line = line.strip()
3921 if not line or line.startswith('#'):
3922 continue
3923 allowed_owners_files.add(line)
3924
3925 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3926
3927 for f in input_api.AffectedFiles(include_deletes=False):
3928 if not f.LocalPath().endswith('OWNERS'):
3929 continue
3930
3931 found_owners_files = set()
3932 found_set_noparent_lines = dict()
3933
3934 # Parse the OWNERS file.
3935 for lineno, line in enumerate(f.NewContents(), 1):
3936 line = line.strip()
3937 if line.startswith('set noparent'):
3938 found_set_noparent_lines[''] = lineno
3939 if line.startswith('file://'):
3940 if line in allowed_owners_files:
3941 found_owners_files.add('')
3942 if line.startswith('per-file'):
3943 match = per_file_pattern.match(line)
3944 if match:
3945 glob = match.group(1).strip()
3946 directive = match.group(2).strip()
3947 if directive == 'set noparent':
3948 found_set_noparent_lines[glob] = lineno
3949 if directive.startswith('file://'):
3950 if directive in allowed_owners_files:
3951 found_owners_files.add(glob)
3952
3953 # Check that every set noparent line has a corresponding file:// line
3954 # listed in build/OWNERS.setnoparent. An exception is made for top level
3955 # directories since src/OWNERS shouldn't review them.
Bruce Dawson6bb0d672022-04-06 15:13:493956 linux_path = f.LocalPath().replace(input_api.os_path.sep, '/')
3957 if (linux_path.count('/') != 1
3958 and (not linux_path in _EXCLUDED_SET_NO_PARENT_PATHS)):
Sam Maiera6e76d72022-02-11 21:43:503959 for set_noparent_line in found_set_noparent_lines:
3960 if set_noparent_line in found_owners_files:
3961 continue
3962 errors.append(' %s:%d' %
Bruce Dawson6bb0d672022-04-06 15:13:493963 (linux_path,
Sam Maiera6e76d72022-02-11 21:43:503964 found_set_noparent_lines[set_noparent_line]))
3965
3966 results = []
3967 if errors:
3968 if input_api.is_committing:
3969 output = output_api.PresubmitError
3970 else:
3971 output = output_api.PresubmitPromptWarning
3972 results.append(
3973 output(
3974 'Found the following "set noparent" restrictions in OWNERS files that '
3975 'do not include owners from build/OWNERS.setnoparent:',
3976 long_text='\n\n'.join(errors)))
3977 return results
3978
3979
3980def CheckUselessForwardDeclarations(input_api, output_api):
3981 """Checks that added or removed lines in non third party affected
3982 header files do not lead to new useless class or struct forward
3983 declaration.
3984 """
3985 results = []
3986 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3987 input_api.re.MULTILINE)
3988 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3989 input_api.re.MULTILINE)
3990 for f in input_api.AffectedFiles(include_deletes=False):
3991 if (f.LocalPath().startswith('third_party')
3992 and not f.LocalPath().startswith('third_party/blink')
3993 and not f.LocalPath().startswith('third_party\\blink')):
3994 continue
3995
3996 if not f.LocalPath().endswith('.h'):
3997 continue
3998
3999 contents = input_api.ReadFile(f)
4000 fwd_decls = input_api.re.findall(class_pattern, contents)
4001 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
4002
4003 useless_fwd_decls = []
4004 for decl in fwd_decls:
4005 count = sum(1 for _ in input_api.re.finditer(
4006 r'\b%s\b' % input_api.re.escape(decl), contents))
4007 if count == 1:
4008 useless_fwd_decls.append(decl)
4009
4010 if not useless_fwd_decls:
4011 continue
4012
4013 for line in f.GenerateScmDiff().splitlines():
4014 if (line.startswith('-') and not line.startswith('--')
4015 or line.startswith('+') and not line.startswith('++')):
4016 for decl in useless_fwd_decls:
4017 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
4018 results.append(
4019 output_api.PresubmitPromptWarning(
4020 '%s: %s forward declaration is no longer needed'
4021 % (f.LocalPath(), decl)))
4022 useless_fwd_decls.remove(decl)
4023
4024 return results
4025
4026
4027def _CheckAndroidDebuggableBuild(input_api, output_api):
4028 """Checks that code uses BuildInfo.isDebugAndroid() instead of
4029 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
4030 this is a debuggable build of Android.
4031 """
4032 build_type_check_pattern = input_api.re.compile(
4033 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
4034
4035 errors = []
4036
4037 sources = lambda affected_file: input_api.FilterSourceFile(
4038 affected_file,
4039 files_to_skip=(
4040 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4041 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314042 r"^android_webview/support_library/boundary_interfaces/",
4043 r"^chrome/android/webapk/.*",
4044 r'^third_party/.*',
4045 r"tools/android/customtabs_benchmark/.*",
4046 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504047 )),
4048 files_to_check=[r'.*\.java$'])
4049
4050 for f in input_api.AffectedSourceFiles(sources):
4051 for line_num, line in f.ChangedContents():
4052 if build_type_check_pattern.search(line):
4053 errors.append("%s:%d" % (f.LocalPath(), line_num))
4054
4055 results = []
4056
4057 if errors:
4058 results.append(
4059 output_api.PresubmitPromptWarning(
4060 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
4061 ' Please use BuildInfo.isDebugAndroid() instead.', errors))
4062
4063 return results
4064
4065# TODO: add unit tests
4066def _CheckAndroidToastUsage(input_api, output_api):
4067 """Checks that code uses org.chromium.ui.widget.Toast instead of
4068 android.widget.Toast (Chromium Toast doesn't force hardware
4069 acceleration on low-end devices, saving memory).
4070 """
4071 toast_import_pattern = input_api.re.compile(
4072 r'^import android\.widget\.Toast;$')
4073
4074 errors = []
4075
4076 sources = lambda affected_file: input_api.FilterSourceFile(
4077 affected_file,
4078 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
Bruce Dawson40fece62022-09-16 19:58:314079 DEFAULT_FILES_TO_SKIP + (r'^chromecast/.*',
4080 r'^remoting/.*')),
Sam Maiera6e76d72022-02-11 21:43:504081 files_to_check=[r'.*\.java$'])
4082
4083 for f in input_api.AffectedSourceFiles(sources):
4084 for line_num, line in f.ChangedContents():
4085 if toast_import_pattern.search(line):
4086 errors.append("%s:%d" % (f.LocalPath(), line_num))
4087
4088 results = []
4089
4090 if errors:
4091 results.append(
4092 output_api.PresubmitError(
4093 'android.widget.Toast usage is detected. Android toasts use hardware'
4094 ' acceleration, and can be\ncostly on low-end devices. Please use'
4095 ' org.chromium.ui.widget.Toast instead.\n'
4096 'Contact dskiba@chromium.org if you have any questions.',
4097 errors))
4098
4099 return results
4100
4101
4102def _CheckAndroidCrLogUsage(input_api, output_api):
4103 """Checks that new logs using org.chromium.base.Log:
4104 - Are using 'TAG' as variable name for the tags (warn)
4105 - Are using a tag that is shorter than 20 characters (error)
4106 """
4107
4108 # Do not check format of logs in the given files
4109 cr_log_check_excluded_paths = [
4110 # //chrome/android/webapk cannot depend on //base
Bruce Dawson40fece62022-09-16 19:58:314111 r"^chrome/android/webapk/.*",
Sam Maiera6e76d72022-02-11 21:43:504112 # WebView license viewer code cannot depend on //base; used in stub APK.
Bruce Dawson40fece62022-09-16 19:58:314113 r"^android_webview/glue/java/src/com/android/"
4114 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504115 # The customtabs_benchmark is a small app that does not depend on Chromium
4116 # java pieces.
Bruce Dawson40fece62022-09-16 19:58:314117 r"tools/android/customtabs_benchmark/.*",
Sam Maiera6e76d72022-02-11 21:43:504118 ]
4119
4120 cr_log_import_pattern = input_api.re.compile(
4121 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
4122 class_in_base_pattern = input_api.re.compile(
4123 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
4124 has_some_log_import_pattern = input_api.re.compile(r'^import .*\.Log;$',
4125 input_api.re.MULTILINE)
4126 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
4127 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
4128 log_decl_pattern = input_api.re.compile(
4129 r'static final String TAG = "(?P<name>(.*))"')
4130 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
4131
4132 REF_MSG = ('See docs/android_logging.md for more info.')
4133 sources = lambda x: input_api.FilterSourceFile(
4134 x,
4135 files_to_check=[r'.*\.java$'],
4136 files_to_skip=cr_log_check_excluded_paths)
4137
4138 tag_decl_errors = []
4139 tag_length_errors = []
4140 tag_errors = []
4141 tag_with_dot_errors = []
4142 util_log_errors = []
4143
4144 for f in input_api.AffectedSourceFiles(sources):
4145 file_content = input_api.ReadFile(f)
4146 has_modified_logs = False
4147 # Per line checks
4148 if (cr_log_import_pattern.search(file_content)
4149 or (class_in_base_pattern.search(file_content)
4150 and not has_some_log_import_pattern.search(file_content))):
4151 # Checks to run for files using cr log
4152 for line_num, line in f.ChangedContents():
4153 if rough_log_decl_pattern.search(line):
4154 has_modified_logs = True
4155
4156 # Check if the new line is doing some logging
4157 match = log_call_pattern.search(line)
4158 if match:
4159 has_modified_logs = True
4160
4161 # Make sure it uses "TAG"
4162 if not match.group('tag') == 'TAG':
4163 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
4164 else:
4165 # Report non cr Log function calls in changed lines
4166 for line_num, line in f.ChangedContents():
4167 if log_call_pattern.search(line):
4168 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
4169
4170 # Per file checks
4171 if has_modified_logs:
4172 # Make sure the tag is using the "cr" prefix and is not too long
4173 match = log_decl_pattern.search(file_content)
4174 tag_name = match.group('name') if match else None
4175 if not tag_name:
4176 tag_decl_errors.append(f.LocalPath())
4177 elif len(tag_name) > 20:
4178 tag_length_errors.append(f.LocalPath())
4179 elif '.' in tag_name:
4180 tag_with_dot_errors.append(f.LocalPath())
4181
4182 results = []
4183 if tag_decl_errors:
4184 results.append(
4185 output_api.PresubmitPromptWarning(
4186 'Please define your tags using the suggested format: .\n'
4187 '"private static final String TAG = "<package tag>".\n'
4188 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
4189 tag_decl_errors))
4190
4191 if tag_length_errors:
4192 results.append(
4193 output_api.PresubmitError(
4194 'The tag length is restricted by the system to be at most '
4195 '20 characters.\n' + REF_MSG, tag_length_errors))
4196
4197 if tag_errors:
4198 results.append(
4199 output_api.PresubmitPromptWarning(
4200 'Please use a variable named "TAG" for your log tags.\n' +
4201 REF_MSG, tag_errors))
4202
4203 if util_log_errors:
4204 results.append(
4205 output_api.PresubmitPromptWarning(
4206 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
4207 util_log_errors))
4208
4209 if tag_with_dot_errors:
4210 results.append(
4211 output_api.PresubmitPromptWarning(
4212 'Dot in log tags cause them to be elided in crash reports.\n' +
4213 REF_MSG, tag_with_dot_errors))
4214
4215 return results
4216
4217
4218def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
4219 """Checks that junit.framework.* is no longer used."""
4220 deprecated_junit_framework_pattern = input_api.re.compile(
4221 r'^import junit\.framework\..*;', input_api.re.MULTILINE)
4222 sources = lambda x: input_api.FilterSourceFile(
4223 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
4224 errors = []
4225 for f in input_api.AffectedFiles(file_filter=sources):
4226 for line_num, line in f.ChangedContents():
4227 if deprecated_junit_framework_pattern.search(line):
4228 errors.append("%s:%d" % (f.LocalPath(), line_num))
4229
4230 results = []
4231 if errors:
4232 results.append(
4233 output_api.PresubmitError(
4234 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
4235 '(org.junit.*) from //third_party/junit. Contact yolandyan@chromium.org'
4236 ' if you have any question.', errors))
4237 return results
4238
4239
4240def _CheckAndroidTestJUnitInheritance(input_api, output_api):
4241 """Checks that if new Java test classes have inheritance.
4242 Either the new test class is JUnit3 test or it is a JUnit4 test class
4243 with a base class, either case is undesirable.
4244 """
4245 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
4246
4247 sources = lambda x: input_api.FilterSourceFile(
4248 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
4249 errors = []
4250 for f in input_api.AffectedFiles(file_filter=sources):
4251 if not f.OldContents():
4252 class_declaration_start_flag = False
4253 for line_num, line in f.ChangedContents():
4254 if class_declaration_pattern.search(line):
4255 class_declaration_start_flag = True
4256 if class_declaration_start_flag and ' extends ' in line:
4257 errors.append('%s:%d' % (f.LocalPath(), line_num))
4258 if '{' in line:
4259 class_declaration_start_flag = False
4260
4261 results = []
4262 if errors:
4263 results.append(
4264 output_api.PresubmitPromptWarning(
4265 'The newly created files include Test classes that inherits from base'
4266 ' class. Please do not use inheritance in JUnit4 tests or add new'
4267 ' JUnit3 tests. Contact yolandyan@chromium.org if you have any'
4268 ' questions.', errors))
4269 return results
4270
4271
4272def _CheckAndroidTestAnnotationUsage(input_api, output_api):
4273 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
4274 deprecated_annotation_import_pattern = input_api.re.compile(
4275 r'^import android\.test\.suitebuilder\.annotation\..*;',
4276 input_api.re.MULTILINE)
4277 sources = lambda x: input_api.FilterSourceFile(
4278 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
4279 errors = []
4280 for f in input_api.AffectedFiles(file_filter=sources):
4281 for line_num, line in f.ChangedContents():
4282 if deprecated_annotation_import_pattern.search(line):
4283 errors.append("%s:%d" % (f.LocalPath(), line_num))
4284
4285 results = []
4286 if errors:
4287 results.append(
4288 output_api.PresubmitError(
4289 'Annotations in android.test.suitebuilder.annotation have been'
Mohamed Heikal3d7a94c2023-03-28 16:55:244290 ' deprecated since API level 24. Please use androidx.test.filters'
4291 ' from //third_party/androidx:androidx_test_runner_java instead.'
Sam Maiera6e76d72022-02-11 21:43:504292 ' Contact yolandyan@chromium.org if you have any questions.',
4293 errors))
4294 return results
4295
4296
4297def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
4298 """Checks if MDPI assets are placed in a correct directory."""
Bruce Dawson6c05e852022-07-21 15:48:514299 file_filter = lambda f: (f.LocalPath().endswith(
4300 '.png') and ('/res/drawable/'.replace('/', input_api.os_path.sep) in f.
4301 LocalPath() or '/res/drawable-ldrtl/'.replace(
4302 '/', input_api.os_path.sep) in f.LocalPath()))
Sam Maiera6e76d72022-02-11 21:43:504303 errors = []
4304 for f in input_api.AffectedFiles(include_deletes=False,
4305 file_filter=file_filter):
4306 errors.append(' %s' % f.LocalPath())
4307
4308 results = []
4309 if errors:
4310 results.append(
4311 output_api.PresubmitError(
4312 'MDPI assets should be placed in /res/drawable-mdpi/ or '
4313 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
4314 '/res/drawable-ldrtl/.\n'
4315 'Contact newt@chromium.org if you have questions.', errors))
4316 return results
4317
4318
4319def _CheckAndroidWebkitImports(input_api, output_api):
4320 """Checks that code uses org.chromium.base.Callback instead of
4321 android.webview.ValueCallback except in the WebView glue layer
4322 and WebLayer.
4323 """
4324 valuecallback_import_pattern = input_api.re.compile(
4325 r'^import android\.webkit\.ValueCallback;$')
4326
4327 errors = []
4328
4329 sources = lambda affected_file: input_api.FilterSourceFile(
4330 affected_file,
4331 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4332 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314333 r'^android_webview/glue/.*',
4334 r'^weblayer/.*',
Sam Maiera6e76d72022-02-11 21:43:504335 )),
4336 files_to_check=[r'.*\.java$'])
4337
4338 for f in input_api.AffectedSourceFiles(sources):
4339 for line_num, line in f.ChangedContents():
4340 if valuecallback_import_pattern.search(line):
4341 errors.append("%s:%d" % (f.LocalPath(), line_num))
4342
4343 results = []
4344
4345 if errors:
4346 results.append(
4347 output_api.PresubmitError(
4348 'android.webkit.ValueCallback usage is detected outside of the glue'
4349 ' layer. To stay compatible with the support library, android.webkit.*'
4350 ' classes should only be used inside the glue layer and'
4351 ' org.chromium.base.Callback should be used instead.', errors))
4352
4353 return results
4354
4355
4356def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
4357 """Checks Android XML styles """
4358
4359 # Return early if no relevant files were modified.
4360 if not any(
4361 _IsXmlOrGrdFile(input_api, f.LocalPath())
4362 for f in input_api.AffectedFiles(include_deletes=False)):
4363 return []
4364
4365 import sys
4366 original_sys_path = sys.path
4367 try:
4368 sys.path = sys.path + [
4369 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4370 'android', 'checkxmlstyle')
4371 ]
4372 import checkxmlstyle
4373 finally:
4374 # Restore sys.path to what it was before.
4375 sys.path = original_sys_path
4376
4377 if is_check_on_upload:
4378 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
4379 else:
4380 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
4381
4382
4383def _CheckAndroidInfoBarDeprecation(input_api, output_api):
4384 """Checks Android Infobar Deprecation """
4385
4386 import sys
4387 original_sys_path = sys.path
4388 try:
4389 sys.path = sys.path + [
4390 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4391 'android', 'infobar_deprecation')
4392 ]
4393 import infobar_deprecation
4394 finally:
4395 # Restore sys.path to what it was before.
4396 sys.path = original_sys_path
4397
4398 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
4399
4400
4401class _PydepsCheckerResult:
4402 def __init__(self, cmd, pydeps_path, process, old_contents):
4403 self._cmd = cmd
4404 self._pydeps_path = pydeps_path
4405 self._process = process
4406 self._old_contents = old_contents
4407
4408 def GetError(self):
4409 """Returns an error message, or None."""
4410 import difflib
4411 if self._process.wait() != 0:
4412 # STDERR should already be printed.
4413 return 'Command failed: ' + self._cmd
4414 new_contents = self._process.stdout.read().splitlines()[2:]
4415 if self._old_contents != new_contents:
4416 diff = '\n'.join(
4417 difflib.context_diff(self._old_contents, new_contents))
4418 return ('File is stale: {}\n'
4419 'Diff (apply to fix):\n'
4420 '{}\n'
4421 'To regenerate, run:\n\n'
4422 ' {}').format(self._pydeps_path, diff, self._cmd)
4423 return None
4424
4425
4426class PydepsChecker:
4427 def __init__(self, input_api, pydeps_files):
4428 self._file_cache = {}
4429 self._input_api = input_api
4430 self._pydeps_files = pydeps_files
4431
4432 def _LoadFile(self, path):
4433 """Returns the list of paths within a .pydeps file relative to //."""
4434 if path not in self._file_cache:
4435 with open(path, encoding='utf-8') as f:
4436 self._file_cache[path] = f.read()
4437 return self._file_cache[path]
4438
4439 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
Gao Shenga79ebd42022-08-08 17:25:594440 """Returns an iterable of paths within the .pydep, relativized to //."""
Sam Maiera6e76d72022-02-11 21:43:504441 pydeps_data = self._LoadFile(pydeps_path)
4442 uses_gn_paths = '--gn-paths' in pydeps_data
4443 entries = (l for l in pydeps_data.splitlines()
4444 if not l.startswith('#'))
4445 if uses_gn_paths:
4446 # Paths look like: //foo/bar/baz
4447 return (e[2:] for e in entries)
4448 else:
4449 # Paths look like: path/relative/to/file.pydeps
4450 os_path = self._input_api.os_path
4451 pydeps_dir = os_path.dirname(pydeps_path)
4452 return (os_path.normpath(os_path.join(pydeps_dir, e))
4453 for e in entries)
4454
4455 def _CreateFilesToPydepsMap(self):
4456 """Returns a map of local_path -> list_of_pydeps."""
4457 ret = {}
4458 for pydep_local_path in self._pydeps_files:
4459 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
4460 ret.setdefault(path, []).append(pydep_local_path)
4461 return ret
4462
4463 def ComputeAffectedPydeps(self):
4464 """Returns an iterable of .pydeps files that might need regenerating."""
4465 affected_pydeps = set()
4466 file_to_pydeps_map = None
4467 for f in self._input_api.AffectedFiles(include_deletes=True):
4468 local_path = f.LocalPath()
4469 # Changes to DEPS can lead to .pydeps changes if any .py files are in
4470 # subrepositories. We can't figure out which files change, so re-check
4471 # all files.
4472 # Changes to print_python_deps.py affect all .pydeps.
4473 if local_path in ('DEPS', 'PRESUBMIT.py'
4474 ) or local_path.endswith('print_python_deps.py'):
4475 return self._pydeps_files
4476 elif local_path.endswith('.pydeps'):
4477 if local_path in self._pydeps_files:
4478 affected_pydeps.add(local_path)
4479 elif local_path.endswith('.py'):
4480 if file_to_pydeps_map is None:
4481 file_to_pydeps_map = self._CreateFilesToPydepsMap()
4482 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
4483 return affected_pydeps
4484
4485 def DetermineIfStaleAsync(self, pydeps_path):
4486 """Runs print_python_deps.py to see if the files is stale."""
4487 import os
4488
4489 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
4490 if old_pydeps_data:
4491 cmd = old_pydeps_data[1][1:].strip()
4492 if '--output' not in cmd:
4493 cmd += ' --output ' + pydeps_path
4494 old_contents = old_pydeps_data[2:]
4495 else:
4496 # A default cmd that should work in most cases (as long as pydeps filename
4497 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
4498 # file is empty/new.
4499 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
4500 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
4501 old_contents = []
4502 env = dict(os.environ)
4503 env['PYTHONDONTWRITEBYTECODE'] = '1'
4504 process = self._input_api.subprocess.Popen(
4505 cmd + ' --output ""',
4506 shell=True,
4507 env=env,
4508 stdout=self._input_api.subprocess.PIPE,
4509 encoding='utf-8')
4510 return _PydepsCheckerResult(cmd, pydeps_path, process, old_contents)
agrievef32bcc72016-04-04 14:57:404511
4512
Tibor Goldschwendt360793f72019-06-25 18:23:494513def _ParseGclientArgs():
Sam Maiera6e76d72022-02-11 21:43:504514 args = {}
4515 with open('build/config/gclient_args.gni', 'r') as f:
4516 for line in f:
4517 line = line.strip()
4518 if not line or line.startswith('#'):
4519 continue
4520 attribute, value = line.split('=')
4521 args[attribute.strip()] = value.strip()
4522 return args
Tibor Goldschwendt360793f72019-06-25 18:23:494523
4524
Saagar Sanghavifceeaae2020-08-12 16:40:364525def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
Sam Maiera6e76d72022-02-11 21:43:504526 """Checks if a .pydeps file needs to be regenerated."""
4527 # This check is for Python dependency lists (.pydeps files), and involves
4528 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
4529 # doesn't work on Windows and Mac, so skip it on other platforms.
4530 if not input_api.platform.startswith('linux'):
4531 return []
Erik Staabc734cd7a2021-11-23 03:11:524532
Sam Maiera6e76d72022-02-11 21:43:504533 results = []
4534 # First, check for new / deleted .pydeps.
4535 for f in input_api.AffectedFiles(include_deletes=True):
4536 # Check whether we are running the presubmit check for a file in src.
4537 # f.LocalPath is relative to repo (src, or internal repo).
4538 # os_path.exists is relative to src repo.
4539 # Therefore if os_path.exists is true, it means f.LocalPath is relative
4540 # to src and we can conclude that the pydeps is in src.
4541 if f.LocalPath().endswith('.pydeps'):
4542 if input_api.os_path.exists(f.LocalPath()):
4543 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
4544 results.append(
4545 output_api.PresubmitError(
4546 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
4547 'remove %s' % f.LocalPath()))
4548 elif f.Action() != 'D' and f.LocalPath(
4549 ) not in _ALL_PYDEPS_FILES:
4550 results.append(
4551 output_api.PresubmitError(
4552 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
4553 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:404554
Sam Maiera6e76d72022-02-11 21:43:504555 if results:
4556 return results
4557
4558 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
4559 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
4560 affected_pydeps = set(checker.ComputeAffectedPydeps())
4561 affected_android_pydeps = affected_pydeps.intersection(
4562 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
4563 if affected_android_pydeps and not is_android:
4564 results.append(
4565 output_api.PresubmitPromptOrNotify(
4566 'You have changed python files that may affect pydeps for android\n'
Gao Shenga79ebd42022-08-08 17:25:594567 'specific scripts. However, the relevant presubmit check cannot be\n'
Sam Maiera6e76d72022-02-11 21:43:504568 'run because you are not using an Android checkout. To validate that\n'
4569 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
4570 'use the android-internal-presubmit optional trybot.\n'
4571 'Possibly stale pydeps files:\n{}'.format(
4572 '\n'.join(affected_android_pydeps))))
4573
4574 all_pydeps = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
4575 pydeps_to_check = affected_pydeps.intersection(all_pydeps)
4576 # Process these concurrently, as each one takes 1-2 seconds.
4577 pydep_results = [checker.DetermineIfStaleAsync(p) for p in pydeps_to_check]
4578 for result in pydep_results:
4579 error_msg = result.GetError()
4580 if error_msg:
4581 results.append(output_api.PresubmitError(error_msg))
4582
agrievef32bcc72016-04-04 14:57:404583 return results
4584
agrievef32bcc72016-04-04 14:57:404585
Saagar Sanghavifceeaae2020-08-12 16:40:364586def CheckSingletonInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504587 """Checks to make sure no header files have |Singleton<|."""
4588
4589 def FileFilter(affected_file):
4590 # It's ok for base/memory/singleton.h to have |Singleton<|.
4591 files_to_skip = (_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
Bruce Dawson40fece62022-09-16 19:58:314592 (r"^base/memory/singleton\.h$",
4593 r"^net/quic/platform/impl/quic_singleton_impl\.h$"))
Sam Maiera6e76d72022-02-11 21:43:504594 return input_api.FilterSourceFile(affected_file,
4595 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:434596
Sam Maiera6e76d72022-02-11 21:43:504597 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
4598 files = []
4599 for f in input_api.AffectedSourceFiles(FileFilter):
4600 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx')
4601 or f.LocalPath().endswith('.hpp')
4602 or f.LocalPath().endswith('.inl')):
4603 contents = input_api.ReadFile(f)
4604 for line in contents.splitlines(False):
4605 if (not line.lstrip().startswith('//')
4606 and # Strip C++ comment.
4607 pattern.search(line)):
4608 files.append(f)
4609 break
glidere61efad2015-02-18 17:39:434610
Sam Maiera6e76d72022-02-11 21:43:504611 if files:
4612 return [
4613 output_api.PresubmitError(
4614 'Found base::Singleton<T> in the following header files.\n' +
4615 'Please move them to an appropriate source file so that the ' +
4616 'template gets instantiated in a single compilation unit.',
4617 files)
4618 ]
4619 return []
glidere61efad2015-02-18 17:39:434620
4621
jchaffraix@chromium.orgfd20b902014-05-09 02:14:534622_DEPRECATED_CSS = [
4623 # Values
4624 ( "-webkit-box", "flex" ),
4625 ( "-webkit-inline-box", "inline-flex" ),
4626 ( "-webkit-flex", "flex" ),
4627 ( "-webkit-inline-flex", "inline-flex" ),
4628 ( "-webkit-min-content", "min-content" ),
4629 ( "-webkit-max-content", "max-content" ),
4630
4631 # Properties
4632 ( "-webkit-background-clip", "background-clip" ),
4633 ( "-webkit-background-origin", "background-origin" ),
4634 ( "-webkit-background-size", "background-size" ),
4635 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:444636 ( "-webkit-user-select", "user-select" ),
jchaffraix@chromium.orgfd20b902014-05-09 02:14:534637
4638 # Functions
4639 ( "-webkit-gradient", "gradient" ),
4640 ( "-webkit-repeating-gradient", "repeating-gradient" ),
4641 ( "-webkit-linear-gradient", "linear-gradient" ),
4642 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
4643 ( "-webkit-radial-gradient", "radial-gradient" ),
4644 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
4645]
4646
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:204647
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:494648# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:364649def CheckNoDeprecatedCss(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504650 """ Make sure that we don't use deprecated CSS
4651 properties, functions or values. Our external
4652 documentation and iOS CSS for dom distiller
4653 (reader mode) are ignored by the hooks as it
4654 needs to be consumed by WebKit. """
4655 results = []
4656 file_inclusion_pattern = [r".+\.css$"]
4657 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
4658 input_api.DEFAULT_FILES_TO_SKIP +
4659 (r"^chrome/common/extensions/docs", r"^chrome/docs",
4660 r"^native_client_sdk"))
4661 file_filter = lambda f: input_api.FilterSourceFile(
4662 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
4663 for fpath in input_api.AffectedFiles(file_filter=file_filter):
4664 for line_num, line in fpath.ChangedContents():
4665 for (deprecated_value, value) in _DEPRECATED_CSS:
4666 if deprecated_value in line:
4667 results.append(
4668 output_api.PresubmitError(
4669 "%s:%d: Use of deprecated CSS %s, use %s instead" %
4670 (fpath.LocalPath(), line_num, deprecated_value,
4671 value)))
4672 return results
jchaffraix@chromium.orgfd20b902014-05-09 02:14:534673
mohan.reddyf21db962014-10-16 12:26:474674
Saagar Sanghavifceeaae2020-08-12 16:40:364675def CheckForRelativeIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504676 bad_files = {}
4677 for f in input_api.AffectedFiles(include_deletes=False):
4678 if (f.LocalPath().startswith('third_party')
4679 and not f.LocalPath().startswith('third_party/blink')
4680 and not f.LocalPath().startswith('third_party\\blink')):
4681 continue
rlanday6802cf632017-05-30 17:48:364682
Sam Maiera6e76d72022-02-11 21:43:504683 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
4684 continue
rlanday6802cf632017-05-30 17:48:364685
Sam Maiera6e76d72022-02-11 21:43:504686 relative_includes = [
4687 line for _, line in f.ChangedContents()
4688 if "#include" in line and "../" in line
4689 ]
4690 if not relative_includes:
4691 continue
4692 bad_files[f.LocalPath()] = relative_includes
rlanday6802cf632017-05-30 17:48:364693
Sam Maiera6e76d72022-02-11 21:43:504694 if not bad_files:
4695 return []
rlanday6802cf632017-05-30 17:48:364696
Sam Maiera6e76d72022-02-11 21:43:504697 error_descriptions = []
4698 for file_path, bad_lines in bad_files.items():
4699 error_description = file_path
4700 for line in bad_lines:
4701 error_description += '\n ' + line
4702 error_descriptions.append(error_description)
rlanday6802cf632017-05-30 17:48:364703
Sam Maiera6e76d72022-02-11 21:43:504704 results = []
4705 results.append(
4706 output_api.PresubmitError(
4707 'You added one or more relative #include paths (including "../").\n'
4708 'These shouldn\'t be used because they can be used to include headers\n'
4709 'from code that\'s not correctly specified as a dependency in the\n'
4710 'relevant BUILD.gn file(s).', error_descriptions))
rlanday6802cf632017-05-30 17:48:364711
Sam Maiera6e76d72022-02-11 21:43:504712 return results
rlanday6802cf632017-05-30 17:48:364713
Takeshi Yoshinoe387aa32017-08-02 13:16:134714
Saagar Sanghavifceeaae2020-08-12 16:40:364715def CheckForCcIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504716 """Check that nobody tries to include a cc file. It's a relatively
4717 common error which results in duplicate symbols in object
4718 files. This may not always break the build until someone later gets
4719 very confusing linking errors."""
4720 results = []
4721 for f in input_api.AffectedFiles(include_deletes=False):
4722 # We let third_party code do whatever it wants
4723 if (f.LocalPath().startswith('third_party')
4724 and not f.LocalPath().startswith('third_party/blink')
4725 and not f.LocalPath().startswith('third_party\\blink')):
4726 continue
Daniel Bratell65b033262019-04-23 08:17:064727
Sam Maiera6e76d72022-02-11 21:43:504728 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
4729 continue
Daniel Bratell65b033262019-04-23 08:17:064730
Sam Maiera6e76d72022-02-11 21:43:504731 for _, line in f.ChangedContents():
4732 if line.startswith('#include "'):
4733 included_file = line.split('"')[1]
4734 if _IsCPlusPlusFile(input_api, included_file):
4735 # The most common naming for external files with C++ code,
4736 # apart from standard headers, is to call them foo.inc, but
4737 # Chromium sometimes uses foo-inc.cc so allow that as well.
4738 if not included_file.endswith(('.h', '-inc.cc')):
4739 results.append(
4740 output_api.PresubmitError(
4741 'Only header files or .inc files should be included in other\n'
4742 'C++ files. Compiling the contents of a cc file more than once\n'
4743 'will cause duplicate information in the build which may later\n'
4744 'result in strange link_errors.\n' +
4745 f.LocalPath() + ':\n ' + line))
Daniel Bratell65b033262019-04-23 08:17:064746
Sam Maiera6e76d72022-02-11 21:43:504747 return results
Daniel Bratell65b033262019-04-23 08:17:064748
4749
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204750def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
Sam Maiera6e76d72022-02-11 21:43:504751 if not isinstance(key, ast.Str):
4752 return 'Key at line %d must be a string literal' % key.lineno
4753 if not isinstance(value, ast.Dict):
4754 return 'Value at line %d must be a dict' % value.lineno
4755 if len(value.keys) != 1:
4756 return 'Dict at line %d must have single entry' % value.lineno
4757 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
4758 return (
4759 'Entry at line %d must have a string literal \'filepath\' as key' %
4760 value.lineno)
4761 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:134762
Takeshi Yoshinoe387aa32017-08-02 13:16:134763
Sergey Ulanov4af16052018-11-08 02:41:464764def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Sam Maiera6e76d72022-02-11 21:43:504765 if not isinstance(key, ast.Str):
4766 return 'Key at line %d must be a string literal' % key.lineno
4767 if not isinstance(value, ast.List):
4768 return 'Value at line %d must be a list' % value.lineno
4769 for element in value.elts:
4770 if not isinstance(element, ast.Str):
4771 return 'Watchlist elements on line %d is not a string' % key.lineno
4772 if not email_regex.match(element.s):
4773 return ('Watchlist element on line %d doesn\'t look like a valid '
4774 + 'email: %s') % (key.lineno, element.s)
4775 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:134776
Takeshi Yoshinoe387aa32017-08-02 13:16:134777
Sergey Ulanov4af16052018-11-08 02:41:464778def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Sam Maiera6e76d72022-02-11 21:43:504779 mismatch_template = (
4780 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
4781 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:134782
Sam Maiera6e76d72022-02-11 21:43:504783 email_regex = input_api.re.compile(
4784 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
Sergey Ulanov4af16052018-11-08 02:41:464785
Sam Maiera6e76d72022-02-11 21:43:504786 ast = input_api.ast
4787 i = 0
4788 last_key = ''
4789 while True:
4790 if i >= len(wd_dict.keys):
4791 if i >= len(w_dict.keys):
4792 return None
4793 return mismatch_template % ('missing',
4794 'line %d' % w_dict.keys[i].lineno)
4795 elif i >= len(w_dict.keys):
4796 return (mismatch_template %
4797 ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:134798
Sam Maiera6e76d72022-02-11 21:43:504799 wd_key = wd_dict.keys[i]
4800 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:134801
Sam Maiera6e76d72022-02-11 21:43:504802 result = _CheckWatchlistDefinitionsEntrySyntax(wd_key,
4803 wd_dict.values[i], ast)
4804 if result is not None:
4805 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:134806
Sam Maiera6e76d72022-02-11 21:43:504807 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast,
4808 email_regex)
4809 if result is not None:
4810 return 'Bad entry in WATCHLISTS dict: %s' % result
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204811
Sam Maiera6e76d72022-02-11 21:43:504812 if wd_key.s != w_key.s:
4813 return mismatch_template % ('%s at line %d' %
4814 (wd_key.s, wd_key.lineno),
4815 '%s at line %d' %
4816 (w_key.s, w_key.lineno))
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204817
Sam Maiera6e76d72022-02-11 21:43:504818 if wd_key.s < last_key:
4819 return (
4820 'WATCHLISTS dict is not sorted lexicographically at line %d and %d'
4821 % (wd_key.lineno, w_key.lineno))
4822 last_key = wd_key.s
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204823
Sam Maiera6e76d72022-02-11 21:43:504824 i = i + 1
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204825
4826
Sergey Ulanov4af16052018-11-08 02:41:464827def _CheckWATCHLISTSSyntax(expression, input_api):
Sam Maiera6e76d72022-02-11 21:43:504828 ast = input_api.ast
4829 if not isinstance(expression, ast.Expression):
4830 return 'WATCHLISTS file must contain a valid expression'
4831 dictionary = expression.body
4832 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
4833 return 'WATCHLISTS file must have single dict with exactly two entries'
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204834
Sam Maiera6e76d72022-02-11 21:43:504835 first_key = dictionary.keys[0]
4836 first_value = dictionary.values[0]
4837 second_key = dictionary.keys[1]
4838 second_value = dictionary.values[1]
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204839
Sam Maiera6e76d72022-02-11 21:43:504840 if (not isinstance(first_key, ast.Str)
4841 or first_key.s != 'WATCHLIST_DEFINITIONS'
4842 or not isinstance(first_value, ast.Dict)):
4843 return ('The first entry of the dict in WATCHLISTS file must be '
4844 'WATCHLIST_DEFINITIONS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204845
Sam Maiera6e76d72022-02-11 21:43:504846 if (not isinstance(second_key, ast.Str) or second_key.s != 'WATCHLISTS'
4847 or not isinstance(second_value, ast.Dict)):
4848 return ('The second entry of the dict in WATCHLISTS file must be '
4849 'WATCHLISTS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204850
Sam Maiera6e76d72022-02-11 21:43:504851 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:134852
4853
Saagar Sanghavifceeaae2020-08-12 16:40:364854def CheckWATCHLISTS(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504855 for f in input_api.AffectedFiles(include_deletes=False):
4856 if f.LocalPath() == 'WATCHLISTS':
4857 contents = input_api.ReadFile(f, 'r')
Takeshi Yoshinoe387aa32017-08-02 13:16:134858
Sam Maiera6e76d72022-02-11 21:43:504859 try:
4860 # First, make sure that it can be evaluated.
4861 input_api.ast.literal_eval(contents)
4862 # Get an AST tree for it and scan the tree for detailed style checking.
4863 expression = input_api.ast.parse(contents,
4864 filename='WATCHLISTS',
4865 mode='eval')
4866 except ValueError as e:
4867 return [
4868 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4869 long_text=repr(e))
4870 ]
4871 except SyntaxError as e:
4872 return [
4873 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4874 long_text=repr(e))
4875 ]
4876 except TypeError as e:
4877 return [
4878 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4879 long_text=repr(e))
4880 ]
Takeshi Yoshinoe387aa32017-08-02 13:16:134881
Sam Maiera6e76d72022-02-11 21:43:504882 result = _CheckWATCHLISTSSyntax(expression, input_api)
4883 if result is not None:
4884 return [output_api.PresubmitError(result)]
4885 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134886
Sam Maiera6e76d72022-02-11 21:43:504887 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:134888
Sean Kaucb7c9b32022-10-25 21:25:524889def CheckGnRebasePath(input_api, output_api):
4890 """Checks that target_gen_dir is not used wtih "//" in rebase_path().
4891
4892 Developers should use root_build_dir instead of "//" when using target_gen_dir because
4893 Chromium is sometimes built outside of the source tree.
4894 """
4895
4896 def gn_files(f):
4897 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
4898
4899 rebase_path_regex = input_api.re.compile(r'rebase_path\(("\$target_gen_dir"|target_gen_dir), ("/"|"//")\)')
4900 problems = []
4901 for f in input_api.AffectedSourceFiles(gn_files):
4902 for line_num, line in f.ChangedContents():
4903 if rebase_path_regex.search(line):
4904 problems.append(
4905 'Absolute path in rebase_path() in %s:%d' %
4906 (f.LocalPath(), line_num))
4907
4908 if problems:
4909 return [
4910 output_api.PresubmitPromptWarning(
4911 'Using an absolute path in rebase_path()',
4912 items=sorted(problems),
4913 long_text=(
4914 'rebase_path() should use root_build_dir instead of "/" ',
4915 'since builds can be initiated from outside of the source ',
4916 'root.'))
4917 ]
4918 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:134919
Andrew Grieve1b290e4a22020-11-24 20:07:014920def CheckGnGlobForward(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504921 """Checks that forward_variables_from(invoker, "*") follows best practices.
Andrew Grieve1b290e4a22020-11-24 20:07:014922
Sam Maiera6e76d72022-02-11 21:43:504923 As documented at //build/docs/writing_gn_templates.md
4924 """
Andrew Grieve1b290e4a22020-11-24 20:07:014925
Sam Maiera6e76d72022-02-11 21:43:504926 def gn_files(f):
4927 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
Andrew Grieve1b290e4a22020-11-24 20:07:014928
Sam Maiera6e76d72022-02-11 21:43:504929 problems = []
4930 for f in input_api.AffectedSourceFiles(gn_files):
4931 for line_num, line in f.ChangedContents():
4932 if 'forward_variables_from(invoker, "*")' in line:
4933 problems.append(
4934 'Bare forward_variables_from(invoker, "*") in %s:%d' %
4935 (f.LocalPath(), line_num))
4936
4937 if problems:
4938 return [
4939 output_api.PresubmitPromptWarning(
4940 'forward_variables_from("*") without exclusions',
4941 items=sorted(problems),
4942 long_text=(
Gao Shenga79ebd42022-08-08 17:25:594943 'The variables "visibility" and "test_only" should be '
Sam Maiera6e76d72022-02-11 21:43:504944 'explicitly listed in forward_variables_from(). For more '
4945 'details, see:\n'
4946 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
4947 'build/docs/writing_gn_templates.md'
4948 '#Using-forward_variables_from'))
4949 ]
4950 return []
Andrew Grieve1b290e4a22020-11-24 20:07:014951
Saagar Sanghavifceeaae2020-08-12 16:40:364952def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504953 """Checks that newly added header files have corresponding GN changes.
4954 Note that this is only a heuristic. To be precise, run script:
4955 build/check_gn_headers.py.
4956 """
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194957
Sam Maiera6e76d72022-02-11 21:43:504958 def headers(f):
4959 return input_api.FilterSourceFile(
4960 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194961
Sam Maiera6e76d72022-02-11 21:43:504962 new_headers = []
4963 for f in input_api.AffectedSourceFiles(headers):
4964 if f.Action() != 'A':
4965 continue
4966 new_headers.append(f.LocalPath())
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194967
Sam Maiera6e76d72022-02-11 21:43:504968 def gn_files(f):
4969 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194970
Sam Maiera6e76d72022-02-11 21:43:504971 all_gn_changed_contents = ''
4972 for f in input_api.AffectedSourceFiles(gn_files):
4973 for _, line in f.ChangedContents():
4974 all_gn_changed_contents += line
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194975
Sam Maiera6e76d72022-02-11 21:43:504976 problems = []
4977 for header in new_headers:
4978 basename = input_api.os_path.basename(header)
4979 if basename not in all_gn_changed_contents:
4980 problems.append(header)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194981
Sam Maiera6e76d72022-02-11 21:43:504982 if problems:
4983 return [
4984 output_api.PresubmitPromptWarning(
4985 'Missing GN changes for new header files',
4986 items=sorted(problems),
4987 long_text=
4988 'Please double check whether newly added header files need '
4989 'corresponding changes in gn or gni files.\nThis checking is only a '
4990 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4991 'Read https://crbug.com/661774 for more info.')
4992 ]
4993 return []
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194994
4995
Saagar Sanghavifceeaae2020-08-12 16:40:364996def CheckCorrectProductNameInMessages(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504997 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
Michael Giuffridad3bc8672018-10-25 22:48:024998
Sam Maiera6e76d72022-02-11 21:43:504999 This assumes we won't intentionally reference one product from the other
5000 product.
5001 """
5002 all_problems = []
5003 test_cases = [{
5004 "filename_postfix": "google_chrome_strings.grd",
5005 "correct_name": "Chrome",
5006 "incorrect_name": "Chromium",
5007 }, {
5008 "filename_postfix": "chromium_strings.grd",
5009 "correct_name": "Chromium",
5010 "incorrect_name": "Chrome",
5011 }]
Michael Giuffridad3bc8672018-10-25 22:48:025012
Sam Maiera6e76d72022-02-11 21:43:505013 for test_case in test_cases:
5014 problems = []
5015 filename_filter = lambda x: x.LocalPath().endswith(test_case[
5016 "filename_postfix"])
Michael Giuffridad3bc8672018-10-25 22:48:025017
Sam Maiera6e76d72022-02-11 21:43:505018 # Check each new line. Can yield false positives in multiline comments, but
5019 # easier than trying to parse the XML because messages can have nested
5020 # children, and associating message elements with affected lines is hard.
5021 for f in input_api.AffectedSourceFiles(filename_filter):
5022 for line_num, line in f.ChangedContents():
5023 if "<message" in line or "<!--" in line or "-->" in line:
5024 continue
5025 if test_case["incorrect_name"] in line:
5026 problems.append("Incorrect product name in %s:%d" %
5027 (f.LocalPath(), line_num))
Michael Giuffridad3bc8672018-10-25 22:48:025028
Sam Maiera6e76d72022-02-11 21:43:505029 if problems:
5030 message = (
5031 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
5032 % (test_case["correct_name"], test_case["correct_name"],
5033 test_case["incorrect_name"]))
5034 all_problems.append(
5035 output_api.PresubmitPromptWarning(message, items=problems))
Michael Giuffridad3bc8672018-10-25 22:48:025036
Sam Maiera6e76d72022-02-11 21:43:505037 return all_problems
Michael Giuffridad3bc8672018-10-25 22:48:025038
5039
Saagar Sanghavifceeaae2020-08-12 16:40:365040def CheckForTooLargeFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505041 """Avoid large files, especially binary files, in the repository since
5042 git doesn't scale well for those. They will be in everyone's repo
5043 clones forever, forever making Chromium slower to clone and work
5044 with."""
Daniel Bratell93eb6c62019-04-29 20:13:365045
Sam Maiera6e76d72022-02-11 21:43:505046 # Uploading files to cloud storage is not trivial so we don't want
5047 # to set the limit too low, but the upper limit for "normal" large
5048 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
5049 # anything over 20 MB is exceptional.
Bruce Dawsonbb414db2022-12-27 20:21:255050 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024
Daniel Bratell93eb6c62019-04-29 20:13:365051
Sam Maiera6e76d72022-02-11 21:43:505052 too_large_files = []
5053 for f in input_api.AffectedFiles():
5054 # Check both added and modified files (but not deleted files).
5055 if f.Action() in ('A', 'M'):
5056 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Joe DeBlasio10a832f2023-04-21 20:20:185057 if size > TOO_LARGE_FILE_SIZE_LIMIT:
Sam Maiera6e76d72022-02-11 21:43:505058 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
Daniel Bratell93eb6c62019-04-29 20:13:365059
Sam Maiera6e76d72022-02-11 21:43:505060 if too_large_files:
5061 message = (
5062 'Do not commit large files to git since git scales badly for those.\n'
5063 +
5064 'Instead put the large files in cloud storage and use DEPS to\n' +
5065 'fetch them.\n' + '\n'.join(too_large_files))
5066 return [
5067 output_api.PresubmitError('Too large files found in commit',
5068 long_text=message + '\n')
5069 ]
5070 else:
5071 return []
Daniel Bratell93eb6c62019-04-29 20:13:365072
Max Morozb47503b2019-08-08 21:03:275073
Saagar Sanghavifceeaae2020-08-12 16:40:365074def CheckFuzzTargetsOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505075 """Checks specific for fuzz target sources."""
5076 EXPORTED_SYMBOLS = [
5077 'LLVMFuzzerInitialize',
5078 'LLVMFuzzerCustomMutator',
5079 'LLVMFuzzerCustomCrossOver',
5080 'LLVMFuzzerMutate',
5081 ]
Max Morozb47503b2019-08-08 21:03:275082
Sam Maiera6e76d72022-02-11 21:43:505083 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
Max Morozb47503b2019-08-08 21:03:275084
Sam Maiera6e76d72022-02-11 21:43:505085 def FilterFile(affected_file):
5086 """Ignore libFuzzer source code."""
5087 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
Bruce Dawson40fece62022-09-16 19:58:315088 files_to_skip = r"^third_party/libFuzzer"
Max Morozb47503b2019-08-08 21:03:275089
Sam Maiera6e76d72022-02-11 21:43:505090 return input_api.FilterSourceFile(affected_file,
5091 files_to_check=[files_to_check],
5092 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:275093
Sam Maiera6e76d72022-02-11 21:43:505094 files_with_missing_header = []
5095 for f in input_api.AffectedSourceFiles(FilterFile):
5096 contents = input_api.ReadFile(f, 'r')
5097 if REQUIRED_HEADER in contents:
5098 continue
Max Morozb47503b2019-08-08 21:03:275099
Sam Maiera6e76d72022-02-11 21:43:505100 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
5101 files_with_missing_header.append(f.LocalPath())
Max Morozb47503b2019-08-08 21:03:275102
Sam Maiera6e76d72022-02-11 21:43:505103 if not files_with_missing_header:
5104 return []
Max Morozb47503b2019-08-08 21:03:275105
Sam Maiera6e76d72022-02-11 21:43:505106 long_text = (
5107 'If you define any of the libFuzzer optional functions (%s), it is '
5108 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
5109 'work incorrectly on Mac (crbug.com/687076).\nNote that '
5110 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
5111 'to access command line arguments passed to the fuzzer. Instead, prefer '
5112 'static initialization and shared resources as documented in '
5113 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
5114 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n'
5115 % (', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER))
Max Morozb47503b2019-08-08 21:03:275116
Sam Maiera6e76d72022-02-11 21:43:505117 return [
5118 output_api.PresubmitPromptWarning(message="Missing '%s' in:" %
5119 REQUIRED_HEADER,
5120 items=files_with_missing_header,
5121 long_text=long_text)
5122 ]
Max Morozb47503b2019-08-08 21:03:275123
5124
Mohamed Heikald048240a2019-11-12 16:57:375125def _CheckNewImagesWarning(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505126 """
5127 Warns authors who add images into the repo to make sure their images are
5128 optimized before committing.
5129 """
5130 images_added = False
5131 image_paths = []
5132 errors = []
5133 filter_lambda = lambda x: input_api.FilterSourceFile(
5134 x,
5135 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
5136 DEFAULT_FILES_TO_SKIP),
5137 files_to_check=[r'.*\/(drawable|mipmap)'])
5138 for f in input_api.AffectedFiles(include_deletes=False,
5139 file_filter=filter_lambda):
5140 local_path = f.LocalPath().lower()
5141 if any(
5142 local_path.endswith(extension)
5143 for extension in _IMAGE_EXTENSIONS):
5144 images_added = True
5145 image_paths.append(f)
5146 if images_added:
5147 errors.append(
5148 output_api.PresubmitPromptWarning(
5149 'It looks like you are trying to commit some images. If these are '
5150 'non-test-only images, please make sure to read and apply the tips in '
5151 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
5152 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
5153 'FYI only and will not block your CL on the CQ.', image_paths))
5154 return errors
Mohamed Heikald048240a2019-11-12 16:57:375155
5156
Saagar Sanghavifceeaae2020-08-12 16:40:365157def ChecksAndroidSpecificOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505158 """Groups upload checks that target android code."""
5159 results = []
5160 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
5161 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
5162 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
5163 results.extend(_CheckAndroidToastUsage(input_api, output_api))
5164 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
5165 results.extend(_CheckAndroidTestJUnitFrameworkImport(
5166 input_api, output_api))
5167 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
5168 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
5169 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
5170 results.extend(_CheckNewImagesWarning(input_api, output_api))
5171 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
5172 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
5173 return results
5174
Becky Zhou7c69b50992018-12-10 19:37:575175
Saagar Sanghavifceeaae2020-08-12 16:40:365176def ChecksAndroidSpecificOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505177 """Groups commit checks that target android code."""
5178 results = []
5179 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
5180 return results
dgnaa68d5e2015-06-10 10:08:225181
Chris Hall59f8d0c72020-05-01 07:31:195182# TODO(chrishall): could we additionally match on any path owned by
5183# ui/accessibility/OWNERS ?
5184_ACCESSIBILITY_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:315185 r"^chrome/browser.*/accessibility/",
5186 r"^chrome/browser/extensions/api/automation.*/",
5187 r"^chrome/renderer/extensions/accessibility_.*",
5188 r"^chrome/tests/data/accessibility/",
Katie Dektar58ef07b2022-09-27 13:19:175189 r"^components/services/screen_ai/",
Bruce Dawson40fece62022-09-16 19:58:315190 r"^content/browser/accessibility/",
5191 r"^content/renderer/accessibility/",
5192 r"^content/tests/data/accessibility/",
5193 r"^extensions/renderer/api/automation/",
Katie Dektar58ef07b2022-09-27 13:19:175194 r"^services/accessibility/",
Bruce Dawson40fece62022-09-16 19:58:315195 r"^ui/accessibility/",
5196 r"^ui/views/accessibility/",
Chris Hall59f8d0c72020-05-01 07:31:195197)
5198
Saagar Sanghavifceeaae2020-08-12 16:40:365199def CheckAccessibilityRelnotesField(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505200 """Checks that commits to accessibility code contain an AX-Relnotes field in
5201 their commit message."""
Chris Hall59f8d0c72020-05-01 07:31:195202
Sam Maiera6e76d72022-02-11 21:43:505203 def FileFilter(affected_file):
5204 paths = _ACCESSIBILITY_PATHS
5205 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:195206
Sam Maiera6e76d72022-02-11 21:43:505207 # Only consider changes affecting accessibility paths.
5208 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
5209 return []
Akihiro Ota08108e542020-05-20 15:30:535210
Sam Maiera6e76d72022-02-11 21:43:505211 # AX-Relnotes can appear in either the description or the footer.
5212 # When searching the description, require 'AX-Relnotes:' to appear at the
5213 # beginning of a line.
5214 ax_regex = input_api.re.compile('ax-relnotes[:=]')
5215 description_has_relnotes = any(
5216 ax_regex.match(line)
5217 for line in input_api.change.DescriptionText().lower().splitlines())
Chris Hall59f8d0c72020-05-01 07:31:195218
Sam Maiera6e76d72022-02-11 21:43:505219 footer_relnotes = input_api.change.GitFootersFromDescription().get(
5220 'AX-Relnotes', [])
5221 if description_has_relnotes or footer_relnotes:
5222 return []
Chris Hall59f8d0c72020-05-01 07:31:195223
Sam Maiera6e76d72022-02-11 21:43:505224 # TODO(chrishall): link to Relnotes documentation in message.
5225 message = (
5226 "Missing 'AX-Relnotes:' field required for accessibility changes"
5227 "\n please add 'AX-Relnotes: [release notes].' to describe any "
5228 "user-facing changes"
5229 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
5230 "user-facing effects"
5231 "\n if this is confusing or annoying then please contact members "
5232 "of ui/accessibility/OWNERS.")
5233
5234 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:225235
Mark Schillacie5a0be22022-01-19 00:38:395236
5237_ACCESSIBILITY_EVENTS_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315238 r"^content/test/data/accessibility/event/.*\.html",
Mark Schillacie5a0be22022-01-19 00:38:395239)
5240
5241_ACCESSIBILITY_TREE_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315242 r"^content/test/data/accessibility/accname/.*\.html",
5243 r"^content/test/data/accessibility/aria/.*\.html",
5244 r"^content/test/data/accessibility/css/.*\.html",
5245 r"^content/test/data/accessibility/html/.*\.html",
Mark Schillacie5a0be22022-01-19 00:38:395246)
5247
5248_ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315249 r"^.*/WebContentsAccessibilityEventsTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:395250)
5251
5252_ACCESSIBILITY_ANDROID_TREE_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315253 r"^.*/WebContentsAccessibilityTreeTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:395254)
5255
5256def CheckAccessibilityEventsTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505257 """Checks that commits that include a newly added, renamed/moved, or deleted
5258 test in the DumpAccessibilityEventsTest suite also includes a corresponding
5259 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:395260
Sam Maiera6e76d72022-02-11 21:43:505261 def FilePathFilter(affected_file):
5262 paths = _ACCESSIBILITY_EVENTS_TEST_PATH
5263 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395264
Sam Maiera6e76d72022-02-11 21:43:505265 def AndroidFilePathFilter(affected_file):
5266 paths = _ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH
5267 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395268
Sam Maiera6e76d72022-02-11 21:43:505269 # Only consider changes in the events test data path with html type.
5270 if not any(
5271 input_api.AffectedFiles(include_deletes=True,
5272 file_filter=FilePathFilter)):
5273 return []
Mark Schillacie5a0be22022-01-19 00:38:395274
Sam Maiera6e76d72022-02-11 21:43:505275 # If the commit contains any change to the Android test file, ignore.
5276 if any(
5277 input_api.AffectedFiles(include_deletes=True,
5278 file_filter=AndroidFilePathFilter)):
5279 return []
Mark Schillacie5a0be22022-01-19 00:38:395280
Sam Maiera6e76d72022-02-11 21:43:505281 # Only consider changes that are adding/renaming or deleting a file
5282 message = []
5283 for f in input_api.AffectedFiles(include_deletes=True,
5284 file_filter=FilePathFilter):
5285 if f.Action() == 'A' or f.Action() == 'D':
5286 message = (
5287 "It appears that you are adding, renaming or deleting"
5288 "\na dump_accessibility_events* test, but have not included"
5289 "\na corresponding change for Android."
5290 "\nPlease include (or remove) the test from:"
5291 "\n content/public/android/javatests/src/org/chromium/"
5292 "content/browser/accessibility/"
5293 "WebContentsAccessibilityEventsTest.java"
5294 "\nIf this message is confusing or annoying, please contact"
5295 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:395296
Sam Maiera6e76d72022-02-11 21:43:505297 # If no message was set, return empty.
5298 if not len(message):
5299 return []
5300
5301 return [output_api.PresubmitPromptWarning(message)]
5302
Mark Schillacie5a0be22022-01-19 00:38:395303
5304def CheckAccessibilityTreeTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505305 """Checks that commits that include a newly added, renamed/moved, or deleted
5306 test in the DumpAccessibilityTreeTest suite also includes a corresponding
5307 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:395308
Sam Maiera6e76d72022-02-11 21:43:505309 def FilePathFilter(affected_file):
5310 paths = _ACCESSIBILITY_TREE_TEST_PATH
5311 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395312
Sam Maiera6e76d72022-02-11 21:43:505313 def AndroidFilePathFilter(affected_file):
5314 paths = _ACCESSIBILITY_ANDROID_TREE_TEST_PATH
5315 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395316
Sam Maiera6e76d72022-02-11 21:43:505317 # Only consider changes in the various tree test data paths with html type.
5318 if not any(
5319 input_api.AffectedFiles(include_deletes=True,
5320 file_filter=FilePathFilter)):
5321 return []
Mark Schillacie5a0be22022-01-19 00:38:395322
Sam Maiera6e76d72022-02-11 21:43:505323 # If the commit contains any change to the Android test file, ignore.
5324 if any(
5325 input_api.AffectedFiles(include_deletes=True,
5326 file_filter=AndroidFilePathFilter)):
5327 return []
Mark Schillacie5a0be22022-01-19 00:38:395328
Sam Maiera6e76d72022-02-11 21:43:505329 # Only consider changes that are adding/renaming or deleting a file
5330 message = []
5331 for f in input_api.AffectedFiles(include_deletes=True,
5332 file_filter=FilePathFilter):
5333 if f.Action() == 'A' or f.Action() == 'D':
5334 message = (
5335 "It appears that you are adding, renaming or deleting"
5336 "\na dump_accessibility_tree* test, but have not included"
5337 "\na corresponding change for Android."
5338 "\nPlease include (or remove) the test from:"
5339 "\n content/public/android/javatests/src/org/chromium/"
5340 "content/browser/accessibility/"
5341 "WebContentsAccessibilityTreeTest.java"
5342 "\nIf this message is confusing or annoying, please contact"
5343 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:395344
Sam Maiera6e76d72022-02-11 21:43:505345 # If no message was set, return empty.
5346 if not len(message):
5347 return []
5348
5349 return [output_api.PresubmitPromptWarning(message)]
Mark Schillacie5a0be22022-01-19 00:38:395350
5351
Bruce Dawson33806592022-11-16 01:44:515352def CheckEsLintConfigChanges(input_api, output_api):
5353 """Suggest using "git cl presubmit --files" when .eslintrc.js files are
5354 modified. This is important because enabling an error in .eslintrc.js can
5355 trigger errors in any .js or .ts files in its directory, leading to hidden
5356 presubmit errors."""
5357 results = []
5358 eslint_filter = lambda f: input_api.FilterSourceFile(
5359 f, files_to_check=[r'.*\.eslintrc\.js$'])
5360 for f in input_api.AffectedFiles(include_deletes=False,
5361 file_filter=eslint_filter):
5362 local_dir = input_api.os_path.dirname(f.LocalPath())
5363 # Use / characters so that the commands printed work on any OS.
5364 local_dir = local_dir.replace(input_api.os_path.sep, '/')
5365 if local_dir:
5366 local_dir += '/'
5367 results.append(
5368 output_api.PresubmitNotifyResult(
5369 '%(file)s modified. Consider running \'git cl presubmit --files '
5370 '"%(dir)s*.js;%(dir)s*.ts"\' in order to check and fix the affected '
5371 'files before landing this change.' %
5372 { 'file' : f.LocalPath(), 'dir' : local_dir}))
5373 return results
5374
5375
seanmccullough4a9356252021-04-08 19:54:095376# string pattern, sequence of strings to show when pattern matches,
5377# error flag. True if match is a presubmit error, otherwise it's a warning.
5378_NON_INCLUSIVE_TERMS = (
5379 (
5380 # Note that \b pattern in python re is pretty particular. In this
5381 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
5382 # ...' will not. This may require some tweaking to catch these cases
5383 # without triggering a lot of false positives. Leaving it naive and
5384 # less matchy for now.
seanmccullough56d1e3cf2021-12-03 18:18:325385 r'/\b(?i)((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:095386 (
5387 'Please don\'t use blacklist, whitelist, ' # nocheck
5388 'or slave in your', # nocheck
5389 'code and make every effort to use other terms. Using "// nocheck"',
5390 '"# nocheck" or "<!-- nocheck -->"',
5391 'at the end of the offending line will bypass this PRESUBMIT error',
5392 'but avoid using this whenever possible. Reach out to',
5393 'community@chromium.org if you have questions'),
5394 True),)
5395
Saagar Sanghavifceeaae2020-08-12 16:40:365396def ChecksCommon(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505397 """Checks common to both upload and commit."""
5398 results = []
Eric Boren6fd2b932018-01-25 15:05:085399 results.extend(
Sam Maiera6e76d72022-02-11 21:43:505400 input_api.canned_checks.PanProjectChecks(
5401 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:085402
Sam Maiera6e76d72022-02-11 21:43:505403 author = input_api.change.author_email
5404 if author and author not in _KNOWN_ROBOTS:
5405 results.extend(
5406 input_api.canned_checks.CheckAuthorizedAuthor(
5407 input_api, output_api))
marja@chromium.org2299dcf2012-11-15 19:56:245408
Sam Maiera6e76d72022-02-11 21:43:505409 results.extend(
5410 input_api.canned_checks.CheckChangeHasNoTabs(
5411 input_api,
5412 output_api,
5413 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
5414 results.extend(
5415 input_api.RunTests(
5416 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Edward Lesmesce51df52020-08-04 22:10:175417
Bruce Dawsonc8054482022-03-28 15:33:375418 dirmd = 'dirmd.bat' if input_api.is_windows else 'dirmd'
Sam Maiera6e76d72022-02-11 21:43:505419 dirmd_bin = input_api.os_path.join(input_api.PresubmitLocalPath(),
Bruce Dawsonc8054482022-03-28 15:33:375420 'third_party', 'depot_tools', dirmd)
Sam Maiera6e76d72022-02-11 21:43:505421 results.extend(
5422 input_api.RunTests(
5423 input_api.canned_checks.CheckDirMetadataFormat(
5424 input_api, output_api, dirmd_bin)))
5425 results.extend(
5426 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
5427 input_api, output_api))
5428 results.extend(
5429 input_api.canned_checks.CheckNoNewMetadataInOwners(
5430 input_api, output_api))
5431 results.extend(
5432 input_api.canned_checks.CheckInclusiveLanguage(
5433 input_api,
5434 output_api,
5435 excluded_directories_relative_path=[
5436 'infra', 'inclusive_language_presubmit_exempt_dirs.txt'
5437 ],
5438 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Dirk Prankee3c9c62d2021-05-18 18:35:595439
Aleksey Khoroshilov2978c942022-06-13 16:14:125440 presubmit_py_filter = lambda f: input_api.FilterSourceFile(
Bruce Dawson696963f2022-09-13 01:15:475441 f, files_to_check=[r'.*PRESUBMIT\.py$'])
Aleksey Khoroshilov2978c942022-06-13 16:14:125442 for f in input_api.AffectedFiles(include_deletes=False,
5443 file_filter=presubmit_py_filter):
5444 full_path = input_api.os_path.dirname(f.AbsoluteLocalPath())
5445 test_file = input_api.os_path.join(full_path, 'PRESUBMIT_test.py')
5446 # The PRESUBMIT.py file (and the directory containing it) might have
5447 # been affected by being moved or removed, so only try to run the tests
5448 # if they still exist.
5449 if not input_api.os_path.exists(test_file):
5450 continue
Sam Maiera6e76d72022-02-11 21:43:505451
Aleksey Khoroshilov2978c942022-06-13 16:14:125452 results.extend(
5453 input_api.canned_checks.RunUnitTestsInDirectory(
5454 input_api,
5455 output_api,
5456 full_path,
Takuto Ikuta40def482023-06-02 02:23:495457 files_to_check=[r'^PRESUBMIT_test\.py$']))
Sam Maiera6e76d72022-02-11 21:43:505458 return results
maruel@chromium.org1f7b4172010-01-28 01:17:345459
maruel@chromium.orgb337cb5b2011-01-23 21:24:055460
Saagar Sanghavifceeaae2020-08-12 16:40:365461def CheckPatchFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505462 problems = [
5463 f.LocalPath() for f in input_api.AffectedFiles()
5464 if f.LocalPath().endswith(('.orig', '.rej'))
5465 ]
5466 # Cargo.toml.orig files are part of third-party crates downloaded from
5467 # crates.io and should be included.
5468 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
5469 if problems:
5470 return [
5471 output_api.PresubmitError("Don't commit .rej and .orig files.",
5472 problems)
5473 ]
5474 else:
5475 return []
enne@chromium.orgb8079ae4a2012-12-05 19:56:495476
5477
Saagar Sanghavifceeaae2020-08-12 16:40:365478def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505479 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
5480 macro_re = input_api.re.compile(
5481 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
5482 include_re = input_api.re.compile(r'^#include\s+"build/build_config.h"',
5483 input_api.re.MULTILINE)
5484 extension_re = input_api.re.compile(r'\.[a-z]+$')
5485 errors = []
Bruce Dawsonf7679202022-08-09 20:24:005486 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:505487 for f in input_api.AffectedFiles(include_deletes=False):
Bruce Dawsonf7679202022-08-09 20:24:005488 # The build-config macros are allowed to be used in build_config.h
5489 # without including itself.
5490 if f.LocalPath() == config_h_file:
5491 continue
Sam Maiera6e76d72022-02-11 21:43:505492 if not f.LocalPath().endswith(
5493 ('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
5494 continue
5495 found_line_number = None
5496 found_macro = None
5497 all_lines = input_api.ReadFile(f, 'r').splitlines()
5498 for line_num, line in enumerate(all_lines):
5499 match = macro_re.search(line)
5500 if match:
5501 found_line_number = line_num
5502 found_macro = match.group(2)
5503 break
5504 if not found_line_number:
5505 continue
Kent Tamura5a8755d2017-06-29 23:37:075506
Sam Maiera6e76d72022-02-11 21:43:505507 found_include_line = -1
5508 for line_num, line in enumerate(all_lines):
5509 if include_re.search(line):
5510 found_include_line = line_num
5511 break
5512 if found_include_line >= 0 and found_include_line < found_line_number:
5513 continue
Kent Tamura5a8755d2017-06-29 23:37:075514
Sam Maiera6e76d72022-02-11 21:43:505515 if not f.LocalPath().endswith('.h'):
5516 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
5517 try:
5518 content = input_api.ReadFile(primary_header_path, 'r')
5519 if include_re.search(content):
5520 continue
5521 except IOError:
5522 pass
5523 errors.append('%s:%d %s macro is used without first including build/'
5524 'build_config.h.' %
5525 (f.LocalPath(), found_line_number, found_macro))
5526 if errors:
5527 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
5528 return []
Kent Tamura5a8755d2017-06-29 23:37:075529
5530
Lei Zhang1c12a22f2021-05-12 11:28:455531def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505532 stl_include_re = input_api.re.compile(r'^#include\s+<('
5533 r'algorithm|'
5534 r'array|'
5535 r'limits|'
5536 r'list|'
5537 r'map|'
5538 r'memory|'
5539 r'queue|'
5540 r'set|'
5541 r'string|'
5542 r'unordered_map|'
5543 r'unordered_set|'
5544 r'utility|'
5545 r'vector)>')
5546 std_namespace_re = input_api.re.compile(r'std::')
5547 errors = []
5548 for f in input_api.AffectedFiles():
5549 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
5550 continue
Lei Zhang1c12a22f2021-05-12 11:28:455551
Sam Maiera6e76d72022-02-11 21:43:505552 uses_std_namespace = False
5553 has_stl_include = False
5554 for line in f.NewContents():
5555 if has_stl_include and uses_std_namespace:
5556 break
Lei Zhang1c12a22f2021-05-12 11:28:455557
Sam Maiera6e76d72022-02-11 21:43:505558 if not has_stl_include and stl_include_re.search(line):
5559 has_stl_include = True
5560 continue
Lei Zhang1c12a22f2021-05-12 11:28:455561
Bruce Dawson4a5579a2022-04-08 17:11:365562 if not uses_std_namespace and (std_namespace_re.search(line)
5563 or 'no-std-usage-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:505564 uses_std_namespace = True
5565 continue
Lei Zhang1c12a22f2021-05-12 11:28:455566
Sam Maiera6e76d72022-02-11 21:43:505567 if has_stl_include and not uses_std_namespace:
5568 errors.append(
5569 '%s: Includes STL header(s) but does not reference std::' %
5570 f.LocalPath())
5571 if errors:
5572 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
5573 return []
Lei Zhang1c12a22f2021-05-12 11:28:455574
5575
Xiaohan Wang42d96c22022-01-20 17:23:115576def _CheckForDeprecatedOSMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:505577 """Check for sensible looking, totally invalid OS macros."""
5578 preprocessor_statement = input_api.re.compile(r'^\s*#')
5579 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
5580 results = []
5581 for lnum, line in f.ChangedContents():
5582 if preprocessor_statement.search(line):
5583 for match in os_macro.finditer(line):
5584 results.append(
5585 ' %s:%d: %s' %
5586 (f.LocalPath(), lnum, 'defined(OS_' + match.group(1) +
5587 ') -> BUILDFLAG(IS_' + match.group(1) + ')'))
5588 return results
dbeam@chromium.orgb00342e7f2013-03-26 16:21:545589
5590
Xiaohan Wang42d96c22022-01-20 17:23:115591def CheckForDeprecatedOSMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505592 """Check all affected files for invalid OS macros."""
5593 bad_macros = []
Bruce Dawsonf7679202022-08-09 20:24:005594 # The OS_ macros are allowed to be used in build/build_config.h.
5595 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:505596 for f in input_api.AffectedSourceFiles(None):
Bruce Dawsonf7679202022-08-09 20:24:005597 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')) \
5598 and f.LocalPath() != config_h_file:
Sam Maiera6e76d72022-02-11 21:43:505599 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
dbeam@chromium.orgb00342e7f2013-03-26 16:21:545600
Sam Maiera6e76d72022-02-11 21:43:505601 if not bad_macros:
5602 return []
dbeam@chromium.orgb00342e7f2013-03-26 16:21:545603
Sam Maiera6e76d72022-02-11 21:43:505604 return [
5605 output_api.PresubmitError(
5606 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
5607 'defined in build_config.h):', bad_macros)
5608 ]
dbeam@chromium.orgb00342e7f2013-03-26 16:21:545609
lliabraa35bab3932014-10-01 12:16:445610
5611def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:505612 """Check all affected files for invalid "if defined" macros."""
5613 ALWAYS_DEFINED_MACROS = (
5614 "TARGET_CPU_PPC",
5615 "TARGET_CPU_PPC64",
5616 "TARGET_CPU_68K",
5617 "TARGET_CPU_X86",
5618 "TARGET_CPU_ARM",
5619 "TARGET_CPU_MIPS",
5620 "TARGET_CPU_SPARC",
5621 "TARGET_CPU_ALPHA",
5622 "TARGET_IPHONE_SIMULATOR",
5623 "TARGET_OS_EMBEDDED",
5624 "TARGET_OS_IPHONE",
5625 "TARGET_OS_MAC",
5626 "TARGET_OS_UNIX",
5627 "TARGET_OS_WIN32",
5628 )
5629 ifdef_macro = input_api.re.compile(
5630 r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
5631 results = []
5632 for lnum, line in f.ChangedContents():
5633 for match in ifdef_macro.finditer(line):
5634 if match.group(1) in ALWAYS_DEFINED_MACROS:
5635 always_defined = ' %s is always defined. ' % match.group(1)
5636 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
5637 results.append(
5638 ' %s:%d %s\n\t%s' %
5639 (f.LocalPath(), lnum, always_defined, did_you_mean))
5640 return results
lliabraa35bab3932014-10-01 12:16:445641
5642
Saagar Sanghavifceeaae2020-08-12 16:40:365643def CheckForInvalidIfDefinedMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505644 """Check all affected files for invalid "if defined" macros."""
5645 bad_macros = []
5646 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
5647 for f in input_api.AffectedFiles():
5648 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
5649 continue
5650 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
5651 bad_macros.extend(
5652 _CheckForInvalidIfDefinedMacrosInFile(input_api, f))
lliabraa35bab3932014-10-01 12:16:445653
Sam Maiera6e76d72022-02-11 21:43:505654 if not bad_macros:
5655 return []
lliabraa35bab3932014-10-01 12:16:445656
Sam Maiera6e76d72022-02-11 21:43:505657 return [
5658 output_api.PresubmitError(
5659 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
5660 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
5661 bad_macros)
5662 ]
lliabraa35bab3932014-10-01 12:16:445663
5664
Saagar Sanghavifceeaae2020-08-12 16:40:365665def CheckForIPCRules(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505666 """Check for same IPC rules described in
5667 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
5668 """
5669 base_pattern = r'IPC_ENUM_TRAITS\('
5670 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
5671 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
mlamouria82272622014-09-16 18:45:045672
Sam Maiera6e76d72022-02-11 21:43:505673 problems = []
5674 for f in input_api.AffectedSourceFiles(None):
5675 local_path = f.LocalPath()
5676 if not local_path.endswith('.h'):
5677 continue
5678 for line_number, line in f.ChangedContents():
5679 if inclusion_pattern.search(
5680 line) and not comment_pattern.search(line):
5681 problems.append('%s:%d\n %s' %
5682 (local_path, line_number, line.strip()))
mlamouria82272622014-09-16 18:45:045683
Sam Maiera6e76d72022-02-11 21:43:505684 if problems:
5685 return [
5686 output_api.PresubmitPromptWarning(_IPC_ENUM_TRAITS_DEPRECATED,
5687 problems)
5688 ]
5689 else:
5690 return []
mlamouria82272622014-09-16 18:45:045691
dbeam@chromium.orgb00342e7f2013-03-26 16:21:545692
Saagar Sanghavifceeaae2020-08-12 16:40:365693def CheckForLongPathnames(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505694 """Check to make sure no files being submitted have long paths.
5695 This causes issues on Windows.
5696 """
5697 problems = []
5698 for f in input_api.AffectedTestableFiles():
5699 local_path = f.LocalPath()
5700 # Windows has a path limit of 260 characters. Limit path length to 200 so
5701 # that we have some extra for the prefix on dev machines and the bots.
5702 if len(local_path) > 200:
5703 problems.append(local_path)
Stephen Martinis97a394142018-06-07 23:06:055704
Sam Maiera6e76d72022-02-11 21:43:505705 if problems:
5706 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
5707 else:
5708 return []
Stephen Martinis97a394142018-06-07 23:06:055709
5710
Saagar Sanghavifceeaae2020-08-12 16:40:365711def CheckForIncludeGuards(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505712 """Check that header files have proper guards against multiple inclusion.
5713 If a file should not have such guards (and it probably should) then it
Bruce Dawson4a5579a2022-04-08 17:11:365714 should include the string "no-include-guard-because-multiply-included" or
5715 "no-include-guard-because-pch-file".
Sam Maiera6e76d72022-02-11 21:43:505716 """
Daniel Bratell8ba52722018-03-02 16:06:145717
Sam Maiera6e76d72022-02-11 21:43:505718 def is_chromium_header_file(f):
5719 # We only check header files under the control of the Chromium
5720 # project. That is, those outside third_party apart from
5721 # third_party/blink.
5722 # We also exclude *_message_generator.h headers as they use
5723 # include guards in a special, non-typical way.
5724 file_with_path = input_api.os_path.normpath(f.LocalPath())
5725 return (file_with_path.endswith('.h')
5726 and not file_with_path.endswith('_message_generator.h')
Bruce Dawson4c4c2922022-05-02 18:07:335727 and not file_with_path.endswith('com_imported_mstscax.h')
Sam Maiera6e76d72022-02-11 21:43:505728 and (not file_with_path.startswith('third_party')
5729 or file_with_path.startswith(
5730 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:145731
Sam Maiera6e76d72022-02-11 21:43:505732 def replace_special_with_underscore(string):
5733 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:145734
Sam Maiera6e76d72022-02-11 21:43:505735 errors = []
Daniel Bratell8ba52722018-03-02 16:06:145736
Sam Maiera6e76d72022-02-11 21:43:505737 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
5738 guard_name = None
5739 guard_line_number = None
5740 seen_guard_end = False
Daniel Bratell8ba52722018-03-02 16:06:145741
Sam Maiera6e76d72022-02-11 21:43:505742 file_with_path = input_api.os_path.normpath(f.LocalPath())
5743 base_file_name = input_api.os_path.splitext(
5744 input_api.os_path.basename(file_with_path))[0]
5745 upper_base_file_name = base_file_name.upper()
Daniel Bratell8ba52722018-03-02 16:06:145746
Sam Maiera6e76d72022-02-11 21:43:505747 expected_guard = replace_special_with_underscore(
5748 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:145749
Sam Maiera6e76d72022-02-11 21:43:505750 # For "path/elem/file_name.h" we should really only accept
5751 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
5752 # are too many (1000+) files with slight deviations from the
5753 # coding style. The most important part is that the include guard
5754 # is there, and that it's unique, not the name so this check is
5755 # forgiving for existing files.
5756 #
5757 # As code becomes more uniform, this could be made stricter.
Daniel Bratell8ba52722018-03-02 16:06:145758
Sam Maiera6e76d72022-02-11 21:43:505759 guard_name_pattern_list = [
5760 # Anything with the right suffix (maybe with an extra _).
5761 r'\w+_H__?',
Daniel Bratell8ba52722018-03-02 16:06:145762
Sam Maiera6e76d72022-02-11 21:43:505763 # To cover include guards with old Blink style.
5764 r'\w+_h',
Daniel Bratell8ba52722018-03-02 16:06:145765
Sam Maiera6e76d72022-02-11 21:43:505766 # Anything including the uppercase name of the file.
5767 r'\w*' + input_api.re.escape(
5768 replace_special_with_underscore(upper_base_file_name)) +
5769 r'\w*',
5770 ]
5771 guard_name_pattern = '|'.join(guard_name_pattern_list)
5772 guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
5773 guard_name_pattern + ')')
Daniel Bratell8ba52722018-03-02 16:06:145774
Sam Maiera6e76d72022-02-11 21:43:505775 for line_number, line in enumerate(f.NewContents()):
Bruce Dawson4a5579a2022-04-08 17:11:365776 if ('no-include-guard-because-multiply-included' in line
5777 or 'no-include-guard-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:505778 guard_name = 'DUMMY' # To not trigger check outside the loop.
5779 break
Daniel Bratell8ba52722018-03-02 16:06:145780
Sam Maiera6e76d72022-02-11 21:43:505781 if guard_name is None:
5782 match = guard_pattern.match(line)
5783 if match:
5784 guard_name = match.group(1)
5785 guard_line_number = line_number
Daniel Bratell8ba52722018-03-02 16:06:145786
Sam Maiera6e76d72022-02-11 21:43:505787 # We allow existing files to use include guards whose names
5788 # don't match the chromium style guide, but new files should
5789 # get it right.
Bruce Dawson6cc154e2022-04-12 20:39:495790 if guard_name != expected_guard:
Bruce Dawson95eb7562022-09-14 15:27:165791 if f.Action() == 'A': # If file was just 'A'dded
Sam Maiera6e76d72022-02-11 21:43:505792 errors.append(
5793 output_api.PresubmitPromptWarning(
5794 'Header using the wrong include guard name %s'
5795 % guard_name, [
5796 '%s:%d' %
5797 (f.LocalPath(), line_number + 1)
5798 ], 'Expected: %r\nFound: %r' %
5799 (expected_guard, guard_name)))
5800 else:
5801 # The line after #ifndef should have a #define of the same name.
5802 if line_number == guard_line_number + 1:
5803 expected_line = '#define %s' % guard_name
5804 if line != expected_line:
5805 errors.append(
5806 output_api.PresubmitPromptWarning(
5807 'Missing "%s" for include guard' %
5808 expected_line,
5809 ['%s:%d' % (f.LocalPath(), line_number + 1)],
5810 'Expected: %r\nGot: %r' %
5811 (expected_line, line)))
Daniel Bratell8ba52722018-03-02 16:06:145812
Sam Maiera6e76d72022-02-11 21:43:505813 if not seen_guard_end and line == '#endif // %s' % guard_name:
5814 seen_guard_end = True
5815 elif seen_guard_end:
5816 if line.strip() != '':
5817 errors.append(
5818 output_api.PresubmitPromptWarning(
5819 'Include guard %s not covering the whole file'
5820 % (guard_name), [f.LocalPath()]))
5821 break # Nothing else to check and enough to warn once.
Daniel Bratell8ba52722018-03-02 16:06:145822
Sam Maiera6e76d72022-02-11 21:43:505823 if guard_name is None:
5824 errors.append(
5825 output_api.PresubmitPromptWarning(
Bruce Dawson32114b62022-04-11 16:45:495826 'Missing include guard in %s\n'
Sam Maiera6e76d72022-02-11 21:43:505827 'Recommended name: %s\n'
5828 'This check can be disabled by having the string\n'
Bruce Dawson4a5579a2022-04-08 17:11:365829 '"no-include-guard-because-multiply-included" or\n'
5830 '"no-include-guard-because-pch-file" in the header.'
Sam Maiera6e76d72022-02-11 21:43:505831 % (f.LocalPath(), expected_guard)))
5832
5833 return errors
Daniel Bratell8ba52722018-03-02 16:06:145834
5835
Saagar Sanghavifceeaae2020-08-12 16:40:365836def CheckForWindowsLineEndings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505837 """Check source code and known ascii text files for Windows style line
5838 endings.
5839 """
Bruce Dawson5efbdc652022-04-11 19:29:515840 known_text_files = r'.*\.(txt|html|htm|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:235841
Sam Maiera6e76d72022-02-11 21:43:505842 file_inclusion_pattern = (known_text_files,
5843 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
5844 r'.+%s' % _HEADER_EXTENSIONS)
mostynbb639aca52015-01-07 20:31:235845
Sam Maiera6e76d72022-02-11 21:43:505846 problems = []
5847 source_file_filter = lambda f: input_api.FilterSourceFile(
5848 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
5849 for f in input_api.AffectedSourceFiles(source_file_filter):
Bruce Dawson5efbdc652022-04-11 19:29:515850 # Ignore test files that contain crlf intentionally.
5851 if f.LocalPath().endswith('crlf.txt'):
Daniel Chenga37c03db2022-05-12 17:20:345852 continue
Sam Maiera6e76d72022-02-11 21:43:505853 include_file = False
5854 for line in input_api.ReadFile(f, 'r').splitlines(True):
5855 if line.endswith('\r\n'):
5856 include_file = True
5857 if include_file:
5858 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:235859
Sam Maiera6e76d72022-02-11 21:43:505860 if problems:
5861 return [
5862 output_api.PresubmitPromptWarning(
5863 'Are you sure that you want '
5864 'these files to contain Windows style line endings?\n' +
5865 '\n'.join(problems))
5866 ]
mostynbb639aca52015-01-07 20:31:235867
Sam Maiera6e76d72022-02-11 21:43:505868 return []
5869
mostynbb639aca52015-01-07 20:31:235870
Evan Stade6cfc964c12021-05-18 20:21:165871def CheckIconFilesForLicenseHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505872 """Check that .icon files (which are fragments of C++) have license headers.
5873 """
Evan Stade6cfc964c12021-05-18 20:21:165874
Sam Maiera6e76d72022-02-11 21:43:505875 icon_files = (r'.*\.icon$', )
Evan Stade6cfc964c12021-05-18 20:21:165876
Sam Maiera6e76d72022-02-11 21:43:505877 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
5878 return input_api.canned_checks.CheckLicense(input_api,
5879 output_api,
5880 source_file_filter=icons)
5881
Evan Stade6cfc964c12021-05-18 20:21:165882
Jose Magana2b456f22021-03-09 23:26:405883def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505884 """Check source code for use of Chrome App technologies being
5885 deprecated.
5886 """
Jose Magana2b456f22021-03-09 23:26:405887
Sam Maiera6e76d72022-02-11 21:43:505888 def _CheckForDeprecatedTech(input_api,
5889 output_api,
5890 detection_list,
5891 files_to_check=None,
5892 files_to_skip=None):
Jose Magana2b456f22021-03-09 23:26:405893
Sam Maiera6e76d72022-02-11 21:43:505894 if (files_to_check or files_to_skip):
5895 source_file_filter = lambda f: input_api.FilterSourceFile(
5896 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
5897 else:
5898 source_file_filter = None
5899
5900 problems = []
5901
5902 for f in input_api.AffectedSourceFiles(source_file_filter):
5903 if f.Action() == 'D':
5904 continue
5905 for _, line in f.ChangedContents():
5906 if any(detect in line for detect in detection_list):
5907 problems.append(f.LocalPath())
5908
5909 return problems
5910
5911 # to avoid this presubmit script triggering warnings
5912 files_to_skip = ['PRESUBMIT.py', 'PRESUBMIT_test.py']
Jose Magana2b456f22021-03-09 23:26:405913
5914 problems = []
5915
Sam Maiera6e76d72022-02-11 21:43:505916 # NMF: any files with extensions .nmf or NMF
5917 _NMF_FILES = r'\.(nmf|NMF)$'
5918 problems += _CheckForDeprecatedTech(
5919 input_api,
5920 output_api,
5921 detection_list=[''], # any change to the file will trigger warning
5922 files_to_check=[r'.+%s' % _NMF_FILES])
Jose Magana2b456f22021-03-09 23:26:405923
Sam Maiera6e76d72022-02-11 21:43:505924 # MANIFEST: any manifest.json that in its diff includes "app":
5925 _MANIFEST_FILES = r'(manifest\.json)$'
5926 problems += _CheckForDeprecatedTech(
5927 input_api,
5928 output_api,
5929 detection_list=['"app":'],
5930 files_to_check=[r'.*%s' % _MANIFEST_FILES])
Jose Magana2b456f22021-03-09 23:26:405931
Sam Maiera6e76d72022-02-11 21:43:505932 # NaCl / PNaCl: any file that in its diff contains the strings in the list
5933 problems += _CheckForDeprecatedTech(
5934 input_api,
5935 output_api,
5936 detection_list=['config=nacl', 'enable-nacl', 'cpu=pnacl', 'nacl_io'],
Bruce Dawson40fece62022-09-16 19:58:315937 files_to_skip=files_to_skip + [r"^native_client_sdk/"])
Jose Magana2b456f22021-03-09 23:26:405938
Gao Shenga79ebd42022-08-08 17:25:595939 # PPAPI: any C/C++ file that in its diff includes a ppapi library
Sam Maiera6e76d72022-02-11 21:43:505940 problems += _CheckForDeprecatedTech(
5941 input_api,
5942 output_api,
5943 detection_list=['#include "ppapi', '#include <ppapi'],
5944 files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,
5945 r'.+%s' % _IMPLEMENTATION_EXTENSIONS),
Bruce Dawson40fece62022-09-16 19:58:315946 files_to_skip=[r"^ppapi/"])
Jose Magana2b456f22021-03-09 23:26:405947
Sam Maiera6e76d72022-02-11 21:43:505948 if problems:
5949 return [
5950 output_api.PresubmitPromptWarning(
5951 'You are adding/modifying code'
5952 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
5953 ' PNaCl, PPAPI). See this blog post for more details:\n'
5954 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
5955 'and this documentation for options to replace these technologies:\n'
5956 'https://developer.chrome.com/docs/apps/migration/\n' +
5957 '\n'.join(problems))
5958 ]
Jose Magana2b456f22021-03-09 23:26:405959
Sam Maiera6e76d72022-02-11 21:43:505960 return []
Jose Magana2b456f22021-03-09 23:26:405961
mostynbb639aca52015-01-07 20:31:235962
Saagar Sanghavifceeaae2020-08-12 16:40:365963def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
Sam Maiera6e76d72022-02-11 21:43:505964 """Checks that all source files use SYSLOG properly."""
5965 syslog_files = []
5966 for f in input_api.AffectedSourceFiles(src_file_filter):
5967 for line_number, line in f.ChangedContents():
5968 if 'SYSLOG' in line:
5969 syslog_files.append(f.LocalPath() + ':' + str(line_number))
pastarmovj032ba5bc2017-01-12 10:41:565970
Sam Maiera6e76d72022-02-11 21:43:505971 if syslog_files:
5972 return [
5973 output_api.PresubmitPromptWarning(
5974 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
5975 ' calls.\nFiles to check:\n',
5976 items=syslog_files)
5977 ]
5978 return []
pastarmovj89f7ee12016-09-20 14:58:135979
5980
maruel@chromium.org1f7b4172010-01-28 01:17:345981def CheckChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505982 if input_api.version < [2, 0, 0]:
5983 return [
5984 output_api.PresubmitError(
5985 "Your depot_tools is out of date. "
5986 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5987 "but your version is %d.%d.%d" % tuple(input_api.version))
5988 ]
5989 results = []
5990 results.extend(
5991 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
5992 return results
maruel@chromium.orgca8d19842009-02-19 16:33:125993
5994
5995def CheckChangeOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505996 if input_api.version < [2, 0, 0]:
5997 return [
5998 output_api.PresubmitError(
5999 "Your depot_tools is out of date. "
6000 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
6001 "but your version is %d.%d.%d" % tuple(input_api.version))
6002 ]
Saagar Sanghavifceeaae2020-08-12 16:40:366003
Sam Maiera6e76d72022-02-11 21:43:506004 results = []
6005 # Make sure the tree is 'open'.
6006 results.extend(
6007 input_api.canned_checks.CheckTreeIsOpen(
6008 input_api,
6009 output_api,
6010 json_url='http://chromium-status.appspot.com/current?format=json'))
maruel@chromium.org806e98e2010-03-19 17:49:276011
Sam Maiera6e76d72022-02-11 21:43:506012 results.extend(
6013 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
6014 results.extend(
6015 input_api.canned_checks.CheckChangeHasBugField(input_api, output_api))
6016 results.extend(
6017 input_api.canned_checks.CheckChangeHasNoUnwantedTags(
6018 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:506019 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146020
6021
Saagar Sanghavifceeaae2020-08-12 16:40:366022def CheckStrings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506023 """Check string ICU syntax validity and if translation screenshots exist."""
6024 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
6025 # footer is set to true.
6026 git_footers = input_api.change.GitFootersFromDescription()
6027 skip_screenshot_check_footer = [
6028 footer.lower() for footer in git_footers.get(
6029 u'Skip-Translation-Screenshots-Check', [])
6030 ]
6031 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:026032
Sam Maiera6e76d72022-02-11 21:43:506033 import os
6034 import re
6035 import sys
6036 from io import StringIO
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146037
Sam Maiera6e76d72022-02-11 21:43:506038 new_or_added_paths = set(f.LocalPath() for f in input_api.AffectedFiles()
6039 if (f.Action() == 'A' or f.Action() == 'M'))
6040 removed_paths = set(f.LocalPath()
6041 for f in input_api.AffectedFiles(include_deletes=True)
6042 if f.Action() == 'D')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146043
Sam Maiera6e76d72022-02-11 21:43:506044 affected_grds = [
6045 f for f in input_api.AffectedFiles()
6046 if f.LocalPath().endswith(('.grd', '.grdp'))
6047 ]
6048 affected_grds = [
6049 f for f in affected_grds if not 'testdata' in f.LocalPath()
6050 ]
6051 if not affected_grds:
6052 return []
meacer8c0d3832019-12-26 21:46:166053
Sam Maiera6e76d72022-02-11 21:43:506054 affected_png_paths = [
6055 f.AbsoluteLocalPath() for f in input_api.AffectedFiles()
6056 if (f.LocalPath().endswith('.png'))
6057 ]
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146058
Sam Maiera6e76d72022-02-11 21:43:506059 # Check for screenshots. Developers can upload screenshots using
6060 # tools/translation/upload_screenshots.py which finds and uploads
6061 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
6062 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
6063 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
6064 #
6065 # The logic here is as follows:
6066 #
6067 # - If the CL has a .png file under the screenshots directory for a grd
6068 # file, warn the developer. Actual images should never be checked into the
6069 # Chrome repo.
6070 #
6071 # - If the CL contains modified or new messages in grd files and doesn't
6072 # contain the corresponding .sha1 files, warn the developer to add images
6073 # and upload them via tools/translation/upload_screenshots.py.
6074 #
6075 # - If the CL contains modified or new messages in grd files and the
6076 # corresponding .sha1 files, everything looks good.
6077 #
6078 # - If the CL contains removed messages in grd files but the corresponding
6079 # .sha1 files aren't removed, warn the developer to remove them.
6080 unnecessary_screenshots = []
Jens Mueller054652c2023-05-10 15:12:306081 invalid_sha1 = []
Sam Maiera6e76d72022-02-11 21:43:506082 missing_sha1 = []
Bruce Dawson55776c42022-12-09 17:23:476083 missing_sha1_modified = []
Sam Maiera6e76d72022-02-11 21:43:506084 unnecessary_sha1_files = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146085
Sam Maiera6e76d72022-02-11 21:43:506086 # This checks verifies that the ICU syntax of messages this CL touched is
6087 # valid, and reports any found syntax errors.
6088 # Without this presubmit check, ICU syntax errors in Chromium strings can land
6089 # without developers being aware of them. Later on, such ICU syntax errors
6090 # break message extraction for translation, hence would block Chromium
6091 # translations until they are fixed.
6092 icu_syntax_errors = []
Jens Mueller054652c2023-05-10 15:12:306093 sha1_pattern = input_api.re.compile(r'^[a-fA-F0-9]{40}$',
6094 input_api.re.MULTILINE)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146095
Sam Maiera6e76d72022-02-11 21:43:506096 def _CheckScreenshotAdded(screenshots_dir, message_id):
6097 sha1_path = input_api.os_path.join(screenshots_dir,
6098 message_id + '.png.sha1')
6099 if sha1_path not in new_or_added_paths:
6100 missing_sha1.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306101 elif not _CheckValidSha1(sha1_path):
6102 invalid_sha1.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146103
Bruce Dawson55776c42022-12-09 17:23:476104 def _CheckScreenshotModified(screenshots_dir, message_id):
6105 sha1_path = input_api.os_path.join(screenshots_dir,
6106 message_id + '.png.sha1')
6107 if sha1_path not in new_or_added_paths:
6108 missing_sha1_modified.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306109 elif not _CheckValidSha1(sha1_path):
6110 invalid_sha1.append(sha1_path)
6111
6112 def _CheckValidSha1(sha1_path):
6113 return sha1_pattern.search(
6114 next(
6115 "\n".join(f.NewContents())
6116 for f in input_api.AffectedFiles()
6117 if f.LocalPath() == sha1_path
6118 )
6119 )
Bruce Dawson55776c42022-12-09 17:23:476120
Sam Maiera6e76d72022-02-11 21:43:506121 def _CheckScreenshotRemoved(screenshots_dir, message_id):
6122 sha1_path = input_api.os_path.join(screenshots_dir,
6123 message_id + '.png.sha1')
6124 if input_api.os_path.exists(
6125 sha1_path) and sha1_path not in removed_paths:
6126 unnecessary_sha1_files.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146127
Sam Maiera6e76d72022-02-11 21:43:506128 def _ValidateIcuSyntax(text, level, signatures):
6129 """Validates ICU syntax of a text string.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146130
Sam Maiera6e76d72022-02-11 21:43:506131 Check if text looks similar to ICU and checks for ICU syntax correctness
6132 in this case. Reports various issues with ICU syntax and values of
6133 variants. Supports checking of nested messages. Accumulate information of
6134 each ICU messages found in the text for further checking.
Rainhard Findlingfc31844c52020-05-15 09:58:266135
Sam Maiera6e76d72022-02-11 21:43:506136 Args:
6137 text: a string to check.
6138 level: a number of current nesting level.
6139 signatures: an accumulator, a list of tuple of (level, variable,
6140 kind, variants).
Rainhard Findlingfc31844c52020-05-15 09:58:266141
Sam Maiera6e76d72022-02-11 21:43:506142 Returns:
6143 None if a string is not ICU or no issue detected.
6144 A tuple of (message, start index, end index) if an issue detected.
6145 """
6146 valid_types = {
6147 'plural': (frozenset(
6148 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
6149 'other']), frozenset(['=1', 'other'])),
6150 'selectordinal': (frozenset(
6151 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
6152 'other']), frozenset(['one', 'other'])),
6153 'select': (frozenset(), frozenset(['other'])),
6154 }
Rainhard Findlingfc31844c52020-05-15 09:58:266155
Sam Maiera6e76d72022-02-11 21:43:506156 # Check if the message looks like an attempt to use ICU
6157 # plural. If yes - check if its syntax strictly matches ICU format.
6158 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b',
6159 text)
6160 if not like:
6161 signatures.append((level, None, None, None))
6162 return
Rainhard Findlingfc31844c52020-05-15 09:58:266163
Sam Maiera6e76d72022-02-11 21:43:506164 # Check for valid prefix and suffix
6165 m = re.match(
6166 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
6167 r'(plural|selectordinal|select),\s*'
6168 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
6169 if not m:
6170 return (('This message looks like an ICU plural, '
6171 'but does not follow ICU syntax.'), like.start(),
6172 like.end())
6173 starting, variable, kind, variant_pairs = m.groups()
6174 variants, depth, last_pos = _ParseIcuVariants(variant_pairs,
6175 m.start(4))
6176 if depth:
6177 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
6178 len(text))
6179 first = text[0]
6180 ending = text[last_pos:]
6181 if not starting:
6182 return ('Invalid ICU format. No initial opening bracket',
6183 last_pos - 1, last_pos)
6184 if not ending or '}' not in ending:
6185 return ('Invalid ICU format. No final closing bracket',
6186 last_pos - 1, last_pos)
6187 elif first != '{':
6188 return ((
6189 'Invalid ICU format. Extra characters at the start of a complex '
6190 'message (go/icu-message-migration): "%s"') % starting, 0,
6191 len(starting))
6192 elif ending != '}':
6193 return ((
6194 'Invalid ICU format. Extra characters at the end of a complex '
6195 'message (go/icu-message-migration): "%s"') % ending,
6196 last_pos - 1, len(text) - 1)
6197 if kind not in valid_types:
6198 return (('Unknown ICU message type %s. '
6199 'Valid types are: plural, select, selectordinal') % kind,
6200 0, 0)
6201 known, required = valid_types[kind]
6202 defined_variants = set()
6203 for variant, variant_range, value, value_range in variants:
6204 start, end = variant_range
6205 if variant in defined_variants:
6206 return ('Variant "%s" is defined more than once' % variant,
6207 start, end)
6208 elif known and variant not in known:
6209 return ('Variant "%s" is not valid for %s message' %
6210 (variant, kind), start, end)
6211 defined_variants.add(variant)
6212 # Check for nested structure
6213 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
6214 if res:
6215 return (res[0], res[1] + value_range[0] + 1,
6216 res[2] + value_range[0] + 1)
6217 missing = required - defined_variants
6218 if missing:
6219 return ('Required variants missing: %s' % ', '.join(missing), 0,
6220 len(text))
6221 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:266222
Sam Maiera6e76d72022-02-11 21:43:506223 def _ParseIcuVariants(text, offset=0):
6224 """Parse variants part of ICU complex message.
Rainhard Findlingfc31844c52020-05-15 09:58:266225
Sam Maiera6e76d72022-02-11 21:43:506226 Builds a tuple of variant names and values, as well as
6227 their offsets in the input string.
Rainhard Findlingfc31844c52020-05-15 09:58:266228
Sam Maiera6e76d72022-02-11 21:43:506229 Args:
6230 text: a string to parse
6231 offset: additional offset to add to positions in the text to get correct
6232 position in the complete ICU string.
Rainhard Findlingfc31844c52020-05-15 09:58:266233
Sam Maiera6e76d72022-02-11 21:43:506234 Returns:
6235 List of tuples, each tuple consist of four fields: variant name,
6236 variant name span (tuple of two integers), variant value, value
6237 span (tuple of two integers).
6238 """
6239 depth, start, end = 0, -1, -1
6240 variants = []
6241 key = None
6242 for idx, char in enumerate(text):
6243 if char == '{':
6244 if not depth:
6245 start = idx
6246 chunk = text[end + 1:start]
6247 key = chunk.strip()
6248 pos = offset + end + 1 + chunk.find(key)
6249 span = (pos, pos + len(key))
6250 depth += 1
6251 elif char == '}':
6252 if not depth:
6253 return variants, depth, offset + idx
6254 depth -= 1
6255 if not depth:
6256 end = idx
6257 variants.append((key, span, text[start:end + 1],
6258 (offset + start, offset + end + 1)))
6259 return variants, depth, offset + end + 1
Rainhard Findlingfc31844c52020-05-15 09:58:266260
Sam Maiera6e76d72022-02-11 21:43:506261 try:
6262 old_sys_path = sys.path
6263 sys.path = sys.path + [
6264 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
6265 'translation')
6266 ]
6267 from helper import grd_helper
6268 finally:
6269 sys.path = old_sys_path
Rainhard Findlingfc31844c52020-05-15 09:58:266270
Sam Maiera6e76d72022-02-11 21:43:506271 for f in affected_grds:
6272 file_path = f.LocalPath()
6273 old_id_to_msg_map = {}
6274 new_id_to_msg_map = {}
6275 # Note that this code doesn't check if the file has been deleted. This is
6276 # OK because it only uses the old and new file contents and doesn't load
6277 # the file via its path.
6278 # It's also possible that a file's content refers to a renamed or deleted
6279 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
6280 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
6281 # .grdp files.
6282 if file_path.endswith('.grdp'):
6283 if f.OldContents():
6284 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6285 '\n'.join(f.OldContents()))
6286 if f.NewContents():
6287 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6288 '\n'.join(f.NewContents()))
6289 else:
6290 file_dir = input_api.os_path.dirname(file_path) or '.'
6291 if f.OldContents():
6292 old_id_to_msg_map = grd_helper.GetGrdMessages(
6293 StringIO('\n'.join(f.OldContents())), file_dir)
6294 if f.NewContents():
6295 new_id_to_msg_map = grd_helper.GetGrdMessages(
6296 StringIO('\n'.join(f.NewContents())), file_dir)
Rainhard Findlingfc31844c52020-05-15 09:58:266297
Sam Maiera6e76d72022-02-11 21:43:506298 grd_name, ext = input_api.os_path.splitext(
6299 input_api.os_path.basename(file_path))
6300 screenshots_dir = input_api.os_path.join(
6301 input_api.os_path.dirname(file_path),
6302 grd_name + ext.replace('.', '_'))
Rainhard Findlingfc31844c52020-05-15 09:58:266303
Sam Maiera6e76d72022-02-11 21:43:506304 # Compute added, removed and modified message IDs.
6305 old_ids = set(old_id_to_msg_map)
6306 new_ids = set(new_id_to_msg_map)
6307 added_ids = new_ids - old_ids
6308 removed_ids = old_ids - new_ids
6309 modified_ids = set([])
6310 for key in old_ids.intersection(new_ids):
6311 if (old_id_to_msg_map[key].ContentsAsXml('', True) !=
6312 new_id_to_msg_map[key].ContentsAsXml('', True)):
6313 # The message content itself changed. Require an updated screenshot.
6314 modified_ids.add(key)
6315 elif old_id_to_msg_map[key].attrs['meaning'] != \
6316 new_id_to_msg_map[key].attrs['meaning']:
Jens Mueller054652c2023-05-10 15:12:306317 # The message meaning changed. We later check for a screenshot.
6318 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146319
Sam Maiera6e76d72022-02-11 21:43:506320 if run_screenshot_check:
6321 # Check the screenshot directory for .png files. Warn if there is any.
6322 for png_path in affected_png_paths:
6323 if png_path.startswith(screenshots_dir):
6324 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146325
Sam Maiera6e76d72022-02-11 21:43:506326 for added_id in added_ids:
6327 _CheckScreenshotAdded(screenshots_dir, added_id)
Rainhard Findlingd8d04372020-08-13 13:30:096328
Sam Maiera6e76d72022-02-11 21:43:506329 for modified_id in modified_ids:
Bruce Dawson55776c42022-12-09 17:23:476330 _CheckScreenshotModified(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146331
Sam Maiera6e76d72022-02-11 21:43:506332 for removed_id in removed_ids:
6333 _CheckScreenshotRemoved(screenshots_dir, removed_id)
6334
6335 # Check new and changed strings for ICU syntax errors.
6336 for key in added_ids.union(modified_ids):
6337 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
6338 err = _ValidateIcuSyntax(msg, 0, [])
6339 if err is not None:
6340 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
6341
6342 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:266343 if run_screenshot_check:
Sam Maiera6e76d72022-02-11 21:43:506344 if unnecessary_screenshots:
6345 results.append(
6346 output_api.PresubmitError(
6347 'Do not include actual screenshots in the changelist. Run '
6348 'tools/translate/upload_screenshots.py to upload them instead:',
6349 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146350
Sam Maiera6e76d72022-02-11 21:43:506351 if missing_sha1:
6352 results.append(
6353 output_api.PresubmitError(
Bruce Dawson55776c42022-12-09 17:23:476354 'You are adding UI strings.\n'
Sam Maiera6e76d72022-02-11 21:43:506355 'To ensure the best translations, take screenshots of the relevant UI '
6356 '(https://g.co/chrome/translation) and add these files to your '
6357 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146358
Jens Mueller054652c2023-05-10 15:12:306359 if invalid_sha1:
6360 results.append(
6361 output_api.PresubmitError(
6362 'The following files do not seem to contain valid sha1 hashes. '
6363 'Make sure they contain hashes created by '
6364 'tools/translate/upload_screenshots.py:', sorted(invalid_sha1)))
6365
Bruce Dawson55776c42022-12-09 17:23:476366 if missing_sha1_modified:
6367 results.append(
6368 output_api.PresubmitError(
6369 'You are modifying UI strings or their meanings.\n'
6370 'To ensure the best translations, take screenshots of the relevant UI '
6371 '(https://g.co/chrome/translation) and add these files to your '
6372 'changelist:', sorted(missing_sha1_modified)))
6373
Sam Maiera6e76d72022-02-11 21:43:506374 if unnecessary_sha1_files:
6375 results.append(
6376 output_api.PresubmitError(
6377 'You removed strings associated with these files. Remove:',
6378 sorted(unnecessary_sha1_files)))
6379 else:
6380 results.append(
6381 output_api.PresubmitPromptOrNotify('Skipping translation '
6382 'screenshots check.'))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146383
Sam Maiera6e76d72022-02-11 21:43:506384 if icu_syntax_errors:
6385 results.append(
6386 output_api.PresubmitPromptWarning(
6387 'ICU syntax errors were found in the following strings (problems or '
6388 'feedback? Contact rainhard@chromium.org):',
6389 items=icu_syntax_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:266390
Sam Maiera6e76d72022-02-11 21:43:506391 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:126392
6393
Saagar Sanghavifceeaae2020-08-12 16:40:366394def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:126395 repo_root=None,
6396 translation_expectations_path=None,
6397 grd_files=None):
Sam Maiera6e76d72022-02-11 21:43:506398 import sys
6399 affected_grds = [
6400 f for f in input_api.AffectedFiles()
6401 if (f.LocalPath().endswith('.grd') or f.LocalPath().endswith('.grdp'))
6402 ]
6403 if not affected_grds:
6404 return []
6405
6406 try:
6407 old_sys_path = sys.path
6408 sys.path = sys.path + [
6409 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
6410 'translation')
6411 ]
6412 from helper import git_helper
6413 from helper import translation_helper
6414 finally:
6415 sys.path = old_sys_path
6416
6417 # Check that translation expectations can be parsed and we can get a list of
6418 # translatable grd files. |repo_root| and |translation_expectations_path| are
6419 # only passed by tests.
6420 if not repo_root:
6421 repo_root = input_api.PresubmitLocalPath()
6422 if not translation_expectations_path:
6423 translation_expectations_path = input_api.os_path.join(
6424 repo_root, 'tools', 'gritsettings', 'translation_expectations.pyl')
6425 if not grd_files:
6426 grd_files = git_helper.list_grds_in_repository(repo_root)
6427
6428 # Ignore bogus grd files used only for testing
Gao Shenga79ebd42022-08-08 17:25:596429 # ui/webui/resources/tools/generate_grd.py.
Sam Maiera6e76d72022-02-11 21:43:506430 ignore_path = input_api.os_path.join('ui', 'webui', 'resources', 'tools',
6431 'tests')
6432 grd_files = [p for p in grd_files if ignore_path not in p]
6433
6434 try:
6435 translation_helper.get_translatable_grds(
6436 repo_root, grd_files, translation_expectations_path)
6437 except Exception as e:
6438 return [
6439 output_api.PresubmitNotifyResult(
6440 'Failed to get a list of translatable grd files. This happens when:\n'
6441 ' - One of the modified grd or grdp files cannot be parsed or\n'
6442 ' - %s is not updated.\n'
6443 'Stack:\n%s' % (translation_expectations_path, str(e)))
6444 ]
Mustafa Emre Acer51f2f742020-03-09 19:41:126445 return []
6446
Ken Rockotc31f4832020-05-29 18:58:516447
Saagar Sanghavifceeaae2020-08-12 16:40:366448def CheckStableMojomChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506449 """Changes to [Stable] mojom types must preserve backward-compatibility."""
6450 changed_mojoms = input_api.AffectedFiles(
6451 include_deletes=True,
6452 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:526453
Bruce Dawson344ab262022-06-04 11:35:106454 if not changed_mojoms or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:506455 return []
6456
6457 delta = []
6458 for mojom in changed_mojoms:
Sam Maiera6e76d72022-02-11 21:43:506459 delta.append({
6460 'filename': mojom.LocalPath(),
6461 'old': '\n'.join(mojom.OldContents()) or None,
6462 'new': '\n'.join(mojom.NewContents()) or None,
6463 })
6464
6465 process = input_api.subprocess.Popen([
Takuto Ikutadca10222022-04-13 02:51:216466 input_api.python3_executable,
Sam Maiera6e76d72022-02-11 21:43:506467 input_api.os_path.join(
6468 input_api.PresubmitLocalPath(), 'mojo', 'public', 'tools', 'mojom',
6469 'check_stable_mojom_compatibility.py'), '--src-root',
6470 input_api.PresubmitLocalPath()
6471 ],
6472 stdin=input_api.subprocess.PIPE,
6473 stdout=input_api.subprocess.PIPE,
6474 stderr=input_api.subprocess.PIPE,
6475 universal_newlines=True)
6476 (x, error) = process.communicate(input=input_api.json.dumps(delta))
6477 if process.returncode:
6478 return [
6479 output_api.PresubmitError(
6480 'One or more [Stable] mojom definitions appears to have been changed '
6481 'in a way that is not backward-compatible.',
6482 long_text=error)
6483 ]
Erik Staabc734cd7a2021-11-23 03:11:526484 return []
6485
Dominic Battre645d42342020-12-04 16:14:106486def CheckDeprecationOfPreferences(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506487 """Removing a preference should come with a deprecation."""
Dominic Battre645d42342020-12-04 16:14:106488
Sam Maiera6e76d72022-02-11 21:43:506489 def FilterFile(affected_file):
6490 """Accept only .cc files and the like."""
6491 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
6492 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
6493 input_api.DEFAULT_FILES_TO_SKIP)
6494 return input_api.FilterSourceFile(
6495 affected_file,
6496 files_to_check=file_inclusion_pattern,
6497 files_to_skip=files_to_skip)
Dominic Battre645d42342020-12-04 16:14:106498
Sam Maiera6e76d72022-02-11 21:43:506499 def ModifiedLines(affected_file):
6500 """Returns a list of tuples (line number, line text) of added and removed
6501 lines.
Dominic Battre645d42342020-12-04 16:14:106502
Sam Maiera6e76d72022-02-11 21:43:506503 Deleted lines share the same line number as the previous line.
Dominic Battre645d42342020-12-04 16:14:106504
Sam Maiera6e76d72022-02-11 21:43:506505 This relies on the scm diff output describing each changed code section
6506 with a line of the form
Dominic Battre645d42342020-12-04 16:14:106507
Sam Maiera6e76d72022-02-11 21:43:506508 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
6509 """
6510 line_num = 0
6511 modified_lines = []
6512 for line in affected_file.GenerateScmDiff().splitlines():
6513 # Extract <new line num> of the patch fragment (see format above).
6514 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@',
6515 line)
6516 if m:
6517 line_num = int(m.groups(1)[0])
6518 continue
6519 if ((line.startswith('+') and not line.startswith('++'))
6520 or (line.startswith('-') and not line.startswith('--'))):
6521 modified_lines.append((line_num, line))
Dominic Battre645d42342020-12-04 16:14:106522
Sam Maiera6e76d72022-02-11 21:43:506523 if not line.startswith('-'):
6524 line_num += 1
6525 return modified_lines
Dominic Battre645d42342020-12-04 16:14:106526
Sam Maiera6e76d72022-02-11 21:43:506527 def FindLineWith(lines, needle):
6528 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
Dominic Battre645d42342020-12-04 16:14:106529
Sam Maiera6e76d72022-02-11 21:43:506530 If 0 or >1 lines contain `needle`, -1 is returned.
6531 """
6532 matching_line_numbers = [
6533 # + 1 for 1-based counting of line numbers.
6534 i + 1 for i, line in enumerate(lines) if needle in line
6535 ]
6536 return matching_line_numbers[0] if len(
6537 matching_line_numbers) == 1 else -1
Dominic Battre645d42342020-12-04 16:14:106538
Sam Maiera6e76d72022-02-11 21:43:506539 def ModifiedPrefMigration(affected_file):
6540 """Returns whether the MigrateObsolete.*Pref functions were modified."""
6541 # Determine first and last lines of MigrateObsolete.*Pref functions.
6542 new_contents = affected_file.NewContents()
6543 range_1 = (FindLineWith(new_contents,
6544 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
6545 FindLineWith(new_contents,
6546 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
6547 range_2 = (FindLineWith(new_contents,
6548 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
6549 FindLineWith(new_contents,
6550 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
6551 if (-1 in range_1 + range_2):
6552 raise Exception(
6553 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.'
6554 )
Dominic Battre645d42342020-12-04 16:14:106555
Sam Maiera6e76d72022-02-11 21:43:506556 # Check whether any of the modified lines are part of the
6557 # MigrateObsolete.*Pref functions.
6558 for line_nr, line in ModifiedLines(affected_file):
6559 if (range_1[0] <= line_nr <= range_1[1]
6560 or range_2[0] <= line_nr <= range_2[1]):
6561 return True
6562 return False
Dominic Battre645d42342020-12-04 16:14:106563
Sam Maiera6e76d72022-02-11 21:43:506564 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
6565 browser_prefs_file_pattern = input_api.re.compile(
6566 r'chrome/browser/prefs/browser_prefs.cc')
Dominic Battre645d42342020-12-04 16:14:106567
Sam Maiera6e76d72022-02-11 21:43:506568 changes = input_api.AffectedFiles(include_deletes=True,
6569 file_filter=FilterFile)
6570 potential_problems = []
6571 for f in changes:
6572 for line in f.GenerateScmDiff().splitlines():
6573 # Check deleted lines for pref registrations.
6574 if (line.startswith('-') and not line.startswith('--')
6575 and register_pref_pattern.search(line)):
6576 potential_problems.append('%s: %s' % (f.LocalPath(), line))
Dominic Battre645d42342020-12-04 16:14:106577
Sam Maiera6e76d72022-02-11 21:43:506578 if browser_prefs_file_pattern.search(f.LocalPath()):
6579 # If the developer modified the MigrateObsolete.*Prefs() functions, we
6580 # assume that they knew that they have to deprecate preferences and don't
6581 # warn.
6582 try:
6583 if ModifiedPrefMigration(f):
6584 return []
6585 except Exception as e:
6586 return [output_api.PresubmitError(str(e))]
Dominic Battre645d42342020-12-04 16:14:106587
Sam Maiera6e76d72022-02-11 21:43:506588 if potential_problems:
6589 return [
6590 output_api.PresubmitPromptWarning(
6591 'Discovered possible removal of preference registrations.\n\n'
6592 'Please make sure to properly deprecate preferences by clearing their\n'
6593 'value for a couple of milestones before finally removing the code.\n'
6594 'Otherwise data may stay in the preferences files forever. See\n'
6595 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
6596 'chrome/browser/prefs/README.md for examples.\n'
6597 'This may be a false positive warning (e.g. if you move preference\n'
6598 'registrations to a different place).\n', potential_problems)
6599 ]
6600 return []
6601
Matt Stark6ef08872021-07-29 01:21:466602
6603def CheckConsistentGrdChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506604 """Changes to GRD files must be consistent for tools to read them."""
6605 changed_grds = input_api.AffectedFiles(
6606 include_deletes=False,
6607 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
6608 errors = []
6609 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
6610 for matcher, msg in _INVALID_GRD_FILE_LINE]
6611 for grd in changed_grds:
6612 for i, line in enumerate(grd.NewContents()):
6613 for matcher, msg in invalid_file_regexes:
6614 if matcher.search(line):
6615 errors.append(
6616 output_api.PresubmitError(
6617 'Problem on {grd}:{i} - {msg}'.format(
6618 grd=grd.LocalPath(), i=i + 1, msg=msg)))
6619 return errors
6620
Kevin McNee967dd2d22021-11-15 16:09:296621
Henrique Ferreiro2a4b55942021-11-29 23:45:366622def CheckAssertAshOnlyCode(input_api, output_api):
6623 """Errors if a BUILD.gn file in an ash/ directory doesn't include
6624 assert(is_chromeos_ash).
6625 """
6626
6627 def FileFilter(affected_file):
6628 """Includes directories known to be Ash only."""
6629 return input_api.FilterSourceFile(
6630 affected_file,
6631 files_to_check=(
6632 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
6633 r'.*/ash/.*BUILD\.gn'), # Any path component.
6634 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
6635
6636 errors = []
6637 pattern = input_api.re.compile(r'assert\(is_chromeos_ash')
Jameson Thies0ce669f2021-12-09 15:56:566638 for f in input_api.AffectedFiles(include_deletes=False,
6639 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:366640 if (not pattern.search(input_api.ReadFile(f))):
6641 errors.append(
6642 output_api.PresubmitError(
6643 'Please add assert(is_chromeos_ash) to %s. If that\'s not '
6644 'possible, please create and issue and add a comment such '
6645 'as:\n # TODO(https://crbug.com/XXX): add '
6646 'assert(is_chromeos_ash) when ...' % f.LocalPath()))
6647 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:276648
6649
6650def _IsRendererOnlyCppFile(input_api, affected_file):
Sam Maiera6e76d72022-02-11 21:43:506651 path = affected_file.LocalPath()
6652 if not _IsCPlusPlusFile(input_api, path):
6653 return False
6654
6655 # Any code under a "renderer" subdirectory is assumed to be Renderer-only.
6656 if "/renderer/" in path:
6657 return True
6658
6659 # Blink's public/web API is only used/included by Renderer-only code. Note
6660 # that public/platform API may be used in non-Renderer processes (e.g. there
6661 # are some includes in code used by Utility, PDF, or Plugin processes).
6662 if "/blink/public/web/" in path:
6663 return True
6664
6665 # We assume that everything else may be used outside of Renderer processes.
Lukasz Anforowicz7016d05e2021-11-30 03:56:276666 return False
6667
Lukasz Anforowicz7016d05e2021-11-30 03:56:276668# TODO(https://crbug.com/1273182): Remove these checks, once they are replaced
6669# by the Chromium Clang Plugin (which will be preferable because it will
6670# 1) report errors earlier - at compile-time and 2) cover more rules).
6671def CheckRawPtrUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506672 """Rough checks that raw_ptr<T> usage guidelines are followed."""
6673 errors = []
6674 # The regex below matches "raw_ptr<" following a word boundary, but not in a
6675 # C++ comment.
6676 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
6677 file_filter = lambda f: _IsRendererOnlyCppFile(input_api, f)
6678 for f, line_num, line in input_api.RightHandSideLines(file_filter):
6679 if raw_ptr_matcher.search(line):
6680 errors.append(
6681 output_api.PresubmitError(
6682 'Problem on {path}:{line} - '\
6683 'raw_ptr<T> should not be used in Renderer-only code '\
6684 '(as documented in the "Pointers to unprotected memory" '\
6685 'section in //base/memory/raw_ptr.md)'.format(
6686 path=f.LocalPath(), line=line_num)))
6687 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:566688
6689
6690def CheckPythonShebang(input_api, output_api):
6691 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
6692 system-wide python.
6693 """
6694 errors = []
6695 sources = lambda affected_file: input_api.FilterSourceFile(
6696 affected_file,
6697 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
6698 r'third_party/blink/web_tests/external/') + input_api.
6699 DEFAULT_FILES_TO_SKIP),
6700 files_to_check=[r'.*\.py$'])
6701 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:276702 for line_num, line in f.ChangedContents():
6703 if line_num == 1 and line.startswith('#!/usr/bin/python'):
6704 errors.append(f.LocalPath())
6705 break
Henrique Ferreirof9819f2e32021-11-30 13:31:566706
6707 result = []
6708 for file in errors:
6709 result.append(
6710 output_api.PresubmitError(
6711 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
6712 file))
6713 return result
James Shen81cc0e22022-06-15 21:10:456714
6715
6716def CheckBatchAnnotation(input_api, output_api):
6717 """Checks that tests have either @Batch or @DoNotBatch annotation. If this
6718 is not an instrumentation test, disregard."""
6719
6720 batch_annotation = input_api.re.compile(r'^\s*@Batch')
6721 do_not_batch_annotation = input_api.re.compile(r'^\s*@DoNotBatch')
6722 robolectric_test = input_api.re.compile(r'[rR]obolectric')
6723 test_class_declaration = input_api.re.compile(r'^\s*public\sclass.*Test')
6724 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
6725
ckitagawae8fd23b2022-06-17 15:29:386726 missing_annotation_errors = []
6727 extra_annotation_errors = []
James Shen81cc0e22022-06-15 21:10:456728
6729 def _FilterFile(affected_file):
6730 return input_api.FilterSourceFile(
6731 affected_file,
6732 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
6733 files_to_check=[r'.*Test\.java$'])
6734
6735 for f in input_api.AffectedSourceFiles(_FilterFile):
6736 batch_matched = None
6737 do_not_batch_matched = None
6738 is_instrumentation_test = True
6739 for line in f.NewContents():
6740 if robolectric_test.search(line) or uiautomator_test.search(line):
6741 # Skip Robolectric and UiAutomator tests.
6742 is_instrumentation_test = False
6743 break
6744 if not batch_matched:
6745 batch_matched = batch_annotation.search(line)
6746 if not do_not_batch_matched:
6747 do_not_batch_matched = do_not_batch_annotation.search(line)
6748 test_class_declaration_matched = test_class_declaration.search(
6749 line)
6750 if test_class_declaration_matched:
6751 break
6752 if (is_instrumentation_test and
6753 not batch_matched and
6754 not do_not_batch_matched):
Sam Maier4cef9242022-10-03 14:21:246755 missing_annotation_errors.append(str(f.LocalPath()))
ckitagawae8fd23b2022-06-17 15:29:386756 if (not is_instrumentation_test and
6757 (batch_matched or
6758 do_not_batch_matched)):
Sam Maier4cef9242022-10-03 14:21:246759 extra_annotation_errors.append(str(f.LocalPath()))
James Shen81cc0e22022-06-15 21:10:456760
6761 results = []
6762
ckitagawae8fd23b2022-06-17 15:29:386763 if missing_annotation_errors:
James Shen81cc0e22022-06-15 21:10:456764 results.append(
6765 output_api.PresubmitPromptWarning(
6766 """
Henrique Nakashimacb4c55a2023-01-30 20:09:096767Instrumentation tests should use either @Batch or @DoNotBatch. Use
6768@Batch(Batch.PER_CLASS) in most cases. Use @Batch(Batch.UNIT_TESTS) when tests
6769have no side-effects. If the tests are not safe to run in batch, please use
6770@DoNotBatch with reasons.
Jens Mueller2085ff82023-02-27 11:54:496771See https://source.chromium.org/chromium/chromium/src/+/main:docs/testing/batching_instrumentation_tests.md
ckitagawae8fd23b2022-06-17 15:29:386772""", missing_annotation_errors))
6773 if extra_annotation_errors:
6774 results.append(
6775 output_api.PresubmitPromptWarning(
6776 """
6777Robolectric tests do not need a @Batch or @DoNotBatch annotations.
6778""", extra_annotation_errors))
James Shen81cc0e22022-06-15 21:10:456779
6780 return results
Sam Maier4cef9242022-10-03 14:21:246781
6782
6783def CheckMockAnnotation(input_api, output_api):
6784 """Checks that we have annotated all Mockito.mock()-ed or Mockito.spy()-ed
6785 classes with @Mock or @Spy. If this is not an instrumentation test,
6786 disregard."""
6787
6788 # This is just trying to be approximately correct. We are not writing a
6789 # Java parser, so special cases like statically importing mock() then
6790 # calling an unrelated non-mockito spy() function will cause a false
6791 # positive.
6792 package_name = input_api.re.compile(r'^package\s+(\w+(?:\.\w+)+);')
6793 mock_static_import = input_api.re.compile(
6794 r'^import\s+static\s+org.mockito.Mockito.(?:mock|spy);')
6795 import_class = input_api.re.compile(r'import\s+((?:\w+\.)+)(\w+);')
6796 mock_annotation = input_api.re.compile(r'^\s*@(?:Mock|Spy)')
6797 field_type = input_api.re.compile(r'(\w+)(?:<\w+>)?\s+\w+\s*(?:;|=)')
6798 mock_or_spy_function_call = r'(?:mock|spy)\(\s*(?:new\s*)?(\w+)(?:\.class|\()'
6799 fully_qualified_mock_function = input_api.re.compile(
6800 r'Mockito\.' + mock_or_spy_function_call)
6801 statically_imported_mock_function = input_api.re.compile(
6802 r'\W' + mock_or_spy_function_call)
6803 robolectric_test = input_api.re.compile(r'[rR]obolectric')
6804 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
6805
6806 def _DoClassLookup(class_name, class_name_map, package):
6807 found = class_name_map.get(class_name)
6808 if found is not None:
6809 return found
6810 else:
6811 return package + '.' + class_name
6812
6813 def _FilterFile(affected_file):
6814 return input_api.FilterSourceFile(
6815 affected_file,
6816 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
6817 files_to_check=[r'.*Test\.java$'])
6818
6819 mocked_by_function_classes = set()
6820 mocked_by_annotation_classes = set()
6821 class_to_filename = {}
6822 for f in input_api.AffectedSourceFiles(_FilterFile):
6823 mock_function_regex = fully_qualified_mock_function
6824 next_line_is_annotated = False
6825 fully_qualified_class_map = {}
6826 package = None
6827
6828 for line in f.NewContents():
6829 if robolectric_test.search(line) or uiautomator_test.search(line):
6830 # Skip Robolectric and UiAutomator tests.
6831 break
6832
6833 m = package_name.search(line)
6834 if m:
6835 package = m.group(1)
6836 continue
6837
6838 if mock_static_import.search(line):
6839 mock_function_regex = statically_imported_mock_function
6840 continue
6841
6842 m = import_class.search(line)
6843 if m:
6844 fully_qualified_class_map[m.group(2)] = m.group(1) + m.group(2)
6845 continue
6846
6847 if next_line_is_annotated:
6848 next_line_is_annotated = False
6849 fully_qualified_class = _DoClassLookup(
6850 field_type.search(line).group(1), fully_qualified_class_map,
6851 package)
6852 mocked_by_annotation_classes.add(fully_qualified_class)
6853 continue
6854
6855 if mock_annotation.search(line):
6856 next_line_is_annotated = True
6857 continue
6858
6859 m = mock_function_regex.search(line)
6860 if m:
6861 fully_qualified_class = _DoClassLookup(m.group(1),
6862 fully_qualified_class_map, package)
6863 # Skipping builtin classes, since they don't get optimized.
6864 if fully_qualified_class.startswith(
6865 'android.') or fully_qualified_class.startswith(
6866 'java.'):
6867 continue
6868 class_to_filename[fully_qualified_class] = str(f.LocalPath())
6869 mocked_by_function_classes.add(fully_qualified_class)
6870
6871 results = []
6872 missed_classes = mocked_by_function_classes - mocked_by_annotation_classes
6873 if missed_classes:
6874 error_locations = []
6875 for c in missed_classes:
6876 error_locations.append(c + ' in ' + class_to_filename[c])
6877 results.append(
6878 output_api.PresubmitPromptWarning(
6879 """
6880Mockito.mock()/spy() cause issues with our Java optimizer. You have 3 options:
68811) If the mocked variable can be a class member, annotate the member with
6882 @Mock/@Spy.
68832) If the mocked variable cannot be a class member, create a dummy member
6884 variable of that type, annotated with @Mock/@Spy. This dummy does not need
6885 to be used or initialized in any way.
68863) If the mocked type is definitely not going to be optimized, whether it's a
6887 builtin type which we don't ship, or a class you know R8 will treat
6888 specially, you can ignore this warning.
6889""", error_locations))
6890
6891 return results
Mike Dougherty1b8be712022-10-20 00:15:136892
6893def CheckNoJsInIos(input_api, output_api):
6894 """Checks to make sure that JavaScript files are not used on iOS."""
6895
6896 def _FilterFile(affected_file):
6897 return input_api.FilterSourceFile(
6898 affected_file,
6899 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP +
Mike Dougherty7bc8a812023-05-02 06:55:216900 (r'^ios/third_party/*', r'^ios/tools/*', r'^third_party/*'),
Mike Dougherty1b8be712022-10-20 00:15:136901 files_to_check=[r'^ios/.*\.js$', r'.*/ios/.*\.js$'])
6902
Mike Dougherty4d1050b2023-03-14 15:59:536903 deleted_files = []
6904
6905 # Collect filenames of all removed JS files.
6906 for f in input_api.AffectedSourceFiles(_FilterFile):
6907 local_path = f.LocalPath()
6908
6909 if input_api.os_path.splitext(local_path)[1] == '.js' and f.Action() == 'D':
6910 deleted_files.append(input_api.os_path.basename(local_path))
6911
Mike Dougherty1b8be712022-10-20 00:15:136912 error_paths = []
Mike Dougherty4d1050b2023-03-14 15:59:536913 moved_paths = []
Mike Dougherty1b8be712022-10-20 00:15:136914 warning_paths = []
6915
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':
6920 if f.Action() == 'A':
Mike Dougherty4d1050b2023-03-14 15:59:536921 if input_api.os_path.basename(local_path) in deleted_files:
6922 # This script was probably moved rather than newly created.
6923 # Present a warning instead of an error for these cases.
6924 moved_paths.append(local_path)
6925 else:
6926 error_paths.append(local_path)
Mike Dougherty1b8be712022-10-20 00:15:136927 elif f.Action() != 'D':
6928 warning_paths.append(local_path)
6929
6930 results = []
6931
6932 if warning_paths:
6933 results.append(output_api.PresubmitPromptWarning(
6934 'TypeScript is now fully supported for iOS feature scripts. '
6935 'Consider converting JavaScript files to TypeScript. See '
6936 '//ios/web/public/js_messaging/README.md for more details.',
6937 warning_paths))
6938
Mike Dougherty4d1050b2023-03-14 15:59:536939 if moved_paths:
6940 results.append(output_api.PresubmitPromptWarning(
6941 'Do not use JavaScript on iOS for new files as TypeScript is '
6942 'fully supported. (If this is a moved file, you may leave the '
6943 'script unconverted.) See //ios/web/public/js_messaging/README.md '
6944 'for help using scripts on iOS.', moved_paths))
6945
Mike Dougherty1b8be712022-10-20 00:15:136946 if error_paths:
6947 results.append(output_api.PresubmitError(
6948 'Do not use JavaScript on iOS as TypeScript is fully supported. '
6949 'See //ios/web/public/js_messaging/README.md for help using '
6950 'scripts on iOS.', error_paths))
6951
6952 return results
Hans Wennborg23a81d52023-03-24 16:38:136953
6954def CheckLibcxxRevisionsMatch(input_api, output_api):
6955 """Check to make sure the libc++ version matches across deps files."""
Andrew Grieve21bb6792023-03-27 19:06:486956 # Disable check for changes to sub-repositories.
6957 if input_api.PresubmitLocalPath() != input_api.change.RepositoryRoot():
6958 return []
Hans Wennborg23a81d52023-03-24 16:38:136959
6960 DEPS_FILES = [ 'DEPS', 'buildtools/deps_revisions.gni' ]
6961
6962 file_filter = lambda f: f.LocalPath().replace(
6963 input_api.os_path.sep, '/') in DEPS_FILES
6964 changed_deps_files = input_api.AffectedFiles(file_filter=file_filter)
6965 if not changed_deps_files:
6966 return []
6967
6968 def LibcxxRevision(file):
6969 file = input_api.os_path.join(input_api.PresubmitLocalPath(),
6970 *file.split('/'))
6971 return input_api.re.search(
6972 r'libcxx_revision.*[:=].*[\'"](\w+)[\'"]',
6973 input_api.ReadFile(file)).group(1)
6974
6975 if len(set([LibcxxRevision(f) for f in DEPS_FILES])) == 1:
6976 return []
6977
6978 return [output_api.PresubmitError(
6979 'libcxx_revision not equal across %s' % ', '.join(DEPS_FILES),
6980 changed_deps_files)]