blob: 01455200ea74b7272b3ee0d9cf1f423cd7776e60 [file] [log] [blame]
Avi Drissman24976592022-09-12 15:24:311# Copyright 2012 The Chromium Authors
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
Daniel Chengd88244472022-05-16 09:08:477See https://www.chromium.org/developers/how-tos/depottools/presubmit-scripts/
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d1982009-02-19 16:33:129"""
Daniel Chenga44a1bcd2022-03-15 20:00:1510
Daniel Chenga37c03db2022-05-12 17:20:3411from typing import Callable
Daniel Chenga44a1bcd2022-03-15 20:00:1512from typing import Optional
13from typing import Sequence
14from dataclasses import dataclass
15
Saagar Sanghavifceeaae2020-08-12 16:40:3616PRESUBMIT_VERSION = '2.0.0'
[email protected]eea609a2011-11-18 13:10:1217
Dirk Prankee3c9c62d2021-05-18 18:35:5918
[email protected]379e7dd2010-01-28 17:39:2119_EXCLUDED_PATHS = (
Bruce Dawson7f8566b2022-05-06 16:22:1820 # Generated file
Bruce Dawson40fece62022-09-16 19:58:3121 (r"chrome/android/webapk/shell_apk/src/org/chromium"
22 r"/webapk/lib/runtime_library/IWebApkApi.java"),
Mila Greene3aa7222021-09-07 16:34:0823 # File needs to write to stdout to emulate a tool it's replacing.
Bruce Dawson40fece62022-09-16 19:58:3124 r"chrome/updater/mac/keystone/ksadmin.mm",
Ilya Shermane8a7d2d2020-07-25 04:33:4725 # Generated file.
Bruce Dawson40fece62022-09-16 19:58:3126 (r"^components/variations/proto/devtools/"
Ilya Shermanc167a962020-08-18 18:40:2627 r"client_variations.js"),
Bruce Dawson3bd976c2022-05-06 22:47:5228 # These are video files, not typescript.
Bruce Dawson40fece62022-09-16 19:58:3129 r"^media/test/data/.*.ts",
30 r"^native_client_sdksrc/build_tools/make_rules.py",
31 r"^native_client_sdk/src/build_tools/make_simple.py",
32 r"^native_client_sdk/src/tools/.*.mk",
33 r"^net/tools/spdyshark/.*",
34 r"^skia/.*",
35 r"^third_party/blink/.*",
36 r"^third_party/breakpad/.*",
Darwin Huangd74a9d32019-07-17 17:58:4637 # sqlite is an imported third party dependency.
Bruce Dawson40fece62022-09-16 19:58:3138 r"^third_party/sqlite/.*",
39 r"^v8/.*",
[email protected]3e4eb112011-01-18 03:29:5440 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5341 r".+_autogen\.h$",
Yue Shecf1380552022-08-23 20:59:2042 r".+_pb2(_grpc)?\.py$",
Bruce Dawson40fece62022-09-16 19:58:3143 r".+/pnacl_shim\.c$",
44 r"^gpu/config/.*_list_json\.cc$",
45 r"tools/md_browser/.*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1446 # Test pages for Maps telemetry tests.
Bruce Dawson40fece62022-09-16 19:58:3147 r"tools/perf/page_sets/maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5448 # Test pages for WebRTC telemetry tests.
Bruce Dawson40fece62022-09-16 19:58:3149 r"tools/perf/page_sets/webrtc_cases.*",
dpapad2efd4452023-04-06 01:43:4550 # Test file compared with generated output.
51 r"tools/polymer/tests/html_to_wrapper/.*.html.ts$",
[email protected]4306417642009-06-11 00:33:4052)
[email protected]ca8d1982009-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
[email protected]06e6d0ff2012-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
[email protected]06e6d0ff2012-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,
[email protected]06e6d0ff2012-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' %
[email protected]e2d7e6f2013-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/.*',
[email protected]7b054982013-11-27 00:44:4797 # Non-production example code.
Bruce Dawson40fece62022-09-16 19:58:3198 r'mojo/examples/.*',
[email protected]8176de12014-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/*'
[email protected]06e6d0ff2012-12-11 01:36:44107)
[email protected]ca8d1982009-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
[email protected]eea609a2011-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.')
[email protected]eea609a2011-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
[email protected]cf9b78f2012-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 Newsoneb6f5ce2022-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 '
Thiago Perrotta099034f2023-06-05 18:10:20291 'between batched tests. Use HistogramWatcher to check histogram records '
292 'instead.',
Henrique Nakashimabbf2b262023-03-10 17:21:39293 ),
294 False,
295 excluded_paths=(
296 'base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java',
297 'base/test/android/javatests/src/org/chromium/base/test/util/HistogramWatcher.java',
298 ),
299 ),
Eric Stevensona9a980972017-09-23 00:04:41300)
301
Clement Yan9b330cb2022-11-17 05:25:29302_BANNED_JAVASCRIPT_FUNCTIONS : Sequence [BanRule] = (
303 BanRule(
304 r'/\bchrome\.send\b',
305 (
306 '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).',
307 'Please use mojo instead for new webuis. https://docs.google.com/document/d/1RF-GSUoveYa37eoyZ9EhwMtaIwoW7Z88pIgNZ9YzQi4/edit#heading=h.gkk22wgk6wff',
308 ),
309 True,
310 (
311 r'^(?!ash\/webui).+',
312 # TODO(crbug.com/1385601): pre-existing violations still need to be
313 # cleaned up.
Rebekah Potter57aa94df2022-12-13 20:30:58314 'ash/webui/common/resources/cr.m.js',
Clement Yan9b330cb2022-11-17 05:25:29315 'ash/webui/common/resources/multidevice_setup/multidevice_setup_browser_proxy.js',
Martin Bidlingmaiera921fee72023-06-03 07:52:22316 'ash/webui/common/resources/quick_unlock/lock_screen_constants.ts',
Clement Yan9b330cb2022-11-17 05:25:29317 'ash/webui/common/resources/smb_shares/smb_browser_proxy.js',
318 'ash/webui/connectivity_diagnostics/resources/connectivity_diagnostics.js',
319 'ash/webui/diagnostics_ui/resources/diagnostics_browser_proxy.ts',
320 'ash/webui/multidevice_debug/resources/logs.js',
321 'ash/webui/multidevice_debug/resources/webui.js',
322 'ash/webui/projector_app/resources/annotator/trusted/annotator_browser_proxy.js',
323 'ash/webui/projector_app/resources/app/trusted/projector_browser_proxy.js',
324 'ash/webui/scanning/resources/scanning_browser_proxy.js',
325 ),
326 ),
327)
328
Daniel Cheng917ce542022-03-15 20:46:57329_BANNED_OBJC_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15330 BanRule(
[email protected]127f18ec2012-06-16 05:05:59331 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20332 (
333 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59334 'prohibited. Please use CrTrackingArea instead.',
335 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
336 ),
337 False,
338 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15339 BanRule(
[email protected]eaae1972014-04-16 04:17:26340 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20341 (
342 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59343 'instead.',
344 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
345 ),
346 False,
347 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15348 BanRule(
[email protected]127f18ec2012-06-16 05:05:59349 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20350 (
351 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59352 'Please use |convertPoint:(point) fromView:nil| instead.',
353 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
354 ),
355 True,
356 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15357 BanRule(
[email protected]127f18ec2012-06-16 05:05:59358 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20359 (
360 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59361 'Please use |convertPoint:(point) toView:nil| instead.',
362 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
363 ),
364 True,
365 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15366 BanRule(
[email protected]127f18ec2012-06-16 05:05:59367 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20368 (
369 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59370 'Please use |convertRect:(point) fromView:nil| instead.',
371 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
372 ),
373 True,
374 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15375 BanRule(
[email protected]127f18ec2012-06-16 05:05:59376 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20377 (
378 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59379 'Please use |convertRect:(point) toView:nil| instead.',
380 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
381 ),
382 True,
383 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15384 BanRule(
[email protected]127f18ec2012-06-16 05:05:59385 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20386 (
387 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59388 'Please use |convertSize:(point) fromView:nil| instead.',
389 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
390 ),
391 True,
392 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15393 BanRule(
[email protected]127f18ec2012-06-16 05:05:59394 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20395 (
396 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59397 'Please use |convertSize:(point) toView:nil| instead.',
398 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
399 ),
400 True,
401 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15402 BanRule(
jif65398702016-10-27 10:19:48403 r"/\s+UTF8String\s*]",
404 (
405 'The use of -[NSString UTF8String] is dangerous as it can return null',
406 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
407 'Please use |SysNSStringToUTF8| instead.',
408 ),
409 True,
410 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15411 BanRule(
Sylvain Defresne4cf1d182017-09-18 14:16:34412 r'__unsafe_unretained',
413 (
414 'The use of __unsafe_unretained is almost certainly wrong, unless',
415 'when interacting with NSFastEnumeration or NSInvocation.',
416 'Please use __weak in files build with ARC, nothing otherwise.',
417 ),
418 False,
419 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15420 BanRule(
Avi Drissman7382afa02019-04-29 23:27:13421 'freeWhenDone:NO',
422 (
423 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
424 'Foundation types is prohibited.',
425 ),
426 True,
427 ),
Avi Drissman3d243a42023-08-01 16:53:59428 BanRule(
429 'This file requires ARC support.',
430 (
431 'ARC compilation is default in Chromium; do not add boilerplate to ',
432 'files that require ARC.',
433 ),
434 True,
435 ),
[email protected]127f18ec2012-06-16 05:05:59436)
437
Sylvain Defresnea8b73d252018-02-28 15:45:54438_BANNED_IOS_OBJC_FUNCTIONS = (
Daniel Chenga44a1bcd2022-03-15 20:00:15439 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54440 r'/\bTEST[(]',
441 (
442 'TEST() macro should not be used in Objective-C++ code as it does not ',
443 'drain the autorelease pool at the end of the test. Use TEST_F() ',
444 'macro instead with a fixture inheriting from PlatformTest (or a ',
445 'typedef).'
446 ),
447 True,
448 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15449 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54450 r'/\btesting::Test\b',
451 (
452 'testing::Test should not be used in Objective-C++ code as it does ',
453 'not drain the autorelease pool at the end of the test. Use ',
454 'PlatformTest instead.'
455 ),
456 True,
457 ),
Ewann2ecc8d72022-07-18 07:41:23458 BanRule(
459 ' systemImageNamed:',
460 (
461 '+[UIImage systemImageNamed:] should not be used to create symbols.',
462 'Instead use a wrapper defined in:',
Victor Vianna77a40f62023-01-31 19:04:53463 'ios/chrome/browser/ui/icons/symbol_helpers.h'
Ewann2ecc8d72022-07-18 07:41:23464 ),
465 True,
Ewann450a2ef2022-07-19 14:38:23466 excluded_paths=(
Gauthier Ambard4d8756b2023-04-07 17:26:41467 'ios/chrome/browser/shared/ui/symbols/symbol_helpers.mm',
Gauthier Ambardd36c10b12023-03-16 08:45:03468 'ios/chrome/search_widget_extension/',
Ewann450a2ef2022-07-19 14:38:23469 ),
Ewann2ecc8d72022-07-18 07:41:23470 ),
Sylvain Defresnea8b73d252018-02-28 15:45:54471)
472
Daniel Cheng917ce542022-03-15 20:46:57473_BANNED_IOS_EGTEST_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15474 BanRule(
Peter K. Lee6c03ccff2019-07-15 14:40:05475 r'/\bEXPECT_OCMOCK_VERIFY\b',
476 (
477 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
478 'it is meant for GTests. Use [mock verify] instead.'
479 ),
480 True,
481 ),
482)
483
Daniel Cheng917ce542022-03-15 20:46:57484_BANNED_CPP_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15485 BanRule(
Peter Kasting94a56c42019-10-25 21:54:04486 r'/\busing namespace ',
487 (
488 'Using directives ("using namespace x") are banned by the Google Style',
489 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
490 'Explicitly qualify symbols or use using declarations ("using x::foo").',
491 ),
492 True,
493 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
494 ),
Antonio Gomes07300d02019-03-13 20:59:57495 # Make sure that gtest's FRIEND_TEST() macro is not used; the
496 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
497 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
Daniel Chenga44a1bcd2022-03-15 20:00:15498 BanRule(
[email protected]23e6cbc2012-06-16 18:51:20499 'FRIEND_TEST(',
500 (
[email protected]e3c945502012-06-26 20:01:49501 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20502 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
503 ),
504 False,
[email protected]7345da02012-11-27 14:31:49505 (),
[email protected]23e6cbc2012-06-16 18:51:20506 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15507 BanRule(
tomhudsone2c14d552016-05-26 17:07:46508 'setMatrixClip',
509 (
510 'Overriding setMatrixClip() is prohibited; ',
511 'the base function is deprecated. ',
512 ),
513 True,
514 (),
515 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15516 BanRule(
[email protected]52657f62013-05-20 05:30:31517 'SkRefPtr',
518 (
519 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22520 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31521 ),
522 True,
523 (),
524 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15525 BanRule(
[email protected]52657f62013-05-20 05:30:31526 'SkAutoRef',
527 (
528 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22529 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31530 ),
531 True,
532 (),
533 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15534 BanRule(
[email protected]52657f62013-05-20 05:30:31535 'SkAutoTUnref',
536 (
537 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22538 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31539 ),
540 True,
541 (),
542 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15543 BanRule(
[email protected]52657f62013-05-20 05:30:31544 'SkAutoUnref',
545 (
546 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
547 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22548 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31549 ),
550 True,
551 (),
552 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15553 BanRule(
[email protected]d89eec82013-12-03 14:10:59554 r'/HANDLE_EINTR\(.*close',
555 (
556 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
557 'descriptor will be closed, and it is incorrect to retry the close.',
558 'Either call close directly and ignore its return value, or wrap close',
559 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
560 ),
561 True,
562 (),
563 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15564 BanRule(
[email protected]d89eec82013-12-03 14:10:59565 r'/IGNORE_EINTR\((?!.*close)',
566 (
567 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
568 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
569 ),
570 True,
571 (
572 # Files that #define IGNORE_EINTR.
Bruce Dawson40fece62022-09-16 19:58:31573 r'^base/posix/eintr_wrapper\.h$',
574 r'^ppapi/tests/test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59575 ),
576 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15577 BanRule(
[email protected]ec5b3f02014-04-04 18:43:43578 r'/v8::Extension\(',
579 (
580 'Do not introduce new v8::Extensions into the code base, use',
581 'gin::Wrappable instead. See http://crbug.com/334679',
582 ),
583 True,
[email protected]f55c90ee62014-04-12 00:50:03584 (
Bruce Dawson40fece62022-09-16 19:58:31585 r'extensions/renderer/safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03586 ),
[email protected]ec5b3f02014-04-04 18:43:43587 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15588 BanRule(
jame2d1a952016-04-02 00:27:10589 '#pragma comment(lib,',
590 (
591 'Specify libraries to link with in build files and not in the source.',
592 ),
593 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41594 (
Bruce Dawson40fece62022-09-16 19:58:31595 r'^base/third_party/symbolize/.*',
596 r'^third_party/abseil-cpp/.*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41597 ),
jame2d1a952016-04-02 00:27:10598 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15599 BanRule(
Gabriel Charette7cc6c432018-04-25 20:52:02600 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59601 (
602 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
603 ),
604 False,
605 (),
606 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15607 BanRule(
Gabriel Charette7cc6c432018-04-25 20:52:02608 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59609 (
610 'Consider using THREAD_CHECKER macros instead of the class directly.',
611 ),
612 False,
613 (),
614 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15615 BanRule(
Sean Maher03efef12022-09-23 22:43:13616 r'/\b(?!(Sequenced|SingleThread))\w*TaskRunner::(GetCurrentDefault|CurrentDefaultHandle)',
617 (
618 'It is not allowed to call these methods from the subclasses ',
619 'of Sequenced or SingleThread task runners.',
620 ),
621 True,
622 (),
623 ),
624 BanRule(
Yuri Wiitala2f8de5c2017-07-21 00:11:06625 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
626 (
627 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
628 'deprecated (http://crbug.com/634507). Please avoid converting away',
629 'from the Time types in Chromium code, especially if any math is',
630 'being done on time values. For interfacing with platform/library',
631 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
632 'type converter methods instead. For faking TimeXXX values (for unit',
Peter Kasting53fd6ee2021-10-05 20:40:48633 'testing only), use TimeXXX() + Microseconds(N). For',
Yuri Wiitala2f8de5c2017-07-21 00:11:06634 'other use cases, please contact base/time/OWNERS.',
635 ),
636 False,
637 (),
638 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15639 BanRule(
dbeamb6f4fde2017-06-15 04:03:06640 'CallJavascriptFunctionUnsafe',
641 (
642 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
643 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
644 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
645 ),
646 False,
647 (
Bruce Dawson40fece62022-09-16 19:58:31648 r'^content/browser/webui/web_ui_impl\.(cc|h)$',
649 r'^content/public/browser/web_ui\.h$',
650 r'^content/public/test/test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06651 ),
652 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15653 BanRule(
dskiba1474c2bfd62017-07-20 02:19:24654 'leveldb::DB::Open',
655 (
656 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
657 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
658 "Chrome's tracing, making their memory usage visible.",
659 ),
660 True,
661 (
662 r'^third_party/leveldatabase/.*\.(cc|h)$',
663 ),
Gabriel Charette0592c3a2017-07-26 12:02:04664 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15665 BanRule(
Chris Mumfordc38afb62017-10-09 17:55:08666 'leveldb::NewMemEnv',
667 (
668 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58669 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
670 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08671 ),
672 True,
673 (
674 r'^third_party/leveldatabase/.*\.(cc|h)$',
675 ),
676 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15677 BanRule(
Gabriel Charetted9839bc2017-07-29 14:17:47678 'RunLoop::QuitCurrent',
679 (
Robert Liao64b7ab22017-08-04 23:03:43680 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
681 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47682 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41683 False,
Gabriel Charetted9839bc2017-07-29 14:17:47684 (),
Gabriel Charettea44975052017-08-21 23:14:04685 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15686 BanRule(
Gabriel Charettea44975052017-08-21 23:14:04687 'base::ScopedMockTimeMessageLoopTaskRunner',
688 (
Gabriel Charette87cc1af2018-04-25 20:52:51689 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11690 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51691 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
692 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
693 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04694 ),
Gabriel Charette87cc1af2018-04-25 20:52:51695 False,
Gabriel Charettea44975052017-08-21 23:14:04696 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57697 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15698 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44699 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57700 (
701 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02702 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57703 ),
704 True,
Robert Ogden4c43a712023-06-28 22:03:19705 [
706 # Abseil's benchmarks never linked into chrome.
707 'third_party/abseil-cpp/.*_benchmark.cc',
Robert Ogden4c43a712023-06-28 22:03:19708 ],
Francois Doray43670e32017-09-27 12:40:38709 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15710 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:08711 r'/\bstd::sto(i|l|ul|ll|ull)\b',
Peter Kasting991618a62019-06-17 22:00:09712 (
Peter Kastinge2c5ee82023-02-15 17:23:08713 'std::sto{i,l,ul,ll,ull}() use exceptions to communicate results. ',
714 'Use base::StringTo[U]Int[64]() instead.',
Peter Kasting991618a62019-06-17 22:00:09715 ),
716 True,
717 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
718 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15719 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:08720 r'/\bstd::sto(f|d|ld)\b',
Peter Kasting991618a62019-06-17 22:00:09721 (
Peter Kastinge2c5ee82023-02-15 17:23:08722 'std::sto{f,d,ld}() use exceptions to communicate results. ',
Peter Kasting991618a62019-06-17 22:00:09723 'For locale-independent values, e.g. reading numbers from disk',
724 'profiles, use base::StringToDouble().',
725 'For user-visible values, parse using ICU.',
726 ),
727 True,
728 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
729 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15730 BanRule(
Daniel Bratell69334cc2019-03-26 11:07:45731 r'/\bstd::to_string\b',
732 (
Peter Kastinge2c5ee82023-02-15 17:23:08733 'std::to_string() is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09734 'For locale-independent strings, e.g. writing numbers to disk',
735 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45736 'For user-visible strings, use base::FormatNumber() and',
737 'the related functions in base/i18n/number_formatting.h.',
738 ),
Peter Kasting991618a62019-06-17 22:00:09739 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21740 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45741 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15742 BanRule(
Peter Kasting6f79b202023-08-09 21:25:41743 r'/#include <(cctype|ctype\.h|cwctype|wctype.h)>',
744 (
745 '<cctype>/<ctype.h>/<cwctype>/<wctype.h> are banned. Use',
746 '"third_party/abseil-cpp/absl/strings/ascii.h" instead.',
747 ),
748 True,
749 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
750 ),
751 BanRule(
Daniel Bratell69334cc2019-03-26 11:07:45752 r'/\bstd::shared_ptr\b',
753 (
Peter Kastinge2c5ee82023-02-15 17:23:08754 'std::shared_ptr is banned. Use scoped_refptr instead.',
Daniel Bratell69334cc2019-03-26 11:07:45755 ),
756 True,
Ulan Degenbaev947043882021-02-10 14:02:31757 [
758 # Needed for interop with third-party library.
759 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
Alex Chau9eb03cdd52020-07-13 21:04:57760 'array_buffer_contents\.(cc|h)',
Ben Kelly39bf6bef2021-10-04 22:54:58761 '^third_party/blink/renderer/bindings/core/v8/' +
762 'v8_wasm_response_extensions.cc',
Wez5f56be52021-05-04 09:30:58763 '^gin/array_buffer\.(cc|h)',
Jiahe Zhange97ba772023-07-27 02:46:41764 '^gin/per_isolate_data\.(cc|h)',
Wez5f56be52021-05-04 09:30:58765 '^chrome/services/sharing/nearby/',
Stephen Nuskoe09c8ef22022-09-29 00:47:28766 # Needed for interop with third-party library libunwindstack.
Stephen Nuskoe51c1382022-09-26 15:49:03767 '^base/profiler/libunwindstack_unwinder_android\.(cc|h)',
Bob Beck03509d282022-12-07 21:49:05768 # Needed for interop with third-party boringssl cert verifier
769 '^third_party/boringssl/',
770 '^net/cert/',
771 '^net/tools/cert_verify_tool/',
772 '^services/cert_verifier/',
773 '^components/certificate_transparency/',
774 '^components/media_router/common/providers/cast/certificate/',
Meilin Wang00efc7c2021-05-13 01:12:42775 # gRPC provides some C++ libraries that use std::shared_ptr<>.
Yeunjoo Choi1b644402022-08-25 02:36:10776 '^chromeos/ash/services/libassistant/grpc/',
Vigen Issahhanjanfdf9de52021-12-22 21:13:59777 '^chromecast/cast_core/grpc',
778 '^chromecast/cast_core/runtime/browser',
Yue Shef83d95202022-09-26 20:23:45779 '^ios/chrome/test/earl_grey/chrome_egtest_plugin_client\.(mm|h)',
Wez5f56be52021-05-04 09:30:58780 # Fuchsia provides C++ libraries that use std::shared_ptr<>.
Wez6da2e412022-11-23 11:28:48781 '^base/fuchsia/.*\.(cc|h)',
Wez5f56be52021-05-04 09:30:58782 '.*fuchsia.*test\.(cc|h)',
miktb599ed12023-05-26 07:03:56783 # Clang plugins have different build config.
784 '^tools/clang/plugins/',
Alex Chau9eb03cdd52020-07-13 21:04:57785 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21786 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15787 BanRule(
Peter Kasting991618a62019-06-17 22:00:09788 r'/\bstd::weak_ptr\b',
789 (
Peter Kastinge2c5ee82023-02-15 17:23:08790 'std::weak_ptr is banned. Use base::WeakPtr instead.',
Peter Kasting991618a62019-06-17 22:00:09791 ),
792 True,
793 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
794 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15795 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21796 r'/\blong long\b',
797 (
Peter Kastinge2c5ee82023-02-15 17:23:08798 'long long is banned. Use [u]int64_t instead.',
Daniel Bratell609102be2019-03-27 20:53:21799 ),
800 False, # Only a warning since it is already used.
801 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
802 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15803 BanRule(
Daniel Cheng192683f2022-11-01 20:52:44804 r'/\b(absl|std)::any\b',
Daniel Chengc05fcc62022-01-12 16:54:29805 (
Peter Kastinge2c5ee82023-02-15 17:23:08806 '{absl,std}::any are banned due to incompatibility with the component ',
807 'build.',
Daniel Chengc05fcc62022-01-12 16:54:29808 ),
809 True,
810 # Not an error in third party folders, though it probably should be :)
811 [_THIRD_PARTY_EXCEPT_BLINK],
812 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15813 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21814 r'/\bstd::bind\b',
815 (
Peter Kastinge2c5ee82023-02-15 17:23:08816 'std::bind() is banned because of lifetime risks. Use ',
817 'base::Bind{Once,Repeating}() instead.',
Daniel Bratell609102be2019-03-27 20:53:21818 ),
819 True,
820 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
821 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15822 BanRule(
Daniel Cheng192683f2022-11-01 20:52:44823 (
Peter Kastingc7460d982023-03-14 21:01:42824 r'/\bstd::(?:'
825 r'linear_congruential_engine|mersenne_twister_engine|'
826 r'subtract_with_carry_engine|discard_block_engine|'
827 r'independent_bits_engine|shuffle_order_engine|'
828 r'minstd_rand0?|mt19937(_64)?|ranlux(24|48)(_base)?|knuth_b|'
829 r'default_random_engine|'
830 r'random_device|'
831 r'seed_seq'
Daniel Cheng192683f2022-11-01 20:52:44832 r')\b'
833 ),
834 (
835 'STL random number engines and generators are banned. Use the ',
836 'helpers in base/rand_util.h instead, e.g. base::RandBytes() or ',
837 'base::RandomBitGenerator.'
838 ),
839 True,
840 [
841 # Not an error in third_party folders.
842 _THIRD_PARTY_EXCEPT_BLINK,
843 # Various tools which build outside of Chrome.
844 r'testing/libfuzzer',
845 r'tools/android/io_benchmark/',
846 # Fuzzers are allowed to use standard library random number generators
847 # since fuzzing speed + reproducibility is important.
848 r'tools/ipc_fuzzer/',
849 r'.+_fuzzer\.cc$',
850 r'.+_fuzzertest\.cc$',
851 # TODO(https://crbug.com/1380528): These are all unsanctioned uses of
852 # the standard library's random number generators, and should be
853 # migrated to the //base equivalent.
854 r'ash/ambient/model/ambient_topic_queue\.cc',
855 r'base/allocator/partition_allocator/partition_alloc_unittest\.cc',
856 r'base/ranges/algorithm_unittest\.cc',
857 r'base/test/launcher/test_launcher\.cc',
858 r'cc/metrics/video_playback_roughness_reporter_unittest\.cc',
859 r'chrome/browser/apps/app_service/metrics/website_metrics\.cc',
860 r'chrome/browser/ash/power/auto_screen_brightness/monotone_cubic_spline_unittest\.cc',
861 r'chrome/browser/ash/printing/zeroconf_printer_detector_unittest\.cc',
862 r'chrome/browser/nearby_sharing/contacts/nearby_share_contact_manager_impl_unittest\.cc',
863 r'chrome/browser/nearby_sharing/contacts/nearby_share_contacts_sorter_unittest\.cc',
864 r'chrome/browser/privacy_budget/mesa_distribution_unittest\.cc',
865 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
866 r'chrome/browser/web_applications/test/web_app_test_utils\.cc',
867 r'chrome/browser/win/conflicts/module_blocklist_cache_util_unittest\.cc',
868 r'chrome/chrome_cleaner/logging/detailed_info_sampler\.cc',
869 r'chromeos/ash/components/memory/userspace_swap/swap_storage_unittest\.cc',
870 r'chromeos/ash/components/memory/userspace_swap/userspace_swap\.cc',
871 r'components/metrics/metrics_state_manager\.cc',
872 r'components/omnibox/browser/history_quick_provider_performance_unittest\.cc',
873 r'components/zucchini/disassembler_elf_unittest\.cc',
874 r'content/browser/webid/federated_auth_request_impl\.cc',
875 r'content/browser/webid/federated_auth_request_impl\.cc',
876 r'media/cast/test/utility/udp_proxy\.h',
877 r'sql/recover_module/module_unittest\.cc',
878 ],
879 ),
880 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:08881 r'/\b(absl,std)::bind_front\b',
Peter Kasting4f35bfc2022-10-18 18:39:12882 (
Peter Kastinge2c5ee82023-02-15 17:23:08883 '{absl,std}::bind_front() are banned. Use base::Bind{Once,Repeating}() '
884 'instead.',
Peter Kasting4f35bfc2022-10-18 18:39:12885 ),
886 True,
887 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
888 ),
889 BanRule(
890 r'/\bABSL_FLAG\b',
891 (
892 'ABSL_FLAG is banned. Use base::CommandLine instead.',
893 ),
894 True,
895 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
896 ),
897 BanRule(
898 r'/\babsl::c_',
899 (
Peter Kastinge2c5ee82023-02-15 17:23:08900 'Abseil container utilities are banned. Use base/ranges/algorithm.h ',
Peter Kasting4f35bfc2022-10-18 18:39:12901 'instead.',
902 ),
903 True,
904 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
905 ),
906 BanRule(
907 r'/\babsl::FunctionRef\b',
908 (
909 'absl::FunctionRef is banned. Use base::FunctionRef instead.',
910 ),
911 True,
912 [
913 # base::Bind{Once,Repeating} references absl::FunctionRef to disallow
914 # interoperability.
915 r'^base/functional/bind_internal\.h',
916 # base::FunctionRef is implemented on top of absl::FunctionRef.
917 r'^base/functional/function_ref.*\..+',
918 # Not an error in third_party folders.
919 _THIRD_PARTY_EXCEPT_BLINK,
920 ],
921 ),
922 BanRule(
923 r'/\babsl::(Insecure)?BitGen\b',
924 (
Daniel Cheng192683f2022-11-01 20:52:44925 'absl random number generators are banned. Use the helpers in '
926 'base/rand_util.h instead, e.g. base::RandBytes() or ',
927 'base::RandomBitGenerator.'
Peter Kasting4f35bfc2022-10-18 18:39:12928 ),
929 True,
930 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
931 ),
932 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:08933 r'/(\babsl::Span\b|#include <span>)',
Peter Kasting4f35bfc2022-10-18 18:39:12934 (
Peter Kastinge2c5ee82023-02-15 17:23:08935 'absl::Span is banned and <span> is not allowed yet ',
936 '(https://crbug.com/1414652). Use base::span instead.',
Peter Kasting4f35bfc2022-10-18 18:39:12937 ),
938 True,
Victor Vasiliev23b9ea6a2023-01-05 19:42:29939 [
940 # Needed to use QUICHE API.
941 r'services/network/web_transport\.cc',
Brianna Goldstein846d8002023-05-16 19:24:30942 r'chrome/browser/ip_protection/.*',
Victor Vasiliev23b9ea6a2023-01-05 19:42:29943 # Not an error in third_party folders.
944 _THIRD_PARTY_EXCEPT_BLINK
945 ],
Peter Kasting4f35bfc2022-10-18 18:39:12946 ),
947 BanRule(
948 r'/\babsl::StatusOr\b',
949 (
950 'absl::StatusOr is banned. Use base::expected instead.',
951 ),
952 True,
Adithya Srinivasanb2041882022-10-21 19:34:20953 [
954 # Needed to use liburlpattern API.
955 r'third_party/blink/renderer/core/url_pattern/.*',
Louise Brettc6d23872023-04-11 02:48:32956 r'third_party/blink/renderer/modules/manifest/manifest_parser\.cc',
Brianna Goldstein846d8002023-05-16 19:24:30957 # Needed to use QUICHE API.
958 r'chrome/browser/ip_protection/.*',
Adithya Srinivasanb2041882022-10-21 19:34:20959 # Not an error in third_party folders.
960 _THIRD_PARTY_EXCEPT_BLINK
961 ],
Peter Kasting4f35bfc2022-10-18 18:39:12962 ),
963 BanRule(
964 r'/\babsl::StrFormat\b',
965 (
Peter Kastinge2c5ee82023-02-15 17:23:08966 'absl::StrFormat() is not allowed yet (https://crbug.com/1371963). ',
967 'Use base::StringPrintf() instead.',
Peter Kasting4f35bfc2022-10-18 18:39:12968 ),
969 True,
970 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
971 ),
972 BanRule(
Peter Kasting4f35bfc2022-10-18 18:39:12973 r'/\babsl::(StrSplit|StrJoin|StrCat|StrAppend|Substitute|StrContains)\b',
974 (
975 'Abseil string utilities are banned. Use base/strings instead.',
976 ),
977 True,
978 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
979 ),
980 BanRule(
981 r'/\babsl::(Mutex|CondVar|Notification|Barrier|BlockingCounter)\b',
982 (
983 'Abseil synchronization primitives are banned. Use',
984 'base/synchronization instead.',
985 ),
986 True,
987 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
988 ),
989 BanRule(
990 r'/\babsl::(Duration|Time|TimeZone|CivilDay)\b',
991 (
992 'Abseil\'s time library is banned. Use base/time instead.',
993 ),
994 True,
Dustin J. Mitchell626a6d322023-06-26 15:02:48995 [
996 # Needed to use QUICHE API.
997 r'chrome/browser/ip_protection/.*',
998 _THIRD_PARTY_EXCEPT_BLINK # Not an error in third_party folders.
999 ],
Peter Kasting4f35bfc2022-10-18 18:39:121000 ),
1001 BanRule(
Avi Drissman48ee39e2022-02-16 16:31:031002 r'/\bstd::optional\b',
1003 (
Peter Kastinge2c5ee82023-02-15 17:23:081004 'std::optional is not allowed yet (https://crbug.com/1373619). Use ',
1005 'absl::optional instead.',
Avi Drissman48ee39e2022-02-16 16:31:031006 ),
1007 True,
miktb599ed12023-05-26 07:03:561008 [
1009 # Clang plugins have different build config.
1010 '^tools/clang/plugins/',
1011 # Not an error in third_party folders.
1012 _THIRD_PARTY_EXCEPT_BLINK,
1013 ],
Avi Drissman48ee39e2022-02-16 16:31:031014 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151015 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081016 r'/#include <chrono>',
Daniel Bratell609102be2019-03-27 20:53:211017 (
Peter Kastinge2c5ee82023-02-15 17:23:081018 '<chrono> is banned. Use base/time instead.',
Daniel Bratell609102be2019-03-27 20:53:211019 ),
1020 True,
1021 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1022 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151023 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081024 r'/#include <exception>',
Daniel Bratell609102be2019-03-27 20:53:211025 (
1026 'Exceptions are banned and disabled in Chromium.',
1027 ),
1028 True,
1029 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1030 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151031 BanRule(
Daniel Bratell609102be2019-03-27 20:53:211032 r'/\bstd::function\b',
1033 (
Peter Kastinge2c5ee82023-02-15 17:23:081034 'std::function is banned. Use base::{Once,Repeating}Callback instead.',
Daniel Bratell609102be2019-03-27 20:53:211035 ),
Daniel Chenge5583e3c2022-09-22 00:19:411036 True,
Daniel Chengcd23b8b2022-09-16 17:16:241037 [
1038 # Has tests that template trait helpers don't unintentionally match
1039 # std::function.
Daniel Chenge5583e3c2022-09-22 00:19:411040 r'base/functional/callback_helpers_unittest\.cc',
1041 # Required to implement interfaces from the third-party perfetto
1042 # library.
1043 r'base/tracing/perfetto_task_runner\.cc',
1044 r'base/tracing/perfetto_task_runner\.h',
1045 # Needed for interop with the third-party nearby library type
1046 # location::nearby::connections::ResultCallback.
1047 'chrome/services/sharing/nearby/nearby_connections_conversions\.cc'
1048 # Needed for interop with the internal libassistant library.
1049 'chromeos/ash/services/libassistant/callback_utils\.h',
1050 # Needed for interop with Fuchsia fidl APIs.
1051 'fuchsia_web/webengine/browser/context_impl_browsertest\.cc',
1052 'fuchsia_web/webengine/browser/cookie_manager_impl_unittest\.cc',
1053 'fuchsia_web/webengine/browser/media_player_impl_unittest\.cc',
1054 # Required to interop with interfaces from the third-party perfetto
1055 # library.
1056 'services/tracing/public/cpp/perfetto/custom_event_recorder\.cc',
1057 'services/tracing/public/cpp/perfetto/perfetto_traced_process\.cc',
1058 'services/tracing/public/cpp/perfetto/perfetto_traced_process\.h',
1059 'services/tracing/public/cpp/perfetto/perfetto_tracing_backend\.cc',
1060 'services/tracing/public/cpp/perfetto/producer_client\.cc',
1061 'services/tracing/public/cpp/perfetto/producer_client\.h',
1062 'services/tracing/public/cpp/perfetto/producer_test_utils\.cc',
1063 'services/tracing/public/cpp/perfetto/producer_test_utils\.h',
1064 # Required for interop with the third-party webrtc library.
1065 'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.cc',
1066 'third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl\.h',
Bob Beck5fc0be82022-12-12 23:32:521067 # This code is in the process of being extracted into a third-party library.
1068 # See https://crbug.com/1322914
1069 '^net/cert/pki/path_builder_unittest\.cc',
Daniel Chenge5583e3c2022-09-22 00:19:411070 # TODO(https://crbug.com/1364577): Various uses that should be
1071 # migrated to something else.
1072 # Should use base::OnceCallback or base::RepeatingCallback.
1073 'base/allocator/dispatcher/initializer_unittest\.cc',
1074 'chrome/browser/ash/accessibility/speech_monitor\.cc',
1075 'chrome/browser/ash/accessibility/speech_monitor\.h',
1076 'chrome/browser/ash/login/ash_hud_login_browsertest\.cc',
1077 'chromecast/base/observer_unittest\.cc',
1078 'chromecast/browser/cast_web_view\.h',
1079 'chromecast/public/cast_media_shlib\.h',
1080 'device/bluetooth/floss/exported_callback_manager\.h',
1081 'device/bluetooth/floss/floss_dbus_client\.h',
1082 'device/fido/cable/v2_handshake_unittest\.cc',
1083 'device/fido/pin\.cc',
1084 'services/tracing/perfetto/test_utils\.h',
1085 # Should use base::FunctionRef.
1086 'chrome/browser/media/webrtc/test_stats_dictionary\.cc',
1087 'chrome/browser/media/webrtc/test_stats_dictionary\.h',
1088 'chromeos/ash/services/libassistant/device_settings_controller\.cc',
1089 'components/browser_ui/client_certificate/android/ssl_client_certificate_request\.cc',
1090 'components/gwp_asan/client/sampling_malloc_shims_unittest\.cc',
1091 'content/browser/font_unique_name_lookup/font_unique_name_lookup_unittest\.cc',
1092 # Does not need std::function at all.
1093 'components/omnibox/browser/autocomplete_result\.cc',
1094 'device/fido/win/webauthn_api\.cc',
1095 'media/audio/alsa/alsa_util\.cc',
1096 'media/remoting/stream_provider\.h',
1097 'sql/vfs_wrapper\.cc',
1098 # TODO(https://crbug.com/1364585): Remove usage and exception list
1099 # entries.
1100 'extensions/renderer/api/automation/automation_internal_custom_bindings\.cc',
1101 'extensions/renderer/api/automation/automation_internal_custom_bindings\.h',
1102 # TODO(https://crbug.com/1364579): Remove usage and exception list
1103 # entry.
1104 'ui/views/controls/focus_ring\.h',
1105
1106 # Various pre-existing uses in //tools that is low-priority to fix.
1107 'tools/binary_size/libsupersize/viewer/caspian/diff\.cc',
1108 'tools/binary_size/libsupersize/viewer/caspian/model\.cc',
1109 'tools/binary_size/libsupersize/viewer/caspian/model\.h',
1110 'tools/binary_size/libsupersize/viewer/caspian/tree_builder\.h',
1111 'tools/clang/base_bind_rewriters/BaseBindRewriters\.cpp',
1112
Daniel Chengcd23b8b2022-09-16 17:16:241113 # Not an error in third_party folders.
1114 _THIRD_PARTY_EXCEPT_BLINK
1115 ],
Daniel Bratell609102be2019-03-27 20:53:211116 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151117 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081118 r'/#include <X11/',
Tom Andersona95e12042020-09-09 23:08:001119 (
1120 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
1121 ),
1122 True,
1123 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1124 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151125 BanRule(
Daniel Bratell609102be2019-03-27 20:53:211126 r'/\bstd::ratio\b',
1127 (
1128 'std::ratio is banned by the Google Style Guide.',
1129 ),
1130 True,
1131 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:451132 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151133 BanRule(
Peter Kasting6d77e9d2023-02-09 21:58:181134 r'/\bstd::aligned_alloc\b',
1135 (
Peter Kastinge2c5ee82023-02-15 17:23:081136 'std::aligned_alloc() is not yet allowed (crbug.com/1412818). Use ',
1137 'base::AlignedAlloc() instead.',
Peter Kasting6d77e9d2023-02-09 21:58:181138 ),
1139 True,
1140 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1141 ),
1142 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081143 r'/#include <(barrier|latch|semaphore|stop_token)>',
Peter Kasting6d77e9d2023-02-09 21:58:181144 (
Peter Kastinge2c5ee82023-02-15 17:23:081145 'The thread support library is banned. Use base/synchronization '
1146 'instead.',
Peter Kasting6d77e9d2023-02-09 21:58:181147 ),
1148 True,
1149 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1150 ),
1151 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081152 r'/\bstd::(c8rtomb|mbrtoc8)\b',
Peter Kasting6d77e9d2023-02-09 21:58:181153 (
Peter Kastinge2c5ee82023-02-15 17:23:081154 'std::c8rtomb() and std::mbrtoc8() are banned.',
Peter Kasting6d77e9d2023-02-09 21:58:181155 ),
1156 True,
1157 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1158 ),
1159 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081160 r'/\bchar8_t|std::u8string\b',
Peter Kasting6d77e9d2023-02-09 21:58:181161 (
Peter Kastinge2c5ee82023-02-15 17:23:081162 'char8_t and std::u8string are not yet allowed. Can you use [unsigned]',
1163 ' char and std::string instead?',
1164 ),
1165 True,
Daniel Cheng893c563f2023-04-21 09:54:521166 [
1167 # The demangler does not use this type but needs to know about it.
1168 'base/third_party/symbolize/demangle\.cc',
1169 # Don't warn in third_party folders.
1170 _THIRD_PARTY_EXCEPT_BLINK
1171 ],
Peter Kastinge2c5ee82023-02-15 17:23:081172 ),
1173 BanRule(
1174 r'/(\b(co_await|co_return|co_yield)\b|#include <coroutine>)',
1175 (
1176 'Coroutines are not yet allowed (https://crbug.com/1403840).',
1177 ),
1178 True,
1179 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1180 ),
1181 BanRule(
Peter Kastingcc152522023-03-22 20:17:371182 r'/^\s*(export\s|import\s+["<:\w]|module(;|\s+[:\w]))',
Peter Kasting69357dc2023-03-14 01:34:291183 (
1184 'Modules are disallowed for now due to lack of toolchain support.',
1185 ),
1186 True,
1187 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1188 ),
1189 BanRule(
Peter Kastinge2c5ee82023-02-15 17:23:081190 r'/\[\[(un)?likely\]\]',
1191 (
1192 '[[likely]] and [[unlikely]] are not yet allowed ',
1193 '(https://crbug.com/1414620). Use [UN]LIKELY instead.',
1194 ),
1195 True,
1196 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1197 ),
1198 BanRule(
1199 r'/#include <format>',
1200 (
1201 '<format> is not yet allowed. Use base::StringPrintf() instead.',
1202 ),
1203 True,
1204 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1205 ),
1206 BanRule(
1207 r'/#include <ranges>',
1208 (
1209 '<ranges> is not yet allowed. Use base/ranges/algorithm.h instead.',
1210 ),
1211 True,
1212 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1213 ),
1214 BanRule(
1215 r'/#include <source_location>',
1216 (
1217 '<source_location> is not yet allowed. Use base/location.h instead.',
1218 ),
1219 True,
1220 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1221 ),
1222 BanRule(
1223 r'/#include <syncstream>',
1224 (
1225 '<syncstream> is banned.',
Peter Kasting6d77e9d2023-02-09 21:58:181226 ),
1227 True,
1228 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
1229 ),
1230 BanRule(
Michael Giuffrida7f93d6922019-04-19 14:39:581231 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:191232 (
1233 'RunMessageLoop is deprecated, use RunLoop instead.',
1234 ),
1235 False,
1236 (),
1237 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151238 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441239 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:191240 (
1241 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
1242 "if you're convinced you need this.",
1243 ),
1244 False,
1245 (),
1246 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151247 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441248 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:191249 (
1250 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:041251 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:191252 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
1253 'async events instead of flushing threads.',
1254 ),
1255 False,
1256 (),
1257 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151258 BanRule(
Gabriel Charette147335ea2018-03-22 15:59:191259 r'MessageLoopRunner',
1260 (
1261 'MessageLoopRunner is deprecated, use RunLoop instead.',
1262 ),
1263 False,
1264 (),
1265 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151266 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441267 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:191268 (
1269 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
1270 "gab@ if you found a use case where this is the only solution.",
1271 ),
1272 False,
1273 (),
1274 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151275 BanRule(
Victor Costane48a2e82019-03-15 22:02:341276 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:161277 (
Victor Costane48a2e82019-03-15 22:02:341278 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:161279 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
1280 ),
1281 True,
1282 (
1283 r'^sql/initialization\.(cc|h)$',
1284 r'^third_party/sqlite/.*\.(c|cc|h)$',
1285 ),
1286 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151287 BanRule(
Austin Sullivand661ab52022-11-16 08:55:151288 'CREATE VIEW',
1289 (
1290 'SQL views are disabled in Chromium feature code',
1291 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-views',
1292 ),
1293 True,
1294 (
1295 _THIRD_PARTY_EXCEPT_BLINK,
1296 # sql/ itself uses views when using memory-mapped IO.
1297 r'^sql/.*',
1298 # Various performance tools that do not build as part of Chrome.
1299 r'^infra/.*',
1300 r'^tools/perf.*',
1301 r'.*perfetto.*',
1302 ),
1303 ),
1304 BanRule(
1305 'CREATE VIRTUAL TABLE',
1306 (
1307 'SQL virtual tables are disabled in Chromium feature code',
1308 'https://chromium.googlesource.com/chromium/src/+/HEAD/sql#no-virtual-tables',
1309 ),
1310 True,
1311 (
1312 _THIRD_PARTY_EXCEPT_BLINK,
1313 # sql/ itself uses virtual tables in the recovery module and tests.
1314 r'^sql/.*',
1315 # TODO(https://crbug.com/695592): Remove once WebSQL is deprecated.
1316 r'third_party/blink/web_tests/storage/websql/.*'
1317 # Various performance tools that do not build as part of Chrome.
1318 r'^tools/perf.*',
1319 r'.*perfetto.*',
1320 ),
1321 ),
1322 BanRule(
Dave Tapuska98199b612019-07-10 13:30:441323 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:471324 (
1325 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
1326 'base::RandomShuffle instead.'
1327 ),
1328 True,
1329 (),
1330 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151331 BanRule(
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:241332 'ios/web/public/test/http_server',
1333 (
1334 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
1335 ),
1336 False,
1337 (),
1338 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151339 BanRule(
Robert Liao764c9492019-01-24 18:46:281340 'GetAddressOf',
1341 (
1342 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:531343 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:111344 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:531345 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:281346 ),
1347 True,
1348 (),
1349 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151350 BanRule(
Ben Lewisa9514602019-04-29 17:53:051351 'SHFileOperation',
1352 (
1353 'SHFileOperation was deprecated in Windows Vista, and there are less ',
1354 'complex functions to achieve the same goals. Use IFileOperation for ',
1355 'any esoteric actions instead.'
1356 ),
1357 True,
1358 (),
1359 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151360 BanRule(
Cliff Smolinsky81951642019-04-30 21:39:511361 'StringFromGUID2',
1362 (
1363 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241364 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511365 ),
1366 True,
1367 (
Daniel Chenga44a1bcd2022-03-15 20:00:151368 r'/base/win/win_util_unittest.cc',
Cliff Smolinsky81951642019-04-30 21:39:511369 ),
1370 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151371 BanRule(
Cliff Smolinsky81951642019-04-30 21:39:511372 'StringFromCLSID',
1373 (
1374 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241375 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511376 ),
1377 True,
1378 (
Daniel Chenga44a1bcd2022-03-15 20:00:151379 r'/base/win/win_util_unittest.cc',
Cliff Smolinsky81951642019-04-30 21:39:511380 ),
1381 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151382 BanRule(
Avi Drissman7382afa02019-04-29 23:27:131383 'kCFAllocatorNull',
1384 (
1385 'The use of kCFAllocatorNull with the NoCopy creation of ',
1386 'CoreFoundation types is prohibited.',
1387 ),
1388 True,
1389 (),
1390 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151391 BanRule(
Oksana Zhuravlovafd247772019-05-16 16:57:291392 'mojo::ConvertTo',
1393 (
1394 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1395 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1396 'StringTraits if you would like to convert between custom types and',
1397 'the wire format of mojom types.'
1398 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221399 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291400 (
David Dorwin13dc48b2022-06-03 21:18:421401 r'^fuchsia_web/webengine/browser/url_request_rewrite_rules_manager\.cc$',
1402 r'^fuchsia_web/webengine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291403 r'^third_party/blink/.*\.(cc|h)$',
1404 r'^content/renderer/.*\.(cc|h)$',
1405 ),
1406 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151407 BanRule(
Oksana Zhuravlovac8222d22019-12-19 19:21:161408 'GetInterfaceProvider',
1409 (
1410 'InterfaceProvider is deprecated.',
1411 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1412 'or Platform::GetBrowserInterfaceBroker.'
1413 ),
1414 False,
1415 (),
1416 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151417 BanRule(
Robert Liao1d78df52019-11-11 20:02:011418 'CComPtr',
1419 (
1420 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1421 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1422 'details.'
1423 ),
1424 False,
1425 (),
1426 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151427 BanRule(
Xiaohan Wang72bd2ba2020-02-18 21:38:201428 r'/\b(IFACE|STD)METHOD_?\(',
1429 (
1430 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1431 'Instead, always use IFACEMETHODIMP in the declaration.'
1432 ),
1433 False,
1434 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1435 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151436 BanRule(
Allen Bauer53b43fb12020-03-12 17:21:471437 'set_owned_by_client',
1438 (
1439 'set_owned_by_client is deprecated.',
1440 'views::View already owns the child views by default. This introduces ',
1441 'a competing ownership model which makes the code difficult to reason ',
1442 'about. See http://crbug.com/1044687 for more details.'
1443 ),
1444 False,
1445 (),
1446 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151447 BanRule(
Peter Boström7ff41522021-07-29 03:43:271448 'RemoveAllChildViewsWithoutDeleting',
1449 (
1450 'RemoveAllChildViewsWithoutDeleting is deprecated.',
1451 'This method is deemed dangerous as, unless raw pointers are re-added,',
1452 'calls to this method introduce memory leaks.'
1453 ),
1454 False,
1455 (),
1456 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151457 BanRule(
Eric Secklerbe6f48d2020-05-06 18:09:121458 r'/\bTRACE_EVENT_ASYNC_',
1459 (
1460 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1461 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1462 ),
1463 False,
1464 (
1465 r'^base/trace_event/.*',
1466 r'^base/tracing/.*',
1467 ),
1468 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151469 BanRule(
Aditya Kushwah5a286b72022-02-10 04:54:431470 r'/\bbase::debug::DumpWithoutCrashingUnthrottled[(][)]',
1471 (
1472 'base::debug::DumpWithoutCrashingUnthrottled() does not throttle',
1473 'dumps and may spam crash reports. Consider if the throttled',
1474 'variants suffice instead.',
1475 ),
1476 False,
1477 (),
1478 ),
Daniel Chenga44a1bcd2022-03-15 20:00:151479 BanRule(
Robert Liao22f66a52021-04-10 00:57:521480 'RoInitialize',
1481 (
Robert Liao48018922021-04-16 23:03:021482 'Improper use of [base::win]::RoInitialize() has been implicated in a ',
Robert Liao22f66a52021-04-10 00:57:521483 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
1484 'instead. See http://crbug.com/1197722 for more information.'
1485 ),
1486 True,
Robert Liao48018922021-04-16 23:03:021487 (
Bruce Dawson40fece62022-09-16 19:58:311488 r'^base/win/scoped_winrt_initializer\.cc$',
Danil Chapovalov07694382023-05-24 17:55:211489 r'^third_party/abseil-cpp/absl/.*',
Robert Liao48018922021-04-16 23:03:021490 ),
Robert Liao22f66a52021-04-10 00:57:521491 ),
Patrick Monettec343bb982022-06-01 17:18:451492 BanRule(
1493 r'base::Watchdog',
1494 (
1495 'base::Watchdog is deprecated because it creates its own thread.',
1496 'Instead, manually start a timer on a SequencedTaskRunner.',
1497 ),
1498 False,
1499 (),
1500 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091501 BanRule(
1502 'base::Passed',
1503 (
1504 'Do not use base::Passed. It is a legacy helper for capturing ',
1505 'move-only types with base::BindRepeating, but invoking the ',
1506 'resulting RepeatingCallback moves the captured value out of ',
1507 'the callback storage, and subsequent invocations may pass the ',
1508 'value in a valid but undefined state. Prefer base::BindOnce().',
1509 'See http://crbug.com/1326449 for context.'
1510 ),
1511 False,
Daniel Cheng91f6fbaf2022-09-16 12:07:481512 (
1513 # False positive, but it is also fine to let bind internals reference
1514 # base::Passed.
Daniel Chengcd23b8b2022-09-16 17:16:241515 r'^base[\\/]functional[\\/]bind\.h',
Daniel Cheng91f6fbaf2022-09-16 12:07:481516 r'^base[\\/]functional[\\/]bind_internal\.h',
1517 ),
Andrew Rayskiy04a51ce2022-06-07 11:47:091518 ),
Daniel Cheng2248b332022-07-27 06:16:591519 BanRule(
Daniel Chengba3bc2e2022-10-03 02:45:431520 r'base::Feature k',
1521 (
1522 'Please use BASE_DECLARE_FEATURE() or BASE_FEATURE() instead of ',
1523 'directly declaring/defining features.'
1524 ),
1525 True,
1526 [
1527 _THIRD_PARTY_EXCEPT_BLINK,
1528 ],
1529 ),
Robert Ogden92101dcb2022-10-19 23:49:361530 BanRule(
Arthur Sonzogni1da65fa2023-03-27 16:01:521531 r'/\bchartorune\b',
Robert Ogden92101dcb2022-10-19 23:49:361532 (
1533 'chartorune is not memory-safe, unless you can guarantee the input ',
1534 'string is always null-terminated. Otherwise, please use charntorune ',
1535 'from libphonenumber instead.'
1536 ),
1537 True,
1538 [
1539 _THIRD_PARTY_EXCEPT_BLINK,
1540 # Exceptions to this rule should have a fuzzer.
1541 ],
1542 ),
Arthur Sonzogni1da65fa2023-03-27 16:01:521543 BanRule(
1544 r'/\b#include "base/atomicops\.h"\b',
1545 (
1546 'Do not use base::subtle atomics, but std::atomic, which are simpler '
1547 'to use, have better understood, clearer and richer semantics, and are '
1548 'harder to mis-use. See details in base/atomicops.h.',
1549 ),
1550 False,
1551 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Benoit Lize79cf0592023-01-27 10:01:571552 ),
Arthur Sonzogni60348572e2023-04-07 10:22:521553 BanRule(
1554 r'CrossThreadPersistent<',
1555 (
1556 'Do not use blink::CrossThreadPersistent, but '
1557 'blink::CrossThreadHandle. It is harder to mis-use.',
1558 'More info: '
1559 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1560 'Please contact platform-architecture-dev@ before adding new instances.'
1561 ),
1562 False,
1563 []
1564 ),
1565 BanRule(
1566 r'CrossThreadWeakPersistent<',
1567 (
1568 'Do not use blink::CrossThreadWeakPersistent, but '
1569 'blink::CrossThreadWeakHandle. It is harder to mis-use.',
1570 'More info: '
1571 'https://docs.google.com/document/d/1GIT0ysdQ84sGhIo1r9EscF_fFt93lmNVM_q4vvHj2FQ/edit#heading=h.3e4d6y61tgs',
1572 'Please contact platform-architecture-dev@ before adding new instances.'
1573 ),
1574 False,
1575 []
1576 ),
Avi Drissman491617c2023-04-13 17:33:151577 BanRule(
1578 r'objc/objc.h',
1579 (
1580 'Do not include <objc/objc.h>. It defines away ARC lifetime '
1581 'annotations, and is thus dangerous.',
1582 'Please use the pimpl pattern; search for `ObjCStorage` for examples.',
1583 'For further reading on how to safely mix C++ and Obj-C, see',
1584 'https://chromium.googlesource.com/chromium/src/+/main/docs/mac/mixing_cpp_and_objc.md'
1585 ),
1586 True,
1587 []
1588 ),
Grace Park8d59b54b2023-04-26 17:53:351589 BanRule(
1590 r'/#include <filesystem>',
1591 (
1592 'libc++ <filesystem> is banned per the Google C++ styleguide.',
1593 ),
1594 True,
1595 # This fuzzing framework is a standalone open source project and
1596 # cannot rely on Chromium base.
1597 (r'third_party/centipede'),
1598 ),
Daniel Cheng72153e02023-05-18 21:18:141599 BanRule(
1600 r'TopDocument()',
1601 (
1602 'TopDocument() does not work correctly with out-of-process iframes. '
1603 'Please do not introduce new uses.',
1604 ),
1605 True,
1606 (
1607 # TODO(crbug.com/617677): Remove all remaining uses.
1608 r'^third_party/blink/renderer/core/dom/document\.cc',
1609 r'^third_party/blink/renderer/core/dom/document\.h',
1610 r'^third_party/blink/renderer/core/dom/element\.cc',
1611 r'^third_party/blink/renderer/core/exported/web_disallow_transition_scope_test\.cc',
1612 r'^third_party/blink/renderer/core/exported/web_document_test\.cc',
Daniel Cheng72153e02023-05-18 21:18:141613 r'^third_party/blink/renderer/core/html/html_anchor_element\.cc',
1614 r'^third_party/blink/renderer/core/html/html_dialog_element\.cc',
1615 r'^third_party/blink/renderer/core/html/html_element\.cc',
1616 r'^third_party/blink/renderer/core/html/html_frame_owner_element\.cc',
1617 r'^third_party/blink/renderer/core/html/media/video_wake_lock\.cc',
1618 r'^third_party/blink/renderer/core/loader/anchor_element_interaction_tracker\.cc',
1619 r'^third_party/blink/renderer/core/page/scrolling/root_scroller_controller\.cc',
1620 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.cc',
1621 r'^third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller\.h',
1622 r'^third_party/blink/renderer/core/script/classic_pending_script\.cc',
1623 r'^third_party/blink/renderer/core/script/script_loader\.cc',
1624 ),
1625 ),
Arthur Sonzognif0eea302023-08-18 19:20:311626 BanRule(
1627 pattern = r'base::raw_ptr<',
1628 explanation = (
1629 'Do not use base::raw_ptr, use raw_ptr.',
1630 ),
1631 treat_as_error = True,
1632 excluded_paths = (
1633 '^base/',
1634 '^tools/',
1635 ),
1636 ),
1637 BanRule(
1638 pattern = r'base:raw_ref<',
1639 explanation = (
1640 'Do not use base::raw_ref, use raw_ref.',
1641 ),
1642 treat_as_error = True,
1643 excluded_paths = (
1644 '^base/',
1645 '^tools/',
1646 ),
1647 ),
[email protected]127f18ec2012-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]
[email protected]127f18ec2012-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',
Andrew Grieve4c4cede2020-11-20 22:09:361711 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041712 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361713 'build/android/gyp/aar.pydeps',
1714 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271715 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361716 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381717 'build/android/gyp/assert_static_initializers.pydeps',
Mohamed Heikal133e1f22023-04-18 20:04:371718 'build/android/gyp/binary_baseline_profile.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361719 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021720 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:221721 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111722 'build/android/gyp/compile_java.pydeps',
Peter Weneaa963f2023-01-20 19:40:301723 'build/android/gyp/compile_kt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361724 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361725 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361726 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111727 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041728 'build/android/gyp/create_app_bundle_apks.pydeps',
1729 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361730 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121731 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091732 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221733 'build/android/gyp/create_size_info_files.pydeps',
Peter Wene6e017e2022-07-27 21:40:401734 'build/android/gyp/create_test_apk_wrapper_script.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001735 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361736 'build/android/gyp/dex.pydeps',
1737 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361738 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:211739 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361740 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361741 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361742 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581743 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361744 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141745 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261746 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:471747 'build/android/gyp/java_google_api_keys.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041748 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361749 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361750 'build/android/gyp/merge_manifest.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:101751 'build/android/gyp/optimize_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361752 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221753 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361754 'build/android/gyp/proguard.pydeps',
Andrew Grievee3a775ab2022-05-16 15:59:221755 'build/android/gyp/system_image_apks.pydeps',
Bruce Dawson853b739e62022-05-03 23:03:101756 'build/android/gyp/trace_event_bytecode_rewriter.pydeps',
Peter Wen578730b2020-03-19 19:55:461757 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:301758 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241759 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361760 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461761 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561762 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361763 'build/android/incremental_install/generate_android_manifest.pydeps',
1764 'build/android/incremental_install/write_installer_json.pydeps',
Stephanie Kim392913b452022-06-15 17:25:321765 'build/android/pylib/results/presentation/test_results_presentation.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041766 'build/android/resource_sizes.pydeps',
1767 'build/android/test_runner.pydeps',
1768 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361769 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361770 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321771 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271772 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1773 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:041774 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001775 'components/cronet/tools/generate_javadoc.pydeps',
1776 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381777 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001778 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381779 'net/tools/testserver/testserver.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181780 'testing/scripts/run_isolated_script_test.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411781 'testing/merge_scripts/standard_isolated_script_merge.pydeps',
1782 'testing/merge_scripts/standard_gtest_merge.pydeps',
1783 'testing/merge_scripts/code_coverage/merge_results.pydeps',
1784 'testing/merge_scripts/code_coverage/merge_steps.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041785 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421786 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
Yuki Shiino38eeaad12022-08-11 06:40:251787 'third_party/blink/renderer/bindings/scripts/check_generated_file_list.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421788 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131789 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Yuki Shiinoea477d32023-08-21 06:24:341790 'third_party/blink/renderer/bindings/scripts/generate_event_interface_names.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:501791 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411792 'third_party/blink/tools/blinkpy/web_tests/merge_results.pydeps',
1793 'third_party/blink/tools/merge_web_test_results.pydeps',
Sam Maierb926c58c2023-08-08 19:58:251794 'third_party/jni_zero/jni_zero.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('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451807 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591808 ) | set('%[email protected]' % 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('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271817 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041818 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:161819 for s in ('chromium-internal-autoroll',)
1820 ) | set('%[email protected]' % s
Chong Gub277e342022-10-15 03:30:551821 for s in ('swarming-tasks',)
1822 ) | set('%[email protected]' % 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]
[email protected]55459852011-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_]+::$')
[email protected]55459852011-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)
[email protected]55459852011-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)
[email protected]55459852011-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 []
[email protected]55459852011-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)
Andrew Grieve40f451d2023-07-06 19:46:511972 allowlist_re = input_api.re.compile(r'// IN-TEST$')
Vaclav Brozek7dbc28c2018-03-27 08:35:231973
Sam Maiera6e76d72022-02-11 21:43:501974 problems = []
1975 sources = lambda x: input_api.FilterSourceFile(
1976 x,
1977 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
1978 DEFAULT_FILES_TO_SKIP),
1979 files_to_check=[r'.*\.java$'])
1980 for f in input_api.AffectedFiles(include_deletes=False,
1981 file_filter=sources):
1982 local_path = f.LocalPath()
Vaclav Brozek7dbc28c2018-03-27 08:35:231983 is_inside_javadoc = False
Sam Maiera6e76d72022-02-11 21:43:501984 for line_number, line in f.ChangedContents():
1985 if is_inside_javadoc and javadoc_end_re.search(line):
1986 is_inside_javadoc = False
1987 if not is_inside_javadoc and javadoc_start_re.search(line):
1988 is_inside_javadoc = True
1989 if is_inside_javadoc:
1990 continue
1991 if (inclusion_re.search(line) and not comment_re.search(line)
1992 and not annotation_re.search(line)
Andrew Grieve40f451d2023-07-06 19:46:511993 and not allowlist_re.search(line)
Sam Maiera6e76d72022-02-11 21:43:501994 and not exclusion_re.search(line)):
1995 problems.append('%s:%d\n %s' %
1996 (local_path, line_number, line.strip()))
Vaclav Brozek7dbc28c2018-03-27 08:35:231997
Sam Maiera6e76d72022-02-11 21:43:501998 if problems:
1999 return [
2000 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
2001 ]
2002 else:
2003 return []
Vaclav Brozek7dbc28c2018-03-27 08:35:232004
2005
Saagar Sanghavifceeaae2020-08-12 16:40:362006def CheckNoIOStreamInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502007 """Checks to make sure no .h files include <iostream>."""
2008 files = []
2009 pattern = input_api.re.compile(r'^#include\s*<iostream>',
2010 input_api.re.MULTILINE)
2011 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2012 if not f.LocalPath().endswith('.h'):
2013 continue
2014 contents = input_api.ReadFile(f)
2015 if pattern.search(contents):
2016 files.append(f)
[email protected]10689ca2011-09-02 02:31:542017
Sam Maiera6e76d72022-02-11 21:43:502018 if len(files):
2019 return [
2020 output_api.PresubmitError(
2021 'Do not #include <iostream> in header files, since it inserts static '
2022 'initialization into every file including the header. Instead, '
2023 '#include <ostream>. See http://crbug.com/94794', files)
2024 ]
2025 return []
2026
[email protected]10689ca2011-09-02 02:31:542027
Aleksey Khoroshilov9b28c032022-06-03 16:35:322028def CheckNoStrCatRedefines(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502029 """Checks no windows headers with StrCat redefined are included directly."""
2030 files = []
Aleksey Khoroshilov9b28c032022-06-03 16:35:322031 files_to_check = (r'.+%s' % _HEADER_EXTENSIONS,
2032 r'.+%s' % _IMPLEMENTATION_EXTENSIONS)
2033 files_to_skip = (input_api.DEFAULT_FILES_TO_SKIP +
2034 _NON_BASE_DEPENDENT_PATHS)
2035 sources_filter = lambda f: input_api.FilterSourceFile(
2036 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
2037
Sam Maiera6e76d72022-02-11 21:43:502038 pattern_deny = input_api.re.compile(
2039 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
2040 input_api.re.MULTILINE)
2041 pattern_allow = input_api.re.compile(
2042 r'^#include\s"base/win/windows_defines.inc"', input_api.re.MULTILINE)
Aleksey Khoroshilov9b28c032022-06-03 16:35:322043 for f in input_api.AffectedSourceFiles(sources_filter):
Sam Maiera6e76d72022-02-11 21:43:502044 contents = input_api.ReadFile(f)
2045 if pattern_deny.search(
2046 contents) and not pattern_allow.search(contents):
2047 files.append(f.LocalPath())
Danil Chapovalov3518f362018-08-11 16:13:432048
Sam Maiera6e76d72022-02-11 21:43:502049 if len(files):
2050 return [
2051 output_api.PresubmitError(
2052 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
2053 'directly since they pollute code with StrCat macro. Instead, '
2054 'include matching header from base/win. See http://crbug.com/856536',
2055 files)
2056 ]
2057 return []
Danil Chapovalov3518f362018-08-11 16:13:432058
[email protected]10689ca2011-09-02 02:31:542059
Andrew Williamsc9f69b482023-07-10 16:07:362060def _CheckNoUNIT_TESTInSourceFiles(input_api, f):
2061 problems = []
2062
2063 unit_test_macro = input_api.re.compile(
2064 '^\s*#.*(?:ifn?def\s+UNIT_TEST|defined\s*\(?\s*UNIT_TEST\s*\)?)(?:$|\s+)')
2065 for line_num, line in f.ChangedContents():
2066 if unit_test_macro.match(line):
2067 problems.append(' %s:%d' % (f.LocalPath(), line_num))
2068
2069 return problems
2070
2071
Saagar Sanghavifceeaae2020-08-12 16:40:362072def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502073 """Checks to make sure no source files use UNIT_TEST."""
2074 problems = []
2075 for f in input_api.AffectedFiles():
2076 if (not f.LocalPath().endswith(('.cc', '.mm'))):
2077 continue
Andrew Williamsc9f69b482023-07-10 16:07:362078 problems.extend(
2079 _CheckNoUNIT_TESTInSourceFiles(input_api, f))
[email protected]72df4e782012-06-21 16:28:182080
Sam Maiera6e76d72022-02-11 21:43:502081 if not problems:
2082 return []
2083 return [
2084 output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
2085 '\n'.join(problems))
2086 ]
2087
[email protected]72df4e782012-06-21 16:28:182088
Saagar Sanghavifceeaae2020-08-12 16:40:362089def CheckNoDISABLETypoInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502090 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
Dominic Battre033531052018-09-24 15:45:342091
Sam Maiera6e76d72022-02-11 21:43:502092 This test warns if somebody tries to disable a test with the DISABLE_ prefix
2093 instead of DISABLED_. To filter false positives, reports are only generated
2094 if a corresponding MAYBE_ line exists.
2095 """
2096 problems = []
Dominic Battre033531052018-09-24 15:45:342097
Sam Maiera6e76d72022-02-11 21:43:502098 # The following two patterns are looked for in tandem - is a test labeled
2099 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
2100 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
2101 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
Dominic Battre033531052018-09-24 15:45:342102
Sam Maiera6e76d72022-02-11 21:43:502103 # This is for the case that a test is disabled on all platforms.
2104 full_disable_pattern = input_api.re.compile(
2105 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
2106 input_api.re.MULTILINE)
Dominic Battre033531052018-09-24 15:45:342107
Sam Maiera6e76d72022-02-11 21:43:502108 for f in input_api.AffectedFiles(False):
2109 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2110 continue
Dominic Battre033531052018-09-24 15:45:342111
Sam Maiera6e76d72022-02-11 21:43:502112 # Search for MABYE_, DISABLE_ pairs.
2113 disable_lines = {} # Maps of test name to line number.
2114 maybe_lines = {}
2115 for line_num, line in f.ChangedContents():
2116 disable_match = disable_pattern.search(line)
2117 if disable_match:
2118 disable_lines[disable_match.group(1)] = line_num
2119 maybe_match = maybe_pattern.search(line)
2120 if maybe_match:
2121 maybe_lines[maybe_match.group(1)] = line_num
Dominic Battre033531052018-09-24 15:45:342122
Sam Maiera6e76d72022-02-11 21:43:502123 # Search for DISABLE_ occurrences within a TEST() macro.
2124 disable_tests = set(disable_lines.keys())
2125 maybe_tests = set(maybe_lines.keys())
2126 for test in disable_tests.intersection(maybe_tests):
2127 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
Dominic Battre033531052018-09-24 15:45:342128
Sam Maiera6e76d72022-02-11 21:43:502129 contents = input_api.ReadFile(f)
2130 full_disable_match = full_disable_pattern.search(contents)
2131 if full_disable_match:
2132 problems.append(' %s' % f.LocalPath())
Dominic Battre033531052018-09-24 15:45:342133
Sam Maiera6e76d72022-02-11 21:43:502134 if not problems:
2135 return []
2136 return [
2137 output_api.PresubmitPromptWarning(
2138 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
2139 '\n'.join(problems))
2140 ]
2141
Dominic Battre033531052018-09-24 15:45:342142
Nina Satragnof7660532021-09-20 18:03:352143def CheckForgettingMAYBEInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502144 """Checks to make sure tests disabled conditionally are not missing a
2145 corresponding MAYBE_ prefix.
2146 """
2147 # Expect at least a lowercase character in the test name. This helps rule out
2148 # false positives with macros wrapping the actual tests name.
2149 define_maybe_pattern = input_api.re.compile(
2150 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
Bruce Dawsonffc55292022-04-20 04:18:192151 # The test_maybe_pattern needs to handle all of these forms. The standard:
2152 # IN_PROC_TEST_F(SyncTest, MAYBE_Start) {
2153 # With a wrapper macro around the test name:
2154 # IN_PROC_TEST_F(SyncTest, E2E_ENABLED(MAYBE_Start)) {
2155 # And the odd-ball NACL_BROWSER_TEST_f format:
2156 # NACL_BROWSER_TEST_F(NaClBrowserTest, SimpleLoad, {
2157 # The optional E2E_ENABLED-style is handled with (\w*\()?
2158 # The NACL_BROWSER_TEST_F pattern is handled by allowing a trailing comma or
2159 # trailing ')'.
2160 test_maybe_pattern = (
2161 r'^\s*\w*TEST[^(]*\(\s*\w+,\s*(\w*\()?MAYBE_{test_name}[\),]')
Sam Maiera6e76d72022-02-11 21:43:502162 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
2163 warnings = []
Nina Satragnof7660532021-09-20 18:03:352164
Sam Maiera6e76d72022-02-11 21:43:502165 # Read the entire files. We can't just read the affected lines, forgetting to
2166 # add MAYBE_ on a change would not show up otherwise.
2167 for f in input_api.AffectedFiles(False):
2168 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
2169 continue
2170 contents = input_api.ReadFile(f)
2171 lines = contents.splitlines(True)
2172 current_position = 0
2173 warning_test_names = set()
2174 for line_num, line in enumerate(lines, start=1):
2175 current_position += len(line)
2176 maybe_match = define_maybe_pattern.search(line)
2177 if maybe_match:
2178 test_name = maybe_match.group('test_name')
2179 # Do not warn twice for the same test.
2180 if (test_name in warning_test_names):
2181 continue
2182 warning_test_names.add(test_name)
Nina Satragnof7660532021-09-20 18:03:352183
Sam Maiera6e76d72022-02-11 21:43:502184 # Attempt to find the corresponding MAYBE_ test or suite, starting from
2185 # the current position.
2186 test_match = input_api.re.compile(
2187 test_maybe_pattern.format(test_name=test_name),
2188 input_api.re.MULTILINE).search(contents, current_position)
2189 suite_match = input_api.re.compile(
2190 suite_maybe_pattern.format(test_name=test_name),
2191 input_api.re.MULTILINE).search(contents, current_position)
2192 if not test_match and not suite_match:
2193 warnings.append(
2194 output_api.PresubmitPromptWarning(
2195 '%s:%d found MAYBE_ defined without corresponding test %s'
2196 % (f.LocalPath(), line_num, test_name)))
2197 return warnings
2198
[email protected]72df4e782012-06-21 16:28:182199
Saagar Sanghavifceeaae2020-08-12 16:40:362200def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502201 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
2202 errors = []
Kalvin Lee4a3b79de2022-05-26 16:00:162203 pattern = input_api.re.compile(r'\bDCHECK_IS_ON\b(?!\(\))',
Sam Maiera6e76d72022-02-11 21:43:502204 input_api.re.MULTILINE)
2205 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2206 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
2207 continue
2208 for lnum, line in f.ChangedContents():
2209 if input_api.re.search(pattern, line):
2210 errors.append(
2211 output_api.PresubmitError((
2212 '%s:%d: Use of DCHECK_IS_ON() must be written as "#if '
2213 + 'DCHECK_IS_ON()", not forgetting the parentheses.') %
2214 (f.LocalPath(), lnum)))
2215 return errors
danakj61c1aa22015-10-26 19:55:522216
2217
Weilun Shia487fad2020-10-28 00:10:342218# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
2219# more reliable way. See
2220# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:192221
wnwenbdc444e2016-05-25 13:44:152222
Saagar Sanghavifceeaae2020-08-12 16:40:362223def CheckFlakyTestUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502224 """Check that FlakyTest annotation is our own instead of the android one"""
2225 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
2226 files = []
2227 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2228 if f.LocalPath().endswith('Test.java'):
2229 if pattern.search(input_api.ReadFile(f)):
2230 files.append(f)
2231 if len(files):
2232 return [
2233 output_api.PresubmitError(
2234 'Use org.chromium.base.test.util.FlakyTest instead of '
2235 'android.test.FlakyTest', files)
2236 ]
2237 return []
mcasasb7440c282015-02-04 14:52:192238
wnwenbdc444e2016-05-25 13:44:152239
Saagar Sanghavifceeaae2020-08-12 16:40:362240def CheckNoDEPSGIT(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502241 """Make sure .DEPS.git is never modified manually."""
2242 if any(f.LocalPath().endswith('.DEPS.git')
2243 for f in input_api.AffectedFiles()):
2244 return [
2245 output_api.PresubmitError(
2246 'Never commit changes to .DEPS.git. This file is maintained by an\n'
2247 'automated system based on what\'s in DEPS and your changes will be\n'
2248 'overwritten.\n'
2249 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
2250 'get-the-code#Rolling_DEPS\n'
2251 'for more information')
2252 ]
2253 return []
[email protected]2a8ac9c2011-10-19 17:20:442254
2255
Sven Zheng76a79ea2022-12-21 21:25:242256def CheckCrosApiNeedBrowserTest(input_api, output_api):
2257 """Check new crosapi should add browser test."""
2258 has_new_crosapi = False
2259 has_browser_test = False
2260 for f in input_api.AffectedFiles():
2261 path = f.LocalPath()
2262 if (path.startswith('chromeos/crosapi/mojom') and
2263 _IsMojomFile(input_api, path) and f.Action() == 'A'):
2264 has_new_crosapi = True
2265 if path.endswith('browsertest.cc') or path.endswith('browser_test.cc'):
2266 has_browser_test = True
2267 if has_new_crosapi and not has_browser_test:
2268 return [
2269 output_api.PresubmitPromptWarning(
2270 'You are adding a new crosapi, but there is no file ends with '
2271 'browsertest.cc file being added or modified. It is important '
2272 'to add crosapi browser test coverage to avoid version '
2273 ' skew issues.\n'
2274 'Check //docs/lacros/test_instructions.md for more information.'
2275 )
2276 ]
2277 return []
2278
2279
Saagar Sanghavifceeaae2020-08-12 16:40:362280def CheckValidHostsInDEPSOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502281 """Checks that DEPS file deps are from allowed_hosts."""
2282 # Run only if DEPS file has been modified to annoy fewer bystanders.
2283 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
2284 return []
2285 # Outsource work to gclient verify
2286 try:
2287 gclient_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
2288 'third_party', 'depot_tools',
2289 'gclient.py')
2290 input_api.subprocess.check_output(
Bruce Dawson8a43cf72022-05-13 17:10:322291 [input_api.python3_executable, gclient_path, 'verify'],
Sam Maiera6e76d72022-02-11 21:43:502292 stderr=input_api.subprocess.STDOUT)
2293 return []
2294 except input_api.subprocess.CalledProcessError as error:
2295 return [
2296 output_api.PresubmitError(
2297 'DEPS file must have only git dependencies.',
2298 long_text=error.output)
2299 ]
tandriief664692014-09-23 14:51:472300
2301
Mario Sanchez Prada2472cab2019-09-18 10:58:312302def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152303 ban_rule):
Allen Bauer84778682022-09-22 16:28:562304 """Helper method for checking for banned constructs.
Mario Sanchez Prada2472cab2019-09-18 10:58:312305
Sam Maiera6e76d72022-02-11 21:43:502306 Returns an string composed of the name of the file, the line number where the
2307 match has been found and the additional text passed as |message| in case the
2308 target type name matches the text inside the line passed as parameter.
2309 """
2310 result = []
Peng Huang9c5949a02020-06-11 19:20:542311
Daniel Chenga44a1bcd2022-03-15 20:00:152312 # Ignore comments about banned types.
2313 if input_api.re.search(r"^ *//", line):
Sam Maiera6e76d72022-02-11 21:43:502314 return result
Daniel Chenga44a1bcd2022-03-15 20:00:152315 # A // nocheck comment will bypass this error.
2316 if line.endswith(" nocheck"):
Sam Maiera6e76d72022-02-11 21:43:502317 return result
2318
2319 matched = False
Daniel Chenga44a1bcd2022-03-15 20:00:152320 if ban_rule.pattern[0:1] == '/':
2321 regex = ban_rule.pattern[1:]
Sam Maiera6e76d72022-02-11 21:43:502322 if input_api.re.search(regex, line):
2323 matched = True
Daniel Chenga44a1bcd2022-03-15 20:00:152324 elif ban_rule.pattern in line:
Sam Maiera6e76d72022-02-11 21:43:502325 matched = True
2326
2327 if matched:
2328 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
Daniel Chenga44a1bcd2022-03-15 20:00:152329 for line in ban_rule.explanation:
2330 result.append(' %s' % line)
Sam Maiera6e76d72022-02-11 21:43:502331
danakjd18e8892020-12-17 17:42:012332 return result
Mario Sanchez Prada2472cab2019-09-18 10:58:312333
2334
Saagar Sanghavifceeaae2020-08-12 16:40:362335def CheckNoBannedFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502336 """Make sure that banned functions are not used."""
2337 warnings = []
2338 errors = []
[email protected]127f18ec2012-06-16 05:05:592339
Sam Maiera6e76d72022-02-11 21:43:502340 def IsExcludedFile(affected_file, excluded_paths):
Daniel Chenga44a1bcd2022-03-15 20:00:152341 if not excluded_paths:
2342 return False
2343
Sam Maiera6e76d72022-02-11 21:43:502344 local_path = affected_file.LocalPath()
Bruce Dawson40fece62022-09-16 19:58:312345 # Consistently use / as path separator to simplify the writing of regex
2346 # expressions.
2347 local_path = local_path.replace(input_api.os_path.sep, '/')
Sam Maiera6e76d72022-02-11 21:43:502348 for item in excluded_paths:
2349 if input_api.re.match(item, local_path):
2350 return True
2351 return False
wnwenbdc444e2016-05-25 13:44:152352
Sam Maiera6e76d72022-02-11 21:43:502353 def IsIosObjcFile(affected_file):
2354 local_path = affected_file.LocalPath()
2355 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m',
2356 '.h'):
2357 return False
2358 basename = input_api.os_path.basename(local_path)
2359 if 'ios' in basename.split('_'):
2360 return True
2361 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
2362 if sep and 'ios' in local_path.split(sep):
2363 return True
2364 return False
Sylvain Defresnea8b73d252018-02-28 15:45:542365
Daniel Chenga44a1bcd2022-03-15 20:00:152366 def CheckForMatch(affected_file, line_num: int, line: str,
2367 ban_rule: BanRule):
2368 if IsExcludedFile(affected_file, ban_rule.excluded_paths):
2369 return
2370
Sam Maiera6e76d72022-02-11 21:43:502371 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
Daniel Chenga44a1bcd2022-03-15 20:00:152372 ban_rule)
Sam Maiera6e76d72022-02-11 21:43:502373 if problems:
Daniel Chenga44a1bcd2022-03-15 20:00:152374 if ban_rule.treat_as_error is not None and ban_rule.treat_as_error:
Sam Maiera6e76d72022-02-11 21:43:502375 errors.extend(problems)
2376 else:
2377 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:152378
Sam Maiera6e76d72022-02-11 21:43:502379 file_filter = lambda f: f.LocalPath().endswith(('.java'))
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_JAVA_FUNCTIONS:
2383 CheckForMatch(f, line_num, line, ban_rule)
Eric Stevensona9a980972017-09-23 00:04:412384
Clement Yan9b330cb2022-11-17 05:25:292385 file_filter = lambda f: f.LocalPath().endswith(('.js', '.ts'))
2386 for f in input_api.AffectedFiles(file_filter=file_filter):
2387 for line_num, line in f.ChangedContents():
2388 for ban_rule in _BANNED_JAVASCRIPT_FUNCTIONS:
2389 CheckForMatch(f, line_num, line, ban_rule)
2390
Sam Maiera6e76d72022-02-11 21:43:502391 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
2392 for f in input_api.AffectedFiles(file_filter=file_filter):
2393 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152394 for ban_rule in _BANNED_OBJC_FUNCTIONS:
2395 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:592396
Sam Maiera6e76d72022-02-11 21:43:502397 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
2398 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152399 for ban_rule in _BANNED_IOS_OBJC_FUNCTIONS:
2400 CheckForMatch(f, line_num, line, ban_rule)
Sylvain Defresnea8b73d252018-02-28 15:45:542401
Sam Maiera6e76d72022-02-11 21:43:502402 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
2403 for f in input_api.AffectedFiles(file_filter=egtest_filter):
2404 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152405 for ban_rule in _BANNED_IOS_EGTEST_FUNCTIONS:
2406 CheckForMatch(f, line_num, line, ban_rule)
Peter K. Lee6c03ccff2019-07-15 14:40:052407
Sam Maiera6e76d72022-02-11 21:43:502408 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
2409 for f in input_api.AffectedFiles(file_filter=file_filter):
2410 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152411 for ban_rule in _BANNED_CPP_FUNCTIONS:
2412 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:592413
Daniel Cheng92c15e32022-03-16 17:48:222414 file_filter = lambda f: f.LocalPath().endswith(('.mojom'))
2415 for f in input_api.AffectedFiles(file_filter=file_filter):
2416 for line_num, line in f.ChangedContents():
2417 for ban_rule in _BANNED_MOJOM_PATTERNS:
2418 CheckForMatch(f, line_num, line, ban_rule)
2419
2420
Sam Maiera6e76d72022-02-11 21:43:502421 result = []
2422 if (warnings):
2423 result.append(
2424 output_api.PresubmitPromptWarning('Banned functions were used.\n' +
2425 '\n'.join(warnings)))
2426 if (errors):
2427 result.append(
2428 output_api.PresubmitError('Banned functions were used.\n' +
2429 '\n'.join(errors)))
2430 return result
[email protected]127f18ec2012-06-16 05:05:592431
Allen Bauer84778682022-09-22 16:28:562432def CheckNoLayoutCallsInTests(input_api, output_api):
2433 """Make sure there are no explicit calls to View::Layout() in tests"""
2434 warnings = []
2435 ban_rule = BanRule(
2436 r'/(\.|->)Layout\(\);',
2437 (
2438 'Direct calls to View::Layout() are not allowed in tests. '
2439 'If the view must be laid out here, use RunScheduledLayout(view). It '
2440 'is found in //ui/views/test/views_test_utils.h. '
2441 'See http://crbug.com/1350521 for more details.',
2442 ),
2443 False,
2444 )
2445 file_filter = lambda f: input_api.re.search(
2446 r'_(unittest|browsertest|ui_test).*\.(cc|mm)$', f.LocalPath())
2447 for f in input_api.AffectedFiles(file_filter = file_filter):
2448 for line_num, line in f.ChangedContents():
2449 problems = _GetMessageForMatchingType(input_api, f,
2450 line_num, line,
2451 ban_rule)
2452 if problems:
2453 warnings.extend(problems)
2454 result = []
2455 if (warnings):
2456 result.append(
2457 output_api.PresubmitPromptWarning(
2458 'Banned call to View::Layout() in tests.\n\n'.join(warnings)))
2459 return result
[email protected]127f18ec2012-06-16 05:05:592460
Michael Thiessen44457642020-02-06 00:24:152461def _CheckAndroidNoBannedImports(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502462 """Make sure that banned java imports are not used."""
2463 errors = []
Michael Thiessen44457642020-02-06 00:24:152464
Sam Maiera6e76d72022-02-11 21:43:502465 file_filter = lambda f: f.LocalPath().endswith(('.java'))
2466 for f in input_api.AffectedFiles(file_filter=file_filter):
2467 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:152468 for ban_rule in _BANNED_JAVA_IMPORTS:
2469 # Consider merging this into the above function. There is no
2470 # real difference anymore other than helping with a little
2471 # bit of boilerplate text. Doing so means things like
2472 # `treat_as_error` will also be uniformly handled.
Sam Maiera6e76d72022-02-11 21:43:502473 problems = _GetMessageForMatchingType(input_api, f, line_num,
Daniel Chenga44a1bcd2022-03-15 20:00:152474 line, ban_rule)
Sam Maiera6e76d72022-02-11 21:43:502475 if problems:
2476 errors.extend(problems)
2477 result = []
2478 if (errors):
2479 result.append(
2480 output_api.PresubmitError('Banned imports were used.\n' +
2481 '\n'.join(errors)))
2482 return result
Michael Thiessen44457642020-02-06 00:24:152483
2484
Saagar Sanghavifceeaae2020-08-12 16:40:362485def CheckNoPragmaOnce(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502486 """Make sure that banned functions are not used."""
2487 files = []
2488 pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
2489 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2490 if not f.LocalPath().endswith('.h'):
2491 continue
Bruce Dawson4c4c2922022-05-02 18:07:332492 if f.LocalPath().endswith('com_imported_mstscax.h'):
2493 continue
Sam Maiera6e76d72022-02-11 21:43:502494 contents = input_api.ReadFile(f)
2495 if pattern.search(contents):
2496 files.append(f)
[email protected]6c063c62012-07-11 19:11:062497
Sam Maiera6e76d72022-02-11 21:43:502498 if files:
2499 return [
2500 output_api.PresubmitError(
2501 'Do not use #pragma once in header files.\n'
2502 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
2503 files)
2504 ]
2505 return []
[email protected]6c063c62012-07-11 19:11:062506
[email protected]127f18ec2012-06-16 05:05:592507
Saagar Sanghavifceeaae2020-08-12 16:40:362508def CheckNoTrinaryTrueFalse(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502509 """Checks to make sure we don't introduce use of foo ? true : false."""
2510 problems = []
2511 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
2512 for f in input_api.AffectedFiles():
2513 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2514 continue
[email protected]e7479052012-09-19 00:26:122515
Sam Maiera6e76d72022-02-11 21:43:502516 for line_num, line in f.ChangedContents():
2517 if pattern.match(line):
2518 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]e7479052012-09-19 00:26:122519
Sam Maiera6e76d72022-02-11 21:43:502520 if not problems:
2521 return []
2522 return [
2523 output_api.PresubmitPromptWarning(
2524 'Please consider avoiding the "? true : false" pattern if possible.\n'
2525 + '\n'.join(problems))
2526 ]
[email protected]e7479052012-09-19 00:26:122527
2528
Saagar Sanghavifceeaae2020-08-12 16:40:362529def CheckUnwantedDependencies(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502530 """Runs checkdeps on #include and import statements added in this
2531 change. Breaking - rules is an error, breaking ! rules is a
2532 warning.
2533 """
2534 # Return early if no relevant file types were modified.
2535 for f in input_api.AffectedFiles():
2536 path = f.LocalPath()
2537 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path)
2538 or _IsJavaFile(input_api, path)):
2539 break
[email protected]55f9f382012-07-31 11:02:182540 else:
Sam Maiera6e76d72022-02-11 21:43:502541 return []
rhalavati08acd232017-04-03 07:23:282542
Sam Maiera6e76d72022-02-11 21:43:502543 import sys
2544 # We need to wait until we have an input_api object and use this
2545 # roundabout construct to import checkdeps because this file is
2546 # eval-ed and thus doesn't have __file__.
2547 original_sys_path = sys.path
2548 try:
2549 sys.path = sys.path + [
2550 input_api.os_path.join(input_api.PresubmitLocalPath(),
2551 'buildtools', 'checkdeps')
2552 ]
2553 import checkdeps
2554 from rules import Rule
2555 finally:
2556 # Restore sys.path to what it was before.
2557 sys.path = original_sys_path
[email protected]55f9f382012-07-31 11:02:182558
Sam Maiera6e76d72022-02-11 21:43:502559 added_includes = []
2560 added_imports = []
2561 added_java_imports = []
2562 for f in input_api.AffectedFiles():
2563 if _IsCPlusPlusFile(input_api, f.LocalPath()):
2564 changed_lines = [line for _, line in f.ChangedContents()]
2565 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
2566 elif _IsProtoFile(input_api, f.LocalPath()):
2567 changed_lines = [line for _, line in f.ChangedContents()]
2568 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
2569 elif _IsJavaFile(input_api, f.LocalPath()):
2570 changed_lines = [line for _, line in f.ChangedContents()]
2571 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:242572
Sam Maiera6e76d72022-02-11 21:43:502573 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
2574
2575 error_descriptions = []
2576 warning_descriptions = []
2577 error_subjects = set()
2578 warning_subjects = set()
2579
2580 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2581 added_includes):
2582 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2583 description_with_path = '%s\n %s' % (path, rule_description)
2584 if rule_type == Rule.DISALLOW:
2585 error_descriptions.append(description_with_path)
2586 error_subjects.add("#includes")
2587 else:
2588 warning_descriptions.append(description_with_path)
2589 warning_subjects.add("#includes")
2590
2591 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2592 added_imports):
2593 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2594 description_with_path = '%s\n %s' % (path, rule_description)
2595 if rule_type == Rule.DISALLOW:
2596 error_descriptions.append(description_with_path)
2597 error_subjects.add("imports")
2598 else:
2599 warning_descriptions.append(description_with_path)
2600 warning_subjects.add("imports")
2601
2602 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
2603 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
2604 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
2605 description_with_path = '%s\n %s' % (path, rule_description)
2606 if rule_type == Rule.DISALLOW:
2607 error_descriptions.append(description_with_path)
2608 error_subjects.add("imports")
2609 else:
2610 warning_descriptions.append(description_with_path)
2611 warning_subjects.add("imports")
2612
2613 results = []
2614 if error_descriptions:
2615 results.append(
2616 output_api.PresubmitError(
2617 'You added one or more %s that violate checkdeps rules.' %
2618 " and ".join(error_subjects), error_descriptions))
2619 if warning_descriptions:
2620 results.append(
2621 output_api.PresubmitPromptOrNotify(
2622 'You added one or more %s of files that are temporarily\n'
2623 'allowed but being removed. Can you avoid introducing the\n'
2624 '%s? See relevant DEPS file(s) for details and contacts.' %
2625 (" and ".join(warning_subjects), "/".join(warning_subjects)),
2626 warning_descriptions))
2627 return results
[email protected]55f9f382012-07-31 11:02:182628
2629
Saagar Sanghavifceeaae2020-08-12 16:40:362630def CheckFilePermissions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502631 """Check that all files have their permissions properly set."""
2632 if input_api.platform == 'win32':
2633 return []
2634 checkperms_tool = input_api.os_path.join(input_api.PresubmitLocalPath(),
2635 'tools', 'checkperms',
2636 'checkperms.py')
2637 args = [
Bruce Dawson8a43cf72022-05-13 17:10:322638 input_api.python3_executable, checkperms_tool, '--root',
Sam Maiera6e76d72022-02-11 21:43:502639 input_api.change.RepositoryRoot()
2640 ]
2641 with input_api.CreateTemporaryFile() as file_list:
2642 for f in input_api.AffectedFiles():
2643 # checkperms.py file/directory arguments must be relative to the
2644 # repository.
2645 file_list.write((f.LocalPath() + '\n').encode('utf8'))
2646 file_list.close()
2647 args += ['--file-list', file_list.name]
2648 try:
2649 input_api.subprocess.check_output(args)
2650 return []
2651 except input_api.subprocess.CalledProcessError as error:
2652 return [
2653 output_api.PresubmitError('checkperms.py failed:',
2654 long_text=error.output.decode(
2655 'utf-8', 'ignore'))
2656 ]
[email protected]fbcafe5a2012-08-08 15:31:222657
2658
Saagar Sanghavifceeaae2020-08-12 16:40:362659def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502660 """Makes sure we don't include ui/aura/window_property.h
2661 in header files.
2662 """
2663 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2664 errors = []
2665 for f in input_api.AffectedFiles():
2666 if not f.LocalPath().endswith('.h'):
2667 continue
2668 for line_num, line in f.ChangedContents():
2669 if pattern.match(line):
2670 errors.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]c8278b32012-10-30 20:35:492671
Sam Maiera6e76d72022-02-11 21:43:502672 results = []
2673 if errors:
2674 results.append(
2675 output_api.PresubmitError(
2676 'Header files should not include ui/aura/window_property.h',
2677 errors))
2678 return results
[email protected]c8278b32012-10-30 20:35:492679
2680
Omer Katzcc77ea92021-04-26 10:23:282681def CheckNoInternalHeapIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502682 """Makes sure we don't include any headers from
2683 third_party/blink/renderer/platform/heap/impl or
2684 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
2685 third_party/blink/renderer/platform/heap
2686 """
2687 impl_pattern = input_api.re.compile(
2688 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
2689 v8_wrapper_pattern = input_api.re.compile(
2690 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"'
2691 )
Bruce Dawson40fece62022-09-16 19:58:312692 # Consistently use / as path separator to simplify the writing of regex
2693 # expressions.
Sam Maiera6e76d72022-02-11 21:43:502694 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:312695 r"^third_party/blink/renderer/platform/heap/.*",
2696 f.LocalPath().replace(input_api.os_path.sep, '/'))
Sam Maiera6e76d72022-02-11 21:43:502697 errors = []
Omer Katzcc77ea92021-04-26 10:23:282698
Sam Maiera6e76d72022-02-11 21:43:502699 for f in input_api.AffectedFiles(file_filter=file_filter):
2700 for line_num, line in f.ChangedContents():
2701 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
2702 errors.append(' %s:%d' % (f.LocalPath(), line_num))
Omer Katzcc77ea92021-04-26 10:23:282703
Sam Maiera6e76d72022-02-11 21:43:502704 results = []
2705 if errors:
2706 results.append(
2707 output_api.PresubmitError(
2708 'Do not include files from third_party/blink/renderer/platform/heap/impl'
2709 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
2710 'relevant counterparts from third_party/blink/renderer/platform/heap',
2711 errors))
2712 return results
Omer Katzcc77ea92021-04-26 10:23:282713
2714
[email protected]70ca77752012-11-20 03:45:032715def _CheckForVersionControlConflictsInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:502716 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2717 errors = []
2718 for line_num, line in f.ChangedContents():
2719 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
2720 # First-level headers in markdown look a lot like version control
2721 # conflict markers. http://daringfireball.net/projects/markdown/basics
2722 continue
2723 if pattern.match(line):
2724 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2725 return errors
[email protected]70ca77752012-11-20 03:45:032726
2727
Saagar Sanghavifceeaae2020-08-12 16:40:362728def CheckForVersionControlConflicts(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502729 """Usually this is not intentional and will cause a compile failure."""
2730 errors = []
2731 for f in input_api.AffectedFiles():
2732 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
[email protected]70ca77752012-11-20 03:45:032733
Sam Maiera6e76d72022-02-11 21:43:502734 results = []
2735 if errors:
2736 results.append(
2737 output_api.PresubmitError(
2738 'Version control conflict markers found, please resolve.',
2739 errors))
2740 return results
[email protected]70ca77752012-11-20 03:45:032741
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202742
Saagar Sanghavifceeaae2020-08-12 16:40:362743def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502744 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2745 errors = []
2746 for f in input_api.AffectedFiles():
2747 for line_num, line in f.ChangedContents():
2748 if pattern.search(line):
2749 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
estadee17314a02017-01-12 16:22:162750
Sam Maiera6e76d72022-02-11 21:43:502751 results = []
2752 if errors:
2753 results.append(
2754 output_api.PresubmitPromptWarning(
2755 'Found Google support URL addressed by answer number. Please replace '
2756 'with a p= identifier instead. See crbug.com/679462\n',
2757 errors))
2758 return results
estadee17314a02017-01-12 16:22:162759
[email protected]70ca77752012-11-20 03:45:032760
Saagar Sanghavifceeaae2020-08-12 16:40:362761def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502762 def FilterFile(affected_file):
2763 """Filter function for use with input_api.AffectedSourceFiles,
2764 below. This filters out everything except non-test files from
2765 top-level directories that generally speaking should not hard-code
2766 service URLs (e.g. src/android_webview/, src/content/ and others).
2767 """
2768 return input_api.FilterSourceFile(
2769 affected_file,
Bruce Dawson40fece62022-09-16 19:58:312770 files_to_check=[r'^(android_webview|base|content|net)/.*'],
Sam Maiera6e76d72022-02-11 21:43:502771 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2772 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442773
Sam Maiera6e76d72022-02-11 21:43:502774 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2775 '\.(com|net)[^"]*"')
2776 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2777 pattern = input_api.re.compile(base_pattern)
2778 problems = [] # items are (filename, line_number, line)
2779 for f in input_api.AffectedSourceFiles(FilterFile):
2780 for line_num, line in f.ChangedContents():
2781 if not comment_pattern.search(line) and pattern.search(line):
2782 problems.append((f.LocalPath(), line_num, line))
[email protected]06e6d0ff2012-12-11 01:36:442783
Sam Maiera6e76d72022-02-11 21:43:502784 if problems:
2785 return [
2786 output_api.PresubmitPromptOrNotify(
2787 'Most layers below src/chrome/ should not hardcode service URLs.\n'
2788 'Are you sure this is correct?', [
2789 ' %s:%d: %s' % (problem[0], problem[1], problem[2])
2790 for problem in problems
2791 ])
2792 ]
2793 else:
2794 return []
[email protected]06e6d0ff2012-12-11 01:36:442795
2796
Saagar Sanghavifceeaae2020-08-12 16:40:362797def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502798 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
James Cook6b6597c2019-11-06 22:05:292799
Sam Maiera6e76d72022-02-11 21:43:502800 def FileFilter(affected_file):
2801 """Includes directories known to be Chrome OS only."""
2802 return input_api.FilterSourceFile(
2803 affected_file,
2804 files_to_check=(
2805 '^ash/',
2806 '^chromeos/', # Top-level src/chromeos.
2807 '.*/chromeos/', # Any path component.
2808 '^components/arc',
2809 '^components/exo'),
2810 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292811
Sam Maiera6e76d72022-02-11 21:43:502812 prefs = []
2813 priority_prefs = []
2814 for f in input_api.AffectedFiles(file_filter=FileFilter):
2815 for line_num, line in f.ChangedContents():
2816 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF',
2817 line):
2818 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2819 prefs.append(' %s' % line)
2820 if input_api.re.search(
2821 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2822 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2823 priority_prefs.append(' %s' % line)
2824
2825 results = []
2826 if (prefs):
2827 results.append(
2828 output_api.PresubmitPromptWarning(
2829 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2830 'by browser sync settings. If these prefs should be controlled by OS '
2831 'sync settings use SYNCABLE_OS_PREF instead.\n' +
2832 '\n'.join(prefs)))
2833 if (priority_prefs):
2834 results.append(
2835 output_api.PresubmitPromptWarning(
2836 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2837 'controlled by browser sync settings. If these prefs should be '
2838 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2839 'instead.\n' + '\n'.join(prefs)))
2840 return results
James Cook6b6597c2019-11-06 22:05:292841
2842
Saagar Sanghavifceeaae2020-08-12 16:40:362843def CheckNoAbbreviationInPngFileName(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502844 """Makes sure there are no abbreviations in the name of PNG files.
2845 The native_client_sdk directory is excluded because it has auto-generated PNG
2846 files for documentation.
2847 """
2848 errors = []
Yuanqing Zhu9eef02832022-12-04 14:42:172849 files_to_check = [r'.*\.png$']
Bruce Dawson40fece62022-09-16 19:58:312850 files_to_skip = [r'^native_client_sdk/',
2851 r'^services/test/',
2852 r'^third_party/blink/web_tests/',
Bruce Dawson3db456212022-05-02 05:34:182853 ]
Sam Maiera6e76d72022-02-11 21:43:502854 file_filter = lambda f: input_api.FilterSourceFile(
2855 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Yuanqing Zhu9eef02832022-12-04 14:42:172856 abbreviation = input_api.re.compile('.+_[a-z]\.png|.+_[a-z]_.*\.png')
Sam Maiera6e76d72022-02-11 21:43:502857 for f in input_api.AffectedFiles(include_deletes=False,
2858 file_filter=file_filter):
Yuanqing Zhu9eef02832022-12-04 14:42:172859 file_name = input_api.os_path.split(f.LocalPath())[1]
2860 if abbreviation.search(file_name):
2861 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272862
Sam Maiera6e76d72022-02-11 21:43:502863 results = []
2864 if errors:
2865 results.append(
2866 output_api.PresubmitError(
2867 'The name of PNG files should not have abbreviations. \n'
2868 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2869 'Contact [email protected] if you have questions.', errors))
2870 return results
[email protected]d2530012013-01-25 16:39:272871
Evan Stade7cd4a2c2022-08-04 23:37:252872def CheckNoProductIconsAddedToPublicRepo(input_api, output_api):
2873 """Heuristically identifies product icons based on their file name and reminds
2874 contributors not to add them to the Chromium repository.
2875 """
2876 errors = []
2877 files_to_check = [r'.*google.*\.png$|.*google.*\.svg$|.*google.*\.icon$']
2878 file_filter = lambda f: input_api.FilterSourceFile(
2879 f, files_to_check=files_to_check)
2880 for f in input_api.AffectedFiles(include_deletes=False,
2881 file_filter=file_filter):
2882 errors.append(' %s' % f.LocalPath())
2883
2884 results = []
2885 if errors:
Bruce Dawson3bcf0c92022-08-12 00:03:082886 # Give warnings instead of errors on presubmit --all and presubmit
2887 # --files.
2888 message_type = (output_api.PresubmitNotifyResult if input_api.no_diffs
2889 else output_api.PresubmitError)
Evan Stade7cd4a2c2022-08-04 23:37:252890 results.append(
Bruce Dawson3bcf0c92022-08-12 00:03:082891 message_type(
Evan Stade7cd4a2c2022-08-04 23:37:252892 'Trademarked images should not be added to the public repo. '
2893 'See crbug.com/944754', errors))
2894 return results
2895
[email protected]d2530012013-01-25 16:39:272896
Daniel Cheng4dcdb6b2017-04-13 08:30:172897def _ExtractAddRulesFromParsedDeps(parsed_deps):
Sam Maiera6e76d72022-02-11 21:43:502898 """Extract the rules that add dependencies from a parsed DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172899
Sam Maiera6e76d72022-02-11 21:43:502900 Args:
2901 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2902 add_rules = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172903 add_rules.update([
Sam Maiera6e76d72022-02-11 21:43:502904 rule[1:] for rule in parsed_deps.get('include_rules', [])
Daniel Cheng4dcdb6b2017-04-13 08:30:172905 if rule.startswith('+') or rule.startswith('!')
2906 ])
Sam Maiera6e76d72022-02-11 21:43:502907 for _, rules in parsed_deps.get('specific_include_rules', {}).items():
2908 add_rules.update([
2909 rule[1:] for rule in rules
2910 if rule.startswith('+') or rule.startswith('!')
2911 ])
2912 return add_rules
Daniel Cheng4dcdb6b2017-04-13 08:30:172913
2914
2915def _ParseDeps(contents):
Sam Maiera6e76d72022-02-11 21:43:502916 """Simple helper for parsing DEPS files."""
Daniel Cheng4dcdb6b2017-04-13 08:30:172917
Sam Maiera6e76d72022-02-11 21:43:502918 # Stubs for handling special syntax in the root DEPS file.
2919 class _VarImpl:
2920 def __init__(self, local_scope):
2921 self._local_scope = local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172922
Sam Maiera6e76d72022-02-11 21:43:502923 def Lookup(self, var_name):
2924 """Implements the Var syntax."""
2925 try:
2926 return self._local_scope['vars'][var_name]
2927 except KeyError:
2928 raise Exception('Var is not defined: %s' % var_name)
Daniel Cheng4dcdb6b2017-04-13 08:30:172929
Sam Maiera6e76d72022-02-11 21:43:502930 local_scope = {}
2931 global_scope = {
2932 'Var': _VarImpl(local_scope).Lookup,
2933 'Str': str,
2934 }
Dirk Pranke1b9e06382021-05-14 01:16:222935
Sam Maiera6e76d72022-02-11 21:43:502936 exec(contents, global_scope, local_scope)
2937 return local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172938
2939
2940def _CalculateAddedDeps(os_path, old_contents, new_contents):
Sam Maiera6e76d72022-02-11 21:43:502941 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
2942 a set of DEPS entries that we should look up.
[email protected]14a6131c2014-01-08 01:15:412943
Sam Maiera6e76d72022-02-11 21:43:502944 For a directory (rather than a specific filename) we fake a path to
2945 a specific filename by adding /DEPS. This is chosen as a file that
2946 will seldom or never be subject to per-file include_rules.
2947 """
2948 # We ignore deps entries on auto-generated directories.
2949 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082950
Sam Maiera6e76d72022-02-11 21:43:502951 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2952 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
Daniel Cheng4dcdb6b2017-04-13 08:30:172953
Sam Maiera6e76d72022-02-11 21:43:502954 added_deps = new_deps.difference(old_deps)
Daniel Cheng4dcdb6b2017-04-13 08:30:172955
Sam Maiera6e76d72022-02-11 21:43:502956 results = set()
2957 for added_dep in added_deps:
2958 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2959 continue
2960 # Assume that a rule that ends in .h is a rule for a specific file.
2961 if added_dep.endswith('.h'):
2962 results.add(added_dep)
2963 else:
2964 results.add(os_path.join(added_dep, 'DEPS'))
2965 return results
[email protected]f32e2d1e2013-07-26 21:39:082966
2967
Saagar Sanghavifceeaae2020-08-12 16:40:362968def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502969 """When a dependency prefixed with + is added to a DEPS file, we
2970 want to make sure that the change is reviewed by an OWNER of the
2971 target file or directory, to avoid layering violations from being
2972 introduced. This check verifies that this happens.
2973 """
2974 # We rely on Gerrit's code-owners to check approvals.
2975 # input_api.gerrit is always set for Chromium, but other projects
2976 # might not use Gerrit.
Bruce Dawson344ab262022-06-04 11:35:102977 if not input_api.gerrit or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:502978 return []
Bruce Dawsonb357aeb2022-08-09 15:38:302979 if 'PRESUBMIT_SKIP_NETWORK' in input_api.environ:
Sam Maiera6e76d72022-02-11 21:43:502980 return []
Bruce Dawsonb357aeb2022-08-09 15:38:302981 try:
2982 if (input_api.change.issue and
2983 input_api.gerrit.IsOwnersOverrideApproved(
2984 input_api.change.issue)):
2985 # Skip OWNERS check when Owners-Override label is approved. This is
2986 # intended for global owners, trusted bots, and on-call sheriffs.
2987 # Review is still required for these changes.
2988 return []
2989 except Exception as e:
Sam Maier4cef9242022-10-03 14:21:242990 return [output_api.PresubmitPromptWarning(
2991 'Failed to retrieve owner override status - %s' % str(e))]
Edward Lesmes6fba51082021-01-20 04:20:232992
Sam Maiera6e76d72022-02-11 21:43:502993 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242994
Bruce Dawson40fece62022-09-16 19:58:312995 # Consistently use / as path separator to simplify the writing of regex
2996 # expressions.
Sam Maiera6e76d72022-02-11 21:43:502997 file_filter = lambda f: not input_api.re.match(
Bruce Dawson40fece62022-09-16 19:58:312998 r"^third_party/blink/.*",
2999 f.LocalPath().replace(input_api.os_path.sep, '/'))
Sam Maiera6e76d72022-02-11 21:43:503000 for f in input_api.AffectedFiles(include_deletes=False,
3001 file_filter=file_filter):
3002 filename = input_api.os_path.basename(f.LocalPath())
3003 if filename == 'DEPS':
3004 virtual_depended_on_files.update(
3005 _CalculateAddedDeps(input_api.os_path,
3006 '\n'.join(f.OldContents()),
3007 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:553008
Sam Maiera6e76d72022-02-11 21:43:503009 if not virtual_depended_on_files:
3010 return []
[email protected]e871964c2013-05-13 14:14:553011
Sam Maiera6e76d72022-02-11 21:43:503012 if input_api.is_committing:
3013 if input_api.tbr:
3014 return [
3015 output_api.PresubmitNotifyResult(
3016 '--tbr was specified, skipping OWNERS check for DEPS additions'
3017 )
3018 ]
Daniel Cheng3008dc12022-05-13 04:02:113019 # TODO(dcheng): Make this generate an error on dry runs if the reviewer
3020 # is not added, to prevent review serialization.
Sam Maiera6e76d72022-02-11 21:43:503021 if input_api.dry_run:
3022 return [
3023 output_api.PresubmitNotifyResult(
3024 'This is a dry run, skipping OWNERS check for DEPS additions'
3025 )
3026 ]
3027 if not input_api.change.issue:
3028 return [
3029 output_api.PresubmitError(
3030 "DEPS approval by OWNERS check failed: this change has "
3031 "no change number, so we can't check it for approvals.")
3032 ]
3033 output = output_api.PresubmitError
[email protected]14a6131c2014-01-08 01:15:413034 else:
Sam Maiera6e76d72022-02-11 21:43:503035 output = output_api.PresubmitNotifyResult
[email protected]e871964c2013-05-13 14:14:553036
Sam Maiera6e76d72022-02-11 21:43:503037 owner_email, reviewers = (
3038 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3039 input_api, None, approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:553040
Sam Maiera6e76d72022-02-11 21:43:503041 owner_email = owner_email or input_api.change.author_email
3042
3043 approval_status = input_api.owners_client.GetFilesApprovalStatus(
3044 virtual_depended_on_files, reviewers.union([owner_email]), [])
3045 missing_files = [
3046 f for f in virtual_depended_on_files
3047 if approval_status[f] != input_api.owners_client.APPROVED
3048 ]
3049
3050 # We strip the /DEPS part that was added by
3051 # _FilesToCheckForIncomingDeps to fake a path to a file in a
3052 # directory.
3053 def StripDeps(path):
3054 start_deps = path.rfind('/DEPS')
3055 if start_deps != -1:
3056 return path[:start_deps]
3057 else:
3058 return path
3059
3060 unapproved_dependencies = [
3061 "'+%s'," % StripDeps(path) for path in missing_files
3062 ]
3063
3064 if unapproved_dependencies:
3065 output_list = [
3066 output(
3067 'You need LGTM from owners of depends-on paths in DEPS that were '
3068 'modified in this CL:\n %s' %
3069 '\n '.join(sorted(unapproved_dependencies)))
3070 ]
3071 suggested_owners = input_api.owners_client.SuggestOwners(
3072 missing_files, exclude=[owner_email])
3073 output_list.append(
3074 output('Suggested missing target path OWNERS:\n %s' %
3075 '\n '.join(suggested_owners or [])))
3076 return output_list
3077
3078 return []
[email protected]e871964c2013-05-13 14:14:553079
3080
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493081# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:363082def CheckSpamLogging(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503083 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3084 files_to_skip = (
3085 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3086 input_api.DEFAULT_FILES_TO_SKIP + (
Jaewon Jung2f323bb2022-12-07 23:55:013087 r"^base/fuchsia/scoped_fx_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313088 r"^base/logging\.h$",
3089 r"^base/logging\.cc$",
3090 r"^base/task/thread_pool/task_tracker\.cc$",
3091 r"^chrome/app/chrome_main_delegate\.cc$",
Yao Li359937b2023-02-15 23:43:033092 r"^chrome/browser/ash/arc/enterprise/cert_store/arc_cert_installer\.cc$",
3093 r"^chrome/browser/ash/policy/remote_commands/user_command_arc_job\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313094 r"^chrome/browser/chrome_browser_main\.cc$",
3095 r"^chrome/browser/ui/startup/startup_browser_creator\.cc$",
3096 r"^chrome/browser/browser_switcher/bho/.*",
3097 r"^chrome/browser/diagnostics/diagnostics_writer\.cc$",
3098 r"^chrome/chrome_cleaner/.*",
3099 r"^chrome/chrome_elf/dll_hash/dll_hash_main\.cc$",
3100 r"^chrome/installer/setup/.*",
3101 r"^chromecast/",
Vigen Issahhanjane2d93822023-06-30 15:57:203102 r"^components/cast",
Bruce Dawson40fece62022-09-16 19:58:313103 r"^components/media_control/renderer/media_playback_options\.cc$",
Salma Elmahallawy52976452023-01-27 17:04:493104 r"^components/policy/core/common/policy_logger\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313105 r"^components/viz/service/display/"
Sam Maiera6e76d72022-02-11 21:43:503106 r"overlay_strategy_underlay_cast\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313107 r"^components/zucchini/.*",
Sam Maiera6e76d72022-02-11 21:43:503108 # TODO(peter): Remove exception. https://crbug.com/534537
Bruce Dawson40fece62022-09-16 19:58:313109 r"^content/browser/notifications/"
Sam Maiera6e76d72022-02-11 21:43:503110 r"notification_event_dispatcher_impl\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313111 r"^content/common/gpu/client/gl_helper_benchmark\.cc$",
3112 r"^courgette/courgette_minimal_tool\.cc$",
3113 r"^courgette/courgette_tool\.cc$",
3114 r"^extensions/renderer/logging_native_handler\.cc$",
3115 r"^fuchsia_web/common/init_logging\.cc$",
3116 r"^fuchsia_web/runners/common/web_component\.cc$",
Caroline Liua7050132023-02-13 22:23:153117 r"^fuchsia_web/shell/.*\.cc$",
Bruce Dawson40fece62022-09-16 19:58:313118 r"^headless/app/headless_shell\.cc$",
3119 r"^ipc/ipc_logging\.cc$",
3120 r"^native_client_sdk/",
3121 r"^remoting/base/logging\.h$",
3122 r"^remoting/host/.*",
3123 r"^sandbox/linux/.*",
3124 r"^storage/browser/file_system/dump_file_system\.cc$",
3125 r"^tools/",
3126 r"^ui/base/resource/data_pack\.cc$",
3127 r"^ui/aura/bench/bench_main\.cc$",
3128 r"^ui/ozone/platform/cast/",
3129 r"^ui/base/x/xwmstartupcheck/"
Sam Maiera6e76d72022-02-11 21:43:503130 r"xwmstartupcheck\.cc$"))
3131 source_file_filter = lambda x: input_api.FilterSourceFile(
3132 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:403133
Sam Maiera6e76d72022-02-11 21:43:503134 log_info = set([])
3135 printf = set([])
[email protected]85218562013-11-22 07:41:403136
Sam Maiera6e76d72022-02-11 21:43:503137 for f in input_api.AffectedSourceFiles(source_file_filter):
3138 for _, line in f.ChangedContents():
3139 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
3140 log_info.add(f.LocalPath())
3141 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
3142 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:373143
Sam Maiera6e76d72022-02-11 21:43:503144 if input_api.re.search(r"\bprintf\(", line):
3145 printf.add(f.LocalPath())
3146 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
3147 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:403148
Sam Maiera6e76d72022-02-11 21:43:503149 if log_info:
3150 return [
3151 output_api.PresubmitError(
3152 'These files spam the console log with LOG(INFO):',
3153 items=log_info)
3154 ]
3155 if printf:
3156 return [
3157 output_api.PresubmitError(
3158 'These files spam the console log with printf/fprintf:',
3159 items=printf)
3160 ]
3161 return []
[email protected]85218562013-11-22 07:41:403162
3163
Saagar Sanghavifceeaae2020-08-12 16:40:363164def CheckForAnonymousVariables(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503165 """These types are all expected to hold locks while in scope and
3166 so should never be anonymous (which causes them to be immediately
3167 destroyed)."""
3168 they_who_must_be_named = [
3169 'base::AutoLock',
3170 'base::AutoReset',
3171 'base::AutoUnlock',
3172 'SkAutoAlphaRestore',
3173 'SkAutoBitmapShaderInstall',
3174 'SkAutoBlitterChoose',
3175 'SkAutoBounderCommit',
3176 'SkAutoCallProc',
3177 'SkAutoCanvasRestore',
3178 'SkAutoCommentBlock',
3179 'SkAutoDescriptor',
3180 'SkAutoDisableDirectionCheck',
3181 'SkAutoDisableOvalCheck',
3182 'SkAutoFree',
3183 'SkAutoGlyphCache',
3184 'SkAutoHDC',
3185 'SkAutoLockColors',
3186 'SkAutoLockPixels',
3187 'SkAutoMalloc',
3188 'SkAutoMaskFreeImage',
3189 'SkAutoMutexAcquire',
3190 'SkAutoPathBoundsUpdate',
3191 'SkAutoPDFRelease',
3192 'SkAutoRasterClipValidate',
3193 'SkAutoRef',
3194 'SkAutoTime',
3195 'SkAutoTrace',
3196 'SkAutoUnref',
3197 ]
3198 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
3199 # bad: base::AutoLock(lock.get());
3200 # not bad: base::AutoLock lock(lock.get());
3201 bad_pattern = input_api.re.compile(anonymous)
3202 # good: new base::AutoLock(lock.get())
3203 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
3204 errors = []
[email protected]49aa76a2013-12-04 06:59:163205
Sam Maiera6e76d72022-02-11 21:43:503206 for f in input_api.AffectedFiles():
3207 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
3208 continue
3209 for linenum, line in f.ChangedContents():
3210 if bad_pattern.search(line) and not good_pattern.search(line):
3211 errors.append('%s:%d' % (f.LocalPath(), linenum))
[email protected]49aa76a2013-12-04 06:59:163212
Sam Maiera6e76d72022-02-11 21:43:503213 if errors:
3214 return [
3215 output_api.PresubmitError(
3216 'These lines create anonymous variables that need to be named:',
3217 items=errors)
3218 ]
3219 return []
[email protected]49aa76a2013-12-04 06:59:163220
3221
Saagar Sanghavifceeaae2020-08-12 16:40:363222def CheckUniquePtrOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503223 # Returns whether |template_str| is of the form <T, U...> for some types T
3224 # and U. Assumes that |template_str| is already in the form <...>.
3225 def HasMoreThanOneArg(template_str):
3226 # Level of <...> nesting.
3227 nesting = 0
3228 for c in template_str:
3229 if c == '<':
3230 nesting += 1
3231 elif c == '>':
3232 nesting -= 1
3233 elif c == ',' and nesting == 1:
3234 return True
3235 return False
Vaclav Brozekb7fadb692018-08-30 06:39:533236
Sam Maiera6e76d72022-02-11 21:43:503237 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
3238 sources = lambda affected_file: input_api.FilterSourceFile(
3239 affected_file,
3240 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3241 DEFAULT_FILES_TO_SKIP),
3242 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:553243
Sam Maiera6e76d72022-02-11 21:43:503244 # Pattern to capture a single "<...>" block of template arguments. It can
3245 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
3246 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
3247 # latter would likely require counting that < and > match, which is not
3248 # expressible in regular languages. Should the need arise, one can introduce
3249 # limited counting (matching up to a total number of nesting depth), which
3250 # should cover all practical cases for already a low nesting limit.
3251 template_arg_pattern = (
3252 r'<[^>]*' # Opening block of <.
3253 r'>([^<]*>)?') # Closing block of >.
3254 # Prefix expressing that whatever follows is not already inside a <...>
3255 # block.
3256 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
3257 null_construct_pattern = input_api.re.compile(
3258 not_inside_template_arg_pattern + r'\bstd::unique_ptr' +
3259 template_arg_pattern + r'\(\)')
Vaclav Brozeka54c528b2018-04-06 19:23:553260
Sam Maiera6e76d72022-02-11 21:43:503261 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
3262 template_arg_no_array_pattern = (
3263 r'<[^>]*[^]]' # Opening block of <.
3264 r'>([^(<]*[^]]>)?') # Closing block of >.
3265 # Prefix saying that what follows is the start of an expression.
3266 start_of_expr_pattern = r'(=|\breturn|^)\s*'
3267 # Suffix saying that what follows are call parentheses with a non-empty list
3268 # of arguments.
3269 nonempty_arg_list_pattern = r'\(([^)]|$)'
3270 # Put the template argument into a capture group for deeper examination later.
3271 return_construct_pattern = input_api.re.compile(
3272 start_of_expr_pattern + r'std::unique_ptr' + '(?P<template_arg>' +
3273 template_arg_no_array_pattern + ')' + nonempty_arg_list_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:553274
Sam Maiera6e76d72022-02-11 21:43:503275 problems_constructor = []
3276 problems_nullptr = []
3277 for f in input_api.AffectedSourceFiles(sources):
3278 for line_number, line in f.ChangedContents():
3279 # Disallow:
3280 # return std::unique_ptr<T>(foo);
3281 # bar = std::unique_ptr<T>(foo);
3282 # But allow:
3283 # return std::unique_ptr<T[]>(foo);
3284 # bar = std::unique_ptr<T[]>(foo);
3285 # And also allow cases when the second template argument is present. Those
3286 # cases cannot be handled by std::make_unique:
3287 # return std::unique_ptr<T, U>(foo);
3288 # bar = std::unique_ptr<T, U>(foo);
3289 local_path = f.LocalPath()
3290 return_construct_result = return_construct_pattern.search(line)
3291 if return_construct_result and not HasMoreThanOneArg(
3292 return_construct_result.group('template_arg')):
3293 problems_constructor.append(
3294 '%s:%d\n %s' % (local_path, line_number, line.strip()))
3295 # Disallow:
3296 # std::unique_ptr<T>()
3297 if null_construct_pattern.search(line):
3298 problems_nullptr.append(
3299 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Vaclav Brozek851d9602018-04-04 16:13:053300
Sam Maiera6e76d72022-02-11 21:43:503301 errors = []
3302 if problems_nullptr:
3303 errors.append(
3304 output_api.PresubmitPromptWarning(
3305 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
3306 problems_nullptr))
3307 if problems_constructor:
3308 errors.append(
3309 output_api.PresubmitError(
3310 'The following files use explicit std::unique_ptr constructor. '
3311 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
3312 'std::make_unique is not an option.', problems_constructor))
3313 return errors
Peter Kasting4844e46e2018-02-23 07:27:103314
3315
Saagar Sanghavifceeaae2020-08-12 16:40:363316def CheckUserActionUpdate(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503317 """Checks if any new user action has been added."""
3318 if any('actions.xml' == input_api.os_path.basename(f)
3319 for f in input_api.LocalPaths()):
3320 # If actions.xml is already included in the changelist, the PRESUBMIT
3321 # for actions.xml will do a more complete presubmit check.
3322 return []
3323
3324 file_inclusion_pattern = [r'.*\.(cc|mm)$']
3325 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3326 input_api.DEFAULT_FILES_TO_SKIP)
3327 file_filter = lambda f: input_api.FilterSourceFile(
3328 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
3329
3330 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
3331 current_actions = None
3332 for f in input_api.AffectedFiles(file_filter=file_filter):
3333 for line_num, line in f.ChangedContents():
3334 match = input_api.re.search(action_re, line)
3335 if match:
3336 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
3337 # loaded only once.
3338 if not current_actions:
Bruce Dawson6cb2d4d2023-03-01 21:35:093339 with open('tools/metrics/actions/actions.xml',
3340 encoding='utf-8') as actions_f:
Sam Maiera6e76d72022-02-11 21:43:503341 current_actions = actions_f.read()
3342 # Search for the matched user action name in |current_actions|.
3343 for action_name in match.groups():
3344 action = 'name="{0}"'.format(action_name)
3345 if action not in current_actions:
3346 return [
3347 output_api.PresubmitPromptWarning(
3348 'File %s line %d: %s is missing in '
3349 'tools/metrics/actions/actions.xml. Please run '
3350 'tools/metrics/actions/extract_actions.py to update.'
3351 % (f.LocalPath(), line_num, action_name))
3352 ]
[email protected]999261d2014-03-03 20:08:083353 return []
3354
[email protected]999261d2014-03-03 20:08:083355
Daniel Cheng13ca61a882017-08-25 15:11:253356def _ImportJSONCommentEater(input_api):
Sam Maiera6e76d72022-02-11 21:43:503357 import sys
3358 sys.path = sys.path + [
3359 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3360 'json_comment_eater')
3361 ]
3362 import json_comment_eater
3363 return json_comment_eater
Daniel Cheng13ca61a882017-08-25 15:11:253364
3365
[email protected]99171a92014-06-03 08:44:473366def _GetJSONParseError(input_api, filename, eat_comments=True):
dchenge07de812016-06-20 19:27:173367 try:
Sam Maiera6e76d72022-02-11 21:43:503368 contents = input_api.ReadFile(filename)
3369 if eat_comments:
3370 json_comment_eater = _ImportJSONCommentEater(input_api)
3371 contents = json_comment_eater.Nom(contents)
dchenge07de812016-06-20 19:27:173372
Sam Maiera6e76d72022-02-11 21:43:503373 input_api.json.loads(contents)
3374 except ValueError as e:
3375 return e
Andrew Grieve4deedb12022-02-03 21:34:503376 return None
3377
3378
Sam Maiera6e76d72022-02-11 21:43:503379def _GetIDLParseError(input_api, filename):
3380 try:
3381 contents = input_api.ReadFile(filename)
Devlin Croninf7582a12022-04-21 21:14:283382 for i, char in enumerate(contents):
Daniel Chenga37c03db2022-05-12 17:20:343383 if not char.isascii():
3384 return (
3385 'Non-ascii character "%s" (ord %d) found at offset %d.' %
3386 (char, ord(char), i))
Sam Maiera6e76d72022-02-11 21:43:503387 idl_schema = input_api.os_path.join(input_api.PresubmitLocalPath(),
3388 'tools', 'json_schema_compiler',
3389 'idl_schema.py')
3390 process = input_api.subprocess.Popen(
Bruce Dawson679fb082022-04-14 00:47:283391 [input_api.python3_executable, idl_schema],
Sam Maiera6e76d72022-02-11 21:43:503392 stdin=input_api.subprocess.PIPE,
3393 stdout=input_api.subprocess.PIPE,
3394 stderr=input_api.subprocess.PIPE,
3395 universal_newlines=True)
3396 (_, error) = process.communicate(input=contents)
3397 return error or None
3398 except ValueError as e:
3399 return e
agrievef32bcc72016-04-04 14:57:403400
agrievef32bcc72016-04-04 14:57:403401
Sam Maiera6e76d72022-02-11 21:43:503402def CheckParseErrors(input_api, output_api):
3403 """Check that IDL and JSON files do not contain syntax errors."""
3404 actions = {
3405 '.idl': _GetIDLParseError,
3406 '.json': _GetJSONParseError,
3407 }
3408 # Most JSON files are preprocessed and support comments, but these do not.
3409 json_no_comments_patterns = [
Bruce Dawson40fece62022-09-16 19:58:313410 r'^testing/',
Sam Maiera6e76d72022-02-11 21:43:503411 ]
3412 # Only run IDL checker on files in these directories.
3413 idl_included_patterns = [
Bruce Dawson40fece62022-09-16 19:58:313414 r'^chrome/common/extensions/api/',
3415 r'^extensions/common/api/',
Sam Maiera6e76d72022-02-11 21:43:503416 ]
agrievef32bcc72016-04-04 14:57:403417
Sam Maiera6e76d72022-02-11 21:43:503418 def get_action(affected_file):
3419 filename = affected_file.LocalPath()
3420 return actions.get(input_api.os_path.splitext(filename)[1])
agrievef32bcc72016-04-04 14:57:403421
Sam Maiera6e76d72022-02-11 21:43:503422 def FilterFile(affected_file):
3423 action = get_action(affected_file)
3424 if not action:
3425 return False
3426 path = affected_file.LocalPath()
agrievef32bcc72016-04-04 14:57:403427
Sam Maiera6e76d72022-02-11 21:43:503428 if _MatchesFile(input_api,
3429 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS, path):
3430 return False
3431
3432 if (action == _GetIDLParseError
3433 and not _MatchesFile(input_api, idl_included_patterns, path)):
3434 return False
3435 return True
3436
3437 results = []
3438 for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
3439 include_deletes=False):
3440 action = get_action(affected_file)
3441 kwargs = {}
3442 if (action == _GetJSONParseError
3443 and _MatchesFile(input_api, json_no_comments_patterns,
3444 affected_file.LocalPath())):
3445 kwargs['eat_comments'] = False
3446 parse_error = action(input_api, affected_file.AbsoluteLocalPath(),
3447 **kwargs)
3448 if parse_error:
3449 results.append(
3450 output_api.PresubmitError(
3451 '%s could not be parsed: %s' %
3452 (affected_file.LocalPath(), parse_error)))
3453 return results
3454
3455
3456def CheckJavaStyle(input_api, output_api):
3457 """Runs checkstyle on changed java files and returns errors if any exist."""
3458
3459 # Return early if no java files were modified.
3460 if not any(
3461 _IsJavaFile(input_api, f.LocalPath())
3462 for f in input_api.AffectedFiles()):
3463 return []
3464
3465 import sys
3466 original_sys_path = sys.path
3467 try:
3468 sys.path = sys.path + [
3469 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3470 'android', 'checkstyle')
3471 ]
3472 import checkstyle
3473 finally:
3474 # Restore sys.path to what it was before.
3475 sys.path = original_sys_path
3476
Andrew Grieve4f88e3ca2022-11-22 19:09:203477 return checkstyle.run_presubmit(
Sam Maiera6e76d72022-02-11 21:43:503478 input_api,
3479 output_api,
Sam Maiera6e76d72022-02-11 21:43:503480 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
3481
3482
3483def CheckPythonDevilInit(input_api, output_api):
3484 """Checks to make sure devil is initialized correctly in python scripts."""
3485 script_common_initialize_pattern = input_api.re.compile(
3486 r'script_common\.InitializeEnvironment\(')
3487 devil_env_config_initialize = input_api.re.compile(
3488 r'devil_env\.config\.Initialize\(')
3489
3490 errors = []
3491
3492 sources = lambda affected_file: input_api.FilterSourceFile(
3493 affected_file,
3494 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:313495 r'^build/android/devil_chromium\.py',
3496 r'^third_party/.*',
Sam Maiera6e76d72022-02-11 21:43:503497 )),
3498 files_to_check=[r'.*\.py$'])
3499
3500 for f in input_api.AffectedSourceFiles(sources):
3501 for line_num, line in f.ChangedContents():
3502 if (script_common_initialize_pattern.search(line)
3503 or devil_env_config_initialize.search(line)):
3504 errors.append("%s:%d" % (f.LocalPath(), line_num))
3505
3506 results = []
3507
3508 if errors:
3509 results.append(
3510 output_api.PresubmitError(
3511 'Devil initialization should always be done using '
3512 'devil_chromium.Initialize() in the chromium project, to use better '
3513 'defaults for dependencies (ex. up-to-date version of adb).',
3514 errors))
3515
3516 return results
3517
3518
3519def _MatchesFile(input_api, patterns, path):
Bruce Dawson40fece62022-09-16 19:58:313520 # Consistently use / as path separator to simplify the writing of regex
3521 # expressions.
3522 path = path.replace(input_api.os_path.sep, '/')
Sam Maiera6e76d72022-02-11 21:43:503523 for pattern in patterns:
3524 if input_api.re.search(pattern, path):
3525 return True
3526 return False
3527
3528
Daniel Chenga37c03db2022-05-12 17:20:343529def _ChangeHasSecurityReviewer(input_api, owners_file):
3530 """Returns True iff the CL has a reviewer from SECURITY_OWNERS.
Sam Maiera6e76d72022-02-11 21:43:503531
Daniel Chenga37c03db2022-05-12 17:20:343532 Args:
3533 input_api: The presubmit input API.
3534 owners_file: OWNERS file with required reviewers. Typically, this is
3535 something like ipc/SECURITY_OWNERS.
3536
3537 Note: if the presubmit is running for commit rather than for upload, this
3538 only returns True if a security reviewer has also approved the CL.
Sam Maiera6e76d72022-02-11 21:43:503539 """
Daniel Chengd88244472022-05-16 09:08:473540 # Owners-Override should bypass all additional OWNERS enforcement checks.
3541 # A CR+1 vote will still be required to land this change.
3542 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
3543 input_api.change.issue)):
3544 return True
3545
Daniel Chenga37c03db2022-05-12 17:20:343546 owner_email, reviewers = (
3547 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
Daniel Cheng3008dc12022-05-13 04:02:113548 input_api,
3549 None,
3550 approval_needed=input_api.is_committing and not input_api.dry_run))
Sam Maiera6e76d72022-02-11 21:43:503551
Daniel Chenga37c03db2022-05-12 17:20:343552 security_owners = input_api.owners_client.ListOwners(owners_file)
3553 return any(owner in reviewers for owner in security_owners)
Sam Maiera6e76d72022-02-11 21:43:503554
Daniel Chenga37c03db2022-05-12 17:20:343555
3556@dataclass
Daniel Cheng171dad8d2022-05-21 00:40:253557class _SecurityProblemWithItems:
3558 problem: str
3559 items: Sequence[str]
3560
3561
3562@dataclass
Daniel Chenga37c03db2022-05-12 17:20:343563class _MissingSecurityOwnersResult:
Daniel Cheng171dad8d2022-05-21 00:40:253564 owners_file_problems: Sequence[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:343565 has_security_sensitive_files: bool
Daniel Cheng171dad8d2022-05-21 00:40:253566 missing_reviewer_problem: Optional[_SecurityProblemWithItems]
Daniel Chenga37c03db2022-05-12 17:20:343567
3568
3569def _FindMissingSecurityOwners(input_api,
3570 output_api,
3571 file_patterns: Sequence[str],
3572 excluded_patterns: Sequence[str],
3573 required_owners_file: str,
3574 custom_rule_function: Optional[Callable] = None
3575 ) -> _MissingSecurityOwnersResult:
3576 """Find OWNERS files missing per-file rules for security-sensitive files.
3577
3578 Args:
3579 input_api: the PRESUBMIT input API object.
3580 output_api: the PRESUBMIT output API object.
3581 file_patterns: basename patterns that require a corresponding per-file
3582 security restriction.
3583 excluded_patterns: path patterns that should be exempted from
3584 requiring a security restriction.
3585 required_owners_file: path to the required OWNERS file, e.g.
3586 ipc/SECURITY_OWNERS
3587 cc_alias: If not None, email that will be CCed automatically if the
3588 change contains security-sensitive files, as determined by
3589 `file_patterns` and `excluded_patterns`.
3590 custom_rule_function: If not None, will be called with `input_api` and
3591 the current file under consideration. Returning True will add an
3592 exact match per-file rule check for the current file.
3593 """
3594
3595 # `to_check` is a mapping of an OWNERS file path to Patterns.
3596 #
3597 # Patterns is a dictionary mapping glob patterns (suitable for use in
3598 # per-file rules) to a PatternEntry.
3599 #
Sam Maiera6e76d72022-02-11 21:43:503600 # PatternEntry is a dictionary with two keys:
3601 # - 'files': the files that are matched by this pattern
3602 # - 'rules': the per-file rules needed for this pattern
Daniel Chenga37c03db2022-05-12 17:20:343603 #
Sam Maiera6e76d72022-02-11 21:43:503604 # For example, if we expect OWNERS file to contain rules for *.mojom and
3605 # *_struct_traits*.*, Patterns might look like this:
3606 # {
3607 # '*.mojom': {
3608 # 'files': ...,
3609 # 'rules': [
3610 # 'per-file *.mojom=set noparent',
3611 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
3612 # ],
3613 # },
3614 # '*_struct_traits*.*': {
3615 # 'files': ...,
3616 # 'rules': [
3617 # 'per-file *_struct_traits*.*=set noparent',
3618 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
3619 # ],
3620 # },
3621 # }
3622 to_check = {}
Daniel Chenga37c03db2022-05-12 17:20:343623 files_to_review = []
Sam Maiera6e76d72022-02-11 21:43:503624
Daniel Chenga37c03db2022-05-12 17:20:343625 def AddPatternToCheck(file, pattern):
Sam Maiera6e76d72022-02-11 21:43:503626 owners_file = input_api.os_path.join(
Daniel Chengd88244472022-05-16 09:08:473627 input_api.os_path.dirname(file.LocalPath()), 'OWNERS')
Sam Maiera6e76d72022-02-11 21:43:503628 if owners_file not in to_check:
3629 to_check[owners_file] = {}
3630 if pattern not in to_check[owners_file]:
3631 to_check[owners_file][pattern] = {
3632 'files': [],
3633 'rules': [
Daniel Chenga37c03db2022-05-12 17:20:343634 f'per-file {pattern}=set noparent',
3635 f'per-file {pattern}=file://{required_owners_file}',
Sam Maiera6e76d72022-02-11 21:43:503636 ]
3637 }
Daniel Chenged57a162022-05-25 02:56:343638 to_check[owners_file][pattern]['files'].append(file.LocalPath())
Daniel Chenga37c03db2022-05-12 17:20:343639 files_to_review.append(file.LocalPath())
Sam Maiera6e76d72022-02-11 21:43:503640
Daniel Chenga37c03db2022-05-12 17:20:343641 # Only enforce security OWNERS rules for a directory if that directory has a
3642 # file that matches `file_patterns`. For example, if a directory only
3643 # contains *.mojom files and no *_messages*.h files, the check should only
3644 # ensure that rules for *.mojom files are present.
3645 for file in input_api.AffectedFiles(include_deletes=False):
3646 file_basename = input_api.os_path.basename(file.LocalPath())
3647 if custom_rule_function is not None and custom_rule_function(
3648 input_api, file):
3649 AddPatternToCheck(file, file_basename)
3650 continue
Sam Maiera6e76d72022-02-11 21:43:503651
Daniel Chenga37c03db2022-05-12 17:20:343652 if any(
3653 input_api.fnmatch.fnmatch(file.LocalPath(), pattern)
3654 for pattern in excluded_patterns):
Sam Maiera6e76d72022-02-11 21:43:503655 continue
3656
3657 for pattern in file_patterns:
Daniel Chenga37c03db2022-05-12 17:20:343658 # Unlike `excluded_patterns`, `file_patterns` is checked only against the
3659 # file's basename.
3660 if input_api.fnmatch.fnmatch(file_basename, pattern):
3661 AddPatternToCheck(file, pattern)
Sam Maiera6e76d72022-02-11 21:43:503662 break
3663
Daniel Chenga37c03db2022-05-12 17:20:343664 has_security_sensitive_files = bool(to_check)
Daniel Cheng171dad8d2022-05-21 00:40:253665
3666 # Check if any newly added lines in OWNERS files intersect with required
3667 # per-file OWNERS lines. If so, ensure that a security reviewer is included.
3668 # This is a hack, but is needed because the OWNERS check (by design) ignores
3669 # new OWNERS entries; otherwise, a non-owner could add someone as a new
3670 # OWNER and have that newly-added OWNER self-approve their own addition.
3671 newly_covered_files = []
3672 for file in input_api.AffectedFiles(include_deletes=False):
3673 if not file.LocalPath() in to_check:
3674 continue
3675 for _, line in file.ChangedContents():
3676 for _, entry in to_check[file.LocalPath()].items():
3677 if line in entry['rules']:
3678 newly_covered_files.extend(entry['files'])
3679
3680 missing_reviewer_problems = None
3681 if newly_covered_files and not _ChangeHasSecurityReviewer(
Daniel Chenga37c03db2022-05-12 17:20:343682 input_api, required_owners_file):
Daniel Cheng171dad8d2022-05-21 00:40:253683 missing_reviewer_problems = _SecurityProblemWithItems(
3684 f'Review from an owner in {required_owners_file} is required for '
3685 'the following newly-added files:',
3686 [f'{file}' for file in sorted(set(newly_covered_files))])
Sam Maiera6e76d72022-02-11 21:43:503687
3688 # Go through the OWNERS files to check, filtering out rules that are already
3689 # present in that OWNERS file.
3690 for owners_file, patterns in to_check.items():
3691 try:
Daniel Cheng171dad8d2022-05-21 00:40:253692 lines = set(
3693 input_api.ReadFile(
3694 input_api.os_path.join(input_api.change.RepositoryRoot(),
3695 owners_file)).splitlines())
3696 for entry in patterns.values():
3697 entry['rules'] = [
3698 rule for rule in entry['rules'] if rule not in lines
3699 ]
Sam Maiera6e76d72022-02-11 21:43:503700 except IOError:
3701 # No OWNERS file, so all the rules are definitely missing.
3702 continue
3703
3704 # All the remaining lines weren't found in OWNERS files, so emit an error.
Daniel Cheng171dad8d2022-05-21 00:40:253705 owners_file_problems = []
Daniel Chenga37c03db2022-05-12 17:20:343706
Sam Maiera6e76d72022-02-11 21:43:503707 for owners_file, patterns in to_check.items():
3708 missing_lines = []
3709 files = []
3710 for _, entry in patterns.items():
Daniel Chenged57a162022-05-25 02:56:343711 files.extend(entry['files'])
Sam Maiera6e76d72022-02-11 21:43:503712 missing_lines.extend(entry['rules'])
Sam Maiera6e76d72022-02-11 21:43:503713 if missing_lines:
Daniel Cheng171dad8d2022-05-21 00:40:253714 joined_missing_lines = '\n'.join(line for line in missing_lines)
3715 owners_file_problems.append(
3716 _SecurityProblemWithItems(
3717 'Found missing OWNERS lines for security-sensitive files. '
3718 f'Please add the following lines to {owners_file}:\n'
3719 f'{joined_missing_lines}\n\nTo ensure security review for:',
3720 files))
Daniel Chenga37c03db2022-05-12 17:20:343721
Daniel Cheng171dad8d2022-05-21 00:40:253722 return _MissingSecurityOwnersResult(owners_file_problems,
Daniel Chenga37c03db2022-05-12 17:20:343723 has_security_sensitive_files,
Daniel Cheng171dad8d2022-05-21 00:40:253724 missing_reviewer_problems)
Daniel Chenga37c03db2022-05-12 17:20:343725
3726
3727def _CheckChangeForIpcSecurityOwners(input_api, output_api):
3728 # Whether or not a file affects IPC is (mostly) determined by a simple list
3729 # of filename patterns.
3730 file_patterns = [
3731 # Legacy IPC:
3732 '*_messages.cc',
3733 '*_messages*.h',
3734 '*_param_traits*.*',
3735 # Mojo IPC:
3736 '*.mojom',
3737 '*_mojom_traits*.*',
3738 '*_type_converter*.*',
3739 # Android native IPC:
3740 '*.aidl',
3741 ]
3742
Daniel Chenga37c03db2022-05-12 17:20:343743 excluded_patterns = [
Daniel Cheng518943f2022-05-12 22:15:463744 # These third_party directories do not contain IPCs, but contain files
3745 # matching the above patterns, which trigger false positives.
Daniel Chenga37c03db2022-05-12 17:20:343746 'third_party/crashpad/*',
3747 'third_party/blink/renderer/platform/bindings/*',
3748 'third_party/protobuf/benchmarks/python/*',
3749 'third_party/win_build_output/*',
Daniel Chengd88244472022-05-16 09:08:473750 # Enum-only mojoms used for web metrics, so no security review needed.
3751 'third_party/blink/public/mojom/use_counter/metrics/*',
Daniel Chenga37c03db2022-05-12 17:20:343752 # These files are just used to communicate between class loaders running
3753 # in the same process.
3754 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
3755 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
3756 ]
3757
3758 def IsMojoServiceManifestFile(input_api, file):
3759 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
3760 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
3761 if not manifest_pattern.search(file.LocalPath()):
3762 return False
3763
3764 if test_manifest_pattern.search(file.LocalPath()):
3765 return False
3766
3767 # All actual service manifest files should contain at least one
3768 # qualified reference to service_manager::Manifest.
3769 return any('service_manager::Manifest' in line
3770 for line in file.NewContents())
3771
3772 return _FindMissingSecurityOwners(
3773 input_api,
3774 output_api,
3775 file_patterns,
3776 excluded_patterns,
3777 'ipc/SECURITY_OWNERS',
3778 custom_rule_function=IsMojoServiceManifestFile)
3779
3780
3781def _CheckChangeForFuchsiaSecurityOwners(input_api, output_api):
3782 file_patterns = [
3783 # Component specifications.
3784 '*.cml', # Component Framework v2.
3785 '*.cmx', # Component Framework v1.
3786
3787 # Fuchsia IDL protocol specifications.
3788 '*.fidl',
3789 ]
3790
3791 # Don't check for owners files for changes in these directories.
3792 excluded_patterns = [
3793 'third_party/crashpad/*',
3794 ]
3795
3796 return _FindMissingSecurityOwners(input_api, output_api, file_patterns,
3797 excluded_patterns,
3798 'build/fuchsia/SECURITY_OWNERS')
3799
3800
3801def CheckSecurityOwners(input_api, output_api):
3802 """Checks that various security-sensitive files have an IPC OWNERS rule."""
3803 ipc_results = _CheckChangeForIpcSecurityOwners(input_api, output_api)
3804 fuchsia_results = _CheckChangeForFuchsiaSecurityOwners(
3805 input_api, output_api)
3806
3807 if ipc_results.has_security_sensitive_files:
3808 output_api.AppendCC('[email protected]')
Sam Maiera6e76d72022-02-11 21:43:503809
3810 results = []
Daniel Chenga37c03db2022-05-12 17:20:343811
Daniel Cheng171dad8d2022-05-21 00:40:253812 missing_reviewer_problems = []
3813 if ipc_results.missing_reviewer_problem:
3814 missing_reviewer_problems.append(ipc_results.missing_reviewer_problem)
3815 if fuchsia_results.missing_reviewer_problem:
3816 missing_reviewer_problems.append(
3817 fuchsia_results.missing_reviewer_problem)
Daniel Chenga37c03db2022-05-12 17:20:343818
Daniel Cheng171dad8d2022-05-21 00:40:253819 # Missing reviewers are an error unless there's no issue number
3820 # associated with this branch; in that case, the presubmit is being run
3821 # with --all or --files.
3822 #
3823 # Note that upload should never be an error; otherwise, it would be
3824 # impossible to upload changes at all.
3825 if input_api.is_committing and input_api.change.issue:
3826 make_presubmit_message = output_api.PresubmitError
3827 else:
3828 make_presubmit_message = output_api.PresubmitNotifyResult
3829 for problem in missing_reviewer_problems:
Sam Maiera6e76d72022-02-11 21:43:503830 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:253831 make_presubmit_message(problem.problem, items=problem.items))
Daniel Chenga37c03db2022-05-12 17:20:343832
Daniel Cheng171dad8d2022-05-21 00:40:253833 owners_file_problems = []
3834 owners_file_problems.extend(ipc_results.owners_file_problems)
3835 owners_file_problems.extend(fuchsia_results.owners_file_problems)
Daniel Chenga37c03db2022-05-12 17:20:343836
Daniel Cheng171dad8d2022-05-21 00:40:253837 for problem in owners_file_problems:
Daniel Cheng3008dc12022-05-13 04:02:113838 # Missing per-file rules are always an error. While swarming and caching
3839 # means that uploading a patchset with updated OWNERS files and sending
3840 # it to the CQ again should not have a large incremental cost, it is
3841 # still frustrating to discover the error only after the change has
3842 # already been uploaded.
Daniel Chenga37c03db2022-05-12 17:20:343843 results.append(
Daniel Cheng171dad8d2022-05-21 00:40:253844 output_api.PresubmitError(problem.problem, items=problem.items))
Sam Maiera6e76d72022-02-11 21:43:503845
3846 return results
3847
3848
3849def _GetFilesUsingSecurityCriticalFunctions(input_api):
3850 """Checks affected files for changes to security-critical calls. This
3851 function checks the full change diff, to catch both additions/changes
3852 and removals.
3853
3854 Returns a dict keyed by file name, and the value is a set of detected
3855 functions.
3856 """
3857 # Map of function pretty name (displayed in an error) to the pattern to
3858 # match it with.
3859 _PATTERNS_TO_CHECK = {
3860 'content::GetServiceSandboxType<>()': 'GetServiceSandboxType\\<'
3861 }
3862 _PATTERNS_TO_CHECK = {
3863 k: input_api.re.compile(v)
3864 for k, v in _PATTERNS_TO_CHECK.items()
3865 }
3866
Sam Maiera6e76d72022-02-11 21:43:503867 # We don't want to trigger on strings within this file.
3868 def presubmit_file_filter(f):
Daniel Chenga37c03db2022-05-12 17:20:343869 return 'PRESUBMIT.py' != input_api.os_path.split(f.LocalPath())[1]
Sam Maiera6e76d72022-02-11 21:43:503870
3871 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3872 files_to_functions = {}
3873 for f in input_api.AffectedFiles(file_filter=presubmit_file_filter):
3874 diff = f.GenerateScmDiff()
3875 for line in diff.split('\n'):
3876 # Not using just RightHandSideLines() because removing a
3877 # call to a security-critical function can be just as important
3878 # as adding or changing the arguments.
3879 if line.startswith('-') or (line.startswith('+')
3880 and not line.startswith('++')):
3881 for name, pattern in _PATTERNS_TO_CHECK.items():
3882 if pattern.search(line):
3883 path = f.LocalPath()
3884 if not path in files_to_functions:
3885 files_to_functions[path] = set()
3886 files_to_functions[path].add(name)
3887 return files_to_functions
3888
3889
3890def CheckSecurityChanges(input_api, output_api):
3891 """Checks that changes involving security-critical functions are reviewed
3892 by the security team.
3893 """
3894 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3895 if not len(files_to_functions):
3896 return []
3897
Sam Maiera6e76d72022-02-11 21:43:503898 owners_file = 'ipc/SECURITY_OWNERS'
Daniel Chenga37c03db2022-05-12 17:20:343899 if _ChangeHasSecurityReviewer(input_api, owners_file):
Sam Maiera6e76d72022-02-11 21:43:503900 return []
3901
Daniel Chenga37c03db2022-05-12 17:20:343902 msg = 'The following files change calls to security-sensitive functions\n' \
Sam Maiera6e76d72022-02-11 21:43:503903 'that need to be reviewed by {}.\n'.format(owners_file)
3904 for path, names in files_to_functions.items():
3905 msg += ' {}\n'.format(path)
3906 for name in names:
3907 msg += ' {}\n'.format(name)
3908 msg += '\n'
3909
3910 if input_api.is_committing:
3911 output = output_api.PresubmitError
Mohamed Heikale217fc852020-07-06 19:44:033912 else:
Sam Maiera6e76d72022-02-11 21:43:503913 output = output_api.PresubmitNotifyResult
3914 return [output(msg)]
3915
3916
3917def CheckSetNoParent(input_api, output_api):
3918 """Checks that set noparent is only used together with an OWNERS file in
3919 //build/OWNERS.setnoparent (see also
3920 //docs/code_reviews.md#owners-files-details)
3921 """
3922 # Return early if no OWNERS files were modified.
3923 if not any(f.LocalPath().endswith('OWNERS')
3924 for f in input_api.AffectedFiles(include_deletes=False)):
3925 return []
3926
3927 errors = []
3928
3929 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3930 allowed_owners_files = set()
Bruce Dawson58a45d22023-02-27 11:24:163931 with open(allowed_owners_files_file, 'r', encoding='utf-8') as f:
Sam Maiera6e76d72022-02-11 21:43:503932 for line in f:
3933 line = line.strip()
3934 if not line or line.startswith('#'):
3935 continue
3936 allowed_owners_files.add(line)
3937
3938 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3939
3940 for f in input_api.AffectedFiles(include_deletes=False):
3941 if not f.LocalPath().endswith('OWNERS'):
3942 continue
3943
3944 found_owners_files = set()
3945 found_set_noparent_lines = dict()
3946
3947 # Parse the OWNERS file.
3948 for lineno, line in enumerate(f.NewContents(), 1):
3949 line = line.strip()
3950 if line.startswith('set noparent'):
3951 found_set_noparent_lines[''] = lineno
3952 if line.startswith('file://'):
3953 if line in allowed_owners_files:
3954 found_owners_files.add('')
3955 if line.startswith('per-file'):
3956 match = per_file_pattern.match(line)
3957 if match:
3958 glob = match.group(1).strip()
3959 directive = match.group(2).strip()
3960 if directive == 'set noparent':
3961 found_set_noparent_lines[glob] = lineno
3962 if directive.startswith('file://'):
3963 if directive in allowed_owners_files:
3964 found_owners_files.add(glob)
3965
3966 # Check that every set noparent line has a corresponding file:// line
3967 # listed in build/OWNERS.setnoparent. An exception is made for top level
3968 # directories since src/OWNERS shouldn't review them.
Bruce Dawson6bb0d672022-04-06 15:13:493969 linux_path = f.LocalPath().replace(input_api.os_path.sep, '/')
3970 if (linux_path.count('/') != 1
3971 and (not linux_path in _EXCLUDED_SET_NO_PARENT_PATHS)):
Sam Maiera6e76d72022-02-11 21:43:503972 for set_noparent_line in found_set_noparent_lines:
3973 if set_noparent_line in found_owners_files:
3974 continue
3975 errors.append(' %s:%d' %
Bruce Dawson6bb0d672022-04-06 15:13:493976 (linux_path,
Sam Maiera6e76d72022-02-11 21:43:503977 found_set_noparent_lines[set_noparent_line]))
3978
3979 results = []
3980 if errors:
3981 if input_api.is_committing:
3982 output = output_api.PresubmitError
3983 else:
3984 output = output_api.PresubmitPromptWarning
3985 results.append(
3986 output(
3987 'Found the following "set noparent" restrictions in OWNERS files that '
3988 'do not include owners from build/OWNERS.setnoparent:',
3989 long_text='\n\n'.join(errors)))
3990 return results
3991
3992
3993def CheckUselessForwardDeclarations(input_api, output_api):
3994 """Checks that added or removed lines in non third party affected
3995 header files do not lead to new useless class or struct forward
3996 declaration.
3997 """
3998 results = []
3999 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
4000 input_api.re.MULTILINE)
4001 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
4002 input_api.re.MULTILINE)
4003 for f in input_api.AffectedFiles(include_deletes=False):
4004 if (f.LocalPath().startswith('third_party')
4005 and not f.LocalPath().startswith('third_party/blink')
4006 and not f.LocalPath().startswith('third_party\\blink')):
4007 continue
4008
4009 if not f.LocalPath().endswith('.h'):
4010 continue
4011
4012 contents = input_api.ReadFile(f)
4013 fwd_decls = input_api.re.findall(class_pattern, contents)
4014 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
4015
4016 useless_fwd_decls = []
4017 for decl in fwd_decls:
4018 count = sum(1 for _ in input_api.re.finditer(
4019 r'\b%s\b' % input_api.re.escape(decl), contents))
4020 if count == 1:
4021 useless_fwd_decls.append(decl)
4022
4023 if not useless_fwd_decls:
4024 continue
4025
4026 for line in f.GenerateScmDiff().splitlines():
4027 if (line.startswith('-') and not line.startswith('--')
4028 or line.startswith('+') and not line.startswith('++')):
4029 for decl in useless_fwd_decls:
4030 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
4031 results.append(
4032 output_api.PresubmitPromptWarning(
4033 '%s: %s forward declaration is no longer needed'
4034 % (f.LocalPath(), decl)))
4035 useless_fwd_decls.remove(decl)
4036
4037 return results
4038
4039
4040def _CheckAndroidDebuggableBuild(input_api, output_api):
4041 """Checks that code uses BuildInfo.isDebugAndroid() instead of
4042 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
4043 this is a debuggable build of Android.
4044 """
4045 build_type_check_pattern = input_api.re.compile(
4046 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
4047
4048 errors = []
4049
4050 sources = lambda affected_file: input_api.FilterSourceFile(
4051 affected_file,
4052 files_to_skip=(
4053 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4054 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314055 r"^android_webview/support_library/boundary_interfaces/",
4056 r"^chrome/android/webapk/.*",
4057 r'^third_party/.*',
4058 r"tools/android/customtabs_benchmark/.*",
4059 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504060 )),
4061 files_to_check=[r'.*\.java$'])
4062
4063 for f in input_api.AffectedSourceFiles(sources):
4064 for line_num, line in f.ChangedContents():
4065 if build_type_check_pattern.search(line):
4066 errors.append("%s:%d" % (f.LocalPath(), line_num))
4067
4068 results = []
4069
4070 if errors:
4071 results.append(
4072 output_api.PresubmitPromptWarning(
4073 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
4074 ' Please use BuildInfo.isDebugAndroid() instead.', errors))
4075
4076 return results
4077
4078# TODO: add unit tests
4079def _CheckAndroidToastUsage(input_api, output_api):
4080 """Checks that code uses org.chromium.ui.widget.Toast instead of
4081 android.widget.Toast (Chromium Toast doesn't force hardware
4082 acceleration on low-end devices, saving memory).
4083 """
4084 toast_import_pattern = input_api.re.compile(
4085 r'^import android\.widget\.Toast;$')
4086
4087 errors = []
4088
4089 sources = lambda affected_file: input_api.FilterSourceFile(
4090 affected_file,
4091 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
Bruce Dawson40fece62022-09-16 19:58:314092 DEFAULT_FILES_TO_SKIP + (r'^chromecast/.*',
4093 r'^remoting/.*')),
Sam Maiera6e76d72022-02-11 21:43:504094 files_to_check=[r'.*\.java$'])
4095
4096 for f in input_api.AffectedSourceFiles(sources):
4097 for line_num, line in f.ChangedContents():
4098 if toast_import_pattern.search(line):
4099 errors.append("%s:%d" % (f.LocalPath(), line_num))
4100
4101 results = []
4102
4103 if errors:
4104 results.append(
4105 output_api.PresubmitError(
4106 'android.widget.Toast usage is detected. Android toasts use hardware'
4107 ' acceleration, and can be\ncostly on low-end devices. Please use'
4108 ' org.chromium.ui.widget.Toast instead.\n'
4109 'Contact [email protected] if you have any questions.',
4110 errors))
4111
4112 return results
4113
4114
4115def _CheckAndroidCrLogUsage(input_api, output_api):
4116 """Checks that new logs using org.chromium.base.Log:
4117 - Are using 'TAG' as variable name for the tags (warn)
4118 - Are using a tag that is shorter than 20 characters (error)
4119 """
4120
4121 # Do not check format of logs in the given files
4122 cr_log_check_excluded_paths = [
4123 # //chrome/android/webapk cannot depend on //base
Bruce Dawson40fece62022-09-16 19:58:314124 r"^chrome/android/webapk/.*",
Sam Maiera6e76d72022-02-11 21:43:504125 # WebView license viewer code cannot depend on //base; used in stub APK.
Bruce Dawson40fece62022-09-16 19:58:314126 r"^android_webview/glue/java/src/com/android/"
4127 r"webview/chromium/License.*",
Sam Maiera6e76d72022-02-11 21:43:504128 # The customtabs_benchmark is a small app that does not depend on Chromium
4129 # java pieces.
Bruce Dawson40fece62022-09-16 19:58:314130 r"tools/android/customtabs_benchmark/.*",
Sam Maiera6e76d72022-02-11 21:43:504131 ]
4132
4133 cr_log_import_pattern = input_api.re.compile(
4134 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
4135 class_in_base_pattern = input_api.re.compile(
4136 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
4137 has_some_log_import_pattern = input_api.re.compile(r'^import .*\.Log;$',
4138 input_api.re.MULTILINE)
4139 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
4140 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
4141 log_decl_pattern = input_api.re.compile(
4142 r'static final String TAG = "(?P<name>(.*))"')
4143 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
4144
4145 REF_MSG = ('See docs/android_logging.md for more info.')
4146 sources = lambda x: input_api.FilterSourceFile(
4147 x,
4148 files_to_check=[r'.*\.java$'],
4149 files_to_skip=cr_log_check_excluded_paths)
4150
4151 tag_decl_errors = []
4152 tag_length_errors = []
4153 tag_errors = []
4154 tag_with_dot_errors = []
4155 util_log_errors = []
4156
4157 for f in input_api.AffectedSourceFiles(sources):
4158 file_content = input_api.ReadFile(f)
4159 has_modified_logs = False
4160 # Per line checks
4161 if (cr_log_import_pattern.search(file_content)
4162 or (class_in_base_pattern.search(file_content)
4163 and not has_some_log_import_pattern.search(file_content))):
4164 # Checks to run for files using cr log
4165 for line_num, line in f.ChangedContents():
4166 if rough_log_decl_pattern.search(line):
4167 has_modified_logs = True
4168
4169 # Check if the new line is doing some logging
4170 match = log_call_pattern.search(line)
4171 if match:
4172 has_modified_logs = True
4173
4174 # Make sure it uses "TAG"
4175 if not match.group('tag') == 'TAG':
4176 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
4177 else:
4178 # Report non cr Log function calls in changed lines
4179 for line_num, line in f.ChangedContents():
4180 if log_call_pattern.search(line):
4181 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
4182
4183 # Per file checks
4184 if has_modified_logs:
4185 # Make sure the tag is using the "cr" prefix and is not too long
4186 match = log_decl_pattern.search(file_content)
4187 tag_name = match.group('name') if match else None
4188 if not tag_name:
4189 tag_decl_errors.append(f.LocalPath())
4190 elif len(tag_name) > 20:
4191 tag_length_errors.append(f.LocalPath())
4192 elif '.' in tag_name:
4193 tag_with_dot_errors.append(f.LocalPath())
4194
4195 results = []
4196 if tag_decl_errors:
4197 results.append(
4198 output_api.PresubmitPromptWarning(
4199 'Please define your tags using the suggested format: .\n'
4200 '"private static final String TAG = "<package tag>".\n'
4201 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
4202 tag_decl_errors))
4203
4204 if tag_length_errors:
4205 results.append(
4206 output_api.PresubmitError(
4207 'The tag length is restricted by the system to be at most '
4208 '20 characters.\n' + REF_MSG, tag_length_errors))
4209
4210 if tag_errors:
4211 results.append(
4212 output_api.PresubmitPromptWarning(
4213 'Please use a variable named "TAG" for your log tags.\n' +
4214 REF_MSG, tag_errors))
4215
4216 if util_log_errors:
4217 results.append(
4218 output_api.PresubmitPromptWarning(
4219 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
4220 util_log_errors))
4221
4222 if tag_with_dot_errors:
4223 results.append(
4224 output_api.PresubmitPromptWarning(
4225 'Dot in log tags cause them to be elided in crash reports.\n' +
4226 REF_MSG, tag_with_dot_errors))
4227
4228 return results
4229
4230
4231def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
4232 """Checks that junit.framework.* is no longer used."""
4233 deprecated_junit_framework_pattern = input_api.re.compile(
4234 r'^import junit\.framework\..*;', input_api.re.MULTILINE)
4235 sources = lambda x: input_api.FilterSourceFile(
4236 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
4237 errors = []
4238 for f in input_api.AffectedFiles(file_filter=sources):
4239 for line_num, line in f.ChangedContents():
4240 if deprecated_junit_framework_pattern.search(line):
4241 errors.append("%s:%d" % (f.LocalPath(), line_num))
4242
4243 results = []
4244 if errors:
4245 results.append(
4246 output_api.PresubmitError(
4247 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
4248 '(org.junit.*) from //third_party/junit. Contact [email protected]'
4249 ' if you have any question.', errors))
4250 return results
4251
4252
4253def _CheckAndroidTestJUnitInheritance(input_api, output_api):
4254 """Checks that if new Java test classes have inheritance.
4255 Either the new test class is JUnit3 test or it is a JUnit4 test class
4256 with a base class, either case is undesirable.
4257 """
4258 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
4259
4260 sources = lambda x: input_api.FilterSourceFile(
4261 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
4262 errors = []
4263 for f in input_api.AffectedFiles(file_filter=sources):
4264 if not f.OldContents():
4265 class_declaration_start_flag = False
4266 for line_num, line in f.ChangedContents():
4267 if class_declaration_pattern.search(line):
4268 class_declaration_start_flag = True
4269 if class_declaration_start_flag and ' extends ' in line:
4270 errors.append('%s:%d' % (f.LocalPath(), line_num))
4271 if '{' in line:
4272 class_declaration_start_flag = False
4273
4274 results = []
4275 if errors:
4276 results.append(
4277 output_api.PresubmitPromptWarning(
4278 'The newly created files include Test classes that inherits from base'
4279 ' class. Please do not use inheritance in JUnit4 tests or add new'
4280 ' JUnit3 tests. Contact [email protected] if you have any'
4281 ' questions.', errors))
4282 return results
4283
4284
4285def _CheckAndroidTestAnnotationUsage(input_api, output_api):
4286 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
4287 deprecated_annotation_import_pattern = input_api.re.compile(
4288 r'^import android\.test\.suitebuilder\.annotation\..*;',
4289 input_api.re.MULTILINE)
4290 sources = lambda x: input_api.FilterSourceFile(
4291 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
4292 errors = []
4293 for f in input_api.AffectedFiles(file_filter=sources):
4294 for line_num, line in f.ChangedContents():
4295 if deprecated_annotation_import_pattern.search(line):
4296 errors.append("%s:%d" % (f.LocalPath(), line_num))
4297
4298 results = []
4299 if errors:
4300 results.append(
4301 output_api.PresubmitError(
4302 'Annotations in android.test.suitebuilder.annotation have been'
Mohamed Heikal3d7a94c2023-03-28 16:55:244303 ' deprecated since API level 24. Please use androidx.test.filters'
4304 ' from //third_party/androidx:androidx_test_runner_java instead.'
Sam Maiera6e76d72022-02-11 21:43:504305 ' Contact [email protected] if you have any questions.',
4306 errors))
4307 return results
4308
4309
4310def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
4311 """Checks if MDPI assets are placed in a correct directory."""
Bruce Dawson6c05e852022-07-21 15:48:514312 file_filter = lambda f: (f.LocalPath().endswith(
4313 '.png') and ('/res/drawable/'.replace('/', input_api.os_path.sep) in f.
4314 LocalPath() or '/res/drawable-ldrtl/'.replace(
4315 '/', input_api.os_path.sep) in f.LocalPath()))
Sam Maiera6e76d72022-02-11 21:43:504316 errors = []
4317 for f in input_api.AffectedFiles(include_deletes=False,
4318 file_filter=file_filter):
4319 errors.append(' %s' % f.LocalPath())
4320
4321 results = []
4322 if errors:
4323 results.append(
4324 output_api.PresubmitError(
4325 'MDPI assets should be placed in /res/drawable-mdpi/ or '
4326 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
4327 '/res/drawable-ldrtl/.\n'
4328 'Contact [email protected] if you have questions.', errors))
4329 return results
4330
4331
4332def _CheckAndroidWebkitImports(input_api, output_api):
4333 """Checks that code uses org.chromium.base.Callback instead of
4334 android.webview.ValueCallback except in the WebView glue layer
4335 and WebLayer.
4336 """
4337 valuecallback_import_pattern = input_api.re.compile(
4338 r'^import android\.webkit\.ValueCallback;$')
4339
4340 errors = []
4341
4342 sources = lambda affected_file: input_api.FilterSourceFile(
4343 affected_file,
4344 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
4345 DEFAULT_FILES_TO_SKIP + (
Bruce Dawson40fece62022-09-16 19:58:314346 r'^android_webview/glue/.*',
4347 r'^weblayer/.*',
Sam Maiera6e76d72022-02-11 21:43:504348 )),
4349 files_to_check=[r'.*\.java$'])
4350
4351 for f in input_api.AffectedSourceFiles(sources):
4352 for line_num, line in f.ChangedContents():
4353 if valuecallback_import_pattern.search(line):
4354 errors.append("%s:%d" % (f.LocalPath(), line_num))
4355
4356 results = []
4357
4358 if errors:
4359 results.append(
4360 output_api.PresubmitError(
4361 'android.webkit.ValueCallback usage is detected outside of the glue'
4362 ' layer. To stay compatible with the support library, android.webkit.*'
4363 ' classes should only be used inside the glue layer and'
4364 ' org.chromium.base.Callback should be used instead.', errors))
4365
4366 return results
4367
4368
4369def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
4370 """Checks Android XML styles """
4371
4372 # Return early if no relevant files were modified.
4373 if not any(
4374 _IsXmlOrGrdFile(input_api, f.LocalPath())
4375 for f in input_api.AffectedFiles(include_deletes=False)):
4376 return []
4377
4378 import sys
4379 original_sys_path = sys.path
4380 try:
4381 sys.path = sys.path + [
4382 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4383 'android', 'checkxmlstyle')
4384 ]
4385 import checkxmlstyle
4386 finally:
4387 # Restore sys.path to what it was before.
4388 sys.path = original_sys_path
4389
4390 if is_check_on_upload:
4391 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
4392 else:
4393 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
4394
4395
4396def _CheckAndroidInfoBarDeprecation(input_api, output_api):
4397 """Checks Android Infobar Deprecation """
4398
4399 import sys
4400 original_sys_path = sys.path
4401 try:
4402 sys.path = sys.path + [
4403 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
4404 'android', 'infobar_deprecation')
4405 ]
4406 import infobar_deprecation
4407 finally:
4408 # Restore sys.path to what it was before.
4409 sys.path = original_sys_path
4410
4411 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
4412
4413
4414class _PydepsCheckerResult:
4415 def __init__(self, cmd, pydeps_path, process, old_contents):
4416 self._cmd = cmd
4417 self._pydeps_path = pydeps_path
4418 self._process = process
4419 self._old_contents = old_contents
4420
4421 def GetError(self):
4422 """Returns an error message, or None."""
4423 import difflib
Andrew Grieved27620b62023-07-13 16:35:074424 new_contents = self._process.stdout.read().splitlines()[2:]
Sam Maiera6e76d72022-02-11 21:43:504425 if self._process.wait() != 0:
4426 # STDERR should already be printed.
4427 return 'Command failed: ' + self._cmd
Sam Maiera6e76d72022-02-11 21:43:504428 if self._old_contents != new_contents:
4429 diff = '\n'.join(
4430 difflib.context_diff(self._old_contents, new_contents))
4431 return ('File is stale: {}\n'
4432 'Diff (apply to fix):\n'
4433 '{}\n'
4434 'To regenerate, run:\n\n'
4435 ' {}').format(self._pydeps_path, diff, self._cmd)
4436 return None
4437
4438
4439class PydepsChecker:
4440 def __init__(self, input_api, pydeps_files):
4441 self._file_cache = {}
4442 self._input_api = input_api
4443 self._pydeps_files = pydeps_files
4444
4445 def _LoadFile(self, path):
4446 """Returns the list of paths within a .pydeps file relative to //."""
4447 if path not in self._file_cache:
4448 with open(path, encoding='utf-8') as f:
4449 self._file_cache[path] = f.read()
4450 return self._file_cache[path]
4451
4452 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
Gao Shenga79ebd42022-08-08 17:25:594453 """Returns an iterable of paths within the .pydep, relativized to //."""
Sam Maiera6e76d72022-02-11 21:43:504454 pydeps_data = self._LoadFile(pydeps_path)
4455 uses_gn_paths = '--gn-paths' in pydeps_data
4456 entries = (l for l in pydeps_data.splitlines()
4457 if not l.startswith('#'))
4458 if uses_gn_paths:
4459 # Paths look like: //foo/bar/baz
4460 return (e[2:] for e in entries)
4461 else:
4462 # Paths look like: path/relative/to/file.pydeps
4463 os_path = self._input_api.os_path
4464 pydeps_dir = os_path.dirname(pydeps_path)
4465 return (os_path.normpath(os_path.join(pydeps_dir, e))
4466 for e in entries)
4467
4468 def _CreateFilesToPydepsMap(self):
4469 """Returns a map of local_path -> list_of_pydeps."""
4470 ret = {}
4471 for pydep_local_path in self._pydeps_files:
4472 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
4473 ret.setdefault(path, []).append(pydep_local_path)
4474 return ret
4475
4476 def ComputeAffectedPydeps(self):
4477 """Returns an iterable of .pydeps files that might need regenerating."""
4478 affected_pydeps = set()
4479 file_to_pydeps_map = None
4480 for f in self._input_api.AffectedFiles(include_deletes=True):
4481 local_path = f.LocalPath()
4482 # Changes to DEPS can lead to .pydeps changes if any .py files are in
4483 # subrepositories. We can't figure out which files change, so re-check
4484 # all files.
4485 # Changes to print_python_deps.py affect all .pydeps.
4486 if local_path in ('DEPS', 'PRESUBMIT.py'
4487 ) or local_path.endswith('print_python_deps.py'):
4488 return self._pydeps_files
4489 elif local_path.endswith('.pydeps'):
4490 if local_path in self._pydeps_files:
4491 affected_pydeps.add(local_path)
4492 elif local_path.endswith('.py'):
4493 if file_to_pydeps_map is None:
4494 file_to_pydeps_map = self._CreateFilesToPydepsMap()
4495 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
4496 return affected_pydeps
4497
4498 def DetermineIfStaleAsync(self, pydeps_path):
4499 """Runs print_python_deps.py to see if the files is stale."""
4500 import os
4501
4502 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
4503 if old_pydeps_data:
4504 cmd = old_pydeps_data[1][1:].strip()
4505 if '--output' not in cmd:
4506 cmd += ' --output ' + pydeps_path
4507 old_contents = old_pydeps_data[2:]
4508 else:
4509 # A default cmd that should work in most cases (as long as pydeps filename
4510 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
4511 # file is empty/new.
4512 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
4513 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
4514 old_contents = []
4515 env = dict(os.environ)
4516 env['PYTHONDONTWRITEBYTECODE'] = '1'
4517 process = self._input_api.subprocess.Popen(
4518 cmd + ' --output ""',
4519 shell=True,
4520 env=env,
4521 stdout=self._input_api.subprocess.PIPE,
4522 encoding='utf-8')
4523 return _PydepsCheckerResult(cmd, pydeps_path, process, old_contents)
agrievef32bcc72016-04-04 14:57:404524
4525
Tibor Goldschwendt360793f72019-06-25 18:23:494526def _ParseGclientArgs():
Sam Maiera6e76d72022-02-11 21:43:504527 args = {}
4528 with open('build/config/gclient_args.gni', 'r') as f:
4529 for line in f:
4530 line = line.strip()
4531 if not line or line.startswith('#'):
4532 continue
4533 attribute, value = line.split('=')
4534 args[attribute.strip()] = value.strip()
4535 return args
Tibor Goldschwendt360793f72019-06-25 18:23:494536
4537
Saagar Sanghavifceeaae2020-08-12 16:40:364538def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
Sam Maiera6e76d72022-02-11 21:43:504539 """Checks if a .pydeps file needs to be regenerated."""
4540 # This check is for Python dependency lists (.pydeps files), and involves
4541 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
4542 # doesn't work on Windows and Mac, so skip it on other platforms.
4543 if not input_api.platform.startswith('linux'):
4544 return []
Erik Staabc734cd7a2021-11-23 03:11:524545
Sam Maiera6e76d72022-02-11 21:43:504546 results = []
4547 # First, check for new / deleted .pydeps.
4548 for f in input_api.AffectedFiles(include_deletes=True):
4549 # Check whether we are running the presubmit check for a file in src.
4550 # f.LocalPath is relative to repo (src, or internal repo).
4551 # os_path.exists is relative to src repo.
4552 # Therefore if os_path.exists is true, it means f.LocalPath is relative
4553 # to src and we can conclude that the pydeps is in src.
4554 if f.LocalPath().endswith('.pydeps'):
4555 if input_api.os_path.exists(f.LocalPath()):
4556 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
4557 results.append(
4558 output_api.PresubmitError(
4559 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
4560 'remove %s' % f.LocalPath()))
4561 elif f.Action() != 'D' and f.LocalPath(
4562 ) not in _ALL_PYDEPS_FILES:
4563 results.append(
4564 output_api.PresubmitError(
4565 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
4566 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:404567
Sam Maiera6e76d72022-02-11 21:43:504568 if results:
4569 return results
4570
4571 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
4572 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
4573 affected_pydeps = set(checker.ComputeAffectedPydeps())
4574 affected_android_pydeps = affected_pydeps.intersection(
4575 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
4576 if affected_android_pydeps and not is_android:
4577 results.append(
4578 output_api.PresubmitPromptOrNotify(
4579 'You have changed python files that may affect pydeps for android\n'
Gao Shenga79ebd42022-08-08 17:25:594580 'specific scripts. However, the relevant presubmit check cannot be\n'
Sam Maiera6e76d72022-02-11 21:43:504581 'run because you are not using an Android checkout. To validate that\n'
4582 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
4583 'use the android-internal-presubmit optional trybot.\n'
4584 'Possibly stale pydeps files:\n{}'.format(
4585 '\n'.join(affected_android_pydeps))))
4586
4587 all_pydeps = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
4588 pydeps_to_check = affected_pydeps.intersection(all_pydeps)
4589 # Process these concurrently, as each one takes 1-2 seconds.
4590 pydep_results = [checker.DetermineIfStaleAsync(p) for p in pydeps_to_check]
4591 for result in pydep_results:
4592 error_msg = result.GetError()
4593 if error_msg:
4594 results.append(output_api.PresubmitError(error_msg))
4595
agrievef32bcc72016-04-04 14:57:404596 return results
4597
agrievef32bcc72016-04-04 14:57:404598
Saagar Sanghavifceeaae2020-08-12 16:40:364599def CheckSingletonInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504600 """Checks to make sure no header files have |Singleton<|."""
4601
4602 def FileFilter(affected_file):
4603 # It's ok for base/memory/singleton.h to have |Singleton<|.
4604 files_to_skip = (_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
Bruce Dawson40fece62022-09-16 19:58:314605 (r"^base/memory/singleton\.h$",
4606 r"^net/quic/platform/impl/quic_singleton_impl\.h$"))
Sam Maiera6e76d72022-02-11 21:43:504607 return input_api.FilterSourceFile(affected_file,
4608 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:434609
Sam Maiera6e76d72022-02-11 21:43:504610 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
4611 files = []
4612 for f in input_api.AffectedSourceFiles(FileFilter):
4613 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx')
4614 or f.LocalPath().endswith('.hpp')
4615 or f.LocalPath().endswith('.inl')):
4616 contents = input_api.ReadFile(f)
4617 for line in contents.splitlines(False):
4618 if (not line.lstrip().startswith('//')
4619 and # Strip C++ comment.
4620 pattern.search(line)):
4621 files.append(f)
4622 break
glidere61efad2015-02-18 17:39:434623
Sam Maiera6e76d72022-02-11 21:43:504624 if files:
4625 return [
4626 output_api.PresubmitError(
4627 'Found base::Singleton<T> in the following header files.\n' +
4628 'Please move them to an appropriate source file so that the ' +
4629 'template gets instantiated in a single compilation unit.',
4630 files)
4631 ]
4632 return []
glidere61efad2015-02-18 17:39:434633
4634
[email protected]fd20b902014-05-09 02:14:534635_DEPRECATED_CSS = [
4636 # Values
4637 ( "-webkit-box", "flex" ),
4638 ( "-webkit-inline-box", "inline-flex" ),
4639 ( "-webkit-flex", "flex" ),
4640 ( "-webkit-inline-flex", "inline-flex" ),
4641 ( "-webkit-min-content", "min-content" ),
4642 ( "-webkit-max-content", "max-content" ),
4643
4644 # Properties
4645 ( "-webkit-background-clip", "background-clip" ),
4646 ( "-webkit-background-origin", "background-origin" ),
4647 ( "-webkit-background-size", "background-size" ),
4648 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:444649 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:534650
4651 # Functions
4652 ( "-webkit-gradient", "gradient" ),
4653 ( "-webkit-repeating-gradient", "repeating-gradient" ),
4654 ( "-webkit-linear-gradient", "linear-gradient" ),
4655 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
4656 ( "-webkit-radial-gradient", "radial-gradient" ),
4657 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
4658]
4659
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:204660
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:494661# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:364662def CheckNoDeprecatedCss(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504663 """ Make sure that we don't use deprecated CSS
4664 properties, functions or values. Our external
4665 documentation and iOS CSS for dom distiller
4666 (reader mode) are ignored by the hooks as it
4667 needs to be consumed by WebKit. """
4668 results = []
4669 file_inclusion_pattern = [r".+\.css$"]
4670 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
4671 input_api.DEFAULT_FILES_TO_SKIP +
4672 (r"^chrome/common/extensions/docs", r"^chrome/docs",
4673 r"^native_client_sdk"))
4674 file_filter = lambda f: input_api.FilterSourceFile(
4675 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
4676 for fpath in input_api.AffectedFiles(file_filter=file_filter):
4677 for line_num, line in fpath.ChangedContents():
4678 for (deprecated_value, value) in _DEPRECATED_CSS:
4679 if deprecated_value in line:
4680 results.append(
4681 output_api.PresubmitError(
4682 "%s:%d: Use of deprecated CSS %s, use %s instead" %
4683 (fpath.LocalPath(), line_num, deprecated_value,
4684 value)))
4685 return results
[email protected]fd20b902014-05-09 02:14:534686
mohan.reddyf21db962014-10-16 12:26:474687
Saagar Sanghavifceeaae2020-08-12 16:40:364688def CheckForRelativeIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504689 bad_files = {}
4690 for f in input_api.AffectedFiles(include_deletes=False):
4691 if (f.LocalPath().startswith('third_party')
4692 and not f.LocalPath().startswith('third_party/blink')
4693 and not f.LocalPath().startswith('third_party\\blink')):
4694 continue
rlanday6802cf632017-05-30 17:48:364695
Sam Maiera6e76d72022-02-11 21:43:504696 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
4697 continue
rlanday6802cf632017-05-30 17:48:364698
Sam Maiera6e76d72022-02-11 21:43:504699 relative_includes = [
4700 line for _, line in f.ChangedContents()
4701 if "#include" in line and "../" in line
4702 ]
4703 if not relative_includes:
4704 continue
4705 bad_files[f.LocalPath()] = relative_includes
rlanday6802cf632017-05-30 17:48:364706
Sam Maiera6e76d72022-02-11 21:43:504707 if not bad_files:
4708 return []
rlanday6802cf632017-05-30 17:48:364709
Sam Maiera6e76d72022-02-11 21:43:504710 error_descriptions = []
4711 for file_path, bad_lines in bad_files.items():
4712 error_description = file_path
4713 for line in bad_lines:
4714 error_description += '\n ' + line
4715 error_descriptions.append(error_description)
rlanday6802cf632017-05-30 17:48:364716
Sam Maiera6e76d72022-02-11 21:43:504717 results = []
4718 results.append(
4719 output_api.PresubmitError(
4720 'You added one or more relative #include paths (including "../").\n'
4721 'These shouldn\'t be used because they can be used to include headers\n'
4722 'from code that\'s not correctly specified as a dependency in the\n'
4723 'relevant BUILD.gn file(s).', error_descriptions))
rlanday6802cf632017-05-30 17:48:364724
Sam Maiera6e76d72022-02-11 21:43:504725 return results
rlanday6802cf632017-05-30 17:48:364726
Takeshi Yoshinoe387aa32017-08-02 13:16:134727
Saagar Sanghavifceeaae2020-08-12 16:40:364728def CheckForCcIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504729 """Check that nobody tries to include a cc file. It's a relatively
4730 common error which results in duplicate symbols in object
4731 files. This may not always break the build until someone later gets
4732 very confusing linking errors."""
4733 results = []
4734 for f in input_api.AffectedFiles(include_deletes=False):
4735 # We let third_party code do whatever it wants
4736 if (f.LocalPath().startswith('third_party')
4737 and not f.LocalPath().startswith('third_party/blink')
4738 and not f.LocalPath().startswith('third_party\\blink')):
4739 continue
Daniel Bratell65b033262019-04-23 08:17:064740
Sam Maiera6e76d72022-02-11 21:43:504741 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
4742 continue
Daniel Bratell65b033262019-04-23 08:17:064743
Sam Maiera6e76d72022-02-11 21:43:504744 for _, line in f.ChangedContents():
4745 if line.startswith('#include "'):
4746 included_file = line.split('"')[1]
4747 if _IsCPlusPlusFile(input_api, included_file):
4748 # The most common naming for external files with C++ code,
4749 # apart from standard headers, is to call them foo.inc, but
4750 # Chromium sometimes uses foo-inc.cc so allow that as well.
4751 if not included_file.endswith(('.h', '-inc.cc')):
4752 results.append(
4753 output_api.PresubmitError(
4754 'Only header files or .inc files should be included in other\n'
4755 'C++ files. Compiling the contents of a cc file more than once\n'
4756 'will cause duplicate information in the build which may later\n'
4757 'result in strange link_errors.\n' +
4758 f.LocalPath() + ':\n ' + line))
Daniel Bratell65b033262019-04-23 08:17:064759
Sam Maiera6e76d72022-02-11 21:43:504760 return results
Daniel Bratell65b033262019-04-23 08:17:064761
4762
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204763def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
Sam Maiera6e76d72022-02-11 21:43:504764 if not isinstance(key, ast.Str):
4765 return 'Key at line %d must be a string literal' % key.lineno
4766 if not isinstance(value, ast.Dict):
4767 return 'Value at line %d must be a dict' % value.lineno
4768 if len(value.keys) != 1:
4769 return 'Dict at line %d must have single entry' % value.lineno
4770 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
4771 return (
4772 'Entry at line %d must have a string literal \'filepath\' as key' %
4773 value.lineno)
4774 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:134775
Takeshi Yoshinoe387aa32017-08-02 13:16:134776
Sergey Ulanov4af16052018-11-08 02:41:464777def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Sam Maiera6e76d72022-02-11 21:43:504778 if not isinstance(key, ast.Str):
4779 return 'Key at line %d must be a string literal' % key.lineno
4780 if not isinstance(value, ast.List):
4781 return 'Value at line %d must be a list' % value.lineno
4782 for element in value.elts:
4783 if not isinstance(element, ast.Str):
4784 return 'Watchlist elements on line %d is not a string' % key.lineno
4785 if not email_regex.match(element.s):
4786 return ('Watchlist element on line %d doesn\'t look like a valid '
4787 + 'email: %s') % (key.lineno, element.s)
4788 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:134789
Takeshi Yoshinoe387aa32017-08-02 13:16:134790
Sergey Ulanov4af16052018-11-08 02:41:464791def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Sam Maiera6e76d72022-02-11 21:43:504792 mismatch_template = (
4793 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
4794 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:134795
Sam Maiera6e76d72022-02-11 21:43:504796 email_regex = input_api.re.compile(
4797 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
Sergey Ulanov4af16052018-11-08 02:41:464798
Sam Maiera6e76d72022-02-11 21:43:504799 ast = input_api.ast
4800 i = 0
4801 last_key = ''
4802 while True:
4803 if i >= len(wd_dict.keys):
4804 if i >= len(w_dict.keys):
4805 return None
4806 return mismatch_template % ('missing',
4807 'line %d' % w_dict.keys[i].lineno)
4808 elif i >= len(w_dict.keys):
4809 return (mismatch_template %
4810 ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:134811
Sam Maiera6e76d72022-02-11 21:43:504812 wd_key = wd_dict.keys[i]
4813 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:134814
Sam Maiera6e76d72022-02-11 21:43:504815 result = _CheckWatchlistDefinitionsEntrySyntax(wd_key,
4816 wd_dict.values[i], ast)
4817 if result is not None:
4818 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:134819
Sam Maiera6e76d72022-02-11 21:43:504820 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast,
4821 email_regex)
4822 if result is not None:
4823 return 'Bad entry in WATCHLISTS dict: %s' % result
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204824
Sam Maiera6e76d72022-02-11 21:43:504825 if wd_key.s != w_key.s:
4826 return mismatch_template % ('%s at line %d' %
4827 (wd_key.s, wd_key.lineno),
4828 '%s at line %d' %
4829 (w_key.s, w_key.lineno))
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204830
Sam Maiera6e76d72022-02-11 21:43:504831 if wd_key.s < last_key:
4832 return (
4833 'WATCHLISTS dict is not sorted lexicographically at line %d and %d'
4834 % (wd_key.lineno, w_key.lineno))
4835 last_key = wd_key.s
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204836
Sam Maiera6e76d72022-02-11 21:43:504837 i = i + 1
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204838
4839
Sergey Ulanov4af16052018-11-08 02:41:464840def _CheckWATCHLISTSSyntax(expression, input_api):
Sam Maiera6e76d72022-02-11 21:43:504841 ast = input_api.ast
4842 if not isinstance(expression, ast.Expression):
4843 return 'WATCHLISTS file must contain a valid expression'
4844 dictionary = expression.body
4845 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
4846 return 'WATCHLISTS file must have single dict with exactly two entries'
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204847
Sam Maiera6e76d72022-02-11 21:43:504848 first_key = dictionary.keys[0]
4849 first_value = dictionary.values[0]
4850 second_key = dictionary.keys[1]
4851 second_value = dictionary.values[1]
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204852
Sam Maiera6e76d72022-02-11 21:43:504853 if (not isinstance(first_key, ast.Str)
4854 or first_key.s != 'WATCHLIST_DEFINITIONS'
4855 or not isinstance(first_value, ast.Dict)):
4856 return ('The first entry of the dict in WATCHLISTS file must be '
4857 'WATCHLIST_DEFINITIONS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204858
Sam Maiera6e76d72022-02-11 21:43:504859 if (not isinstance(second_key, ast.Str) or second_key.s != 'WATCHLISTS'
4860 or not isinstance(second_value, ast.Dict)):
4861 return ('The second entry of the dict in WATCHLISTS file must be '
4862 'WATCHLISTS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204863
Sam Maiera6e76d72022-02-11 21:43:504864 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:134865
4866
Saagar Sanghavifceeaae2020-08-12 16:40:364867def CheckWATCHLISTS(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504868 for f in input_api.AffectedFiles(include_deletes=False):
4869 if f.LocalPath() == 'WATCHLISTS':
4870 contents = input_api.ReadFile(f, 'r')
Takeshi Yoshinoe387aa32017-08-02 13:16:134871
Sam Maiera6e76d72022-02-11 21:43:504872 try:
4873 # First, make sure that it can be evaluated.
4874 input_api.ast.literal_eval(contents)
4875 # Get an AST tree for it and scan the tree for detailed style checking.
4876 expression = input_api.ast.parse(contents,
4877 filename='WATCHLISTS',
4878 mode='eval')
4879 except ValueError as e:
4880 return [
4881 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4882 long_text=repr(e))
4883 ]
4884 except SyntaxError as e:
4885 return [
4886 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4887 long_text=repr(e))
4888 ]
4889 except TypeError as e:
4890 return [
4891 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4892 long_text=repr(e))
4893 ]
Takeshi Yoshinoe387aa32017-08-02 13:16:134894
Sam Maiera6e76d72022-02-11 21:43:504895 result = _CheckWATCHLISTSSyntax(expression, input_api)
4896 if result is not None:
4897 return [output_api.PresubmitError(result)]
4898 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134899
Sam Maiera6e76d72022-02-11 21:43:504900 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:134901
Sean Kaucb7c9b32022-10-25 21:25:524902def CheckGnRebasePath(input_api, output_api):
4903 """Checks that target_gen_dir is not used wtih "//" in rebase_path().
4904
4905 Developers should use root_build_dir instead of "//" when using target_gen_dir because
4906 Chromium is sometimes built outside of the source tree.
4907 """
4908
4909 def gn_files(f):
4910 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
4911
4912 rebase_path_regex = input_api.re.compile(r'rebase_path\(("\$target_gen_dir"|target_gen_dir), ("/"|"//")\)')
4913 problems = []
4914 for f in input_api.AffectedSourceFiles(gn_files):
4915 for line_num, line in f.ChangedContents():
4916 if rebase_path_regex.search(line):
4917 problems.append(
4918 'Absolute path in rebase_path() in %s:%d' %
4919 (f.LocalPath(), line_num))
4920
4921 if problems:
4922 return [
4923 output_api.PresubmitPromptWarning(
4924 'Using an absolute path in rebase_path()',
4925 items=sorted(problems),
4926 long_text=(
4927 'rebase_path() should use root_build_dir instead of "/" ',
4928 'since builds can be initiated from outside of the source ',
4929 'root.'))
4930 ]
4931 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:134932
Andrew Grieve1b290e4a22020-11-24 20:07:014933def CheckGnGlobForward(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504934 """Checks that forward_variables_from(invoker, "*") follows best practices.
Andrew Grieve1b290e4a22020-11-24 20:07:014935
Sam Maiera6e76d72022-02-11 21:43:504936 As documented at //build/docs/writing_gn_templates.md
4937 """
Andrew Grieve1b290e4a22020-11-24 20:07:014938
Sam Maiera6e76d72022-02-11 21:43:504939 def gn_files(f):
4940 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
Andrew Grieve1b290e4a22020-11-24 20:07:014941
Sam Maiera6e76d72022-02-11 21:43:504942 problems = []
4943 for f in input_api.AffectedSourceFiles(gn_files):
4944 for line_num, line in f.ChangedContents():
4945 if 'forward_variables_from(invoker, "*")' in line:
4946 problems.append(
4947 'Bare forward_variables_from(invoker, "*") in %s:%d' %
4948 (f.LocalPath(), line_num))
4949
4950 if problems:
4951 return [
4952 output_api.PresubmitPromptWarning(
4953 'forward_variables_from("*") without exclusions',
4954 items=sorted(problems),
4955 long_text=(
Gao Shenga79ebd42022-08-08 17:25:594956 'The variables "visibility" and "test_only" should be '
Sam Maiera6e76d72022-02-11 21:43:504957 'explicitly listed in forward_variables_from(). For more '
4958 'details, see:\n'
4959 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
4960 'build/docs/writing_gn_templates.md'
4961 '#Using-forward_variables_from'))
4962 ]
4963 return []
Andrew Grieve1b290e4a22020-11-24 20:07:014964
Saagar Sanghavifceeaae2020-08-12 16:40:364965def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504966 """Checks that newly added header files have corresponding GN changes.
4967 Note that this is only a heuristic. To be precise, run script:
4968 build/check_gn_headers.py.
4969 """
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194970
Sam Maiera6e76d72022-02-11 21:43:504971 def headers(f):
4972 return input_api.FilterSourceFile(
4973 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194974
Sam Maiera6e76d72022-02-11 21:43:504975 new_headers = []
4976 for f in input_api.AffectedSourceFiles(headers):
4977 if f.Action() != 'A':
4978 continue
4979 new_headers.append(f.LocalPath())
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194980
Sam Maiera6e76d72022-02-11 21:43:504981 def gn_files(f):
4982 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194983
Sam Maiera6e76d72022-02-11 21:43:504984 all_gn_changed_contents = ''
4985 for f in input_api.AffectedSourceFiles(gn_files):
4986 for _, line in f.ChangedContents():
4987 all_gn_changed_contents += line
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194988
Sam Maiera6e76d72022-02-11 21:43:504989 problems = []
4990 for header in new_headers:
4991 basename = input_api.os_path.basename(header)
4992 if basename not in all_gn_changed_contents:
4993 problems.append(header)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194994
Sam Maiera6e76d72022-02-11 21:43:504995 if problems:
4996 return [
4997 output_api.PresubmitPromptWarning(
4998 'Missing GN changes for new header files',
4999 items=sorted(problems),
5000 long_text=
5001 'Please double check whether newly added header files need '
5002 'corresponding changes in gn or gni files.\nThis checking is only a '
5003 'heuristic. Run build/check_gn_headers.py to be precise.\n'
5004 'Read https://crbug.com/661774 for more info.')
5005 ]
5006 return []
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:195007
5008
Saagar Sanghavifceeaae2020-08-12 16:40:365009def CheckCorrectProductNameInMessages(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505010 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
Michael Giuffridad3bc8672018-10-25 22:48:025011
Sam Maiera6e76d72022-02-11 21:43:505012 This assumes we won't intentionally reference one product from the other
5013 product.
5014 """
5015 all_problems = []
5016 test_cases = [{
5017 "filename_postfix": "google_chrome_strings.grd",
5018 "correct_name": "Chrome",
5019 "incorrect_name": "Chromium",
5020 }, {
Thiago Perrotta099034f2023-06-05 18:10:205021 "filename_postfix": "google_chrome_strings.grd",
5022 "correct_name": "Chrome",
5023 "incorrect_name": "Chrome for Testing",
5024 }, {
Sam Maiera6e76d72022-02-11 21:43:505025 "filename_postfix": "chromium_strings.grd",
5026 "correct_name": "Chromium",
5027 "incorrect_name": "Chrome",
5028 }]
Michael Giuffridad3bc8672018-10-25 22:48:025029
Sam Maiera6e76d72022-02-11 21:43:505030 for test_case in test_cases:
5031 problems = []
5032 filename_filter = lambda x: x.LocalPath().endswith(test_case[
5033 "filename_postfix"])
Michael Giuffridad3bc8672018-10-25 22:48:025034
Sam Maiera6e76d72022-02-11 21:43:505035 # Check each new line. Can yield false positives in multiline comments, but
5036 # easier than trying to parse the XML because messages can have nested
5037 # children, and associating message elements with affected lines is hard.
5038 for f in input_api.AffectedSourceFiles(filename_filter):
5039 for line_num, line in f.ChangedContents():
5040 if "<message" in line or "<!--" in line or "-->" in line:
5041 continue
5042 if test_case["incorrect_name"] in line:
Thiago Perrotta099034f2023-06-05 18:10:205043 # Chrome for Testing is a special edge case: https://goo.gle/chrome-for-testing#bookmark=id.n1rat320av91
5044 if (test_case["correct_name"] == "Chromium" and line.count("Chrome") == line.count("Chrome for Testing")):
5045 continue
Sam Maiera6e76d72022-02-11 21:43:505046 problems.append("Incorrect product name in %s:%d" %
5047 (f.LocalPath(), line_num))
Michael Giuffridad3bc8672018-10-25 22:48:025048
Sam Maiera6e76d72022-02-11 21:43:505049 if problems:
5050 message = (
5051 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
5052 % (test_case["correct_name"], test_case["correct_name"],
5053 test_case["incorrect_name"]))
5054 all_problems.append(
5055 output_api.PresubmitPromptWarning(message, items=problems))
Michael Giuffridad3bc8672018-10-25 22:48:025056
Sam Maiera6e76d72022-02-11 21:43:505057 return all_problems
Michael Giuffridad3bc8672018-10-25 22:48:025058
5059
Saagar Sanghavifceeaae2020-08-12 16:40:365060def CheckForTooLargeFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505061 """Avoid large files, especially binary files, in the repository since
5062 git doesn't scale well for those. They will be in everyone's repo
5063 clones forever, forever making Chromium slower to clone and work
5064 with."""
Daniel Bratell93eb6c62019-04-29 20:13:365065
Sam Maiera6e76d72022-02-11 21:43:505066 # Uploading files to cloud storage is not trivial so we don't want
5067 # to set the limit too low, but the upper limit for "normal" large
5068 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
5069 # anything over 20 MB is exceptional.
Bruce Dawsonbb414db2022-12-27 20:21:255070 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024
Daniel Bratell93eb6c62019-04-29 20:13:365071
Sam Maiera6e76d72022-02-11 21:43:505072 too_large_files = []
5073 for f in input_api.AffectedFiles():
5074 # Check both added and modified files (but not deleted files).
5075 if f.Action() in ('A', 'M'):
5076 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Joe DeBlasio10a832f2023-04-21 20:20:185077 if size > TOO_LARGE_FILE_SIZE_LIMIT:
Sam Maiera6e76d72022-02-11 21:43:505078 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
Daniel Bratell93eb6c62019-04-29 20:13:365079
Sam Maiera6e76d72022-02-11 21:43:505080 if too_large_files:
5081 message = (
5082 'Do not commit large files to git since git scales badly for those.\n'
5083 +
5084 'Instead put the large files in cloud storage and use DEPS to\n' +
5085 'fetch them.\n' + '\n'.join(too_large_files))
5086 return [
5087 output_api.PresubmitError('Too large files found in commit',
5088 long_text=message + '\n')
5089 ]
5090 else:
5091 return []
Daniel Bratell93eb6c62019-04-29 20:13:365092
Max Morozb47503b2019-08-08 21:03:275093
Saagar Sanghavifceeaae2020-08-12 16:40:365094def CheckFuzzTargetsOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505095 """Checks specific for fuzz target sources."""
5096 EXPORTED_SYMBOLS = [
5097 'LLVMFuzzerInitialize',
5098 'LLVMFuzzerCustomMutator',
5099 'LLVMFuzzerCustomCrossOver',
5100 'LLVMFuzzerMutate',
5101 ]
Max Morozb47503b2019-08-08 21:03:275102
Sam Maiera6e76d72022-02-11 21:43:505103 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
Max Morozb47503b2019-08-08 21:03:275104
Sam Maiera6e76d72022-02-11 21:43:505105 def FilterFile(affected_file):
5106 """Ignore libFuzzer source code."""
5107 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
Bruce Dawson40fece62022-09-16 19:58:315108 files_to_skip = r"^third_party/libFuzzer"
Max Morozb47503b2019-08-08 21:03:275109
Sam Maiera6e76d72022-02-11 21:43:505110 return input_api.FilterSourceFile(affected_file,
5111 files_to_check=[files_to_check],
5112 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:275113
Sam Maiera6e76d72022-02-11 21:43:505114 files_with_missing_header = []
5115 for f in input_api.AffectedSourceFiles(FilterFile):
5116 contents = input_api.ReadFile(f, 'r')
5117 if REQUIRED_HEADER in contents:
5118 continue
Max Morozb47503b2019-08-08 21:03:275119
Sam Maiera6e76d72022-02-11 21:43:505120 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
5121 files_with_missing_header.append(f.LocalPath())
Max Morozb47503b2019-08-08 21:03:275122
Sam Maiera6e76d72022-02-11 21:43:505123 if not files_with_missing_header:
5124 return []
Max Morozb47503b2019-08-08 21:03:275125
Sam Maiera6e76d72022-02-11 21:43:505126 long_text = (
5127 'If you define any of the libFuzzer optional functions (%s), it is '
5128 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
5129 'work incorrectly on Mac (crbug.com/687076).\nNote that '
5130 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
5131 'to access command line arguments passed to the fuzzer. Instead, prefer '
5132 'static initialization and shared resources as documented in '
5133 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
5134 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n'
5135 % (', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER))
Max Morozb47503b2019-08-08 21:03:275136
Sam Maiera6e76d72022-02-11 21:43:505137 return [
5138 output_api.PresubmitPromptWarning(message="Missing '%s' in:" %
5139 REQUIRED_HEADER,
5140 items=files_with_missing_header,
5141 long_text=long_text)
5142 ]
Max Morozb47503b2019-08-08 21:03:275143
5144
Mohamed Heikald048240a2019-11-12 16:57:375145def _CheckNewImagesWarning(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505146 """
5147 Warns authors who add images into the repo to make sure their images are
5148 optimized before committing.
5149 """
5150 images_added = False
5151 image_paths = []
5152 errors = []
5153 filter_lambda = lambda x: input_api.FilterSourceFile(
5154 x,
5155 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
5156 DEFAULT_FILES_TO_SKIP),
5157 files_to_check=[r'.*\/(drawable|mipmap)'])
5158 for f in input_api.AffectedFiles(include_deletes=False,
5159 file_filter=filter_lambda):
5160 local_path = f.LocalPath().lower()
5161 if any(
5162 local_path.endswith(extension)
5163 for extension in _IMAGE_EXTENSIONS):
5164 images_added = True
5165 image_paths.append(f)
5166 if images_added:
5167 errors.append(
5168 output_api.PresubmitPromptWarning(
5169 'It looks like you are trying to commit some images. If these are '
5170 'non-test-only images, please make sure to read and apply the tips in '
5171 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
5172 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
5173 'FYI only and will not block your CL on the CQ.', image_paths))
5174 return errors
Mohamed Heikald048240a2019-11-12 16:57:375175
5176
Saagar Sanghavifceeaae2020-08-12 16:40:365177def ChecksAndroidSpecificOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505178 """Groups upload checks that target android code."""
5179 results = []
5180 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
5181 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
5182 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
5183 results.extend(_CheckAndroidToastUsage(input_api, output_api))
5184 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
5185 results.extend(_CheckAndroidTestJUnitFrameworkImport(
5186 input_api, output_api))
5187 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
5188 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
5189 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
5190 results.extend(_CheckNewImagesWarning(input_api, output_api))
5191 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
5192 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
5193 return results
5194
Becky Zhou7c69b50992018-12-10 19:37:575195
Saagar Sanghavifceeaae2020-08-12 16:40:365196def ChecksAndroidSpecificOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505197 """Groups commit checks that target android code."""
5198 results = []
5199 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
5200 return results
dgnaa68d5e2015-06-10 10:08:225201
Chris Hall59f8d0c72020-05-01 07:31:195202# TODO(chrishall): could we additionally match on any path owned by
5203# ui/accessibility/OWNERS ?
5204_ACCESSIBILITY_PATHS = (
Bruce Dawson40fece62022-09-16 19:58:315205 r"^chrome/browser.*/accessibility/",
5206 r"^chrome/browser/extensions/api/automation.*/",
5207 r"^chrome/renderer/extensions/accessibility_.*",
5208 r"^chrome/tests/data/accessibility/",
Katie Dektar58ef07b2022-09-27 13:19:175209 r"^components/services/screen_ai/",
Bruce Dawson40fece62022-09-16 19:58:315210 r"^content/browser/accessibility/",
5211 r"^content/renderer/accessibility/",
5212 r"^content/tests/data/accessibility/",
5213 r"^extensions/renderer/api/automation/",
Katie Dektar58ef07b2022-09-27 13:19:175214 r"^services/accessibility/",
Bruce Dawson40fece62022-09-16 19:58:315215 r"^ui/accessibility/",
5216 r"^ui/views/accessibility/",
Chris Hall59f8d0c72020-05-01 07:31:195217)
5218
Saagar Sanghavifceeaae2020-08-12 16:40:365219def CheckAccessibilityRelnotesField(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505220 """Checks that commits to accessibility code contain an AX-Relnotes field in
5221 their commit message."""
Chris Hall59f8d0c72020-05-01 07:31:195222
Sam Maiera6e76d72022-02-11 21:43:505223 def FileFilter(affected_file):
5224 paths = _ACCESSIBILITY_PATHS
5225 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:195226
Sam Maiera6e76d72022-02-11 21:43:505227 # Only consider changes affecting accessibility paths.
5228 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
5229 return []
Akihiro Ota08108e542020-05-20 15:30:535230
Sam Maiera6e76d72022-02-11 21:43:505231 # AX-Relnotes can appear in either the description or the footer.
5232 # When searching the description, require 'AX-Relnotes:' to appear at the
5233 # beginning of a line.
5234 ax_regex = input_api.re.compile('ax-relnotes[:=]')
5235 description_has_relnotes = any(
5236 ax_regex.match(line)
5237 for line in input_api.change.DescriptionText().lower().splitlines())
Chris Hall59f8d0c72020-05-01 07:31:195238
Sam Maiera6e76d72022-02-11 21:43:505239 footer_relnotes = input_api.change.GitFootersFromDescription().get(
5240 'AX-Relnotes', [])
5241 if description_has_relnotes or footer_relnotes:
5242 return []
Chris Hall59f8d0c72020-05-01 07:31:195243
Sam Maiera6e76d72022-02-11 21:43:505244 # TODO(chrishall): link to Relnotes documentation in message.
5245 message = (
5246 "Missing 'AX-Relnotes:' field required for accessibility changes"
5247 "\n please add 'AX-Relnotes: [release notes].' to describe any "
5248 "user-facing changes"
5249 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
5250 "user-facing effects"
5251 "\n if this is confusing or annoying then please contact members "
5252 "of ui/accessibility/OWNERS.")
5253
5254 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:225255
Mark Schillacie5a0be22022-01-19 00:38:395256
5257_ACCESSIBILITY_EVENTS_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315258 r"^content/test/data/accessibility/event/.*\.html",
Mark Schillacie5a0be22022-01-19 00:38:395259)
5260
5261_ACCESSIBILITY_TREE_TEST_PATH = (
Aaron Leventhal267119f2023-08-18 22:45:345262 r"^content/test/data/accessibility/accname/"
5263 ".*-expected-(mac|win|uia-win|auralinux).txt",
5264 r"^content/test/data/accessibility/aria/"
5265 ".*-expected-(mac|win|uia-win|auralinux).txt",
5266 r"^content/test/data/accessibility/css/"
5267 ".*-expected-(mac|win|uia-win|auralinux).txt",
5268 r"^content/test/data/accessibility/event/"
5269 ".*-expected-(mac|win|uia-win|auralinux).txt",
5270 r"^content/test/data/accessibility/html/"
5271 ".*-expected-(mac|win|uia-win|auralinux).txt",
Mark Schillacie5a0be22022-01-19 00:38:395272)
5273
5274_ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315275 r"^.*/WebContentsAccessibilityEventsTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:395276)
5277
5278_ACCESSIBILITY_ANDROID_TREE_TEST_PATH = (
Bruce Dawson40fece62022-09-16 19:58:315279 r"^.*/WebContentsAccessibilityTreeTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:395280)
5281
5282def CheckAccessibilityEventsTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505283 """Checks that commits that include a newly added, renamed/moved, or deleted
5284 test in the DumpAccessibilityEventsTest suite also includes a corresponding
5285 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:395286
Sam Maiera6e76d72022-02-11 21:43:505287 def FilePathFilter(affected_file):
5288 paths = _ACCESSIBILITY_EVENTS_TEST_PATH
5289 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395290
Sam Maiera6e76d72022-02-11 21:43:505291 def AndroidFilePathFilter(affected_file):
5292 paths = _ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH
5293 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395294
Sam Maiera6e76d72022-02-11 21:43:505295 # Only consider changes in the events test data path with html type.
5296 if not any(
5297 input_api.AffectedFiles(include_deletes=True,
5298 file_filter=FilePathFilter)):
5299 return []
Mark Schillacie5a0be22022-01-19 00:38:395300
Sam Maiera6e76d72022-02-11 21:43:505301 # If the commit contains any change to the Android test file, ignore.
5302 if any(
5303 input_api.AffectedFiles(include_deletes=True,
5304 file_filter=AndroidFilePathFilter)):
5305 return []
Mark Schillacie5a0be22022-01-19 00:38:395306
Sam Maiera6e76d72022-02-11 21:43:505307 # Only consider changes that are adding/renaming or deleting a file
5308 message = []
5309 for f in input_api.AffectedFiles(include_deletes=True,
5310 file_filter=FilePathFilter):
Aaron Leventhal267119f2023-08-18 22:45:345311 if f.Action() == 'A':
Sam Maiera6e76d72022-02-11 21:43:505312 message = (
Aaron Leventhal267119f2023-08-18 22:45:345313 "It appears that you are adding platform expectations for a"
5314 "\ndump_accessibility_* test, but have not included"
Sam Maiera6e76d72022-02-11 21:43:505315 "\na corresponding change for Android."
Aaron Leventhal267119f2023-08-18 22:45:345316 "\nPlease include the test from:"
Sam Maiera6e76d72022-02-11 21:43:505317 "\n content/public/android/javatests/src/org/chromium/"
5318 "content/browser/accessibility/"
5319 "WebContentsAccessibilityEventsTest.java"
5320 "\nIf this message is confusing or annoying, please contact"
5321 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:395322
Sam Maiera6e76d72022-02-11 21:43:505323 # If no message was set, return empty.
5324 if not len(message):
5325 return []
5326
5327 return [output_api.PresubmitPromptWarning(message)]
5328
Mark Schillacie5a0be22022-01-19 00:38:395329
5330def CheckAccessibilityTreeTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505331 """Checks that commits that include a newly added, renamed/moved, or deleted
5332 test in the DumpAccessibilityTreeTest suite also includes a corresponding
5333 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:395334
Sam Maiera6e76d72022-02-11 21:43:505335 def FilePathFilter(affected_file):
5336 paths = _ACCESSIBILITY_TREE_TEST_PATH
5337 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395338
Sam Maiera6e76d72022-02-11 21:43:505339 def AndroidFilePathFilter(affected_file):
5340 paths = _ACCESSIBILITY_ANDROID_TREE_TEST_PATH
5341 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:395342
Sam Maiera6e76d72022-02-11 21:43:505343 # Only consider changes in the various tree test data paths with html type.
5344 if not any(
5345 input_api.AffectedFiles(include_deletes=True,
5346 file_filter=FilePathFilter)):
5347 return []
Mark Schillacie5a0be22022-01-19 00:38:395348
Sam Maiera6e76d72022-02-11 21:43:505349 # If the commit contains any change to the Android test file, ignore.
5350 if any(
5351 input_api.AffectedFiles(include_deletes=True,
5352 file_filter=AndroidFilePathFilter)):
5353 return []
Mark Schillacie5a0be22022-01-19 00:38:395354
Sam Maiera6e76d72022-02-11 21:43:505355 # Only consider changes that are adding/renaming or deleting a file
5356 message = []
5357 for f in input_api.AffectedFiles(include_deletes=True,
5358 file_filter=FilePathFilter):
5359 if f.Action() == 'A' or f.Action() == 'D':
5360 message = (
5361 "It appears that you are adding, renaming or deleting"
5362 "\na dump_accessibility_tree* test, but have not included"
5363 "\na corresponding change for Android."
5364 "\nPlease include (or remove) the test from:"
5365 "\n content/public/android/javatests/src/org/chromium/"
5366 "content/browser/accessibility/"
5367 "WebContentsAccessibilityTreeTest.java"
5368 "\nIf this message is confusing or annoying, please contact"
5369 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:395370
Sam Maiera6e76d72022-02-11 21:43:505371 # If no message was set, return empty.
5372 if not len(message):
5373 return []
5374
5375 return [output_api.PresubmitPromptWarning(message)]
Mark Schillacie5a0be22022-01-19 00:38:395376
5377
Bruce Dawson33806592022-11-16 01:44:515378def CheckEsLintConfigChanges(input_api, output_api):
5379 """Suggest using "git cl presubmit --files" when .eslintrc.js files are
5380 modified. This is important because enabling an error in .eslintrc.js can
5381 trigger errors in any .js or .ts files in its directory, leading to hidden
5382 presubmit errors."""
5383 results = []
5384 eslint_filter = lambda f: input_api.FilterSourceFile(
5385 f, files_to_check=[r'.*\.eslintrc\.js$'])
5386 for f in input_api.AffectedFiles(include_deletes=False,
5387 file_filter=eslint_filter):
5388 local_dir = input_api.os_path.dirname(f.LocalPath())
5389 # Use / characters so that the commands printed work on any OS.
5390 local_dir = local_dir.replace(input_api.os_path.sep, '/')
5391 if local_dir:
5392 local_dir += '/'
5393 results.append(
5394 output_api.PresubmitNotifyResult(
5395 '%(file)s modified. Consider running \'git cl presubmit --files '
5396 '"%(dir)s*.js;%(dir)s*.ts"\' in order to check and fix the affected '
5397 'files before landing this change.' %
5398 { 'file' : f.LocalPath(), 'dir' : local_dir}))
5399 return results
5400
5401
seanmccullough4a9356252021-04-08 19:54:095402# string pattern, sequence of strings to show when pattern matches,
5403# error flag. True if match is a presubmit error, otherwise it's a warning.
5404_NON_INCLUSIVE_TERMS = (
5405 (
5406 # Note that \b pattern in python re is pretty particular. In this
5407 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
5408 # ...' will not. This may require some tweaking to catch these cases
5409 # without triggering a lot of false positives. Leaving it naive and
5410 # less matchy for now.
seanmccullough56d1e3cf2021-12-03 18:18:325411 r'/\b(?i)((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:095412 (
5413 'Please don\'t use blacklist, whitelist, ' # nocheck
5414 'or slave in your', # nocheck
5415 'code and make every effort to use other terms. Using "// nocheck"',
5416 '"# nocheck" or "<!-- nocheck -->"',
5417 'at the end of the offending line will bypass this PRESUBMIT error',
5418 'but avoid using this whenever possible. Reach out to',
5419 '[email protected] if you have questions'),
5420 True),)
5421
Saagar Sanghavifceeaae2020-08-12 16:40:365422def ChecksCommon(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505423 """Checks common to both upload and commit."""
5424 results = []
Eric Boren6fd2b932018-01-25 15:05:085425 results.extend(
Sam Maiera6e76d72022-02-11 21:43:505426 input_api.canned_checks.PanProjectChecks(
5427 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:085428
Sam Maiera6e76d72022-02-11 21:43:505429 author = input_api.change.author_email
5430 if author and author not in _KNOWN_ROBOTS:
5431 results.extend(
5432 input_api.canned_checks.CheckAuthorizedAuthor(
5433 input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:245434
Sam Maiera6e76d72022-02-11 21:43:505435 results.extend(
5436 input_api.canned_checks.CheckChangeHasNoTabs(
5437 input_api,
5438 output_api,
5439 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
5440 results.extend(
5441 input_api.RunTests(
5442 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Edward Lesmesce51df52020-08-04 22:10:175443
Bruce Dawsonc8054482022-03-28 15:33:375444 dirmd = 'dirmd.bat' if input_api.is_windows else 'dirmd'
Sam Maiera6e76d72022-02-11 21:43:505445 dirmd_bin = input_api.os_path.join(input_api.PresubmitLocalPath(),
Bruce Dawsonc8054482022-03-28 15:33:375446 'third_party', 'depot_tools', dirmd)
Sam Maiera6e76d72022-02-11 21:43:505447 results.extend(
5448 input_api.RunTests(
5449 input_api.canned_checks.CheckDirMetadataFormat(
5450 input_api, output_api, dirmd_bin)))
5451 results.extend(
5452 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
5453 input_api, output_api))
5454 results.extend(
5455 input_api.canned_checks.CheckNoNewMetadataInOwners(
5456 input_api, output_api))
5457 results.extend(
5458 input_api.canned_checks.CheckInclusiveLanguage(
5459 input_api,
5460 output_api,
5461 excluded_directories_relative_path=[
5462 'infra', 'inclusive_language_presubmit_exempt_dirs.txt'
5463 ],
5464 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Dirk Prankee3c9c62d2021-05-18 18:35:595465
Aleksey Khoroshilov2978c942022-06-13 16:14:125466 presubmit_py_filter = lambda f: input_api.FilterSourceFile(
Bruce Dawson696963f2022-09-13 01:15:475467 f, files_to_check=[r'.*PRESUBMIT\.py$'])
Aleksey Khoroshilov2978c942022-06-13 16:14:125468 for f in input_api.AffectedFiles(include_deletes=False,
5469 file_filter=presubmit_py_filter):
5470 full_path = input_api.os_path.dirname(f.AbsoluteLocalPath())
5471 test_file = input_api.os_path.join(full_path, 'PRESUBMIT_test.py')
5472 # The PRESUBMIT.py file (and the directory containing it) might have
5473 # been affected by being moved or removed, so only try to run the tests
5474 # if they still exist.
5475 if not input_api.os_path.exists(test_file):
5476 continue
Sam Maiera6e76d72022-02-11 21:43:505477
Aleksey Khoroshilov2978c942022-06-13 16:14:125478 results.extend(
5479 input_api.canned_checks.RunUnitTestsInDirectory(
5480 input_api,
5481 output_api,
5482 full_path,
Takuto Ikuta40def482023-06-02 02:23:495483 files_to_check=[r'^PRESUBMIT_test\.py$']))
Sam Maiera6e76d72022-02-11 21:43:505484 return results
[email protected]1f7b4172010-01-28 01:17:345485
[email protected]b337cb5b2011-01-23 21:24:055486
Saagar Sanghavifceeaae2020-08-12 16:40:365487def CheckPatchFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505488 problems = [
5489 f.LocalPath() for f in input_api.AffectedFiles()
5490 if f.LocalPath().endswith(('.orig', '.rej'))
5491 ]
5492 # Cargo.toml.orig files are part of third-party crates downloaded from
5493 # crates.io and should be included.
5494 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
5495 if problems:
5496 return [
5497 output_api.PresubmitError("Don't commit .rej and .orig files.",
5498 problems)
5499 ]
5500 else:
5501 return []
[email protected]b8079ae4a2012-12-05 19:56:495502
5503
Saagar Sanghavifceeaae2020-08-12 16:40:365504def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505505 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
5506 macro_re = input_api.re.compile(
5507 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
5508 include_re = input_api.re.compile(r'^#include\s+"build/build_config.h"',
5509 input_api.re.MULTILINE)
5510 extension_re = input_api.re.compile(r'\.[a-z]+$')
5511 errors = []
Bruce Dawsonf7679202022-08-09 20:24:005512 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:505513 for f in input_api.AffectedFiles(include_deletes=False):
Bruce Dawsonf7679202022-08-09 20:24:005514 # The build-config macros are allowed to be used in build_config.h
5515 # without including itself.
5516 if f.LocalPath() == config_h_file:
5517 continue
Sam Maiera6e76d72022-02-11 21:43:505518 if not f.LocalPath().endswith(
5519 ('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
5520 continue
5521 found_line_number = None
5522 found_macro = None
5523 all_lines = input_api.ReadFile(f, 'r').splitlines()
5524 for line_num, line in enumerate(all_lines):
5525 match = macro_re.search(line)
5526 if match:
5527 found_line_number = line_num
5528 found_macro = match.group(2)
5529 break
5530 if not found_line_number:
5531 continue
Kent Tamura5a8755d2017-06-29 23:37:075532
Sam Maiera6e76d72022-02-11 21:43:505533 found_include_line = -1
5534 for line_num, line in enumerate(all_lines):
5535 if include_re.search(line):
5536 found_include_line = line_num
5537 break
5538 if found_include_line >= 0 and found_include_line < found_line_number:
5539 continue
Kent Tamura5a8755d2017-06-29 23:37:075540
Sam Maiera6e76d72022-02-11 21:43:505541 if not f.LocalPath().endswith('.h'):
5542 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
5543 try:
5544 content = input_api.ReadFile(primary_header_path, 'r')
5545 if include_re.search(content):
5546 continue
5547 except IOError:
5548 pass
5549 errors.append('%s:%d %s macro is used without first including build/'
5550 'build_config.h.' %
5551 (f.LocalPath(), found_line_number, found_macro))
5552 if errors:
5553 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
5554 return []
Kent Tamura5a8755d2017-06-29 23:37:075555
5556
Lei Zhang1c12a22f2021-05-12 11:28:455557def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505558 stl_include_re = input_api.re.compile(r'^#include\s+<('
5559 r'algorithm|'
5560 r'array|'
5561 r'limits|'
5562 r'list|'
5563 r'map|'
5564 r'memory|'
5565 r'queue|'
5566 r'set|'
5567 r'string|'
5568 r'unordered_map|'
5569 r'unordered_set|'
5570 r'utility|'
5571 r'vector)>')
5572 std_namespace_re = input_api.re.compile(r'std::')
5573 errors = []
5574 for f in input_api.AffectedFiles():
5575 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
5576 continue
Lei Zhang1c12a22f2021-05-12 11:28:455577
Sam Maiera6e76d72022-02-11 21:43:505578 uses_std_namespace = False
5579 has_stl_include = False
5580 for line in f.NewContents():
5581 if has_stl_include and uses_std_namespace:
5582 break
Lei Zhang1c12a22f2021-05-12 11:28:455583
Sam Maiera6e76d72022-02-11 21:43:505584 if not has_stl_include and stl_include_re.search(line):
5585 has_stl_include = True
5586 continue
Lei Zhang1c12a22f2021-05-12 11:28:455587
Bruce Dawson4a5579a2022-04-08 17:11:365588 if not uses_std_namespace and (std_namespace_re.search(line)
5589 or 'no-std-usage-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:505590 uses_std_namespace = True
5591 continue
Lei Zhang1c12a22f2021-05-12 11:28:455592
Sam Maiera6e76d72022-02-11 21:43:505593 if has_stl_include and not uses_std_namespace:
5594 errors.append(
5595 '%s: Includes STL header(s) but does not reference std::' %
5596 f.LocalPath())
5597 if errors:
5598 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
5599 return []
Lei Zhang1c12a22f2021-05-12 11:28:455600
5601
Xiaohan Wang42d96c22022-01-20 17:23:115602def _CheckForDeprecatedOSMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:505603 """Check for sensible looking, totally invalid OS macros."""
5604 preprocessor_statement = input_api.re.compile(r'^\s*#')
5605 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
5606 results = []
5607 for lnum, line in f.ChangedContents():
5608 if preprocessor_statement.search(line):
5609 for match in os_macro.finditer(line):
5610 results.append(
5611 ' %s:%d: %s' %
5612 (f.LocalPath(), lnum, 'defined(OS_' + match.group(1) +
5613 ') -> BUILDFLAG(IS_' + match.group(1) + ')'))
5614 return results
[email protected]b00342e7f2013-03-26 16:21:545615
5616
Xiaohan Wang42d96c22022-01-20 17:23:115617def CheckForDeprecatedOSMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505618 """Check all affected files for invalid OS macros."""
5619 bad_macros = []
Bruce Dawsonf7679202022-08-09 20:24:005620 # The OS_ macros are allowed to be used in build/build_config.h.
5621 config_h_file = input_api.os_path.join('build', 'build_config.h')
Sam Maiera6e76d72022-02-11 21:43:505622 for f in input_api.AffectedSourceFiles(None):
Bruce Dawsonf7679202022-08-09 20:24:005623 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')) \
5624 and f.LocalPath() != config_h_file:
Sam Maiera6e76d72022-02-11 21:43:505625 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
[email protected]b00342e7f2013-03-26 16:21:545626
Sam Maiera6e76d72022-02-11 21:43:505627 if not bad_macros:
5628 return []
[email protected]b00342e7f2013-03-26 16:21:545629
Sam Maiera6e76d72022-02-11 21:43:505630 return [
5631 output_api.PresubmitError(
5632 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
5633 'defined in build_config.h):', bad_macros)
5634 ]
[email protected]b00342e7f2013-03-26 16:21:545635
lliabraa35bab3932014-10-01 12:16:445636
5637def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:505638 """Check all affected files for invalid "if defined" macros."""
5639 ALWAYS_DEFINED_MACROS = (
5640 "TARGET_CPU_PPC",
5641 "TARGET_CPU_PPC64",
5642 "TARGET_CPU_68K",
5643 "TARGET_CPU_X86",
5644 "TARGET_CPU_ARM",
5645 "TARGET_CPU_MIPS",
5646 "TARGET_CPU_SPARC",
5647 "TARGET_CPU_ALPHA",
5648 "TARGET_IPHONE_SIMULATOR",
5649 "TARGET_OS_EMBEDDED",
5650 "TARGET_OS_IPHONE",
5651 "TARGET_OS_MAC",
5652 "TARGET_OS_UNIX",
5653 "TARGET_OS_WIN32",
5654 )
5655 ifdef_macro = input_api.re.compile(
5656 r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
5657 results = []
5658 for lnum, line in f.ChangedContents():
5659 for match in ifdef_macro.finditer(line):
5660 if match.group(1) in ALWAYS_DEFINED_MACROS:
5661 always_defined = ' %s is always defined. ' % match.group(1)
5662 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
5663 results.append(
5664 ' %s:%d %s\n\t%s' %
5665 (f.LocalPath(), lnum, always_defined, did_you_mean))
5666 return results
lliabraa35bab3932014-10-01 12:16:445667
5668
Saagar Sanghavifceeaae2020-08-12 16:40:365669def CheckForInvalidIfDefinedMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505670 """Check all affected files for invalid "if defined" macros."""
5671 bad_macros = []
5672 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
5673 for f in input_api.AffectedFiles():
5674 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
5675 continue
5676 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
5677 bad_macros.extend(
5678 _CheckForInvalidIfDefinedMacrosInFile(input_api, f))
lliabraa35bab3932014-10-01 12:16:445679
Sam Maiera6e76d72022-02-11 21:43:505680 if not bad_macros:
5681 return []
lliabraa35bab3932014-10-01 12:16:445682
Sam Maiera6e76d72022-02-11 21:43:505683 return [
5684 output_api.PresubmitError(
5685 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
5686 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
5687 bad_macros)
5688 ]
lliabraa35bab3932014-10-01 12:16:445689
5690
Saagar Sanghavifceeaae2020-08-12 16:40:365691def CheckForIPCRules(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505692 """Check for same IPC rules described in
5693 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
5694 """
5695 base_pattern = r'IPC_ENUM_TRAITS\('
5696 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
5697 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
mlamouria82272622014-09-16 18:45:045698
Sam Maiera6e76d72022-02-11 21:43:505699 problems = []
5700 for f in input_api.AffectedSourceFiles(None):
5701 local_path = f.LocalPath()
5702 if not local_path.endswith('.h'):
5703 continue
5704 for line_number, line in f.ChangedContents():
5705 if inclusion_pattern.search(
5706 line) and not comment_pattern.search(line):
5707 problems.append('%s:%d\n %s' %
5708 (local_path, line_number, line.strip()))
mlamouria82272622014-09-16 18:45:045709
Sam Maiera6e76d72022-02-11 21:43:505710 if problems:
5711 return [
5712 output_api.PresubmitPromptWarning(_IPC_ENUM_TRAITS_DEPRECATED,
5713 problems)
5714 ]
5715 else:
5716 return []
mlamouria82272622014-09-16 18:45:045717
[email protected]b00342e7f2013-03-26 16:21:545718
Saagar Sanghavifceeaae2020-08-12 16:40:365719def CheckForLongPathnames(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505720 """Check to make sure no files being submitted have long paths.
5721 This causes issues on Windows.
5722 """
5723 problems = []
5724 for f in input_api.AffectedTestableFiles():
5725 local_path = f.LocalPath()
5726 # Windows has a path limit of 260 characters. Limit path length to 200 so
5727 # that we have some extra for the prefix on dev machines and the bots.
5728 if len(local_path) > 200:
5729 problems.append(local_path)
Stephen Martinis97a394142018-06-07 23:06:055730
Sam Maiera6e76d72022-02-11 21:43:505731 if problems:
5732 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
5733 else:
5734 return []
Stephen Martinis97a394142018-06-07 23:06:055735
5736
Saagar Sanghavifceeaae2020-08-12 16:40:365737def CheckForIncludeGuards(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505738 """Check that header files have proper guards against multiple inclusion.
5739 If a file should not have such guards (and it probably should) then it
Bruce Dawson4a5579a2022-04-08 17:11:365740 should include the string "no-include-guard-because-multiply-included" or
5741 "no-include-guard-because-pch-file".
Sam Maiera6e76d72022-02-11 21:43:505742 """
Daniel Bratell8ba52722018-03-02 16:06:145743
Sam Maiera6e76d72022-02-11 21:43:505744 def is_chromium_header_file(f):
5745 # We only check header files under the control of the Chromium
5746 # project. That is, those outside third_party apart from
5747 # third_party/blink.
5748 # We also exclude *_message_generator.h headers as they use
5749 # include guards in a special, non-typical way.
5750 file_with_path = input_api.os_path.normpath(f.LocalPath())
5751 return (file_with_path.endswith('.h')
5752 and not file_with_path.endswith('_message_generator.h')
Bruce Dawson4c4c2922022-05-02 18:07:335753 and not file_with_path.endswith('com_imported_mstscax.h')
Sam Maiera6e76d72022-02-11 21:43:505754 and (not file_with_path.startswith('third_party')
5755 or file_with_path.startswith(
5756 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:145757
Sam Maiera6e76d72022-02-11 21:43:505758 def replace_special_with_underscore(string):
5759 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:145760
Sam Maiera6e76d72022-02-11 21:43:505761 errors = []
Daniel Bratell8ba52722018-03-02 16:06:145762
Sam Maiera6e76d72022-02-11 21:43:505763 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
5764 guard_name = None
5765 guard_line_number = None
5766 seen_guard_end = False
Daniel Bratell8ba52722018-03-02 16:06:145767
Sam Maiera6e76d72022-02-11 21:43:505768 file_with_path = input_api.os_path.normpath(f.LocalPath())
5769 base_file_name = input_api.os_path.splitext(
5770 input_api.os_path.basename(file_with_path))[0]
5771 upper_base_file_name = base_file_name.upper()
Daniel Bratell8ba52722018-03-02 16:06:145772
Sam Maiera6e76d72022-02-11 21:43:505773 expected_guard = replace_special_with_underscore(
5774 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:145775
Sam Maiera6e76d72022-02-11 21:43:505776 # For "path/elem/file_name.h" we should really only accept
5777 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
5778 # are too many (1000+) files with slight deviations from the
5779 # coding style. The most important part is that the include guard
5780 # is there, and that it's unique, not the name so this check is
5781 # forgiving for existing files.
5782 #
5783 # As code becomes more uniform, this could be made stricter.
Daniel Bratell8ba52722018-03-02 16:06:145784
Sam Maiera6e76d72022-02-11 21:43:505785 guard_name_pattern_list = [
5786 # Anything with the right suffix (maybe with an extra _).
5787 r'\w+_H__?',
Daniel Bratell8ba52722018-03-02 16:06:145788
Sam Maiera6e76d72022-02-11 21:43:505789 # To cover include guards with old Blink style.
5790 r'\w+_h',
Daniel Bratell8ba52722018-03-02 16:06:145791
Sam Maiera6e76d72022-02-11 21:43:505792 # Anything including the uppercase name of the file.
5793 r'\w*' + input_api.re.escape(
5794 replace_special_with_underscore(upper_base_file_name)) +
5795 r'\w*',
5796 ]
5797 guard_name_pattern = '|'.join(guard_name_pattern_list)
5798 guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
5799 guard_name_pattern + ')')
Daniel Bratell8ba52722018-03-02 16:06:145800
Sam Maiera6e76d72022-02-11 21:43:505801 for line_number, line in enumerate(f.NewContents()):
Bruce Dawson4a5579a2022-04-08 17:11:365802 if ('no-include-guard-because-multiply-included' in line
5803 or 'no-include-guard-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:505804 guard_name = 'DUMMY' # To not trigger check outside the loop.
5805 break
Daniel Bratell8ba52722018-03-02 16:06:145806
Sam Maiera6e76d72022-02-11 21:43:505807 if guard_name is None:
5808 match = guard_pattern.match(line)
5809 if match:
5810 guard_name = match.group(1)
5811 guard_line_number = line_number
Daniel Bratell8ba52722018-03-02 16:06:145812
Sam Maiera6e76d72022-02-11 21:43:505813 # We allow existing files to use include guards whose names
5814 # don't match the chromium style guide, but new files should
5815 # get it right.
Bruce Dawson6cc154e2022-04-12 20:39:495816 if guard_name != expected_guard:
Bruce Dawson95eb7562022-09-14 15:27:165817 if f.Action() == 'A': # If file was just 'A'dded
Sam Maiera6e76d72022-02-11 21:43:505818 errors.append(
5819 output_api.PresubmitPromptWarning(
5820 'Header using the wrong include guard name %s'
5821 % guard_name, [
5822 '%s:%d' %
5823 (f.LocalPath(), line_number + 1)
5824 ], 'Expected: %r\nFound: %r' %
5825 (expected_guard, guard_name)))
5826 else:
5827 # The line after #ifndef should have a #define of the same name.
5828 if line_number == guard_line_number + 1:
5829 expected_line = '#define %s' % guard_name
5830 if line != expected_line:
5831 errors.append(
5832 output_api.PresubmitPromptWarning(
5833 'Missing "%s" for include guard' %
5834 expected_line,
5835 ['%s:%d' % (f.LocalPath(), line_number + 1)],
5836 'Expected: %r\nGot: %r' %
5837 (expected_line, line)))
Daniel Bratell8ba52722018-03-02 16:06:145838
Sam Maiera6e76d72022-02-11 21:43:505839 if not seen_guard_end and line == '#endif // %s' % guard_name:
5840 seen_guard_end = True
5841 elif seen_guard_end:
5842 if line.strip() != '':
5843 errors.append(
5844 output_api.PresubmitPromptWarning(
5845 'Include guard %s not covering the whole file'
5846 % (guard_name), [f.LocalPath()]))
5847 break # Nothing else to check and enough to warn once.
Daniel Bratell8ba52722018-03-02 16:06:145848
Sam Maiera6e76d72022-02-11 21:43:505849 if guard_name is None:
5850 errors.append(
5851 output_api.PresubmitPromptWarning(
Bruce Dawson32114b62022-04-11 16:45:495852 'Missing include guard in %s\n'
Sam Maiera6e76d72022-02-11 21:43:505853 'Recommended name: %s\n'
5854 'This check can be disabled by having the string\n'
Bruce Dawson4a5579a2022-04-08 17:11:365855 '"no-include-guard-because-multiply-included" or\n'
5856 '"no-include-guard-because-pch-file" in the header.'
Sam Maiera6e76d72022-02-11 21:43:505857 % (f.LocalPath(), expected_guard)))
5858
5859 return errors
Daniel Bratell8ba52722018-03-02 16:06:145860
5861
Saagar Sanghavifceeaae2020-08-12 16:40:365862def CheckForWindowsLineEndings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505863 """Check source code and known ascii text files for Windows style line
5864 endings.
5865 """
Bruce Dawson5efbdc652022-04-11 19:29:515866 known_text_files = r'.*\.(txt|html|htm|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:235867
Sam Maiera6e76d72022-02-11 21:43:505868 file_inclusion_pattern = (known_text_files,
5869 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
5870 r'.+%s' % _HEADER_EXTENSIONS)
mostynbb639aca52015-01-07 20:31:235871
Sam Maiera6e76d72022-02-11 21:43:505872 problems = []
5873 source_file_filter = lambda f: input_api.FilterSourceFile(
5874 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
5875 for f in input_api.AffectedSourceFiles(source_file_filter):
Bruce Dawson5efbdc652022-04-11 19:29:515876 # Ignore test files that contain crlf intentionally.
5877 if f.LocalPath().endswith('crlf.txt'):
Daniel Chenga37c03db2022-05-12 17:20:345878 continue
Sam Maiera6e76d72022-02-11 21:43:505879 include_file = False
5880 for line in input_api.ReadFile(f, 'r').splitlines(True):
5881 if line.endswith('\r\n'):
5882 include_file = True
5883 if include_file:
5884 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:235885
Sam Maiera6e76d72022-02-11 21:43:505886 if problems:
5887 return [
5888 output_api.PresubmitPromptWarning(
5889 'Are you sure that you want '
5890 'these files to contain Windows style line endings?\n' +
5891 '\n'.join(problems))
5892 ]
mostynbb639aca52015-01-07 20:31:235893
Sam Maiera6e76d72022-02-11 21:43:505894 return []
5895
mostynbb639aca52015-01-07 20:31:235896
Evan Stade6cfc964c12021-05-18 20:21:165897def CheckIconFilesForLicenseHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505898 """Check that .icon files (which are fragments of C++) have license headers.
5899 """
Evan Stade6cfc964c12021-05-18 20:21:165900
Sam Maiera6e76d72022-02-11 21:43:505901 icon_files = (r'.*\.icon$', )
Evan Stade6cfc964c12021-05-18 20:21:165902
Sam Maiera6e76d72022-02-11 21:43:505903 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
5904 return input_api.canned_checks.CheckLicense(input_api,
5905 output_api,
5906 source_file_filter=icons)
5907
Evan Stade6cfc964c12021-05-18 20:21:165908
Jose Magana2b456f22021-03-09 23:26:405909def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505910 """Check source code for use of Chrome App technologies being
5911 deprecated.
5912 """
Jose Magana2b456f22021-03-09 23:26:405913
Sam Maiera6e76d72022-02-11 21:43:505914 def _CheckForDeprecatedTech(input_api,
5915 output_api,
5916 detection_list,
5917 files_to_check=None,
5918 files_to_skip=None):
Jose Magana2b456f22021-03-09 23:26:405919
Sam Maiera6e76d72022-02-11 21:43:505920 if (files_to_check or files_to_skip):
5921 source_file_filter = lambda f: input_api.FilterSourceFile(
5922 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
5923 else:
5924 source_file_filter = None
5925
5926 problems = []
5927
5928 for f in input_api.AffectedSourceFiles(source_file_filter):
5929 if f.Action() == 'D':
5930 continue
5931 for _, line in f.ChangedContents():
5932 if any(detect in line for detect in detection_list):
5933 problems.append(f.LocalPath())
5934
5935 return problems
5936
5937 # to avoid this presubmit script triggering warnings
5938 files_to_skip = ['PRESUBMIT.py', 'PRESUBMIT_test.py']
Jose Magana2b456f22021-03-09 23:26:405939
5940 problems = []
5941
Sam Maiera6e76d72022-02-11 21:43:505942 # NMF: any files with extensions .nmf or NMF
5943 _NMF_FILES = r'\.(nmf|NMF)$'
5944 problems += _CheckForDeprecatedTech(
5945 input_api,
5946 output_api,
5947 detection_list=[''], # any change to the file will trigger warning
5948 files_to_check=[r'.+%s' % _NMF_FILES])
Jose Magana2b456f22021-03-09 23:26:405949
Sam Maiera6e76d72022-02-11 21:43:505950 # MANIFEST: any manifest.json that in its diff includes "app":
5951 _MANIFEST_FILES = r'(manifest\.json)$'
5952 problems += _CheckForDeprecatedTech(
5953 input_api,
5954 output_api,
5955 detection_list=['"app":'],
5956 files_to_check=[r'.*%s' % _MANIFEST_FILES])
Jose Magana2b456f22021-03-09 23:26:405957
Sam Maiera6e76d72022-02-11 21:43:505958 # NaCl / PNaCl: any file that in its diff contains the strings in the list
5959 problems += _CheckForDeprecatedTech(
5960 input_api,
5961 output_api,
5962 detection_list=['config=nacl', 'enable-nacl', 'cpu=pnacl', 'nacl_io'],
Bruce Dawson40fece62022-09-16 19:58:315963 files_to_skip=files_to_skip + [r"^native_client_sdk/"])
Jose Magana2b456f22021-03-09 23:26:405964
Gao Shenga79ebd42022-08-08 17:25:595965 # PPAPI: any C/C++ file that in its diff includes a ppapi library
Sam Maiera6e76d72022-02-11 21:43:505966 problems += _CheckForDeprecatedTech(
5967 input_api,
5968 output_api,
5969 detection_list=['#include "ppapi', '#include <ppapi'],
5970 files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,
5971 r'.+%s' % _IMPLEMENTATION_EXTENSIONS),
Bruce Dawson40fece62022-09-16 19:58:315972 files_to_skip=[r"^ppapi/"])
Jose Magana2b456f22021-03-09 23:26:405973
Sam Maiera6e76d72022-02-11 21:43:505974 if problems:
5975 return [
5976 output_api.PresubmitPromptWarning(
5977 'You are adding/modifying code'
5978 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
5979 ' PNaCl, PPAPI). See this blog post for more details:\n'
5980 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
5981 'and this documentation for options to replace these technologies:\n'
5982 'https://developer.chrome.com/docs/apps/migration/\n' +
5983 '\n'.join(problems))
5984 ]
Jose Magana2b456f22021-03-09 23:26:405985
Sam Maiera6e76d72022-02-11 21:43:505986 return []
Jose Magana2b456f22021-03-09 23:26:405987
mostynbb639aca52015-01-07 20:31:235988
Saagar Sanghavifceeaae2020-08-12 16:40:365989def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
Sam Maiera6e76d72022-02-11 21:43:505990 """Checks that all source files use SYSLOG properly."""
5991 syslog_files = []
5992 for f in input_api.AffectedSourceFiles(src_file_filter):
5993 for line_number, line in f.ChangedContents():
5994 if 'SYSLOG' in line:
5995 syslog_files.append(f.LocalPath() + ':' + str(line_number))
pastarmovj032ba5bc2017-01-12 10:41:565996
Sam Maiera6e76d72022-02-11 21:43:505997 if syslog_files:
5998 return [
5999 output_api.PresubmitPromptWarning(
6000 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
6001 ' calls.\nFiles to check:\n',
6002 items=syslog_files)
6003 ]
6004 return []
pastarmovj89f7ee12016-09-20 14:58:136005
6006
[email protected]1f7b4172010-01-28 01:17:346007def CheckChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506008 if input_api.version < [2, 0, 0]:
6009 return [
6010 output_api.PresubmitError(
6011 "Your depot_tools is out of date. "
6012 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
6013 "but your version is %d.%d.%d" % tuple(input_api.version))
6014 ]
6015 results = []
6016 results.extend(
6017 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
6018 return results
[email protected]ca8d1982009-02-19 16:33:126019
6020
6021def CheckChangeOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506022 if input_api.version < [2, 0, 0]:
6023 return [
6024 output_api.PresubmitError(
6025 "Your depot_tools is out of date. "
6026 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
6027 "but your version is %d.%d.%d" % tuple(input_api.version))
6028 ]
Saagar Sanghavifceeaae2020-08-12 16:40:366029
Sam Maiera6e76d72022-02-11 21:43:506030 results = []
6031 # Make sure the tree is 'open'.
6032 results.extend(
6033 input_api.canned_checks.CheckTreeIsOpen(
6034 input_api,
6035 output_api,
6036 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:276037
Sam Maiera6e76d72022-02-11 21:43:506038 results.extend(
6039 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
6040 results.extend(
6041 input_api.canned_checks.CheckChangeHasBugField(input_api, output_api))
6042 results.extend(
6043 input_api.canned_checks.CheckChangeHasNoUnwantedTags(
6044 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:506045 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146046
6047
Saagar Sanghavifceeaae2020-08-12 16:40:366048def CheckStrings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506049 """Check string ICU syntax validity and if translation screenshots exist."""
6050 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
6051 # footer is set to true.
6052 git_footers = input_api.change.GitFootersFromDescription()
6053 skip_screenshot_check_footer = [
6054 footer.lower() for footer in git_footers.get(
6055 u'Skip-Translation-Screenshots-Check', [])
6056 ]
6057 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:026058
Sam Maiera6e76d72022-02-11 21:43:506059 import os
6060 import re
6061 import sys
6062 from io import StringIO
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146063
Sam Maiera6e76d72022-02-11 21:43:506064 new_or_added_paths = set(f.LocalPath() for f in input_api.AffectedFiles()
6065 if (f.Action() == 'A' or f.Action() == 'M'))
6066 removed_paths = set(f.LocalPath()
6067 for f in input_api.AffectedFiles(include_deletes=True)
6068 if f.Action() == 'D')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146069
Sam Maiera6e76d72022-02-11 21:43:506070 affected_grds = [
6071 f for f in input_api.AffectedFiles()
6072 if f.LocalPath().endswith(('.grd', '.grdp'))
6073 ]
6074 affected_grds = [
6075 f for f in affected_grds if not 'testdata' in f.LocalPath()
6076 ]
6077 if not affected_grds:
6078 return []
meacer8c0d3832019-12-26 21:46:166079
Sam Maiera6e76d72022-02-11 21:43:506080 affected_png_paths = [
6081 f.AbsoluteLocalPath() for f in input_api.AffectedFiles()
6082 if (f.LocalPath().endswith('.png'))
6083 ]
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146084
Sam Maiera6e76d72022-02-11 21:43:506085 # Check for screenshots. Developers can upload screenshots using
6086 # tools/translation/upload_screenshots.py which finds and uploads
6087 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
6088 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
6089 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
6090 #
6091 # The logic here is as follows:
6092 #
6093 # - If the CL has a .png file under the screenshots directory for a grd
6094 # file, warn the developer. Actual images should never be checked into the
6095 # Chrome repo.
6096 #
6097 # - If the CL contains modified or new messages in grd files and doesn't
6098 # contain the corresponding .sha1 files, warn the developer to add images
6099 # and upload them via tools/translation/upload_screenshots.py.
6100 #
6101 # - If the CL contains modified or new messages in grd files and the
6102 # corresponding .sha1 files, everything looks good.
6103 #
6104 # - If the CL contains removed messages in grd files but the corresponding
6105 # .sha1 files aren't removed, warn the developer to remove them.
6106 unnecessary_screenshots = []
Jens Mueller054652c2023-05-10 15:12:306107 invalid_sha1 = []
Sam Maiera6e76d72022-02-11 21:43:506108 missing_sha1 = []
Bruce Dawson55776c42022-12-09 17:23:476109 missing_sha1_modified = []
Sam Maiera6e76d72022-02-11 21:43:506110 unnecessary_sha1_files = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146111
Sam Maiera6e76d72022-02-11 21:43:506112 # This checks verifies that the ICU syntax of messages this CL touched is
6113 # valid, and reports any found syntax errors.
6114 # Without this presubmit check, ICU syntax errors in Chromium strings can land
6115 # without developers being aware of them. Later on, such ICU syntax errors
6116 # break message extraction for translation, hence would block Chromium
6117 # translations until they are fixed.
6118 icu_syntax_errors = []
Jens Mueller054652c2023-05-10 15:12:306119 sha1_pattern = input_api.re.compile(r'^[a-fA-F0-9]{40}$',
6120 input_api.re.MULTILINE)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146121
Sam Maiera6e76d72022-02-11 21:43:506122 def _CheckScreenshotAdded(screenshots_dir, message_id):
6123 sha1_path = input_api.os_path.join(screenshots_dir,
6124 message_id + '.png.sha1')
6125 if sha1_path not in new_or_added_paths:
6126 missing_sha1.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306127 elif not _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256128 invalid_sha1.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146129
Bruce Dawson55776c42022-12-09 17:23:476130 def _CheckScreenshotModified(screenshots_dir, message_id):
6131 sha1_path = input_api.os_path.join(screenshots_dir,
6132 message_id + '.png.sha1')
6133 if sha1_path not in new_or_added_paths:
6134 missing_sha1_modified.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306135 elif not _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256136 invalid_sha1.append(sha1_path)
Jens Mueller054652c2023-05-10 15:12:306137
6138 def _CheckValidSha1(sha1_path):
Sam Maierb926c58c2023-08-08 19:58:256139 return sha1_pattern.search(
6140 next("\n".join(f.NewContents()) for f in input_api.AffectedFiles()
6141 if f.LocalPath() == sha1_path))
Bruce Dawson55776c42022-12-09 17:23:476142
Sam Maiera6e76d72022-02-11 21:43:506143 def _CheckScreenshotRemoved(screenshots_dir, message_id):
6144 sha1_path = input_api.os_path.join(screenshots_dir,
6145 message_id + '.png.sha1')
6146 if input_api.os_path.exists(
6147 sha1_path) and sha1_path not in removed_paths:
6148 unnecessary_sha1_files.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146149
Sam Maiera6e76d72022-02-11 21:43:506150 def _ValidateIcuSyntax(text, level, signatures):
6151 """Validates ICU syntax of a text string.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146152
Sam Maiera6e76d72022-02-11 21:43:506153 Check if text looks similar to ICU and checks for ICU syntax correctness
6154 in this case. Reports various issues with ICU syntax and values of
6155 variants. Supports checking of nested messages. Accumulate information of
6156 each ICU messages found in the text for further checking.
Rainhard Findlingfc31844c52020-05-15 09:58:266157
Sam Maiera6e76d72022-02-11 21:43:506158 Args:
6159 text: a string to check.
6160 level: a number of current nesting level.
6161 signatures: an accumulator, a list of tuple of (level, variable,
6162 kind, variants).
Rainhard Findlingfc31844c52020-05-15 09:58:266163
Sam Maiera6e76d72022-02-11 21:43:506164 Returns:
6165 None if a string is not ICU or no issue detected.
6166 A tuple of (message, start index, end index) if an issue detected.
6167 """
6168 valid_types = {
6169 'plural': (frozenset(
6170 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
6171 'other']), frozenset(['=1', 'other'])),
6172 'selectordinal': (frozenset(
6173 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
6174 'other']), frozenset(['one', 'other'])),
6175 'select': (frozenset(), frozenset(['other'])),
6176 }
Rainhard Findlingfc31844c52020-05-15 09:58:266177
Sam Maiera6e76d72022-02-11 21:43:506178 # Check if the message looks like an attempt to use ICU
6179 # plural. If yes - check if its syntax strictly matches ICU format.
6180 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b',
6181 text)
6182 if not like:
6183 signatures.append((level, None, None, None))
6184 return
Rainhard Findlingfc31844c52020-05-15 09:58:266185
Sam Maiera6e76d72022-02-11 21:43:506186 # Check for valid prefix and suffix
6187 m = re.match(
6188 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
6189 r'(plural|selectordinal|select),\s*'
6190 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
6191 if not m:
6192 return (('This message looks like an ICU plural, '
6193 'but does not follow ICU syntax.'), like.start(),
6194 like.end())
6195 starting, variable, kind, variant_pairs = m.groups()
6196 variants, depth, last_pos = _ParseIcuVariants(variant_pairs,
6197 m.start(4))
6198 if depth:
6199 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
6200 len(text))
6201 first = text[0]
6202 ending = text[last_pos:]
6203 if not starting:
6204 return ('Invalid ICU format. No initial opening bracket',
6205 last_pos - 1, last_pos)
6206 if not ending or '}' not in ending:
6207 return ('Invalid ICU format. No final closing bracket',
6208 last_pos - 1, last_pos)
6209 elif first != '{':
6210 return ((
6211 'Invalid ICU format. Extra characters at the start of a complex '
6212 'message (go/icu-message-migration): "%s"') % starting, 0,
6213 len(starting))
6214 elif ending != '}':
6215 return ((
6216 'Invalid ICU format. Extra characters at the end of a complex '
6217 'message (go/icu-message-migration): "%s"') % ending,
6218 last_pos - 1, len(text) - 1)
6219 if kind not in valid_types:
6220 return (('Unknown ICU message type %s. '
6221 'Valid types are: plural, select, selectordinal') % kind,
6222 0, 0)
6223 known, required = valid_types[kind]
6224 defined_variants = set()
6225 for variant, variant_range, value, value_range in variants:
6226 start, end = variant_range
6227 if variant in defined_variants:
6228 return ('Variant "%s" is defined more than once' % variant,
6229 start, end)
6230 elif known and variant not in known:
6231 return ('Variant "%s" is not valid for %s message' %
6232 (variant, kind), start, end)
6233 defined_variants.add(variant)
6234 # Check for nested structure
6235 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
6236 if res:
6237 return (res[0], res[1] + value_range[0] + 1,
6238 res[2] + value_range[0] + 1)
6239 missing = required - defined_variants
6240 if missing:
6241 return ('Required variants missing: %s' % ', '.join(missing), 0,
6242 len(text))
6243 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:266244
Sam Maiera6e76d72022-02-11 21:43:506245 def _ParseIcuVariants(text, offset=0):
6246 """Parse variants part of ICU complex message.
Rainhard Findlingfc31844c52020-05-15 09:58:266247
Sam Maiera6e76d72022-02-11 21:43:506248 Builds a tuple of variant names and values, as well as
6249 their offsets in the input string.
Rainhard Findlingfc31844c52020-05-15 09:58:266250
Sam Maiera6e76d72022-02-11 21:43:506251 Args:
6252 text: a string to parse
6253 offset: additional offset to add to positions in the text to get correct
6254 position in the complete ICU string.
Rainhard Findlingfc31844c52020-05-15 09:58:266255
Sam Maiera6e76d72022-02-11 21:43:506256 Returns:
6257 List of tuples, each tuple consist of four fields: variant name,
6258 variant name span (tuple of two integers), variant value, value
6259 span (tuple of two integers).
6260 """
6261 depth, start, end = 0, -1, -1
6262 variants = []
6263 key = None
6264 for idx, char in enumerate(text):
6265 if char == '{':
6266 if not depth:
6267 start = idx
6268 chunk = text[end + 1:start]
6269 key = chunk.strip()
6270 pos = offset + end + 1 + chunk.find(key)
6271 span = (pos, pos + len(key))
6272 depth += 1
6273 elif char == '}':
6274 if not depth:
6275 return variants, depth, offset + idx
6276 depth -= 1
6277 if not depth:
6278 end = idx
6279 variants.append((key, span, text[start:end + 1],
6280 (offset + start, offset + end + 1)))
6281 return variants, depth, offset + end + 1
Rainhard Findlingfc31844c52020-05-15 09:58:266282
Sam Maiera6e76d72022-02-11 21:43:506283 try:
6284 old_sys_path = sys.path
6285 sys.path = sys.path + [
6286 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
6287 'translation')
6288 ]
6289 from helper import grd_helper
6290 finally:
6291 sys.path = old_sys_path
Rainhard Findlingfc31844c52020-05-15 09:58:266292
Sam Maiera6e76d72022-02-11 21:43:506293 for f in affected_grds:
6294 file_path = f.LocalPath()
6295 old_id_to_msg_map = {}
6296 new_id_to_msg_map = {}
6297 # Note that this code doesn't check if the file has been deleted. This is
6298 # OK because it only uses the old and new file contents and doesn't load
6299 # the file via its path.
6300 # It's also possible that a file's content refers to a renamed or deleted
6301 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
6302 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
6303 # .grdp files.
6304 if file_path.endswith('.grdp'):
6305 if f.OldContents():
6306 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6307 '\n'.join(f.OldContents()))
6308 if f.NewContents():
6309 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
6310 '\n'.join(f.NewContents()))
6311 else:
6312 file_dir = input_api.os_path.dirname(file_path) or '.'
6313 if f.OldContents():
6314 old_id_to_msg_map = grd_helper.GetGrdMessages(
6315 StringIO('\n'.join(f.OldContents())), file_dir)
6316 if f.NewContents():
6317 new_id_to_msg_map = grd_helper.GetGrdMessages(
6318 StringIO('\n'.join(f.NewContents())), file_dir)
Rainhard Findlingfc31844c52020-05-15 09:58:266319
Sam Maiera6e76d72022-02-11 21:43:506320 grd_name, ext = input_api.os_path.splitext(
6321 input_api.os_path.basename(file_path))
6322 screenshots_dir = input_api.os_path.join(
6323 input_api.os_path.dirname(file_path),
6324 grd_name + ext.replace('.', '_'))
Rainhard Findlingfc31844c52020-05-15 09:58:266325
Sam Maiera6e76d72022-02-11 21:43:506326 # Compute added, removed and modified message IDs.
6327 old_ids = set(old_id_to_msg_map)
6328 new_ids = set(new_id_to_msg_map)
6329 added_ids = new_ids - old_ids
6330 removed_ids = old_ids - new_ids
6331 modified_ids = set([])
6332 for key in old_ids.intersection(new_ids):
6333 if (old_id_to_msg_map[key].ContentsAsXml('', True) !=
6334 new_id_to_msg_map[key].ContentsAsXml('', True)):
6335 # The message content itself changed. Require an updated screenshot.
6336 modified_ids.add(key)
6337 elif old_id_to_msg_map[key].attrs['meaning'] != \
6338 new_id_to_msg_map[key].attrs['meaning']:
Jens Mueller054652c2023-05-10 15:12:306339 # The message meaning changed. We later check for a screenshot.
6340 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146341
Sam Maiera6e76d72022-02-11 21:43:506342 if run_screenshot_check:
6343 # Check the screenshot directory for .png files. Warn if there is any.
6344 for png_path in affected_png_paths:
6345 if png_path.startswith(screenshots_dir):
6346 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146347
Sam Maiera6e76d72022-02-11 21:43:506348 for added_id in added_ids:
6349 _CheckScreenshotAdded(screenshots_dir, added_id)
Rainhard Findlingd8d04372020-08-13 13:30:096350
Sam Maiera6e76d72022-02-11 21:43:506351 for modified_id in modified_ids:
Bruce Dawson55776c42022-12-09 17:23:476352 _CheckScreenshotModified(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146353
Sam Maiera6e76d72022-02-11 21:43:506354 for removed_id in removed_ids:
6355 _CheckScreenshotRemoved(screenshots_dir, removed_id)
6356
6357 # Check new and changed strings for ICU syntax errors.
6358 for key in added_ids.union(modified_ids):
6359 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
6360 err = _ValidateIcuSyntax(msg, 0, [])
6361 if err is not None:
6362 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
6363
6364 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:266365 if run_screenshot_check:
Sam Maiera6e76d72022-02-11 21:43:506366 if unnecessary_screenshots:
6367 results.append(
6368 output_api.PresubmitError(
6369 'Do not include actual screenshots in the changelist. Run '
6370 'tools/translate/upload_screenshots.py to upload them instead:',
6371 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146372
Sam Maiera6e76d72022-02-11 21:43:506373 if missing_sha1:
6374 results.append(
6375 output_api.PresubmitError(
Bruce Dawson55776c42022-12-09 17:23:476376 'You are adding UI strings.\n'
Sam Maiera6e76d72022-02-11 21:43:506377 'To ensure the best translations, take screenshots of the relevant UI '
6378 '(https://g.co/chrome/translation) and add these files to your '
6379 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146380
Jens Mueller054652c2023-05-10 15:12:306381 if invalid_sha1:
6382 results.append(
6383 output_api.PresubmitError(
6384 'The following files do not seem to contain valid sha1 hashes. '
6385 'Make sure they contain hashes created by '
6386 'tools/translate/upload_screenshots.py:', sorted(invalid_sha1)))
6387
Bruce Dawson55776c42022-12-09 17:23:476388 if missing_sha1_modified:
6389 results.append(
6390 output_api.PresubmitError(
6391 'You are modifying UI strings or their meanings.\n'
6392 'To ensure the best translations, take screenshots of the relevant UI '
6393 '(https://g.co/chrome/translation) and add these files to your '
6394 'changelist:', sorted(missing_sha1_modified)))
6395
Sam Maiera6e76d72022-02-11 21:43:506396 if unnecessary_sha1_files:
6397 results.append(
6398 output_api.PresubmitError(
6399 'You removed strings associated with these files. Remove:',
6400 sorted(unnecessary_sha1_files)))
6401 else:
6402 results.append(
6403 output_api.PresubmitPromptOrNotify('Skipping translation '
6404 'screenshots check.'))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:146405
Sam Maiera6e76d72022-02-11 21:43:506406 if icu_syntax_errors:
6407 results.append(
6408 output_api.PresubmitPromptWarning(
6409 'ICU syntax errors were found in the following strings (problems or '
6410 'feedback? Contact [email protected]):',
6411 items=icu_syntax_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:266412
Sam Maiera6e76d72022-02-11 21:43:506413 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:126414
6415
Saagar Sanghavifceeaae2020-08-12 16:40:366416def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:126417 repo_root=None,
6418 translation_expectations_path=None,
6419 grd_files=None):
Sam Maiera6e76d72022-02-11 21:43:506420 import sys
6421 affected_grds = [
6422 f for f in input_api.AffectedFiles()
6423 if (f.LocalPath().endswith('.grd') or f.LocalPath().endswith('.grdp'))
6424 ]
6425 if not affected_grds:
6426 return []
6427
6428 try:
6429 old_sys_path = sys.path
6430 sys.path = sys.path + [
6431 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
6432 'translation')
6433 ]
6434 from helper import git_helper
6435 from helper import translation_helper
6436 finally:
6437 sys.path = old_sys_path
6438
6439 # Check that translation expectations can be parsed and we can get a list of
6440 # translatable grd files. |repo_root| and |translation_expectations_path| are
6441 # only passed by tests.
6442 if not repo_root:
6443 repo_root = input_api.PresubmitLocalPath()
6444 if not translation_expectations_path:
6445 translation_expectations_path = input_api.os_path.join(
6446 repo_root, 'tools', 'gritsettings', 'translation_expectations.pyl')
6447 if not grd_files:
6448 grd_files = git_helper.list_grds_in_repository(repo_root)
6449
6450 # Ignore bogus grd files used only for testing
Gao Shenga79ebd42022-08-08 17:25:596451 # ui/webui/resources/tools/generate_grd.py.
Sam Maiera6e76d72022-02-11 21:43:506452 ignore_path = input_api.os_path.join('ui', 'webui', 'resources', 'tools',
6453 'tests')
6454 grd_files = [p for p in grd_files if ignore_path not in p]
6455
6456 try:
6457 translation_helper.get_translatable_grds(
6458 repo_root, grd_files, translation_expectations_path)
6459 except Exception as e:
6460 return [
6461 output_api.PresubmitNotifyResult(
6462 'Failed to get a list of translatable grd files. This happens when:\n'
6463 ' - One of the modified grd or grdp files cannot be parsed or\n'
6464 ' - %s is not updated.\n'
6465 'Stack:\n%s' % (translation_expectations_path, str(e)))
6466 ]
Mustafa Emre Acer51f2f742020-03-09 19:41:126467 return []
6468
Ken Rockotc31f4832020-05-29 18:58:516469
Saagar Sanghavifceeaae2020-08-12 16:40:366470def CheckStableMojomChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506471 """Changes to [Stable] mojom types must preserve backward-compatibility."""
6472 changed_mojoms = input_api.AffectedFiles(
6473 include_deletes=True,
6474 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:526475
Bruce Dawson344ab262022-06-04 11:35:106476 if not changed_mojoms or input_api.no_diffs:
Sam Maiera6e76d72022-02-11 21:43:506477 return []
6478
6479 delta = []
6480 for mojom in changed_mojoms:
Sam Maiera6e76d72022-02-11 21:43:506481 delta.append({
6482 'filename': mojom.LocalPath(),
6483 'old': '\n'.join(mojom.OldContents()) or None,
6484 'new': '\n'.join(mojom.NewContents()) or None,
6485 })
6486
6487 process = input_api.subprocess.Popen([
Takuto Ikutadca10222022-04-13 02:51:216488 input_api.python3_executable,
Sam Maiera6e76d72022-02-11 21:43:506489 input_api.os_path.join(
6490 input_api.PresubmitLocalPath(), 'mojo', 'public', 'tools', 'mojom',
6491 'check_stable_mojom_compatibility.py'), '--src-root',
6492 input_api.PresubmitLocalPath()
6493 ],
6494 stdin=input_api.subprocess.PIPE,
6495 stdout=input_api.subprocess.PIPE,
6496 stderr=input_api.subprocess.PIPE,
6497 universal_newlines=True)
6498 (x, error) = process.communicate(input=input_api.json.dumps(delta))
6499 if process.returncode:
6500 return [
6501 output_api.PresubmitError(
6502 'One or more [Stable] mojom definitions appears to have been changed '
6503 'in a way that is not backward-compatible.',
6504 long_text=error)
6505 ]
Erik Staabc734cd7a2021-11-23 03:11:526506 return []
6507
Dominic Battre645d42342020-12-04 16:14:106508def CheckDeprecationOfPreferences(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506509 """Removing a preference should come with a deprecation."""
Dominic Battre645d42342020-12-04 16:14:106510
Sam Maiera6e76d72022-02-11 21:43:506511 def FilterFile(affected_file):
6512 """Accept only .cc files and the like."""
6513 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
6514 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
6515 input_api.DEFAULT_FILES_TO_SKIP)
6516 return input_api.FilterSourceFile(
6517 affected_file,
6518 files_to_check=file_inclusion_pattern,
6519 files_to_skip=files_to_skip)
Dominic Battre645d42342020-12-04 16:14:106520
Sam Maiera6e76d72022-02-11 21:43:506521 def ModifiedLines(affected_file):
6522 """Returns a list of tuples (line number, line text) of added and removed
6523 lines.
Dominic Battre645d42342020-12-04 16:14:106524
Sam Maiera6e76d72022-02-11 21:43:506525 Deleted lines share the same line number as the previous line.
Dominic Battre645d42342020-12-04 16:14:106526
Sam Maiera6e76d72022-02-11 21:43:506527 This relies on the scm diff output describing each changed code section
6528 with a line of the form
Dominic Battre645d42342020-12-04 16:14:106529
Sam Maiera6e76d72022-02-11 21:43:506530 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
6531 """
6532 line_num = 0
6533 modified_lines = []
6534 for line in affected_file.GenerateScmDiff().splitlines():
6535 # Extract <new line num> of the patch fragment (see format above).
6536 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@',
6537 line)
6538 if m:
6539 line_num = int(m.groups(1)[0])
6540 continue
6541 if ((line.startswith('+') and not line.startswith('++'))
6542 or (line.startswith('-') and not line.startswith('--'))):
6543 modified_lines.append((line_num, line))
Dominic Battre645d42342020-12-04 16:14:106544
Sam Maiera6e76d72022-02-11 21:43:506545 if not line.startswith('-'):
6546 line_num += 1
6547 return modified_lines
Dominic Battre645d42342020-12-04 16:14:106548
Sam Maiera6e76d72022-02-11 21:43:506549 def FindLineWith(lines, needle):
6550 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
Dominic Battre645d42342020-12-04 16:14:106551
Sam Maiera6e76d72022-02-11 21:43:506552 If 0 or >1 lines contain `needle`, -1 is returned.
6553 """
6554 matching_line_numbers = [
6555 # + 1 for 1-based counting of line numbers.
6556 i + 1 for i, line in enumerate(lines) if needle in line
6557 ]
6558 return matching_line_numbers[0] if len(
6559 matching_line_numbers) == 1 else -1
Dominic Battre645d42342020-12-04 16:14:106560
Sam Maiera6e76d72022-02-11 21:43:506561 def ModifiedPrefMigration(affected_file):
6562 """Returns whether the MigrateObsolete.*Pref functions were modified."""
6563 # Determine first and last lines of MigrateObsolete.*Pref functions.
6564 new_contents = affected_file.NewContents()
6565 range_1 = (FindLineWith(new_contents,
6566 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
6567 FindLineWith(new_contents,
6568 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
6569 range_2 = (FindLineWith(new_contents,
6570 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
6571 FindLineWith(new_contents,
6572 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
6573 if (-1 in range_1 + range_2):
6574 raise Exception(
6575 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.'
6576 )
Dominic Battre645d42342020-12-04 16:14:106577
Sam Maiera6e76d72022-02-11 21:43:506578 # Check whether any of the modified lines are part of the
6579 # MigrateObsolete.*Pref functions.
6580 for line_nr, line in ModifiedLines(affected_file):
6581 if (range_1[0] <= line_nr <= range_1[1]
6582 or range_2[0] <= line_nr <= range_2[1]):
6583 return True
6584 return False
Dominic Battre645d42342020-12-04 16:14:106585
Sam Maiera6e76d72022-02-11 21:43:506586 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
6587 browser_prefs_file_pattern = input_api.re.compile(
6588 r'chrome/browser/prefs/browser_prefs.cc')
Dominic Battre645d42342020-12-04 16:14:106589
Sam Maiera6e76d72022-02-11 21:43:506590 changes = input_api.AffectedFiles(include_deletes=True,
6591 file_filter=FilterFile)
6592 potential_problems = []
6593 for f in changes:
6594 for line in f.GenerateScmDiff().splitlines():
6595 # Check deleted lines for pref registrations.
6596 if (line.startswith('-') and not line.startswith('--')
6597 and register_pref_pattern.search(line)):
6598 potential_problems.append('%s: %s' % (f.LocalPath(), line))
Dominic Battre645d42342020-12-04 16:14:106599
Sam Maiera6e76d72022-02-11 21:43:506600 if browser_prefs_file_pattern.search(f.LocalPath()):
6601 # If the developer modified the MigrateObsolete.*Prefs() functions, we
6602 # assume that they knew that they have to deprecate preferences and don't
6603 # warn.
6604 try:
6605 if ModifiedPrefMigration(f):
6606 return []
6607 except Exception as e:
6608 return [output_api.PresubmitError(str(e))]
Dominic Battre645d42342020-12-04 16:14:106609
Sam Maiera6e76d72022-02-11 21:43:506610 if potential_problems:
6611 return [
6612 output_api.PresubmitPromptWarning(
6613 'Discovered possible removal of preference registrations.\n\n'
6614 'Please make sure to properly deprecate preferences by clearing their\n'
6615 'value for a couple of milestones before finally removing the code.\n'
6616 'Otherwise data may stay in the preferences files forever. See\n'
6617 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
6618 'chrome/browser/prefs/README.md for examples.\n'
6619 'This may be a false positive warning (e.g. if you move preference\n'
6620 'registrations to a different place).\n', potential_problems)
6621 ]
6622 return []
6623
Matt Stark6ef08872021-07-29 01:21:466624
6625def CheckConsistentGrdChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506626 """Changes to GRD files must be consistent for tools to read them."""
6627 changed_grds = input_api.AffectedFiles(
6628 include_deletes=False,
6629 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
6630 errors = []
6631 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
6632 for matcher, msg in _INVALID_GRD_FILE_LINE]
6633 for grd in changed_grds:
6634 for i, line in enumerate(grd.NewContents()):
6635 for matcher, msg in invalid_file_regexes:
6636 if matcher.search(line):
6637 errors.append(
6638 output_api.PresubmitError(
6639 'Problem on {grd}:{i} - {msg}'.format(
6640 grd=grd.LocalPath(), i=i + 1, msg=msg)))
6641 return errors
6642
Kevin McNee967dd2d22021-11-15 16:09:296643
Henrique Ferreiro2a4b55942021-11-29 23:45:366644def CheckAssertAshOnlyCode(input_api, output_api):
6645 """Errors if a BUILD.gn file in an ash/ directory doesn't include
6646 assert(is_chromeos_ash).
6647 """
6648
6649 def FileFilter(affected_file):
6650 """Includes directories known to be Ash only."""
6651 return input_api.FilterSourceFile(
6652 affected_file,
6653 files_to_check=(
6654 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
6655 r'.*/ash/.*BUILD\.gn'), # Any path component.
6656 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
6657
6658 errors = []
6659 pattern = input_api.re.compile(r'assert\(is_chromeos_ash')
Jameson Thies0ce669f2021-12-09 15:56:566660 for f in input_api.AffectedFiles(include_deletes=False,
6661 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:366662 if (not pattern.search(input_api.ReadFile(f))):
6663 errors.append(
6664 output_api.PresubmitError(
6665 'Please add assert(is_chromeos_ash) to %s. If that\'s not '
6666 'possible, please create and issue and add a comment such '
6667 'as:\n # TODO(https://crbug.com/XXX): add '
6668 'assert(is_chromeos_ash) when ...' % f.LocalPath()))
6669 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:276670
6671
6672def _IsRendererOnlyCppFile(input_api, affected_file):
Sam Maiera6e76d72022-02-11 21:43:506673 path = affected_file.LocalPath()
6674 if not _IsCPlusPlusFile(input_api, path):
6675 return False
6676
6677 # Any code under a "renderer" subdirectory is assumed to be Renderer-only.
6678 if "/renderer/" in path:
6679 return True
6680
6681 # Blink's public/web API is only used/included by Renderer-only code. Note
6682 # that public/platform API may be used in non-Renderer processes (e.g. there
6683 # are some includes in code used by Utility, PDF, or Plugin processes).
6684 if "/blink/public/web/" in path:
6685 return True
6686
6687 # We assume that everything else may be used outside of Renderer processes.
Lukasz Anforowicz7016d05e2021-11-30 03:56:276688 return False
6689
Lukasz Anforowicz7016d05e2021-11-30 03:56:276690# TODO(https://crbug.com/1273182): Remove these checks, once they are replaced
6691# by the Chromium Clang Plugin (which will be preferable because it will
6692# 1) report errors earlier - at compile-time and 2) cover more rules).
6693def CheckRawPtrUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:506694 """Rough checks that raw_ptr<T> usage guidelines are followed."""
6695 errors = []
6696 # The regex below matches "raw_ptr<" following a word boundary, but not in a
6697 # C++ comment.
6698 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
6699 file_filter = lambda f: _IsRendererOnlyCppFile(input_api, f)
6700 for f, line_num, line in input_api.RightHandSideLines(file_filter):
6701 if raw_ptr_matcher.search(line):
6702 errors.append(
6703 output_api.PresubmitError(
6704 'Problem on {path}:{line} - '\
6705 'raw_ptr<T> should not be used in Renderer-only code '\
6706 '(as documented in the "Pointers to unprotected memory" '\
6707 'section in //base/memory/raw_ptr.md)'.format(
6708 path=f.LocalPath(), line=line_num)))
6709 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:566710
6711
6712def CheckPythonShebang(input_api, output_api):
6713 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
6714 system-wide python.
6715 """
6716 errors = []
6717 sources = lambda affected_file: input_api.FilterSourceFile(
6718 affected_file,
6719 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
6720 r'third_party/blink/web_tests/external/') + input_api.
6721 DEFAULT_FILES_TO_SKIP),
6722 files_to_check=[r'.*\.py$'])
6723 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:276724 for line_num, line in f.ChangedContents():
6725 if line_num == 1 and line.startswith('#!/usr/bin/python'):
6726 errors.append(f.LocalPath())
6727 break
Henrique Ferreirof9819f2e32021-11-30 13:31:566728
6729 result = []
6730 for file in errors:
6731 result.append(
6732 output_api.PresubmitError(
6733 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
6734 file))
6735 return result
James Shen81cc0e22022-06-15 21:10:456736
6737
6738def CheckBatchAnnotation(input_api, output_api):
6739 """Checks that tests have either @Batch or @DoNotBatch annotation. If this
6740 is not an instrumentation test, disregard."""
6741
6742 batch_annotation = input_api.re.compile(r'^\s*@Batch')
6743 do_not_batch_annotation = input_api.re.compile(r'^\s*@DoNotBatch')
6744 robolectric_test = input_api.re.compile(r'[rR]obolectric')
6745 test_class_declaration = input_api.re.compile(r'^\s*public\sclass.*Test')
6746 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
Mark Schillaci8ef0d872023-07-18 22:07:596747 test_annotation_declaration = input_api.re.compile(r'^\s*public\s@interface\s.*{')
James Shen81cc0e22022-06-15 21:10:456748
ckitagawae8fd23b2022-06-17 15:29:386749 missing_annotation_errors = []
6750 extra_annotation_errors = []
James Shen81cc0e22022-06-15 21:10:456751
6752 def _FilterFile(affected_file):
6753 return input_api.FilterSourceFile(
6754 affected_file,
6755 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
6756 files_to_check=[r'.*Test\.java$'])
6757
6758 for f in input_api.AffectedSourceFiles(_FilterFile):
6759 batch_matched = None
6760 do_not_batch_matched = None
6761 is_instrumentation_test = True
Mark Schillaci8ef0d872023-07-18 22:07:596762 test_annotation_declaration_matched = None
James Shen81cc0e22022-06-15 21:10:456763 for line in f.NewContents():
6764 if robolectric_test.search(line) or uiautomator_test.search(line):
6765 # Skip Robolectric and UiAutomator tests.
6766 is_instrumentation_test = False
6767 break
6768 if not batch_matched:
6769 batch_matched = batch_annotation.search(line)
6770 if not do_not_batch_matched:
6771 do_not_batch_matched = do_not_batch_annotation.search(line)
6772 test_class_declaration_matched = test_class_declaration.search(
6773 line)
Mark Schillaci8ef0d872023-07-18 22:07:596774 test_annotation_declaration_matched = test_annotation_declaration.search(line)
6775 if test_class_declaration_matched or test_annotation_declaration_matched:
James Shen81cc0e22022-06-15 21:10:456776 break
Mark Schillaci8ef0d872023-07-18 22:07:596777 if test_annotation_declaration_matched:
6778 continue
James Shen81cc0e22022-06-15 21:10:456779 if (is_instrumentation_test and
6780 not batch_matched and
6781 not do_not_batch_matched):
Sam Maier4cef9242022-10-03 14:21:246782 missing_annotation_errors.append(str(f.LocalPath()))
ckitagawae8fd23b2022-06-17 15:29:386783 if (not is_instrumentation_test and
6784 (batch_matched or
6785 do_not_batch_matched)):
Sam Maier4cef9242022-10-03 14:21:246786 extra_annotation_errors.append(str(f.LocalPath()))
James Shen81cc0e22022-06-15 21:10:456787
6788 results = []
6789
ckitagawae8fd23b2022-06-17 15:29:386790 if missing_annotation_errors:
James Shen81cc0e22022-06-15 21:10:456791 results.append(
6792 output_api.PresubmitPromptWarning(
6793 """
Henrique Nakashimacb4c55a2023-01-30 20:09:096794Instrumentation tests should use either @Batch or @DoNotBatch. Use
6795@Batch(Batch.PER_CLASS) in most cases. Use @Batch(Batch.UNIT_TESTS) when tests
6796have no side-effects. If the tests are not safe to run in batch, please use
6797@DoNotBatch with reasons.
Jens Mueller2085ff82023-02-27 11:54:496798See https://source.chromium.org/chromium/chromium/src/+/main:docs/testing/batching_instrumentation_tests.md
ckitagawae8fd23b2022-06-17 15:29:386799""", missing_annotation_errors))
6800 if extra_annotation_errors:
6801 results.append(
6802 output_api.PresubmitPromptWarning(
6803 """
6804Robolectric tests do not need a @Batch or @DoNotBatch annotations.
6805""", extra_annotation_errors))
James Shen81cc0e22022-06-15 21:10:456806
6807 return results
Sam Maier4cef9242022-10-03 14:21:246808
6809
6810def CheckMockAnnotation(input_api, output_api):
6811 """Checks that we have annotated all Mockito.mock()-ed or Mockito.spy()-ed
6812 classes with @Mock or @Spy. If this is not an instrumentation test,
6813 disregard."""
6814
6815 # This is just trying to be approximately correct. We are not writing a
6816 # Java parser, so special cases like statically importing mock() then
6817 # calling an unrelated non-mockito spy() function will cause a false
6818 # positive.
6819 package_name = input_api.re.compile(r'^package\s+(\w+(?:\.\w+)+);')
6820 mock_static_import = input_api.re.compile(
6821 r'^import\s+static\s+org.mockito.Mockito.(?:mock|spy);')
6822 import_class = input_api.re.compile(r'import\s+((?:\w+\.)+)(\w+);')
6823 mock_annotation = input_api.re.compile(r'^\s*@(?:Mock|Spy)')
6824 field_type = input_api.re.compile(r'(\w+)(?:<\w+>)?\s+\w+\s*(?:;|=)')
6825 mock_or_spy_function_call = r'(?:mock|spy)\(\s*(?:new\s*)?(\w+)(?:\.class|\()'
6826 fully_qualified_mock_function = input_api.re.compile(
6827 r'Mockito\.' + mock_or_spy_function_call)
6828 statically_imported_mock_function = input_api.re.compile(
6829 r'\W' + mock_or_spy_function_call)
6830 robolectric_test = input_api.re.compile(r'[rR]obolectric')
6831 uiautomator_test = input_api.re.compile(r'[uU]i[aA]utomator')
6832
6833 def _DoClassLookup(class_name, class_name_map, package):
6834 found = class_name_map.get(class_name)
6835 if found is not None:
6836 return found
6837 else:
6838 return package + '.' + class_name
6839
6840 def _FilterFile(affected_file):
6841 return input_api.FilterSourceFile(
6842 affected_file,
6843 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
6844 files_to_check=[r'.*Test\.java$'])
6845
6846 mocked_by_function_classes = set()
6847 mocked_by_annotation_classes = set()
6848 class_to_filename = {}
6849 for f in input_api.AffectedSourceFiles(_FilterFile):
6850 mock_function_regex = fully_qualified_mock_function
6851 next_line_is_annotated = False
6852 fully_qualified_class_map = {}
6853 package = None
6854
6855 for line in f.NewContents():
6856 if robolectric_test.search(line) or uiautomator_test.search(line):
6857 # Skip Robolectric and UiAutomator tests.
6858 break
6859
6860 m = package_name.search(line)
6861 if m:
6862 package = m.group(1)
6863 continue
6864
6865 if mock_static_import.search(line):
6866 mock_function_regex = statically_imported_mock_function
6867 continue
6868
6869 m = import_class.search(line)
6870 if m:
6871 fully_qualified_class_map[m.group(2)] = m.group(1) + m.group(2)
6872 continue
6873
6874 if next_line_is_annotated:
6875 next_line_is_annotated = False
6876 fully_qualified_class = _DoClassLookup(
6877 field_type.search(line).group(1), fully_qualified_class_map,
6878 package)
6879 mocked_by_annotation_classes.add(fully_qualified_class)
6880 continue
6881
6882 if mock_annotation.search(line):
6883 next_line_is_annotated = True
6884 continue
6885
6886 m = mock_function_regex.search(line)
6887 if m:
6888 fully_qualified_class = _DoClassLookup(m.group(1),
6889 fully_qualified_class_map, package)
6890 # Skipping builtin classes, since they don't get optimized.
6891 if fully_qualified_class.startswith(
6892 'android.') or fully_qualified_class.startswith(
6893 'java.'):
6894 continue
6895 class_to_filename[fully_qualified_class] = str(f.LocalPath())
6896 mocked_by_function_classes.add(fully_qualified_class)
6897
6898 results = []
6899 missed_classes = mocked_by_function_classes - mocked_by_annotation_classes
6900 if missed_classes:
6901 error_locations = []
6902 for c in missed_classes:
6903 error_locations.append(c + ' in ' + class_to_filename[c])
6904 results.append(
6905 output_api.PresubmitPromptWarning(
6906 """
6907Mockito.mock()/spy() cause issues with our Java optimizer. You have 3 options:
69081) If the mocked variable can be a class member, annotate the member with
6909 @Mock/@Spy.
69102) If the mocked variable cannot be a class member, create a dummy member
6911 variable of that type, annotated with @Mock/@Spy. This dummy does not need
6912 to be used or initialized in any way.
69133) If the mocked type is definitely not going to be optimized, whether it's a
6914 builtin type which we don't ship, or a class you know R8 will treat
6915 specially, you can ignore this warning.
6916""", error_locations))
6917
6918 return results
Mike Dougherty1b8be712022-10-20 00:15:136919
6920def CheckNoJsInIos(input_api, output_api):
6921 """Checks to make sure that JavaScript files are not used on iOS."""
6922
6923 def _FilterFile(affected_file):
6924 return input_api.FilterSourceFile(
6925 affected_file,
6926 files_to_skip=input_api.DEFAULT_FILES_TO_SKIP +
Mike Dougherty7bc8a812023-05-02 06:55:216927 (r'^ios/third_party/*', r'^ios/tools/*', r'^third_party/*'),
Mike Dougherty1b8be712022-10-20 00:15:136928 files_to_check=[r'^ios/.*\.js$', r'.*/ios/.*\.js$'])
6929
Mike Dougherty4d1050b2023-03-14 15:59:536930 deleted_files = []
6931
6932 # Collect filenames of all removed JS files.
6933 for f in input_api.AffectedSourceFiles(_FilterFile):
6934 local_path = f.LocalPath()
6935
6936 if input_api.os_path.splitext(local_path)[1] == '.js' and f.Action() == 'D':
6937 deleted_files.append(input_api.os_path.basename(local_path))
6938
Mike Dougherty1b8be712022-10-20 00:15:136939 error_paths = []
Mike Dougherty4d1050b2023-03-14 15:59:536940 moved_paths = []
Mike Dougherty1b8be712022-10-20 00:15:136941 warning_paths = []
6942
6943 for f in input_api.AffectedSourceFiles(_FilterFile):
6944 local_path = f.LocalPath()
6945
6946 if input_api.os_path.splitext(local_path)[1] == '.js':
6947 if f.Action() == 'A':
Mike Dougherty4d1050b2023-03-14 15:59:536948 if input_api.os_path.basename(local_path) in deleted_files:
6949 # This script was probably moved rather than newly created.
6950 # Present a warning instead of an error for these cases.
6951 moved_paths.append(local_path)
6952 else:
6953 error_paths.append(local_path)
Mike Dougherty1b8be712022-10-20 00:15:136954 elif f.Action() != 'D':
6955 warning_paths.append(local_path)
6956
6957 results = []
6958
6959 if warning_paths:
6960 results.append(output_api.PresubmitPromptWarning(
6961 'TypeScript is now fully supported for iOS feature scripts. '
6962 'Consider converting JavaScript files to TypeScript. See '
6963 '//ios/web/public/js_messaging/README.md for more details.',
6964 warning_paths))
6965
Mike Dougherty4d1050b2023-03-14 15:59:536966 if moved_paths:
6967 results.append(output_api.PresubmitPromptWarning(
6968 'Do not use JavaScript on iOS for new files as TypeScript is '
6969 'fully supported. (If this is a moved file, you may leave the '
6970 'script unconverted.) See //ios/web/public/js_messaging/README.md '
6971 'for help using scripts on iOS.', moved_paths))
6972
Mike Dougherty1b8be712022-10-20 00:15:136973 if error_paths:
6974 results.append(output_api.PresubmitError(
6975 'Do not use JavaScript on iOS as TypeScript is fully supported. '
6976 'See //ios/web/public/js_messaging/README.md for help using '
6977 'scripts on iOS.', error_paths))
6978
6979 return results
Hans Wennborg23a81d52023-03-24 16:38:136980
6981def CheckLibcxxRevisionsMatch(input_api, output_api):
6982 """Check to make sure the libc++ version matches across deps files."""
Andrew Grieve21bb6792023-03-27 19:06:486983 # Disable check for changes to sub-repositories.
6984 if input_api.PresubmitLocalPath() != input_api.change.RepositoryRoot():
Sam Maierb926c58c2023-08-08 19:58:256985 return []
Hans Wennborg23a81d52023-03-24 16:38:136986
6987 DEPS_FILES = [ 'DEPS', 'buildtools/deps_revisions.gni' ]
6988
6989 file_filter = lambda f: f.LocalPath().replace(
6990 input_api.os_path.sep, '/') in DEPS_FILES
6991 changed_deps_files = input_api.AffectedFiles(file_filter=file_filter)
6992 if not changed_deps_files:
6993 return []
6994
6995 def LibcxxRevision(file):
6996 file = input_api.os_path.join(input_api.PresubmitLocalPath(),
6997 *file.split('/'))
6998 return input_api.re.search(
6999 r'libcxx_revision.*[:=].*[\'"](\w+)[\'"]',
7000 input_api.ReadFile(file)).group(1)
7001
7002 if len(set([LibcxxRevision(f) for f in DEPS_FILES])) == 1:
7003 return []
7004
7005 return [output_api.PresubmitError(
7006 'libcxx_revision not equal across %s' % ', '.join(DEPS_FILES),
7007 changed_deps_files)]